From c3acb824648e93d616c7b901b6a101a5aa12b93b Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Thu, 31 Aug 2023 12:59:54 -0500 Subject: [PATCH 01/16] Upgrade Prettier to v3.0.3 --- package.json | 4 +- yarn.lock | 226 +++++++++++++++++++++++++++++++++------------------ 2 files changed, 149 insertions(+), 81 deletions(-) diff --git a/package.json b/package.json index f5883a6..248a78b 100644 --- a/package.json +++ b/package.json @@ -19,9 +19,9 @@ }, "license": "Unlicense", "dependencies": { + "@noble/ciphers": "^0.2.0", "@noble/curves": "1.1.0", "@noble/hashes": "1.3.1", - "@noble/ciphers": "^0.2.0", "@scure/base": "1.1.1", "@scure/bip32": "1.3.1", "@scure/bip39": "1.2.1" @@ -53,7 +53,7 @@ "events": "^3.3.0", "jest": "^29.5.0", "node-fetch": "^2.6.9", - "prettier": "^2.8.4", + "prettier": "^3.0.3", "ts-jest": "^29.1.0", "tsd": "^0.22.0", "typescript": "^5.0.4", diff --git a/yarn.lock b/yarn.lock index a196183..a15cc89 100644 --- a/yarn.lock +++ b/yarn.lock @@ -22,7 +22,7 @@ resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.7.tgz" integrity sha512-KYMqFYTaenzMK4yUtf4EW9wc4N9ef80FsbMtkwool5zpwl4YrT1SdWYSTRcT94KO4hannogdS+LxY7L+arP3gA== -"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.8.0", "@babel/core@>=7.0.0-beta.0 <8": +"@babel/core@^7.11.6", "@babel/core@^7.12.3": version "7.21.8" resolved "https://registry.npmjs.org/@babel/core/-/core-7.21.8.tgz" integrity sha512-YeM22Sondbo523Sz0+CirSPnbj9bG3P0CdHcBZdqUuaeOaYEFbOLoGU7lebvGP6P5J/WE9wOn7u7C4J9HvS1xQ== @@ -299,11 +299,116 @@ resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== +"@esbuild/android-arm64@0.16.9": + version "0.16.9" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.16.9.tgz#474da719599f99d820ec010c92846a4f685fa28a" + integrity sha512-ndIAZJUeLx4O+4AJbFQCurQW4VRUXjDsUvt1L+nP8bVELOWdmdCEOtlIweCUE6P+hU0uxYbEK2AEP0n5IVQvhg== + +"@esbuild/android-arm@0.16.9": + version "0.16.9" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.16.9.tgz#b0747ec074bba3ca652bfa8de3f55acfbb2d259e" + integrity sha512-kW5ccqWHVOOTGUkkJbtfoImtqu3kA1PFkivM+9QPFSHphPfPBlBalX9eDRqPK+wHCqKhU48/78T791qPgC9e9A== + +"@esbuild/android-x64@0.16.9": + version "0.16.9" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.16.9.tgz#1cd75e8ed7d6d7eb5f9896f623df63882bd8e887" + integrity sha512-UbMcJB4EHrAVOnknQklREPgclNU2CPet2h+sCBCXmF2mfoYWopBn/CfTfeyOkb/JglOcdEADqAljFndMKnFtOw== + "@esbuild/darwin-arm64@0.16.9": version "0.16.9" resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.9.tgz" integrity sha512-d7D7/nrt4CxPul98lx4PXhyNZwTYtbdaHhOSdXlZuu5zZIznjqtMqLac8Bv+IuT6SVHiHUwrkL6ywD7mOgLW+A== +"@esbuild/darwin-x64@0.16.9": + version "0.16.9" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.16.9.tgz#5a19c00781595e0dfeef1826b3512d04c37b98ff" + integrity sha512-LZc+Wlz06AkJYtwWsBM3x2rSqTG8lntDuftsUNQ3fCx9ZttYtvlDcVtgb+NQ6t9s6K5No5zutN3pcjZEC2a4iQ== + +"@esbuild/freebsd-arm64@0.16.9": + version "0.16.9" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.9.tgz#2b7c16f5d15c259ed279b293b97c28c4a4bb107f" + integrity sha512-gIj0UQZlQo93CHYouHKkpzP7AuruSaMIm1etcWIxccFEVqCN1xDr6BWlN9bM+ol/f0W9w3hx3HDuEwcJVtGneQ== + +"@esbuild/freebsd-x64@0.16.9": + version "0.16.9" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.16.9.tgz#2db48ffeeab149c2b970494a60b82bf3004b8630" + integrity sha512-GNors4vaMJ7lzGOuhzNc7jvgsQZqErGA8rsW+nck8N1nYu86CvsJW2seigVrQQWOV4QzEP8Zf3gm+QCjA2hnBQ== + +"@esbuild/linux-arm64@0.16.9": + version "0.16.9" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.16.9.tgz#4c63c9f8ddd690d140ac3e0f360226d3fcdd75d8" + integrity sha512-YPxQunReYp8RQ1FvexFrOEqqf+nLbS3bKVZF5FRT2uKM7Wio7BeATqAwO02AyrdSEntt3I5fhFsujUChIa8CZg== + +"@esbuild/linux-arm@0.16.9": + version "0.16.9" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.16.9.tgz#7704de1c2a30bc68d8f615d3ecb1cf68f001256a" + integrity sha512-cNx1EF99c2t1Ztn0lk9N+MuwBijGF8mH6nx9GFsB3e0lpUpPkCE/yt5d+7NP9EwJf5uzqdjutgVYoH1SNqzudA== + +"@esbuild/linux-ia32@0.16.9": + version "0.16.9" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.16.9.tgz#bf0fda9f046e6c8332d7c8350b8a94d63acb4ceb" + integrity sha512-zb12ixDIKNwFpIqR00J88FFitVwOEwO78EiUi8wi8FXlmSc3GtUuKV/BSO+730Kglt0B47+ZrJN1BhhOxZaVrw== + +"@esbuild/linux-loong64@0.16.9": + version "0.16.9" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.16.9.tgz#c16378b898fa38f5f788f76fbce16a45c49c8793" + integrity sha512-X8te4NLxtHiNT6H+4Pfm5RklzItA1Qy4nfyttihGGX+Koc53Ar20ViC+myY70QJ8PDEOehinXZj/F7QK3A+MKQ== + +"@esbuild/linux-mips64el@0.16.9": + version "0.16.9" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.16.9.tgz#492605f13f19dc06c350d94e4048c21478b9dec4" + integrity sha512-ZqyMDLt02c5smoS3enlF54ndK5zK4IpClLTxF0hHfzHJlfm4y8IAkIF8LUW0W7zxcKy7oAwI7BRDqeVvC120SA== + +"@esbuild/linux-ppc64@0.16.9": + version "0.16.9" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.16.9.tgz#ccaf759fc4f7a5fe72bdac05b4f5bf18ef1fe01b" + integrity sha512-k+ca5W5LDBEF3lfDwMV6YNXwm4wEpw9krMnNvvlNz3MrKSD2Eb2c861O0MaKrZkG/buTQAP4vkavbLwgIe6xjg== + +"@esbuild/linux-riscv64@0.16.9": + version "0.16.9" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.16.9.tgz#542d0e68bc99fb658fe732b0917931c09775f1a3" + integrity sha512-GuInVdogjmg9DhgkEmNipHkC+3tzkanPJzgzTC2ihsvrruLyFoR1YrTGixblNSMPudQLpiqkcwGwwe0oqfrvfA== + +"@esbuild/linux-s390x@0.16.9": + version "0.16.9" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.16.9.tgz#4398f9d9d64dba4cfa6eed267476eaa9c9b7f214" + integrity sha512-49wQ0aYkvwXonGsxc7LuuLNICMX8XtO92Iqmug5Qau0kpnV6SP34jk+jIeu4suHwAbSbRhVFtDv75yRmyfQcHw== + +"@esbuild/linux-x64@0.16.9": + version "0.16.9" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.16.9.tgz#67c6b418ef36addbca17af0d7a2274c37ddffba2" + integrity sha512-Nx4oKEAJ6EcQlt4dK7qJyuZUoXZG7CAeY22R7rqZijFzwFfMOD+gLP56uV7RrV86jGf8PeRY8TBsRmOcZoG42w== + +"@esbuild/netbsd-x64@0.16.9": + version "0.16.9" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.16.9.tgz#22ed58e404ebeb2475b821bc4e25f1027eb0c912" + integrity sha512-d0WnpgJ+FTiMZXEQ1NOv9+0gvEhttbgKEvVqWWAtl1u9AvlspKXbodKHzQ5MLP6YV1y52Xp+p8FMYqj8ykTahg== + +"@esbuild/openbsd-x64@0.16.9": + version "0.16.9" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.16.9.tgz#2b2597b4edd4d26946f7c56838680fbeb4d455eb" + integrity sha512-jccK11278dvEscHFfMk5EIPjF4wv1qGD0vps7mBV1a6TspdR36O28fgPem/SA/0pcsCPHjww5ouCLwP+JNAFlw== + +"@esbuild/sunos-x64@0.16.9": + version "0.16.9" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.16.9.tgz#c132603a19ef79c0d7bd95afb09f41618ea8dda2" + integrity sha512-OetwTSsv6mIDLqN7I7I2oX9MmHGwG+AP+wKIHvq+6sIHwcPPJqRx+DJB55jy9JG13CWcdcQno/7V5MTJ5a0xfQ== + +"@esbuild/win32-arm64@0.16.9": + version "0.16.9" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.16.9.tgz#bf74d007d7f0fe1fe32c4fff82d27b271b3e1d58" + integrity sha512-tKSSSK6unhxbGbHg+Cc+JhRzemkcsX0tPBvG0m5qsWbkShDK9c+/LSb13L18LWVdOQZwuA55Vbakxmt6OjBDOQ== + +"@esbuild/win32-ia32@0.16.9": + version "0.16.9" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.16.9.tgz#e46478e77431bca1a8b80f6260fc6b0020aa8127" + integrity sha512-ZTQ5vhNS5gli0KK8I6/s6+LwXmNEfq1ftjnSVyyNm33dBw8zDpstqhGXYUbZSWWLvkqiRRjgxgmoncmi6Yy7Ng== + +"@esbuild/win32-x64@0.16.9": + version "0.16.9" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.16.9.tgz#4595a29c2930c5157aa1be0963abbbac989647c9" + integrity sha512-C4ZX+YFIp6+lPrru3tpH6Gaapy8IBRHw/e7l63fzGDhn/EaiGpQgbIlT5paByyy+oMvRFQoxxyvC4LE0AjJMqQ== + "@eslint-community/eslint-utils@^4.2.0": version "4.4.0" resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz" @@ -551,7 +656,7 @@ slash "^3.0.0" write-file-atomic "^4.0.2" -"@jest/types@^29.0.0", "@jest/types@^29.5.0": +"@jest/types@^29.5.0": version "29.5.0" resolved "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz" integrity sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog== @@ -582,16 +687,16 @@ resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz" integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== -"@jridgewell/sourcemap-codec@^1.4.10": - version "1.4.15" - resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz" - integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== - "@jridgewell/sourcemap-codec@1.4.14": version "1.4.14" resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.15" + resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + "@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.15", "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": version "0.3.18" resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz" @@ -605,14 +710,14 @@ resolved "https://registry.npmjs.org/@noble/ciphers/-/ciphers-0.2.0.tgz" integrity sha512-6YBxJDAapHSdd3bLDv6x2wRPwq4QFMUaB3HvljNBUTThDd12eSm7/3F+2lnfzx2jvM+S6Nsy0jEt9QbPqSwqRw== -"@noble/curves@~1.1.0", "@noble/curves@1.1.0": +"@noble/curves@1.1.0", "@noble/curves@~1.1.0": version "1.1.0" resolved "https://registry.npmjs.org/@noble/curves/-/curves-1.1.0.tgz" integrity sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA== dependencies: "@noble/hashes" "1.3.1" -"@noble/hashes@~1.3.0", "@noble/hashes@~1.3.1", "@noble/hashes@1.3.1": +"@noble/hashes@1.3.1", "@noble/hashes@~1.3.0", "@noble/hashes@~1.3.1": version "1.3.1" resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz" integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA== @@ -625,7 +730,7 @@ "@nodelib/fs.stat" "2.0.5" run-parallel "^1.1.9" -"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": version "2.0.5" resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== @@ -638,7 +743,7 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@scure/base@~1.1.0", "@scure/base@1.1.1": +"@scure/base@1.1.1", "@scure/base@~1.1.0": version "1.1.1" resolved "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz" integrity sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA== @@ -819,7 +924,7 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^5.0.0", "@typescript-eslint/eslint-plugin@^5.51.0": +"@typescript-eslint/eslint-plugin@^5.51.0": version "5.59.2" resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.2.tgz" integrity sha512-yVrXupeHjRxLDcPKL10sGQ/QlVrA8J5IYOEWVqk0lJaSZP7X5DfnP7Ns3cc74/blmbipQ1htFNVGsHX6wsYm0A== @@ -835,7 +940,7 @@ semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/parser@^5.0.0", "@typescript-eslint/parser@^5.51.0": +"@typescript-eslint/parser@^5.51.0": version "5.59.2" resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.2.tgz" integrity sha512-uq0sKyw6ao1iFOZZGk9F8Nro/8+gfB5ezl1cA06SrqbgJAt0SRoFhb9pXaHvkrxUpZaoLxt8KlovHNk8Gp6/HQ== @@ -881,7 +986,7 @@ semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/utils@^5.10.0", "@typescript-eslint/utils@5.59.2": +"@typescript-eslint/utils@5.59.2", "@typescript-eslint/utils@^5.10.0": version "5.59.2" resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.2.tgz" integrity sha512-kSuF6/77TZzyGPhGO4uVp+f0SBoYxCDf+lW3GKhtKru/L8k/Hd7NFQxyWUeY7Z/KGB2C6Fe3yf2vVi4V9TsCSQ== @@ -908,7 +1013,7 @@ acorn-jsx@^5.3.2: resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.8.0: +acorn@^8.8.0: version "8.8.2" resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz" integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== @@ -1002,7 +1107,7 @@ available-typed-arrays@^1.0.5: resolved "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz" integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== -babel-jest@^29.0.0, babel-jest@^29.5.0: +babel-jest@^29.5.0: version "29.5.0" resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz" integrity sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q== @@ -1082,7 +1187,7 @@ braces@^3.0.2: dependencies: fill-range "^7.0.1" -browserslist@^4.21.3, "browserslist@>= 4.21.0": +browserslist@^4.21.3: version "4.21.5" resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz" integrity sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w== @@ -1155,16 +1260,7 @@ caniuse-lite@^1.0.30001449: resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001486.tgz" integrity sha512-uv7/gXuHi10Whlj0pp5q/tsK/32J2QSqVRKQhs2j8VsDCjgyruAh/eEXHF822VqO9yT6iZKw3nRwZRSPBE9OQg== -chalk@^2.0.0: - version "2.4.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^2.4.1: +chalk@^2.0.0, chalk@^2.4.1: version "2.4.2" resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -1229,16 +1325,16 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - color-name@1.1.3: version "1.1.3" resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" @@ -1251,12 +1347,7 @@ concat-map@0.0.1: resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -convert-source-map@^1.6.0: - version "1.9.0" - resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz" - integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== - -convert-source-map@^1.7.0: +convert-source-map@^1.6.0, convert-source-map@^1.7.0: version "1.9.0" resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz" integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== @@ -1293,7 +1384,7 @@ cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" -d@^1.0.1, d@1: +d@1, d@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/d/-/d-1.0.1.tgz" integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== @@ -1598,7 +1689,7 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1: resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz" integrity sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA== -eslint@*, "eslint@^6.0.0 || ^7.0.0 || ^8.0.0", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", "eslint@^7.0.0 || ^8.0.0", eslint@^8.40.0, eslint@>=4.0.0: +eslint@^8.40.0: version "8.40.0" resolved "https://registry.npmjs.org/eslint/-/eslint-8.40.0.tgz" integrity sha512-bvR+TsP9EHL3TqNtj9sCNJVAFK3fBN8Q7g5waghxyRsPLIMwL73XSKnZFK0hk/O2ANC+iAoq6PWMQ+IfBAJIiQ== @@ -1687,12 +1778,7 @@ estraverse@^4.1.1: resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== -estraverse@^5.1.0: - version "5.3.0" - resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" - integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== - -estraverse@^5.2.0: +estraverse@^5.1.0, estraverse@^5.2.0: version "5.3.0" resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== @@ -1761,7 +1847,7 @@ fast-glob@^3.2.9: merge2 "^1.3.0" micromatch "^4.0.4" -fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0, fast-json-stable-stringify@2.x: +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -1799,15 +1885,7 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" -find-up@^4.0.0: - version "4.1.0" - resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz" - integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== - dependencies: - locate-path "^5.0.0" - path-exists "^4.0.0" - -find-up@^4.1.0: +find-up@^4.0.0, find-up@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz" integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== @@ -2534,7 +2612,7 @@ jest-resolve-dependencies@^29.5.0: jest-regex-util "^29.4.3" jest-snapshot "^29.5.0" -jest-resolve@*, jest-resolve@^29.5.0: +jest-resolve@^29.5.0: version "29.5.0" resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz" integrity sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w== @@ -2681,7 +2759,7 @@ jest-worker@^29.5.0: merge-stream "^2.0.0" supports-color "^8.0.0" -jest@^29.0.0, jest@^29.5.0: +jest@^29.5.0: version "29.5.0" resolved "https://registry.npmjs.org/jest/-/jest-29.5.0.tgz" integrity sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ== @@ -3222,10 +3300,10 @@ prelude-ls@^1.2.1: resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -prettier@^2.8.4: - version "2.8.8" - resolved "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz" - integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== +prettier@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.0.3.tgz#432a51f7ba422d1469096c0fdc28e235db8f9643" + integrity sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg== pretty-format@^29.0.0, pretty-format@^29.5.0: version "29.5.0" @@ -3378,32 +3456,22 @@ safe-regex-test@^1.0.0: get-intrinsic "^1.1.3" is-regex "^1.1.4" -semver@^5.5.0: +"semver@2 || 3 || 4 || 5", semver@^5.5.0: version "5.7.1" resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@^6.0.0: - version "6.3.0" - resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - -semver@^6.3.0: - version "6.3.0" - resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - -semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@7.x: +semver@7.x, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8: version "7.5.0" resolved "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz" integrity sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA== dependencies: lru-cache "^6.0.0" -"semver@2 || 3 || 4 || 5": - version "5.7.1" - resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== +semver@^6.0.0, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== shebang-command@^1.2.0: version "1.2.0" @@ -3777,7 +3845,7 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" -typescript@^5.0.2, typescript@^5.0.4, "typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta", "typescript@>=4.3 <6": +typescript@^5.0.2, typescript@^5.0.4: version "5.0.4" resolved "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz" integrity sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw== From 470512bbeb1b145318390368b1fcf814301ece95 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Thu, 31 Aug 2023 13:00:50 -0500 Subject: [PATCH 02/16] prettier: increase printWidth, enable bracketSpacing, alphabetize --- .prettierrc.yaml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.prettierrc.yaml b/.prettierrc.yaml index 16c878e..b49424d 100644 --- a/.prettierrc.yaml +++ b/.prettierrc.yaml @@ -1,10 +1,9 @@ -semi: false arrowParens: avoid +bracketSpacing: true insertPragma: false -printWidth: 80 +printWidth: 120 proseWrap: preserve +semi: false singleQuote: true -trailingComma: none +trailingComma: all useTabs: false -jsxBracketSameLine: false -bracketSpacing: false From c6133f716007602b3a8f18330f19d66989ae663b Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Thu, 31 Aug 2023 13:14:16 -0500 Subject: [PATCH 03/16] ci: run prettier on every commit --- .github/workflows/test.yml | 9 +++++++++ justfile | 3 +++ 2 files changed, 12 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5273edb..8dc95f5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,3 +16,12 @@ jobs: - uses: extractions/setup-just@v1 - run: just install-dependencies - run: just test + format: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 18 + - run: just install-dependencies + - run: just format-check \ No newline at end of file diff --git a/justfile b/justfile index 4cd5b48..c3907ff 100644 --- a/justfile +++ b/justfile @@ -21,3 +21,6 @@ publish: build emit-types format: prettier --plugin-search-dir . --write . + +format-check: + prettier --plugin-search-dir . --check . \ No newline at end of file From 350951b88e03d9827173139ad0be9c2b68b0ae62 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Thu, 31 Aug 2023 13:21:10 -0500 Subject: [PATCH 04/16] Add eslint to `just lint` --- .github/workflows/test.yml | 2 +- justfile | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8dc95f5..5e8d8ce 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,4 +24,4 @@ jobs: with: node-version: 18 - run: just install-dependencies - - run: just format-check \ No newline at end of file + - run: just lint \ No newline at end of file diff --git a/justfile b/justfile index c3907ff..3490084 100644 --- a/justfile +++ b/justfile @@ -22,5 +22,6 @@ publish: build emit-types format: prettier --plugin-search-dir . --write . -format-check: +lint: + eslint --ext .ts . prettier --plugin-search-dir . --check . \ No newline at end of file From fa085367c90d1194aad0f7c3943f9ec3ca1623cb Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Thu, 31 Aug 2023 13:22:43 -0500 Subject: [PATCH 05/16] Add eslint to `just format` --- justfile | 1 + 1 file changed, 1 insertion(+) diff --git a/justfile b/justfile index 3490084..0db18fd 100644 --- a/justfile +++ b/justfile @@ -20,6 +20,7 @@ publish: build emit-types npm publish format: + eslint --ext .ts --fix . prettier --plugin-search-dir . --write . lint: From 864dd28b2611c2ebfe2cc550a7eb70c821c2af00 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Thu, 31 Aug 2023 13:25:30 -0500 Subject: [PATCH 06/16] justfile: improve lint/format commands --- justfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/justfile b/justfile index 0db18fd..386bdee 100644 --- a/justfile +++ b/justfile @@ -21,8 +21,8 @@ publish: build emit-types format: eslint --ext .ts --fix . - prettier --plugin-search-dir . --write . + prettier --write . lint: eslint --ext .ts . - prettier --plugin-search-dir . --check . \ No newline at end of file + prettier --check . \ No newline at end of file From 48cb9046c4a0582668e167dd5b5314875157bc1d Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Thu, 31 Aug 2023 13:27:28 -0500 Subject: [PATCH 07/16] Add eslint-config-prettier to solve conflicts between prettier and eslint --- .eslintrc.json | 1 + package.json | 1 + yarn.lock | 5 +++++ 3 files changed, 7 insertions(+) diff --git a/.eslintrc.json b/.eslintrc.json index 385516f..1542d93 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,5 +1,6 @@ { "root": true, + "extends": ["prettier"], "parser": "@typescript-eslint/parser", "plugins": ["@typescript-eslint", "babel"], diff --git a/package.json b/package.json index 248a78b..064cd0f 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "esbuild": "0.16.9", "esbuild-plugin-alias": "^0.2.1", "eslint": "^8.40.0", + "eslint-config-prettier": "^9.0.0", "eslint-plugin-babel": "^5.3.1", "eslint-plugin-jest": "^27.2.1", "esm-loader-typescript": "^1.0.3", diff --git a/yarn.lock b/yarn.lock index a15cc89..163c523 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1630,6 +1630,11 @@ escape-string-regexp@^4.0.0: resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== +eslint-config-prettier@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz#eb25485946dd0c66cd216a46232dc05451518d1f" + integrity sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw== + eslint-formatter-pretty@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/eslint-formatter-pretty/-/eslint-formatter-pretty-4.1.0.tgz" From 918d514a258a8189a9d5565650857acef91f6611 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Thu, 31 Aug 2023 13:37:45 -0500 Subject: [PATCH 08/16] Upgrade all eslint deps --- package.json | 8 +- yarn.lock | 281 +++++++++++++++++++++++++++++++-------------------- 2 files changed, 176 insertions(+), 113 deletions(-) diff --git a/package.json b/package.json index 064cd0f..cd5f7e1 100644 --- a/package.json +++ b/package.json @@ -42,14 +42,14 @@ "@types/jest": "^29.5.1", "@types/node": "^18.13.0", "@types/node-fetch": "^2.6.3", - "@typescript-eslint/eslint-plugin": "^5.51.0", - "@typescript-eslint/parser": "^5.51.0", + "@typescript-eslint/eslint-plugin": "^6.5.0", + "@typescript-eslint/parser": "^6.5.0", "esbuild": "0.16.9", "esbuild-plugin-alias": "^0.2.1", - "eslint": "^8.40.0", + "eslint": "^8.48.0", "eslint-config-prettier": "^9.0.0", "eslint-plugin-babel": "^5.3.1", - "eslint-plugin-jest": "^27.2.1", + "eslint-plugin-jest": "^27.2.3", "esm-loader-typescript": "^1.0.3", "events": "^3.3.0", "jest": "^29.5.0", diff --git a/yarn.lock b/yarn.lock index 163c523..c6aa6e6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,11 @@ # yarn lockfile v1 +"@aashutoshrathi/word-wrap@^1.2.3": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" + integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== + "@ampproject/remapping@^2.2.0": version "2.2.1" resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz" @@ -409,26 +414,26 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.16.9.tgz#4595a29c2930c5157aa1be0963abbbac989647c9" integrity sha512-C4ZX+YFIp6+lPrru3tpH6Gaapy8IBRHw/e7l63fzGDhn/EaiGpQgbIlT5paByyy+oMvRFQoxxyvC4LE0AjJMqQ== -"@eslint-community/eslint-utils@^4.2.0": +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" - resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== dependencies: eslint-visitor-keys "^3.3.0" -"@eslint-community/regexpp@^4.4.0": - version "4.5.1" - resolved "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz" - integrity sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ== +"@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1": + version "4.8.0" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.8.0.tgz#11195513186f68d42fbf449f9a7136b2c0c92005" + integrity sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg== -"@eslint/eslintrc@^2.0.3": - version "2.0.3" - resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz" - integrity sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ== +"@eslint/eslintrc@^2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.2.tgz#c6936b4b328c64496692f76944e755738be62396" + integrity sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g== dependencies: ajv "^6.12.4" debug "^4.3.2" - espree "^9.5.2" + espree "^9.6.0" globals "^13.19.0" ignore "^5.2.0" import-fresh "^3.2.1" @@ -436,15 +441,15 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.40.0": - version "8.40.0" - resolved "https://registry.npmjs.org/@eslint/js/-/js-8.40.0.tgz" - integrity sha512-ElyB54bJIhXQYVKjDSvCkPO1iU1tSAeVQJbllWJq1XQSmmA4dgFk8CbiBGpiOPxleE48vDogxCtmMYku4HSVLA== +"@eslint/js@8.48.0": + version "8.48.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.48.0.tgz#642633964e217905436033a2bd08bf322849b7fb" + integrity sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw== -"@humanwhocodes/config-array@^0.11.8": - version "0.11.8" - resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz" - integrity sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g== +"@humanwhocodes/config-array@^0.11.10": + version "0.11.11" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.11.tgz#88a04c570dbbc7dd943e4712429c3df09bc32844" + integrity sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA== dependencies: "@humanwhocodes/object-schema" "^1.2.1" debug "^4.1.1" @@ -874,6 +879,11 @@ resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz" integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== +"@types/json-schema@^7.0.12": + version "7.0.12" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb" + integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA== + "@types/minimist@^1.2.0": version "1.2.2" resolved "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz" @@ -907,6 +917,11 @@ resolved "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz" integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw== +"@types/semver@^7.5.0": + version "7.5.1" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.1.tgz#0480eeb7221eb9bc398ad7432c9d7e14b1a5a367" + integrity sha512-cJRQXpObxfNKkFAZbJl2yjWtJCqELQIdShsogr1d2MilP8dKD9TE/nEKHkJgUNHdGKCQaf9HbIynuV2csLGVLg== + "@types/stack-utils@^2.0.0": version "2.0.1" resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz" @@ -924,30 +939,32 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^5.51.0": - version "5.59.2" - resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.2.tgz" - integrity sha512-yVrXupeHjRxLDcPKL10sGQ/QlVrA8J5IYOEWVqk0lJaSZP7X5DfnP7Ns3cc74/blmbipQ1htFNVGsHX6wsYm0A== +"@typescript-eslint/eslint-plugin@^6.5.0": + version "6.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.5.0.tgz#5cee33edf0d45d5ec773e3b3111206b098ac8599" + integrity sha512-2pktILyjvMaScU6iK3925uvGU87E+N9rh372uGZgiMYwafaw9SXq86U04XPq3UH6tzRvNgBsub6x2DacHc33lw== dependencies: - "@eslint-community/regexpp" "^4.4.0" - "@typescript-eslint/scope-manager" "5.59.2" - "@typescript-eslint/type-utils" "5.59.2" - "@typescript-eslint/utils" "5.59.2" + "@eslint-community/regexpp" "^4.5.1" + "@typescript-eslint/scope-manager" "6.5.0" + "@typescript-eslint/type-utils" "6.5.0" + "@typescript-eslint/utils" "6.5.0" + "@typescript-eslint/visitor-keys" "6.5.0" debug "^4.3.4" - grapheme-splitter "^1.0.4" - ignore "^5.2.0" - natural-compare-lite "^1.4.0" - semver "^7.3.7" - tsutils "^3.21.0" + graphemer "^1.4.0" + ignore "^5.2.4" + natural-compare "^1.4.0" + semver "^7.5.4" + ts-api-utils "^1.0.1" -"@typescript-eslint/parser@^5.51.0": - version "5.59.2" - resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.2.tgz" - integrity sha512-uq0sKyw6ao1iFOZZGk9F8Nro/8+gfB5ezl1cA06SrqbgJAt0SRoFhb9pXaHvkrxUpZaoLxt8KlovHNk8Gp6/HQ== +"@typescript-eslint/parser@^6.5.0": + version "6.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.5.0.tgz#3d6ed231c5e307c5f5f4a0d86893ec01e92b8c77" + integrity sha512-LMAVtR5GN8nY0G0BadkG0XIe4AcNMeyEy3DyhKGAh9k4pLSMBO7rF29JvDBpZGCmp5Pgz5RLHP6eCpSYZJQDuQ== dependencies: - "@typescript-eslint/scope-manager" "5.59.2" - "@typescript-eslint/types" "5.59.2" - "@typescript-eslint/typescript-estree" "5.59.2" + "@typescript-eslint/scope-manager" "6.5.0" + "@typescript-eslint/types" "6.5.0" + "@typescript-eslint/typescript-estree" "6.5.0" + "@typescript-eslint/visitor-keys" "6.5.0" debug "^4.3.4" "@typescript-eslint/scope-manager@5.59.2": @@ -958,21 +975,34 @@ "@typescript-eslint/types" "5.59.2" "@typescript-eslint/visitor-keys" "5.59.2" -"@typescript-eslint/type-utils@5.59.2": - version "5.59.2" - resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.2.tgz" - integrity sha512-b1LS2phBOsEy/T381bxkkywfQXkV1dWda/z0PhnIy3bC5+rQWQDS7fk9CSpcXBccPY27Z6vBEuaPBCKCgYezyQ== +"@typescript-eslint/scope-manager@6.5.0": + version "6.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.5.0.tgz#f2cb20895aaad41b3ad27cc3a338ce8598f261c5" + integrity sha512-A8hZ7OlxURricpycp5kdPTH3XnjG85UpJS6Fn4VzeoH4T388gQJ/PGP4ole5NfKt4WDVhmLaQ/dBLNDC4Xl/Kw== dependencies: - "@typescript-eslint/typescript-estree" "5.59.2" - "@typescript-eslint/utils" "5.59.2" + "@typescript-eslint/types" "6.5.0" + "@typescript-eslint/visitor-keys" "6.5.0" + +"@typescript-eslint/type-utils@6.5.0": + version "6.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.5.0.tgz#6d246c93739282bc0d2e623f28d0dec6cfcc38d7" + integrity sha512-f7OcZOkRivtujIBQ4yrJNIuwyCQO1OjocVqntl9dgSIZAdKqicj3xFDqDOzHDlGCZX990LqhLQXWRnQvsapq8A== + dependencies: + "@typescript-eslint/typescript-estree" "6.5.0" + "@typescript-eslint/utils" "6.5.0" debug "^4.3.4" - tsutils "^3.21.0" + ts-api-utils "^1.0.1" "@typescript-eslint/types@5.59.2": version "5.59.2" resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.2.tgz" integrity sha512-LbJ/HqoVs2XTGq5shkiKaNTuVv5tTejdHgfdjqRUGdYhjW1crm/M7og2jhVskMt8/4wS3T1+PfFvL1K3wqYj4w== +"@typescript-eslint/types@6.5.0": + version "6.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.5.0.tgz#f4e55cfd99ac5346ea772770bf212a3e689a8f04" + integrity sha512-eqLLOEF5/lU8jW3Bw+8auf4lZSbbljHR2saKnYqON12G/WsJrGeeDHWuQePoEf9ro22+JkbPfWQwKEC5WwLQ3w== + "@typescript-eslint/typescript-estree@5.59.2": version "5.59.2" resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.2.tgz" @@ -986,7 +1016,33 @@ semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/utils@5.59.2", "@typescript-eslint/utils@^5.10.0": +"@typescript-eslint/typescript-estree@6.5.0": + version "6.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.5.0.tgz#1cef6bc822585e9ef89d88834bc902d911d747ed" + integrity sha512-q0rGwSe9e5Kk/XzliB9h2LBc9tmXX25G0833r7kffbl5437FPWb2tbpIV9wAATebC/018pGa9fwPDuvGN+LxWQ== + dependencies: + "@typescript-eslint/types" "6.5.0" + "@typescript-eslint/visitor-keys" "6.5.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/utils@6.5.0": + version "6.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.5.0.tgz#6668bee4f7f24978b11df8a2ea42d56eebc4662c" + integrity sha512-9nqtjkNykFzeVtt9Pj6lyR9WEdd8npPhhIPM992FWVkZuS6tmxHfGVnlUcjpUP2hv8r4w35nT33mlxd+Be1ACQ== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@types/json-schema" "^7.0.12" + "@types/semver" "^7.5.0" + "@typescript-eslint/scope-manager" "6.5.0" + "@typescript-eslint/types" "6.5.0" + "@typescript-eslint/typescript-estree" "6.5.0" + semver "^7.5.4" + +"@typescript-eslint/utils@^5.10.0": version "5.59.2" resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.2.tgz" integrity sha512-kSuF6/77TZzyGPhGO4uVp+f0SBoYxCDf+lW3GKhtKru/L8k/Hd7NFQxyWUeY7Z/KGB2C6Fe3yf2vVi4V9TsCSQ== @@ -1008,17 +1064,25 @@ "@typescript-eslint/types" "5.59.2" eslint-visitor-keys "^3.3.0" +"@typescript-eslint/visitor-keys@6.5.0": + version "6.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.5.0.tgz#1a6f474a0170a447b76f0699ce6700110fd11436" + integrity sha512-yCB/2wkbv3hPsh02ZS8dFQnij9VVQXJMN/gbQsaaY+zxALkZnxa/wagvLEFsAWMPv7d7lxQmNsIzGU1w/T/WyA== + dependencies: + "@typescript-eslint/types" "6.5.0" + eslint-visitor-keys "^3.4.1" + acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^8.8.0: - version "8.8.2" - resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz" - integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== +acorn@^8.9.0: + version "8.10.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" + integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== -ajv@^6.10.0, ajv@^6.12.4: +ajv@^6.12.4: version "6.12.6" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -1656,10 +1720,10 @@ eslint-plugin-babel@^5.3.1: dependencies: eslint-rule-composer "^0.3.0" -eslint-plugin-jest@^27.2.1: - version "27.2.1" - resolved "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.2.1.tgz" - integrity sha512-l067Uxx7ZT8cO9NJuf+eJHvt6bqJyz2Z29wykyEdz/OtmcELQl2MQGQLX8J94O1cSJWAwUSEvCjwjA7KEK3Hmg== +eslint-plugin-jest@^27.2.3: + version "27.2.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-27.2.3.tgz#6f8a4bb2ca82c0c5d481d1b3be256ab001f5a3ec" + integrity sha512-sRLlSCpICzWuje66Gl9zvdF6mwD5X86I4u55hJyFBsxYOsBCmT5+kSUjf+fkFWVMMgpzNEupjW8WzUqi83hJAQ== dependencies: "@typescript-eslint/utils" "^5.10.0" @@ -1681,10 +1745,10 @@ eslint-scope@^5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" -eslint-scope@^7.2.0: - version "7.2.0" - resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz" - integrity sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw== +eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== dependencies: esrecurse "^4.3.0" estraverse "^5.2.0" @@ -1694,27 +1758,32 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1: resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz" integrity sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA== -eslint@^8.40.0: - version "8.40.0" - resolved "https://registry.npmjs.org/eslint/-/eslint-8.40.0.tgz" - integrity sha512-bvR+TsP9EHL3TqNtj9sCNJVAFK3fBN8Q7g5waghxyRsPLIMwL73XSKnZFK0hk/O2ANC+iAoq6PWMQ+IfBAJIiQ== +eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint@^8.48.0: + version "8.48.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.48.0.tgz#bf9998ba520063907ba7bfe4c480dc8be03c2155" + integrity sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg== dependencies: "@eslint-community/eslint-utils" "^4.2.0" - "@eslint-community/regexpp" "^4.4.0" - "@eslint/eslintrc" "^2.0.3" - "@eslint/js" "8.40.0" - "@humanwhocodes/config-array" "^0.11.8" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.2" + "@eslint/js" "8.48.0" + "@humanwhocodes/config-array" "^0.11.10" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" - ajv "^6.10.0" + ajv "^6.12.4" chalk "^4.0.0" cross-spawn "^7.0.2" debug "^4.3.2" doctrine "^3.0.0" escape-string-regexp "^4.0.0" - eslint-scope "^7.2.0" - eslint-visitor-keys "^3.4.1" - espree "^9.5.2" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" esquery "^1.4.2" esutils "^2.0.2" fast-deep-equal "^3.1.3" @@ -1722,22 +1791,19 @@ eslint@^8.40.0: find-up "^5.0.0" glob-parent "^6.0.2" globals "^13.19.0" - grapheme-splitter "^1.0.4" + graphemer "^1.4.0" ignore "^5.2.0" - import-fresh "^3.0.0" imurmurhash "^0.1.4" is-glob "^4.0.0" is-path-inside "^3.0.3" - js-sdsl "^4.1.4" js-yaml "^4.1.0" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.4.1" lodash.merge "^4.6.2" minimatch "^3.1.2" natural-compare "^1.4.0" - optionator "^0.9.1" + optionator "^0.9.3" strip-ansi "^6.0.1" - strip-json-comments "^3.1.0" text-table "^0.2.0" esm-loader-typescript@^1.0.3: @@ -1750,12 +1816,12 @@ esm-loader-typescript@^1.0.3: semver "^7.3.8" typescript "^5.0.2" -espree@^9.5.2: - version "9.5.2" - resolved "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz" - integrity sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw== +espree@^9.6.0, espree@^9.6.1: + version "9.6.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== dependencies: - acorn "^8.8.0" + acorn "^8.9.0" acorn-jsx "^5.3.2" eslint-visitor-keys "^3.4.1" @@ -2071,10 +2137,10 @@ graceful-fs@^4.1.2, graceful-fs@^4.2.9: resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== -grapheme-splitter@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz" - integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== hard-rejection@^2.1.0: version "2.1.0" @@ -2149,12 +2215,12 @@ human-signals@^2.1.0: resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== -ignore@^5.2.0: +ignore@^5.2.0, ignore@^5.2.4: version "5.2.4" resolved "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz" integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== -import-fresh@^3.0.0, import-fresh@^3.2.1: +import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz" integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== @@ -2774,11 +2840,6 @@ jest@^29.5.0: import-local "^3.0.2" jest-cli "^29.5.0" -js-sdsl@^4.1.4: - version "4.4.0" - resolved "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz" - integrity sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg== - js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" @@ -3031,11 +3092,6 @@ ms@2.1.2: resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -natural-compare-lite@^1.4.0: - version "1.4.0" - resolved "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz" - integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g== - natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" @@ -3154,17 +3210,17 @@ onetime@^5.1.2: dependencies: mimic-fn "^2.1.0" -optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== +optionator@^0.9.3: + version "0.9.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" + integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== dependencies: + "@aashutoshrathi/word-wrap" "^1.2.3" deep-is "^0.1.3" fast-levenshtein "^2.0.6" levn "^0.4.1" prelude-ls "^1.2.1" type-check "^0.4.0" - word-wrap "^1.2.3" p-limit@^2.2.0: version "2.3.0" @@ -3478,6 +3534,13 @@ semver@^6.0.0, semver@^6.3.0: resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@^7.5.4: + version "7.5.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + dependencies: + lru-cache "^6.0.0" + shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz" @@ -3664,7 +3727,7 @@ strip-indent@^3.0.0: dependencies: min-indent "^1.0.0" -strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: +strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== @@ -3744,6 +3807,11 @@ trim-newlines@^3.0.0: resolved "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz" integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== +ts-api-utils@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.0.2.tgz#7c094f753b6705ee4faee25c3c684ade52d66d99" + integrity sha512-Cbu4nIqnEdd+THNEsBdkolnOXhg0I8XteoHaEKgvsxpsbWda4IsUut2c187HxywQCvveojow0Dgw/amxtSKVkQ== + ts-jest@^29.1.0: version "29.1.0" resolved "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.0.tgz" @@ -3981,11 +4049,6 @@ which@^2.0.1: dependencies: isexe "^2.0.0" -word-wrap@^1.2.3: - version "1.2.3" - resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== - wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" From 899c2bd0dcaec721a186a85459dca367e15af2fa Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Thu, 31 Aug 2023 13:41:06 -0500 Subject: [PATCH 09/16] eslint: remove conflicting generator-star-spacing rule --- .eslintrc.json | 1 - 1 file changed, 1 deletion(-) diff --git a/.eslintrc.json b/.eslintrc.json index 1542d93..60544c4 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -46,7 +46,6 @@ "dot-location": [2, "property"], "eol-last": 2, "eqeqeq": [2, "allow-null"], - "generator-star-spacing": [2, {"before": true, "after": true}], "handle-callback-err": [2, "^(err|error)$"], "indent": 0, "jsx-quotes": [2, "prefer-double"], From 9effe807d13c23cd3d40a404871b3213d4ff04a4 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Thu, 31 Aug 2023 13:41:25 -0500 Subject: [PATCH 10/16] filter: remove unused import for Kind --- filter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/filter.ts b/filter.ts index 0fef5f0..811e31f 100644 --- a/filter.ts +++ b/filter.ts @@ -1,4 +1,4 @@ -import {Event, type Kind} from './event.ts' +import {Event} from './event.ts' export type Filter = { ids?: string[] From 2a70bb18ffc497bac29221530dd3dce0289e78e2 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Thu, 31 Aug 2023 13:41:40 -0500 Subject: [PATCH 11/16] pool: use triple-equals --- pool.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pool.ts b/pool.ts index dfb53f2..990b9e0 100644 --- a/pool.ts +++ b/pool.ts @@ -94,7 +94,7 @@ export class SimplePool { }, this.eoseSubTimeout) relays - .filter((r, i, a) => a.indexOf(r) == i) + .filter((r, i, a) => a.indexOf(r) === i) .forEach(async relay => { let r try { From 718032022c66c947704d1b338d1966d1874ed572 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Thu, 31 Aug 2023 13:42:15 -0500 Subject: [PATCH 12/16] just format --- .eslintrc.json | 39 ++--- .github/workflows/test.yml | 2 +- README.md | 82 ++++------ build.js | 12 +- event.test.ts | 92 +++++------ event.ts | 41 ++--- fakejson.test.ts | 26 ++- filter.test.ts | 113 +++++++------ filter.ts | 36 +---- keys.test.ts | 2 +- keys.ts | 4 +- kinds.test.ts | 2 +- nip04.test.ts | 8 +- nip04.ts | 48 ++---- nip05.test.ts | 14 +- nip05.ts | 11 +- nip06.test.ts | 10 +- nip06.ts | 17 +- nip10.test.ts | 315 ++++++++++++------------------------- nip10.ts | 17 +- nip13.test.ts | 2 +- nip13.ts | 4 +- nip18.test.ts | 39 ++--- nip18.ts | 36 +++-- nip19.test.ts | 60 +++---- nip19.ts | 40 +++-- nip21.test.ts | 34 +--- nip21.ts | 9 +- nip25.test.ts | 23 ++- nip25.ts | 30 ++-- nip26.test.ts | 52 +++--- nip26.ts | 51 ++---- nip27.test.ts | 24 +-- nip27.ts | 15 +- nip28.test.ts | 48 ++---- nip28.ts | 39 +++-- nip39.test.ts | 4 +- nip39.ts | 15 +- nip42.test.ts | 14 +- nip42.ts | 14 +- nip44.test.ts | 6 +- nip44.ts | 12 +- nip57.test.ts | 144 +++++++---------- nip57.ts | 47 ++---- nip98.test.ts | 67 ++------ nip98.ts | 57 +++---- pool.test.ts | 84 +++++----- pool.ts | 52 +++--- references.test.ts | 47 ++---- references.ts | 32 ++-- relay.test.ts | 57 +++---- relay.ts | 101 ++++-------- test-helpers.ts | 4 +- utils.test.ts | 234 ++++++++++++++------------- utils.ts | 30 +--- 55 files changed, 930 insertions(+), 1488 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 60544c4..420ac63 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -35,11 +35,11 @@ "rules": { "accessor-pairs": 2, - "arrow-spacing": [2, {"before": true, "after": true}], + "arrow-spacing": [2, { "before": true, "after": true }], "block-spacing": [2, "always"], - "brace-style": [2, "1tbs", {"allowSingleLine": true}], + "brace-style": [2, "1tbs", { "allowSingleLine": true }], "comma-dangle": 0, - "comma-spacing": [2, {"before": false, "after": true}], + "comma-spacing": [2, { "before": false, "after": true }], "comma-style": [2, "last"], "constructor-super": 2, "curly": [0, "multi-line"], @@ -49,8 +49,8 @@ "handle-callback-err": [2, "^(err|error)$"], "indent": 0, "jsx-quotes": [2, "prefer-double"], - "key-spacing": [2, {"beforeColon": false, "afterColon": true}], - "keyword-spacing": [2, {"before": true, "after": true}], + "key-spacing": [2, { "beforeColon": false, "afterColon": true }], + "keyword-spacing": [2, { "before": true, "after": true }], "new-cap": 0, "new-parens": 0, "no-array-constructor": 2, @@ -82,12 +82,12 @@ "no-irregular-whitespace": 2, "no-iterator": 2, "no-label-var": 2, - "no-labels": [2, {"allowLoop": false, "allowSwitch": false}], + "no-labels": [2, { "allowLoop": false, "allowSwitch": false }], "no-lone-blocks": 2, "no-mixed-spaces-and-tabs": 2, "no-multi-spaces": 2, "no-multi-str": 2, - "no-multiple-empty-lines": [2, {"max": 2}], + "no-multiple-empty-lines": [2, { "max": 2 }], "no-native-reassign": 2, "no-negated-in-lhs": 2, "no-new": 0, @@ -115,34 +115,23 @@ "no-undef": 2, "no-undef-init": 2, "no-unexpected-multiline": 2, - "no-unneeded-ternary": [2, {"defaultAssignment": false}], + "no-unneeded-ternary": [2, { "defaultAssignment": false }], "no-unreachable": 2, - "no-unused-vars": [ - 2, - {"vars": "local", "args": "none", "varsIgnorePattern": "^_"} - ], + "no-unused-vars": [2, { "vars": "local", "args": "none", "varsIgnorePattern": "^_" }], "no-useless-call": 2, "no-useless-constructor": 2, "no-with": 2, - "one-var": [0, {"initialized": "never"}], - "operator-linebreak": [ - 2, - "after", - {"overrides": {"?": "before", ":": "before"}} - ], + "one-var": [0, { "initialized": "never" }], + "operator-linebreak": [2, "after", { "overrides": { "?": "before", ":": "before" } }], "padded-blocks": [2, "never"], - "quotes": [ - 2, - "single", - {"avoidEscape": true, "allowTemplateLiterals": true} - ], + "quotes": [2, "single", { "avoidEscape": true, "allowTemplateLiterals": true }], "semi": [2, "never"], - "semi-spacing": [2, {"before": false, "after": true}], + "semi-spacing": [2, { "before": false, "after": true }], "space-before-blocks": [2, "always"], "space-before-function-paren": 0, "space-in-parens": [2, "never"], "space-infix-ops": 2, - "space-unary-ops": [2, {"words": true, "nonwords": false}], + "space-unary-ops": [2, { "words": true, "nonwords": false }], "spaced-comment": 0, "template-curly-spacing": [2, "never"], "use-isnan": 2, diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5e8d8ce..0ccc2e7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,4 +24,4 @@ jobs: with: node-version: 18 - run: just install-dependencies - - run: just lint \ No newline at end of file + - run: just lint diff --git a/README.md b/README.md index 15e921d..c463175 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ This package is only providing lower-level functionality. If you want an easy-to ### Generating a private key and a public key ```js -import {generatePrivateKey, getPublicKey} from 'nostr-tools' +import { generatePrivateKey, getPublicKey } from 'nostr-tools' let sk = generatePrivateKey() // `sk` is a hex string let pk = getPublicKey(sk) // `pk` is a hex string @@ -26,20 +26,14 @@ let pk = getPublicKey(sk) // `pk` is a hex string ### Creating, signing and verifying events ```js -import { - validateEvent, - verifySignature, - getSignature, - getEventHash, - getPublicKey -} from 'nostr-tools' +import { validateEvent, verifySignature, getSignature, getEventHash, getPublicKey } from 'nostr-tools' let event = { kind: 1, created_at: Math.floor(Date.now() / 1000), tags: [], content: 'hello', - pubkey: getPublicKey(privateKey) + pubkey: getPublicKey(privateKey), } event.id = getEventHash(event) @@ -52,12 +46,7 @@ let veryOk = verifySignature(event) ### Interacting with a relay ```js -import { - relayInit, - finishEvent, - generatePrivateKey, - getPublicKey, -} from 'nostr-tools' +import { relayInit, finishEvent, generatePrivateKey, getPublicKey } from 'nostr-tools' const relay = relayInit('wss://relay.example.com') relay.on('connect', () => { @@ -72,8 +61,8 @@ await relay.connect() // let's query for an event that exists let sub = relay.sub([ { - ids: ['d7dd5eb3ab747e16f8d0212d53032ea2a7cadef53837e5a6c66d42849fcb9027'] - } + ids: ['d7dd5eb3ab747e16f8d0212d53032ea2a7cadef53837e5a6c66d42849fcb9027'], + }, ]) sub.on('event', event => { console.log('we got the event we wanted:', event) @@ -89,8 +78,8 @@ let pk = getPublicKey(sk) let sub = relay.sub([ { kinds: [1], - authors: [pk] - } + authors: [pk], + }, ]) sub.on('event', event => { @@ -102,16 +91,16 @@ let event = { pubkey: pk, created_at: Math.floor(Date.now() / 1000), tags: [], - content: 'hello world' + content: 'hello world', } // this calculates the event id and signs the event in a single step const signedEvent = finishEvent(event, sk) await relay.publish(signedEvent) -let events = await relay.list([{kinds: [0, 1]}]) +let events = await relay.list([{ kinds: [0, 1] }]) let event = await relay.get({ - ids: ['44e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245'] + ids: ['44e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245'], }) relay.close() @@ -126,7 +115,7 @@ import 'websocket-polyfill' ### Interacting with multiple relays ```js -import {SimplePool} from 'nostr-tools' +import { SimplePool } from 'nostr-tools' const pool = new SimplePool() @@ -136,11 +125,9 @@ let sub = pool.sub( [...relays, 'wss://relay.example3.com'], [ { - authors: [ - '32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245' - ] - } - ] + authors: ['32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245'], + }, + ], ) sub.on('event', event => { @@ -151,14 +138,12 @@ sub.on('event', event => { let pubs = pool.publish(relays, newEvent) await Promise.all(pubs) -let events = await pool.list(relays, [{kinds: [0, 1]}]) +let events = await pool.list(relays, [{ kinds: [0, 1] }]) let event = await pool.get(relays, { - ids: ['44e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245'] + ids: ['44e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245'], }) -let relaysForEvent = pool.seenOn( - '44e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245' -) +let relaysForEvent = pool.seenOn('44e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245') // relaysForEvent will be an array of URLs from relays a given event was seen on pool.close() @@ -167,12 +152,12 @@ pool.close() ### Parsing references (mentions) from a content using NIP-10 and NIP-27 ```js -import {parseReferences} from 'nostr-tools' +import { parseReferences } from 'nostr-tools' let references = parseReferences(event) let simpleAugmentedContent = event.content for (let i = 0; i < references.length; i++) { - let {text, profile, event, address} = references[i] + let { text, profile, event, address } = references[i] let augmentedReference = profile ? `@${profilesCache[profile.pubkey].name}` : event @@ -187,7 +172,7 @@ for (let i = 0; i < references.length; i++) { ### Querying profile data from a NIP-05 address ```js -import {nip05} from 'nostr-tools' +import { nip05 } from 'nostr-tools' let profile = await nip05.queryProfile('jb55.com') console.log(profile.pubkey) @@ -205,27 +190,24 @@ nip05.useFetchImplementation(require('node-fetch')) ### Encoding and decoding NIP-19 codes ```js -import {nip19, generatePrivateKey, getPublicKey} from 'nostr-tools' +import { nip19, generatePrivateKey, getPublicKey } from 'nostr-tools' let sk = generatePrivateKey() let nsec = nip19.nsecEncode(sk) -let {type, data} = nip19.decode(nsec) +let { type, data } = nip19.decode(nsec) assert(type === 'nsec') assert(data === sk) let pk = getPublicKey(generatePrivateKey()) let npub = nip19.npubEncode(pk) -let {type, data} = nip19.decode(npub) +let { type, data } = nip19.decode(npub) assert(type === 'npub') assert(data === pk) let pk = getPublicKey(generatePrivateKey()) -let relays = [ - 'wss://relay.nostr.example.mydomain.example.com', - 'wss://nostr.banana.com' -] -let nprofile = nip19.nprofileEncode({pubkey: pk, relays}) -let {type, data} = nip19.decode(nprofile) +let relays = ['wss://relay.nostr.example.mydomain.example.com', 'wss://nostr.banana.com'] +let nprofile = nip19.nprofileEncode({ pubkey: pk, relays }) +let { type, data } = nip19.decode(nprofile) assert(type === 'nprofile') assert(data.pubkey === pk) assert(data.relays.length === 2) @@ -234,7 +216,7 @@ assert(data.relays.length === 2) ### Encrypting and decrypting direct messages ```js -import {nip04, getPublicKey, generatePrivateKey} from 'nostr-tools' +import { nip04, getPublicKey, generatePrivateKey } from 'nostr-tools' // sender let sk1 = generatePrivateKey() @@ -253,7 +235,7 @@ let event = { pubkey: pk1, tags: [['p', pk2]], content: ciphertext, - ...otherProperties + ...otherProperties, } sendEvent(event) @@ -269,7 +251,7 @@ sub.on('event', async event => { ### Performing and checking for delegation ```js -import {nip26, getPublicKey, generatePrivateKey} from 'nostr-tools' +import { nip26, getPublicKey, generatePrivateKey } from 'nostr-tools' // delegator let sk1 = generatePrivateKey() @@ -284,7 +266,7 @@ let delegation = nip26.createDelegation(sk1, { pubkey: pk2, kind: 1, since: Math.round(Date.now() / 1000), - until: Math.round(Date.now() / 1000) + 60 * 60 * 24 * 30 /* 30 days */ + until: Math.round(Date.now() / 1000) + 60 * 60 * 24 * 30 /* 30 days */, }) // the delegatee uses the delegation when building an event @@ -293,7 +275,7 @@ let event = { kind: 1, created_at: Math.round(Date.now() / 1000), content: 'hello from a delegated key', - tags: [['delegation', delegation.from, delegation.cond, delegation.sig]] + tags: [['delegation', delegation.from, delegation.cond, delegation.sig]], } // finally any receiver of this event can check for the presence of a valid delegation tag diff --git a/build.js b/build.js index 1b2dce6..b91634f 100755 --- a/build.js +++ b/build.js @@ -6,7 +6,7 @@ const esbuild = require('esbuild') let common = { entryPoints: ['index.ts'], bundle: true, - sourcemap: 'external' + sourcemap: 'external', } esbuild @@ -14,10 +14,10 @@ esbuild ...common, outfile: 'lib/esm/nostr.mjs', format: 'esm', - packages: 'external' + packages: 'external', }) .then(() => { - const packageJson = JSON.stringify({type: 'module'}) + const packageJson = JSON.stringify({ type: 'module' }) fs.writeFileSync(`${__dirname}/lib/esm/package.json`, packageJson, 'utf8') console.log('esm build success.') @@ -28,7 +28,7 @@ esbuild ...common, outfile: 'lib/nostr.cjs.js', format: 'cjs', - packages: 'external' + packages: 'external', }) .then(() => console.log('cjs build success.')) @@ -41,7 +41,7 @@ esbuild define: { window: 'self', global: 'self', - process: '{"env": {}}' - } + process: '{"env": {}}', + }, }) .then(() => console.log('standalone build success.')) diff --git a/event.test.ts b/event.test.ts index 6c2cae4..625447a 100644 --- a/event.test.ts +++ b/event.test.ts @@ -8,7 +8,7 @@ import { getSignature, Kind, } from './event.ts' -import {getPublicKey} from './keys.ts' +import { getPublicKey } from './keys.ts' describe('Event', () => { describe('getBlankEvent', () => { @@ -17,7 +17,7 @@ describe('Event', () => { kind: 255, content: '', tags: [], - created_at: 0 + created_at: 0, }) }) @@ -26,22 +26,21 @@ describe('Event', () => { kind: 1, content: '', tags: [], - created_at: 0 + created_at: 0, }) }) }) describe('finishEvent', () => { it('should create a signed event from a template', () => { - const privateKey = - 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' + const privateKey = 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' const publicKey = getPublicKey(privateKey) const template = { kind: Kind.Text, tags: [], content: 'Hello, world!', - created_at: 1617932115 + created_at: 1617932115, } const event = finishEvent(template, privateKey) @@ -58,8 +57,7 @@ describe('Event', () => { describe('serializeEvent', () => { it('should serialize a valid event object', () => { - const privateKey = - 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' + const privateKey = 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' const publicKey = getPublicKey(privateKey) const unsignedEvent = { @@ -67,7 +65,7 @@ describe('Event', () => { created_at: 1617932115, kind: Kind.Text, tags: [], - content: 'Hello, world!' + content: 'Hello, world!', } const serializedEvent = serializeEvent(unsignedEvent) @@ -79,21 +77,20 @@ describe('Event', () => { unsignedEvent.created_at, unsignedEvent.kind, unsignedEvent.tags, - unsignedEvent.content - ]) + unsignedEvent.content, + ]), ) }) it('should throw an error for an invalid event object', () => { - const privateKey = - 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' + const privateKey = 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' const publicKey = getPublicKey(privateKey) const invalidEvent = { kind: Kind.Text, tags: [], created_at: 1617932115, - pubkey: publicKey // missing content + pubkey: publicKey, // missing content } expect(() => { @@ -105,8 +102,7 @@ describe('Event', () => { describe('getEventHash', () => { it('should return the correct event hash', () => { - const privateKey = - 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' + const privateKey = 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' const publicKey = getPublicKey(privateKey) const unsignedEvent = { @@ -114,7 +110,7 @@ describe('Event', () => { tags: [], content: 'Hello, world!', created_at: 1617932115, - pubkey: publicKey + pubkey: publicKey, } const eventHash = getEventHash(unsignedEvent) @@ -126,8 +122,7 @@ describe('Event', () => { describe('validateEvent', () => { it('should return true for a valid event object', () => { - const privateKey = - 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' + const privateKey = 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' const publicKey = getPublicKey(privateKey) const unsignedEvent = { @@ -135,7 +130,7 @@ describe('Event', () => { tags: [], content: 'Hello, world!', created_at: 1617932115, - pubkey: publicKey + pubkey: publicKey, } const isValid = validateEvent(unsignedEvent) @@ -155,7 +150,7 @@ describe('Event', () => { const invalidEvent = { kind: Kind.Text, tags: [], - created_at: 1617932115 // missing content and pubkey + created_at: 1617932115, // missing content and pubkey } const isValid = validateEvent(invalidEvent) @@ -172,15 +167,14 @@ describe('Event', () => { }) it('should return false for an object with invalid properties', () => { - const privateKey = - 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' + const privateKey = 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' const publicKey = getPublicKey(privateKey) const invalidEvent = { kind: 1, tags: [], created_at: '1617932115', // should be a number - pubkey: publicKey + pubkey: publicKey, } const isValid = validateEvent(invalidEvent) @@ -194,7 +188,7 @@ describe('Event', () => { tags: [], content: 'Hello, world!', created_at: 1617932115, - pubkey: 'invalid_pubkey' + pubkey: 'invalid_pubkey', } const isValid = validateEvent(invalidEvent) @@ -203,8 +197,7 @@ describe('Event', () => { }) it('should return false for an object with invalid tags', () => { - const privateKey = - 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' + const privateKey = 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' const publicKey = getPublicKey(privateKey) const invalidEvent = { @@ -212,7 +205,7 @@ describe('Event', () => { tags: {}, // should be an array content: 'Hello, world!', created_at: 1617932115, - pubkey: publicKey + pubkey: publicKey, } const isValid = validateEvent(invalidEvent) @@ -223,17 +216,16 @@ describe('Event', () => { describe('verifySignature', () => { it('should return true for a valid event signature', () => { - const privateKey = - 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' + const privateKey = 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' const event = finishEvent( { kind: Kind.Text, tags: [], content: 'Hello, world!', - created_at: 1617932115 + created_at: 1617932115, }, - privateKey + privateKey, ) const isValid = verifySignature(event) @@ -242,17 +234,16 @@ describe('Event', () => { }) it('should return false for an invalid event signature', () => { - const privateKey = - 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' + const privateKey = 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' const event = finishEvent( { kind: Kind.Text, tags: [], content: 'Hello, world!', - created_at: 1617932115 + created_at: 1617932115, }, - privateKey + privateKey, ) // tamper with the signature @@ -264,11 +255,9 @@ describe('Event', () => { }) it('should return false when verifying an event with a different private key', () => { - const privateKey1 = - 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' + const privateKey1 = 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' - const privateKey2 = - '5b4a34f4e4b23c63ad55a35e3f84a3b53d96dbf266edf521a8358f71d19cbf67' + const privateKey2 = '5b4a34f4e4b23c63ad55a35e3f84a3b53d96dbf266edf521a8358f71d19cbf67' const publicKey2 = getPublicKey(privateKey2) const event = finishEvent( @@ -276,15 +265,15 @@ describe('Event', () => { kind: Kind.Text, tags: [], content: 'Hello, world!', - created_at: 1617932115 + created_at: 1617932115, }, - privateKey1 + privateKey1, ) // verify with different private key const isValid = verifySignature({ ...event, - pubkey: publicKey2 + pubkey: publicKey2, }) expect(isValid).toEqual(false) @@ -293,8 +282,7 @@ describe('Event', () => { describe('getSignature', () => { it('should produce the correct signature for an event object', () => { - const privateKey = - 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' + const privateKey = 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' const publicKey = getPublicKey(privateKey) const unsignedEvent = { @@ -302,7 +290,7 @@ describe('Event', () => { tags: [], content: 'Hello, world!', created_at: 1617932115, - pubkey: publicKey + pubkey: publicKey, } const sig = getSignature(unsignedEvent, privateKey) @@ -311,7 +299,7 @@ describe('Event', () => { // @ts-expect-error const isValid = verifySignature({ ...unsignedEvent, - sig + sig, }) expect(typeof sig).toEqual('string') @@ -320,19 +308,17 @@ describe('Event', () => { }) it('should not sign an event with different private key', () => { - const privateKey = - 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' + const privateKey = 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' const publicKey = getPublicKey(privateKey) - const wrongPrivateKey = - 'a91e2a9d9e0f70f0877bea0dbf034e8f95d7392a27a7f07da0d14b9e9d456be7' + const wrongPrivateKey = 'a91e2a9d9e0f70f0877bea0dbf034e8f95d7392a27a7f07da0d14b9e9d456be7' const unsignedEvent = { kind: Kind.Text, tags: [], content: 'Hello, world!', created_at: 1617932115, - pubkey: publicKey + pubkey: publicKey, } const sig = getSignature(unsignedEvent, wrongPrivateKey) @@ -341,7 +327,7 @@ describe('Event', () => { // @ts-expect-error const isValid = verifySignature({ ...unsignedEvent, - sig + sig, }) expect(typeof sig).toEqual('string') diff --git a/event.ts b/event.ts index 4358541..ca2039c 100644 --- a/event.ts +++ b/event.ts @@ -1,9 +1,9 @@ -import {schnorr} from '@noble/curves/secp256k1' -import {sha256} from '@noble/hashes/sha256' -import {bytesToHex} from '@noble/hashes/utils' +import { schnorr } from '@noble/curves/secp256k1' +import { sha256 } from '@noble/hashes/sha256' +import { bytesToHex } from '@noble/hashes/utils' -import {getPublicKey} from './keys.ts' -import {utf8Encoder} from './utils.ts' +import { getPublicKey } from './keys.ts' +import { utf8Encoder } from './utils.ts' /** @deprecated Use numbers instead. */ /* eslint-disable no-unused-vars */ @@ -32,7 +32,7 @@ export enum Kind { ProfileBadge = 30008, BadgeDefinition = 30009, Article = 30023, - FileMetadata = 1063 + FileMetadata = 1063, } export type EventTemplate = { @@ -58,14 +58,11 @@ export function getBlankEvent(kind: K | Kind.Blank = Kind.Blank) { kind, content: '', tags: [], - created_at: 0 + created_at: 0, } } -export function finishEvent( - t: EventTemplate, - privateKey: string -): Event { +export function finishEvent(t: EventTemplate, privateKey: string): Event { let event = t as Event event.pubkey = getPublicKey(privateKey) event.id = getEventHash(event) @@ -74,17 +71,9 @@ export function finishEvent( } export function serializeEvent(evt: UnsignedEvent): string { - if (!validateEvent(evt)) - throw new Error("can't serialize event with wrong or missing properties") + if (!validateEvent(evt)) throw new Error("can't serialize event with wrong or missing properties") - return JSON.stringify([ - 0, - evt.pubkey, - evt.created_at, - evt.kind, - evt.tags, - evt.content - ]) + return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content]) } export function getEventHash(event: UnsignedEvent): string { @@ -92,8 +81,7 @@ export function getEventHash(event: UnsignedEvent): string { return bytesToHex(eventHash) } -const isRecord = (obj: unknown): obj is Record => - obj instanceof Object +const isRecord = (obj: unknown): obj is Record => obj instanceof Object export function validateEvent(event: T): event is T & UnsignedEvent { if (!isRecord(event)) return false @@ -126,15 +114,12 @@ export function verifySignature(event: Event): boolean { /** @deprecated Use `getSignature` instead. */ export function signEvent(event: UnsignedEvent, key: string): string { console.warn( - 'nostr-tools: `signEvent` is deprecated and will be removed or changed in the future. Please use `getSignature` instead.' + 'nostr-tools: `signEvent` is deprecated and will be removed or changed in the future. Please use `getSignature` instead.', ) return getSignature(event, key) } /** Calculate the signature for an event. */ -export function getSignature( - event: UnsignedEvent, - key: string -): string { +export function getSignature(event: UnsignedEvent, key: string): string { return bytesToHex(schnorr.sign(getEventHash(event), key)) } diff --git a/fakejson.test.ts b/fakejson.test.ts index fa4f50b..b60c298 100644 --- a/fakejson.test.ts +++ b/fakejson.test.ts @@ -1,18 +1,18 @@ -import {matchEventId, matchEventKind, getSubscriptionId} from './fakejson.ts' +import { matchEventId, matchEventKind, getSubscriptionId } from './fakejson.ts' test('match id', () => { expect( matchEventId( `["EVENT","nostril-query",{"tags":[],"content":"so did we cut all corners and p2p stuff in order to make a decentralized social network that was fast and worked, but in the end what we got was a lot of very slow clients that can't handle the traffic of one jack dorsey tweet?","sig":"ca62629d189edebb8f0811cfa0ac53015013df5f305dcba3f411ba15cfc4074d8c2d517ee7d9e81c9eb72a7328bfbe31c9122156397565ac55e740404e2b1fe7","id":"fef2a50f7d9d3d5a5f38ee761bc087ec16198d3f0140df6d1e8193abf7c2b146","kind":1,"pubkey":"3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d","created_at":1671150419}]`, - 'fef2a50f7d9d3d5a5f38ee761bc087ec16198d3f0140df6d1e8193abf7c2b146' - ) + 'fef2a50f7d9d3d5a5f38ee761bc087ec16198d3f0140df6d1e8193abf7c2b146', + ), ).toBeTruthy() expect( matchEventId( `["EVENT","nostril-query",{"content":"a bunch of mfs interacted with my post using what I assume were \"likes\": https://nostr.build/i/964.png","created_at":1672506879,"id":"f40bdd0905137ad60482537e260890ab50b0863bf16e67cf9383f203bd26c96f","kind":1,"pubkey":"3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d","sig":"8b825d2d4096f0643b18ca39da59ec07a682cd8a3e717f119c845037573d98099f5bea94ec7ddedd5600c8020144a255ed52882a911f7f7ada6d6abb3c0a1eb4","tags":[]}]`, - 'fef2a50f7d9d3d5a5f38ee761bc087ec16198d3f0140df6d1e8193abf7c2b146' - ) + 'fef2a50f7d9d3d5a5f38ee761bc087ec16198d3f0140df6d1e8193abf7c2b146', + ), ).toBeFalsy() }) @@ -20,15 +20,15 @@ test('match kind', () => { expect( matchEventKind( `["EVENT","nostril-query",{"tags":[],"content":"so did we cut all corners and p2p stuff in order to make a decentralized social network that was fast and worked, but in the end what we got was a lot of very slow clients that can't handle the traffic of one jack dorsey tweet?","sig":"ca62629d189edebb8f0811cfa0ac53015013df5f305dcba3f411ba15cfc4074d8c2d517ee7d9e81c9eb72a7328bfbe31c9122156397565ac55e740404e2b1fe7","id":"fef2a50f7d9d3d5a5f38ee761bc087ec16198d3f0140df6d1e8193abf7c2b146","kind":1,"pubkey":"3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d","created_at":1671150419}]`, - 1 - ) + 1, + ), ).toBeTruthy() expect( matchEventKind( `["EVENT","nostril-query",{"content":"{\"name\":\"fiatjaf\",\"about\":\"buy my merch at fiatjaf store\",\"picture\":\"https://fiatjaf.com/static/favicon.jpg\",\"nip05\":\"_@fiatjaf.com\"}","created_at":1671217411,"id":"b52f93f6dfecf9d81f59062827cd941412a0e8398dda60baf960b17499b88900","kind":12720,"pubkey":"3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d","sig":"fc1ea5d45fa5ed0526faed06e8fc7a558e60d1b213e9714f440828584ee999b93407092f9b04deea7e504fa034fc0428f31f7f0f95417b3280ebe6004b80b470","tags":[]}]`, - 12720 - ) + 12720, + ), ).toBeTruthy() }) @@ -36,12 +36,8 @@ test('match subscription id', () => { expect(getSubscriptionId('["EVENT","",{}]')).toEqual('') expect(getSubscriptionId('["EVENT","_",{}]')).toEqual('_') expect(getSubscriptionId('["EVENT","subname",{}]')).toEqual('subname') - expect(getSubscriptionId('["EVENT", "kasjbdjkav", {}]')).toEqual( - 'kasjbdjkav' - ) + expect(getSubscriptionId('["EVENT", "kasjbdjkav", {}]')).toEqual('kasjbdjkav') expect( - getSubscriptionId( - ' [ \n\n "EVENT" , \n\n "y4d5ow45gfwoiudfÇA VSADLKAN KLDASB[12312535]SFMZSNJKLH" , {}]' - ) + getSubscriptionId(' [ \n\n "EVENT" , \n\n "y4d5ow45gfwoiudfÇA VSADLKAN KLDASB[12312535]SFMZSNJKLH" , {}]'), ).toEqual('y4d5ow45gfwoiudfÇA VSADLKAN KLDASB[12312535]SFMZSNJKLH') }) diff --git a/filter.test.ts b/filter.test.ts index 3ca3f10..8120ed0 100644 --- a/filter.test.ts +++ b/filter.test.ts @@ -1,5 +1,5 @@ -import {matchFilter, matchFilters, mergeFilters} from './filter.ts' -import {buildEvent} from './test-helpers.ts' +import { matchFilter, matchFilters, mergeFilters } from './filter.ts' +import { buildEvent } from './test-helpers.ts' describe('Filter', () => { describe('matchFilter', () => { @@ -10,7 +10,7 @@ describe('Filter', () => { authors: ['abc'], since: 100, until: 200, - '#tag': ['value'] + '#tag': ['value'], } const event = buildEvent({ @@ -18,7 +18,7 @@ describe('Filter', () => { kind: 1, pubkey: 'abc', created_at: 150, - tags: [['tag', 'value']] + tags: [['tag', 'value']], }) const result = matchFilter(filter, event) @@ -27,9 +27,9 @@ describe('Filter', () => { }) it('should return false when the event id is not in the filter', () => { - const filter = {ids: ['123', '456']} + const filter = { ids: ['123', '456'] } - const event = buildEvent({id: '789'}) + const event = buildEvent({ id: '789' }) const result = matchFilter(filter, event) @@ -37,9 +37,9 @@ describe('Filter', () => { }) it('should return true when the event id starts with a prefix', () => { - const filter = {ids: ['22', '00']} + const filter = { ids: ['22', '00'] } - const event = buildEvent({id: '001'}) + const event = buildEvent({ id: '001' }) const result = matchFilter(filter, event) @@ -47,9 +47,9 @@ describe('Filter', () => { }) it('should return false when the event kind is not in the filter', () => { - const filter = {kinds: [1, 2, 3]} + const filter = { kinds: [1, 2, 3] } - const event = buildEvent({kind: 4}) + const event = buildEvent({ kind: 4 }) const result = matchFilter(filter, event) @@ -57,9 +57,9 @@ describe('Filter', () => { }) it('should return false when the event author is not in the filter', () => { - const filter = {authors: ['abc', 'def']} + const filter = { authors: ['abc', 'def'] } - const event = buildEvent({pubkey: 'ghi'}) + const event = buildEvent({ pubkey: 'ghi' }) const result = matchFilter(filter, event) @@ -67,9 +67,9 @@ describe('Filter', () => { }) it('should return false when a tag is not present in the event', () => { - const filter = {'#tag': ['value1', 'value2']} + const filter = { '#tag': ['value1', 'value2'] } - const event = buildEvent({tags: [['not_tag', 'value1']]}) + const event = buildEvent({ tags: [['not_tag', 'value1']] }) const result = matchFilter(filter, event) @@ -77,9 +77,9 @@ describe('Filter', () => { }) it('should return false when a tag value is not present in the event', () => { - const filter = {'#tag': ['value1', 'value2']} + const filter = { '#tag': ['value1', 'value2'] } - const event = buildEvent({tags: [['tag', 'value3']]}) + const event = buildEvent({ tags: [['tag', 'value3']] }) const result = matchFilter(filter, event) @@ -87,7 +87,7 @@ describe('Filter', () => { }) it('should return true when filter has tags that is present in the event', () => { - const filter = {'#tag1': ['foo']} + const filter = { '#tag1': ['foo'] } const event = buildEvent({ id: '123', @@ -96,8 +96,8 @@ describe('Filter', () => { created_at: 150, tags: [ ['tag1', 'foo'], - ['tag2', 'bar'] - ] + ['tag2', 'bar'], + ], }) const result = matchFilter(filter, event) @@ -106,9 +106,9 @@ describe('Filter', () => { }) it('should return false when the event is before the filter since value', () => { - const filter = {since: 100} + const filter = { since: 100 } - const event = buildEvent({created_at: 50}) + const event = buildEvent({ created_at: 50 }) const result = matchFilter(filter, event) @@ -116,9 +116,9 @@ describe('Filter', () => { }) it('should return true when the timestamp of event is equal to the filter since value', () => { - const filter = {since: 100} + const filter = { since: 100 } - const event = buildEvent({created_at: 100}) + const event = buildEvent({ created_at: 100 }) const result = matchFilter(filter, event) @@ -126,9 +126,9 @@ describe('Filter', () => { }) it('should return false when the event is after the filter until value', () => { - const filter = {until: 100} + const filter = { until: 100 } - const event = buildEvent({created_at: 150}) + const event = buildEvent({ created_at: 150 }) const result = matchFilter(filter, event) @@ -136,9 +136,9 @@ describe('Filter', () => { }) it('should return true when the timestamp of event is equal to the filter until value', () => { - const filter = {until: 100} + const filter = { until: 100 } - const event = buildEvent({created_at: 100}) + const event = buildEvent({ created_at: 100 }) const result = matchFilter(filter, event) @@ -149,12 +149,12 @@ describe('Filter', () => { describe('matchFilters', () => { it('should return true when at least one filter matches the event', () => { const filters = [ - {ids: ['123'], kinds: [1], authors: ['abc']}, - {ids: ['456'], kinds: [2], authors: ['def']}, - {ids: ['789'], kinds: [3], authors: ['ghi']} + { ids: ['123'], kinds: [1], authors: ['abc'] }, + { ids: ['456'], kinds: [2], authors: ['def'] }, + { ids: ['789'], kinds: [3], authors: ['ghi'] }, ] - const event = buildEvent({id: '789', kind: 3, pubkey: 'ghi'}) + const event = buildEvent({ id: '789', kind: 3, pubkey: 'ghi' }) const result = matchFilters(filters, event) @@ -163,12 +163,12 @@ describe('Filter', () => { it('should return true when at least one prefix matches the event', () => { const filters = [ - {ids: ['1'], kinds: [1], authors: ['a']}, - {ids: ['4'], kinds: [2], authors: ['d']}, - {ids: ['9'], kinds: [3], authors: ['g']} + { ids: ['1'], kinds: [1], authors: ['a'] }, + { ids: ['4'], kinds: [2], authors: ['d'] }, + { ids: ['9'], kinds: [3], authors: ['g'] }, ] - const event = buildEvent({id: '987', kind: 3, pubkey: 'ghi'}) + const event = buildEvent({ id: '987', kind: 3, pubkey: 'ghi' }) const result = matchFilters(filters, event) @@ -177,16 +177,16 @@ describe('Filter', () => { it('should return true when event matches one or more filters and some have limit set', () => { const filters = [ - {ids: ['123'], limit: 1}, - {kinds: [1], limit: 2}, - {authors: ['abc'], limit: 3} + { ids: ['123'], limit: 1 }, + { kinds: [1], limit: 2 }, + { authors: ['abc'], limit: 3 }, ] const event = buildEvent({ id: '123', kind: 1, pubkey: 'abc', - created_at: 150 + created_at: 150, }) const result = matchFilters(filters, event) @@ -196,12 +196,12 @@ describe('Filter', () => { it('should return false when no filters match the event', () => { const filters = [ - {ids: ['123'], kinds: [1], authors: ['abc']}, - {ids: ['456'], kinds: [2], authors: ['def']}, - {ids: ['789'], kinds: [3], authors: ['ghi']} + { ids: ['123'], kinds: [1], authors: ['abc'] }, + { ids: ['456'], kinds: [2], authors: ['def'] }, + { ids: ['789'], kinds: [3], authors: ['ghi'] }, ] - const event = buildEvent({id: '100', kind: 4, pubkey: 'jkl'}) + const event = buildEvent({ id: '100', kind: 4, pubkey: 'jkl' }) const result = matchFilters(filters, event) @@ -210,15 +210,15 @@ describe('Filter', () => { it('should return false when event matches none of the filters and some have limit set', () => { const filters = [ - {ids: ['123'], limit: 1}, - {kinds: [1], limit: 2}, - {authors: ['abc'], limit: 3} + { ids: ['123'], limit: 1 }, + { kinds: [1], limit: 2 }, + { authors: ['abc'], limit: 3 }, ] const event = buildEvent({ id: '456', kind: 2, pubkey: 'def', - created_at: 200 + created_at: 200, }) const result = matchFilters(filters, event) @@ -229,20 +229,15 @@ describe('Filter', () => { describe('mergeFilters', () => { it('should merge filters', () => { - expect( - mergeFilters( - {ids: ['a', 'b'], limit: 3}, - {authors: ['x'], ids: ['b', 'c']} - ) - ).toEqual({ids: ['a', 'b', 'c'], limit: 3, authors: ['x']}) + expect(mergeFilters({ ids: ['a', 'b'], limit: 3 }, { authors: ['x'], ids: ['b', 'c'] })).toEqual({ + ids: ['a', 'b', 'c'], + limit: 3, + authors: ['x'], + }) expect( - mergeFilters( - {kinds: [1], since: 15, until: 30}, - {since: 10, kinds: [7], until: 15}, - {kinds: [9, 10]} - ) - ).toEqual({kinds: [1, 7, 9, 10], since: 10, until: 30}) + mergeFilters({ kinds: [1], since: 15, until: 30 }, { since: 10, kinds: [7], until: 15 }, { kinds: [9, 10] }), + ).toEqual({ kinds: [1, 7, 9, 10], since: 10, until: 30 }) }) }) }) diff --git a/filter.ts b/filter.ts index 811e31f..deea4af 100644 --- a/filter.ts +++ b/filter.ts @@ -1,4 +1,4 @@ -import {Event} from './event.ts' +import { Event } from './event.ts' export type Filter = { ids?: string[] @@ -11,10 +11,7 @@ export type Filter = { [key: `#${string}`]: string[] | undefined } -export function matchFilter( - filter: Filter, - event: Event -): boolean { +export function matchFilter(filter: Filter, event: Event): boolean { if (filter.ids && filter.ids.indexOf(event.id) === -1) { if (!filter.ids.some(prefix => event.id.startsWith(prefix))) { return false @@ -31,13 +28,7 @@ export function matchFilter( if (f[0] === '#') { let tagName = f.slice(1) let values = filter[`#${tagName}`] - if ( - values && - !event.tags.find( - ([t, v]) => t === f.slice(1) && values!.indexOf(v) !== -1 - ) - ) - return false + if (values && !event.tags.find(([t, v]) => t === f.slice(1) && values!.indexOf(v) !== -1)) return false } } @@ -47,10 +38,7 @@ export function matchFilter( return true } -export function matchFilters( - filters: Filter[], - event: Event -): boolean { +export function matchFilters(filters: Filter[], event: Event): boolean { for (let i = 0; i < filters.length; i++) { if (matchFilter(filters[i], event)) return true } @@ -62,12 +50,7 @@ export function mergeFilters(...filters: Filter[]): Filter { for (let i = 0; i < filters.length; i++) { let filter = filters[i] Object.entries(filter).forEach(([property, values]) => { - if ( - property === 'kinds' || - property === 'ids' || - property === 'authors' || - property[0] === '#' - ) { + if (property === 'kinds' || property === 'ids' || property === 'authors' || property[0] === '#') { // @ts-ignore result[property] = result[property] || [] // @ts-ignore @@ -80,12 +63,9 @@ export function mergeFilters(...filters: Filter[]): Filter { } }) - if (filter.limit && (!result.limit || filter.limit > result.limit)) - result.limit = filter.limit - if (filter.until && (!result.until || filter.until > result.until)) - result.until = filter.until - if (filter.since && (!result.since || filter.since < result.since)) - result.since = filter.since + if (filter.limit && (!result.limit || filter.limit > result.limit)) result.limit = filter.limit + if (filter.until && (!result.until || filter.until > result.until)) result.until = filter.until + if (filter.since && (!result.since || filter.since < result.since)) result.since = filter.since } return result diff --git a/keys.test.ts b/keys.test.ts index ff6c26d..aa32cf1 100644 --- a/keys.test.ts +++ b/keys.test.ts @@ -1,4 +1,4 @@ -import {generatePrivateKey, getPublicKey} from './keys.ts' +import { generatePrivateKey, getPublicKey } from './keys.ts' test('private key generation', () => { expect(generatePrivateKey()).toMatch(/[a-f0-9]{64}/) diff --git a/keys.ts b/keys.ts index 9661a8b..03edd1c 100644 --- a/keys.ts +++ b/keys.ts @@ -1,5 +1,5 @@ -import {schnorr} from '@noble/curves/secp256k1' -import {bytesToHex} from '@noble/hashes/utils' +import { schnorr } from '@noble/curves/secp256k1' +import { bytesToHex } from '@noble/hashes/utils' export function generatePrivateKey(): string { return bytesToHex(schnorr.utils.randomPrivateKey()) diff --git a/kinds.test.ts b/kinds.test.ts index a4f3b72..d1775a3 100644 --- a/kinds.test.ts +++ b/kinds.test.ts @@ -1,4 +1,4 @@ -import {classifyKind} from './kinds.ts' +import { classifyKind } from './kinds.ts' test('kind classification', () => { expect(classifyKind(1)).toBe('regular') diff --git a/nip04.test.ts b/nip04.test.ts index 93fe01c..ffa29a4 100644 --- a/nip04.test.ts +++ b/nip04.test.ts @@ -1,7 +1,7 @@ import crypto from 'node:crypto' -import {encrypt, decrypt} from './nip04.ts' -import {getPublicKey, generatePrivateKey} from './keys.ts' +import { encrypt, decrypt } from './nip04.ts' +import { getPublicKey, generatePrivateKey } from './keys.ts' // @ts-ignore // eslint-disable-next-line no-undef @@ -13,7 +13,5 @@ test('encrypt and decrypt message', async () => { let pk1 = getPublicKey(sk1) let pk2 = getPublicKey(sk2) - expect( - await decrypt(sk2, pk1, await encrypt(sk1, pk2, 'hello')) - ).toEqual('hello') + expect(await decrypt(sk2, pk1, await encrypt(sk1, pk2, 'hello'))).toEqual('hello') }) diff --git a/nip04.ts b/nip04.ts index 86438af..334f3a3 100644 --- a/nip04.ts +++ b/nip04.ts @@ -1,8 +1,8 @@ -import {randomBytes} from '@noble/hashes/utils' -import {secp256k1} from '@noble/curves/secp256k1' -import {base64} from '@scure/base' +import { randomBytes } from '@noble/hashes/utils' +import { secp256k1 } from '@noble/curves/secp256k1' +import { base64 } from '@scure/base' -import {utf8Decoder, utf8Encoder} from './utils.ts' +import { utf8Decoder, utf8Encoder } from './utils.ts' // @ts-ignore if (typeof crypto !== 'undefined' && !crypto.subtle && crypto.webcrypto) { @@ -10,58 +10,30 @@ if (typeof crypto !== 'undefined' && !crypto.subtle && crypto.webcrypto) { crypto.subtle = crypto.webcrypto.subtle } -export async function encrypt( - privkey: string, - pubkey: string, - text: string -): Promise { +export async function encrypt(privkey: string, pubkey: string, text: string): Promise { const key = secp256k1.getSharedSecret(privkey, '02' + pubkey) const normalizedKey = getNormalizedX(key) let iv = Uint8Array.from(randomBytes(16)) let plaintext = utf8Encoder.encode(text) - let cryptoKey = await crypto.subtle.importKey( - 'raw', - normalizedKey, - {name: 'AES-CBC'}, - false, - ['encrypt'] - ) - let ciphertext = await crypto.subtle.encrypt( - {name: 'AES-CBC', iv}, - cryptoKey, - plaintext - ) + let cryptoKey = await crypto.subtle.importKey('raw', normalizedKey, { name: 'AES-CBC' }, false, ['encrypt']) + let ciphertext = await crypto.subtle.encrypt({ name: 'AES-CBC', iv }, cryptoKey, plaintext) let ctb64 = base64.encode(new Uint8Array(ciphertext)) let ivb64 = base64.encode(new Uint8Array(iv.buffer)) return `${ctb64}?iv=${ivb64}` } -export async function decrypt( - privkey: string, - pubkey: string, - data: string -): Promise { +export async function decrypt(privkey: string, pubkey: string, data: string): Promise { let [ctb64, ivb64] = data.split('?iv=') let key = secp256k1.getSharedSecret(privkey, '02' + pubkey) let normalizedKey = getNormalizedX(key) - let cryptoKey = await crypto.subtle.importKey( - 'raw', - normalizedKey, - {name: 'AES-CBC'}, - false, - ['decrypt'] - ) + let cryptoKey = await crypto.subtle.importKey('raw', normalizedKey, { name: 'AES-CBC' }, false, ['decrypt']) let ciphertext = base64.decode(ctb64) let iv = base64.decode(ivb64) - let plaintext = await crypto.subtle.decrypt( - {name: 'AES-CBC', iv}, - cryptoKey, - ciphertext - ) + let plaintext = await crypto.subtle.decrypt({ name: 'AES-CBC', iv }, cryptoKey, ciphertext) let text = utf8Decoder.decode(plaintext) return text diff --git a/nip05.test.ts b/nip05.test.ts index 388f03a..848b8a7 100644 --- a/nip05.test.ts +++ b/nip05.test.ts @@ -1,26 +1,20 @@ import fetch from 'node-fetch' -import {useFetchImplementation, queryProfile} from './nip05.ts' +import { useFetchImplementation, queryProfile } from './nip05.ts' test('fetch nip05 profiles', async () => { useFetchImplementation(fetch) let p1 = await queryProfile('jb55.com') - expect(p1!.pubkey).toEqual( - '32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245' - ) + expect(p1!.pubkey).toEqual('32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245') expect(p1!.relays).toEqual(['wss://relay.damus.io']) let p2 = await queryProfile('jb55@jb55.com') - expect(p2!.pubkey).toEqual( - '32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245' - ) + expect(p2!.pubkey).toEqual('32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245') expect(p2!.relays).toEqual(['wss://relay.damus.io']) let p3 = await queryProfile('_@fiatjaf.com') - expect(p3!.pubkey).toEqual( - '3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d' - ) + expect(p3!.pubkey).toEqual('3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d') expect(p3!.relays).toEqual([ 'wss://relay.nostr.bg', 'wss://nos.lol', diff --git a/nip05.ts b/nip05.ts index 53dedc3..b95c9c0 100644 --- a/nip05.ts +++ b/nip05.ts @@ -1,4 +1,4 @@ -import {ProfilePointer} from './nip19.ts' +import { ProfilePointer } from './nip19.ts' /** * NIP-05 regex. The localpart is optional, and should be assumed to be `_` otherwise. @@ -19,14 +19,9 @@ export function useFetchImplementation(fetchImplementation: any) { _fetch = fetchImplementation } -export async function searchDomain( - domain: string, - query = '' -): Promise<{[name: string]: string}> { +export async function searchDomain(domain: string, query = ''): Promise<{ [name: string]: string }> { try { - let res = await ( - await _fetch(`https://${domain}/.well-known/nostr.json?name=${query}`) - ).json() + let res = await (await _fetch(`https://${domain}/.well-known/nostr.json?name=${query}`)).json() return res.names } catch (_) { diff --git a/nip06.test.ts b/nip06.test.ts index b3e31b7..0cbf1a0 100644 --- a/nip06.test.ts +++ b/nip06.test.ts @@ -1,18 +1,14 @@ -import {privateKeyFromSeedWords} from './nip06.ts' +import { privateKeyFromSeedWords } from './nip06.ts' test('generate private key from a mnemonic', async () => { const mnemonic = 'zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong' const privateKey = privateKeyFromSeedWords(mnemonic) - expect(privateKey).toEqual( - 'c26cf31d8ba425b555ca27d00ca71b5008004f2f662470f8c8131822ec129fe2' - ) + expect(privateKey).toEqual('c26cf31d8ba425b555ca27d00ca71b5008004f2f662470f8c8131822ec129fe2') }) test('generate private key from a mnemonic and passphrase', async () => { const mnemonic = 'zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong' const passphrase = '123' const privateKey = privateKeyFromSeedWords(mnemonic, passphrase) - expect(privateKey).toEqual( - '55a22b8203273d0aaf24c22c8fbe99608e70c524b17265641074281c8b978ae4' - ) + expect(privateKey).toEqual('55a22b8203273d0aaf24c22c8fbe99608e70c524b17265641074281c8b978ae4') }) diff --git a/nip06.ts b/nip06.ts index 0c14790..ac12761 100644 --- a/nip06.ts +++ b/nip06.ts @@ -1,16 +1,9 @@ -import {bytesToHex} from '@noble/hashes/utils' -import {wordlist} from '@scure/bip39/wordlists/english' -import { - generateMnemonic, - mnemonicToSeedSync, - validateMnemonic -} from '@scure/bip39' -import {HDKey} from '@scure/bip32' +import { bytesToHex } from '@noble/hashes/utils' +import { wordlist } from '@scure/bip39/wordlists/english' +import { generateMnemonic, mnemonicToSeedSync, validateMnemonic } from '@scure/bip39' +import { HDKey } from '@scure/bip32' -export function privateKeyFromSeedWords( - mnemonic: string, - passphrase?: string -): string { +export function privateKeyFromSeedWords(mnemonic: string, passphrase?: string): string { let root = HDKey.fromMasterSeed(mnemonicToSeedSync(mnemonic, passphrase)) let privateKey = root.derive(`m/44'/1237'/0'/0/0`).privateKey if (!privateKey) throw new Error('could not derive private key') diff --git a/nip10.test.ts b/nip10.test.ts index 93ac7d5..29c4eb0 100644 --- a/nip10.test.ts +++ b/nip10.test.ts @@ -1,252 +1,173 @@ -import {parse} from './nip10.ts' +import { parse } from './nip10.ts' describe('parse NIP10-referenced events', () => { test('legacy + a lot of events', () => { let event = { tags: [ - [ - 'e', - 'b857504288c18a15950dd05b9e8772c62ca6289d5aac373c0a8ee5b132e94e7c' - ], - [ - 'e', - 'bbd72f0ae14374aa8fb166b483cfcf99b57d7f4cf1600ccbf17c350040834631' - ], - [ - 'e', - '5e081ebb19153357d7c31e8a10b9ceeef29313f58dc8d701f66727fab02aef64' - ], - [ - 'e', - '49aff7ae6daeaaa2777931b90f9bb29f6cb01c5a3d7d88c8ba82d890f264afb4' - ], - [ - 'e', - '567b7c11f0fe582361e3cea6fcc7609a8942dfe196ee1b98d5604c93fbeea976' - ], - [ - 'e', - '090c037b2e399ee74d9f134758928948dd9154413ca1a1acb37155046e03a051' - ], - [ - 'e', - '89f220b63465c93542b1a78caa3a952cf4f196e91a50596493c8093c533ebc4d' - ], - [ - 'p', - '77ce56f89d1228f7ff3743ce1ad1b254857b9008564727ebd5a1f317362f6ca7' - ], - [ - 'p', - '534780e44da7b494485e85cd4cca6af4f6caa1627472432b6f2a4ece0e9e54ec' - ], - [ - 'p', - '4ca4f5533e40da5e0508796d409e6bb35a50b26fc304345617ab017183d83ac0' - ] - ] + ['e', 'b857504288c18a15950dd05b9e8772c62ca6289d5aac373c0a8ee5b132e94e7c'], + ['e', 'bbd72f0ae14374aa8fb166b483cfcf99b57d7f4cf1600ccbf17c350040834631'], + ['e', '5e081ebb19153357d7c31e8a10b9ceeef29313f58dc8d701f66727fab02aef64'], + ['e', '49aff7ae6daeaaa2777931b90f9bb29f6cb01c5a3d7d88c8ba82d890f264afb4'], + ['e', '567b7c11f0fe582361e3cea6fcc7609a8942dfe196ee1b98d5604c93fbeea976'], + ['e', '090c037b2e399ee74d9f134758928948dd9154413ca1a1acb37155046e03a051'], + ['e', '89f220b63465c93542b1a78caa3a952cf4f196e91a50596493c8093c533ebc4d'], + ['p', '77ce56f89d1228f7ff3743ce1ad1b254857b9008564727ebd5a1f317362f6ca7'], + ['p', '534780e44da7b494485e85cd4cca6af4f6caa1627472432b6f2a4ece0e9e54ec'], + ['p', '4ca4f5533e40da5e0508796d409e6bb35a50b26fc304345617ab017183d83ac0'], + ], } expect(parse(event)).toEqual({ mentions: [ { id: 'bbd72f0ae14374aa8fb166b483cfcf99b57d7f4cf1600ccbf17c350040834631', - relays: [] + relays: [], }, { id: '5e081ebb19153357d7c31e8a10b9ceeef29313f58dc8d701f66727fab02aef64', - relays: [] + relays: [], }, { id: '49aff7ae6daeaaa2777931b90f9bb29f6cb01c5a3d7d88c8ba82d890f264afb4', - relays: [] + relays: [], }, { id: '567b7c11f0fe582361e3cea6fcc7609a8942dfe196ee1b98d5604c93fbeea976', - relays: [] + relays: [], }, { id: '090c037b2e399ee74d9f134758928948dd9154413ca1a1acb37155046e03a051', - relays: [] - } + relays: [], + }, ], profiles: [ { - pubkey: - '77ce56f89d1228f7ff3743ce1ad1b254857b9008564727ebd5a1f317362f6ca7', - relays: [] + pubkey: '77ce56f89d1228f7ff3743ce1ad1b254857b9008564727ebd5a1f317362f6ca7', + relays: [], }, { - pubkey: - '534780e44da7b494485e85cd4cca6af4f6caa1627472432b6f2a4ece0e9e54ec', - relays: [] + pubkey: '534780e44da7b494485e85cd4cca6af4f6caa1627472432b6f2a4ece0e9e54ec', + relays: [], }, { - pubkey: - '4ca4f5533e40da5e0508796d409e6bb35a50b26fc304345617ab017183d83ac0', - relays: [] - } + pubkey: '4ca4f5533e40da5e0508796d409e6bb35a50b26fc304345617ab017183d83ac0', + relays: [], + }, ], reply: { id: '89f220b63465c93542b1a78caa3a952cf4f196e91a50596493c8093c533ebc4d', - relays: [] + relays: [], }, root: { id: 'b857504288c18a15950dd05b9e8772c62ca6289d5aac373c0a8ee5b132e94e7c', - relays: [] - } + relays: [], + }, }) }) test('legacy + 3 events', () => { let event = { tags: [ - [ - 'e', - 'b857504288c18a15950dd05b9e8772c62ca6289d5aac373c0a8ee5b132e94e7c' - ], - [ - 'e', - 'bbd72f0ae14374aa8fb166b483cfcf99b57d7f4cf1600ccbf17c350040834631' - ], - [ - 'e', - '5e081ebb19153357d7c31e8a10b9ceeef29313f58dc8d701f66727fab02aef64' - ], - [ - 'p', - '77ce56f89d1228f7ff3743ce1ad1b254857b9008564727ebd5a1f317362f6ca7' - ], - [ - 'p', - '534780e44da7b494485e85cd4cca6af4f6caa1627472432b6f2a4ece0e9e54ec' - ], - [ - 'p', - '4ca4f5533e40da5e0508796d409e6bb35a50b26fc304345617ab017183d83ac0' - ] - ] + ['e', 'b857504288c18a15950dd05b9e8772c62ca6289d5aac373c0a8ee5b132e94e7c'], + ['e', 'bbd72f0ae14374aa8fb166b483cfcf99b57d7f4cf1600ccbf17c350040834631'], + ['e', '5e081ebb19153357d7c31e8a10b9ceeef29313f58dc8d701f66727fab02aef64'], + ['p', '77ce56f89d1228f7ff3743ce1ad1b254857b9008564727ebd5a1f317362f6ca7'], + ['p', '534780e44da7b494485e85cd4cca6af4f6caa1627472432b6f2a4ece0e9e54ec'], + ['p', '4ca4f5533e40da5e0508796d409e6bb35a50b26fc304345617ab017183d83ac0'], + ], } expect(parse(event)).toEqual({ mentions: [ { id: 'bbd72f0ae14374aa8fb166b483cfcf99b57d7f4cf1600ccbf17c350040834631', - relays: [] - } + relays: [], + }, ], profiles: [ { - pubkey: - '77ce56f89d1228f7ff3743ce1ad1b254857b9008564727ebd5a1f317362f6ca7', - relays: [] + pubkey: '77ce56f89d1228f7ff3743ce1ad1b254857b9008564727ebd5a1f317362f6ca7', + relays: [], }, { - pubkey: - '534780e44da7b494485e85cd4cca6af4f6caa1627472432b6f2a4ece0e9e54ec', - relays: [] + pubkey: '534780e44da7b494485e85cd4cca6af4f6caa1627472432b6f2a4ece0e9e54ec', + relays: [], }, { - pubkey: - '4ca4f5533e40da5e0508796d409e6bb35a50b26fc304345617ab017183d83ac0', - relays: [] - } + pubkey: '4ca4f5533e40da5e0508796d409e6bb35a50b26fc304345617ab017183d83ac0', + relays: [], + }, ], reply: { id: '5e081ebb19153357d7c31e8a10b9ceeef29313f58dc8d701f66727fab02aef64', - relays: [] + relays: [], }, root: { id: 'b857504288c18a15950dd05b9e8772c62ca6289d5aac373c0a8ee5b132e94e7c', - relays: [] - } + relays: [], + }, }) }) test('legacy + 2 events', () => { let event = { tags: [ - [ - 'e', - 'b857504288c18a15950dd05b9e8772c62ca6289d5aac373c0a8ee5b132e94e7c' - ], - [ - 'e', - 'bbd72f0ae14374aa8fb166b483cfcf99b57d7f4cf1600ccbf17c350040834631' - ], - [ - 'p', - '77ce56f89d1228f7ff3743ce1ad1b254857b9008564727ebd5a1f317362f6ca7' - ], - [ - 'p', - '534780e44da7b494485e85cd4cca6af4f6caa1627472432b6f2a4ece0e9e54ec' - ], - [ - 'p', - '4ca4f5533e40da5e0508796d409e6bb35a50b26fc304345617ab017183d83ac0' - ] - ] + ['e', 'b857504288c18a15950dd05b9e8772c62ca6289d5aac373c0a8ee5b132e94e7c'], + ['e', 'bbd72f0ae14374aa8fb166b483cfcf99b57d7f4cf1600ccbf17c350040834631'], + ['p', '77ce56f89d1228f7ff3743ce1ad1b254857b9008564727ebd5a1f317362f6ca7'], + ['p', '534780e44da7b494485e85cd4cca6af4f6caa1627472432b6f2a4ece0e9e54ec'], + ['p', '4ca4f5533e40da5e0508796d409e6bb35a50b26fc304345617ab017183d83ac0'], + ], } expect(parse(event)).toEqual({ mentions: [], profiles: [ { - pubkey: - '77ce56f89d1228f7ff3743ce1ad1b254857b9008564727ebd5a1f317362f6ca7', - relays: [] + pubkey: '77ce56f89d1228f7ff3743ce1ad1b254857b9008564727ebd5a1f317362f6ca7', + relays: [], }, { - pubkey: - '534780e44da7b494485e85cd4cca6af4f6caa1627472432b6f2a4ece0e9e54ec', - relays: [] + pubkey: '534780e44da7b494485e85cd4cca6af4f6caa1627472432b6f2a4ece0e9e54ec', + relays: [], }, { - pubkey: - '4ca4f5533e40da5e0508796d409e6bb35a50b26fc304345617ab017183d83ac0', - relays: [] - } + pubkey: '4ca4f5533e40da5e0508796d409e6bb35a50b26fc304345617ab017183d83ac0', + relays: [], + }, ], reply: { id: 'bbd72f0ae14374aa8fb166b483cfcf99b57d7f4cf1600ccbf17c350040834631', - relays: [] + relays: [], }, root: { id: 'b857504288c18a15950dd05b9e8772c62ca6289d5aac373c0a8ee5b132e94e7c', - relays: [] - } + relays: [], + }, }) }) test('legacy + 1 event', () => { let event = { tags: [ - [ - 'e', - '9abbfd9b9ac5ecdab45d14b8bf8d746139ea039e931a1b376d19a239f1946590' - ], - [ - 'p', - '534780e44da7b494485e85cd4cca6af4f6caa1627472432b6f2a4ece0e9e54ec' - ] - ] + ['e', '9abbfd9b9ac5ecdab45d14b8bf8d746139ea039e931a1b376d19a239f1946590'], + ['p', '534780e44da7b494485e85cd4cca6af4f6caa1627472432b6f2a4ece0e9e54ec'], + ], } expect(parse(event)).toEqual({ mentions: [], profiles: [ { - pubkey: - '534780e44da7b494485e85cd4cca6af4f6caa1627472432b6f2a4ece0e9e54ec', - relays: [] - } + pubkey: '534780e44da7b494485e85cd4cca6af4f6caa1627472432b6f2a4ece0e9e54ec', + relays: [], + }, ], reply: undefined, root: { id: '9abbfd9b9ac5ecdab45d14b8bf8d746139ea039e931a1b376d19a239f1946590', - relays: [] - } + relays: [], + }, }) }) @@ -257,95 +178,55 @@ describe('parse NIP10-referenced events', () => { test('recommended + 1 event', () => { let event = { tags: [ - [ - 'p', - 'a8c21fcd8aa1f4befba14d72fc7a012397732d30d8b3131af912642f3c726f52', - 'wss://relay.mostr.pub' - ], - [ - 'p', - '003d7fd21fd09ff7f6f63a75daf194dd99feefbe6919cc376b7359d5090aa9a6', - 'wss://relay.mostr.pub' - ], - [ - 'p', - '2f6fbe452edd3987d3c67f3b034c03ec5bcf4d054c521c3a954686f89f03212e', - 'wss://relay.mostr.pub' - ], - [ - 'p', - '44c7c74668ff222b0e0b30579c49fc6e22dafcdeaad091036c947f9856590f1e', - 'wss://relay.mostr.pub' - ], - [ - 'p', - 'c5cf39149caebda4cdd61771c51f6ba91ef5645919004e5c4998a4ea69f00512', - 'wss://relay.mostr.pub' - ], - [ - 'p', - '094d44bb1e812696c57f57ad1c0c707812dedbe72c07e538b80639032c236a9e', - 'wss://relay.mostr.pub' - ], - [ - 'p', - 'a1ba0ac9b6ec098f726a3c11ec654df4a32cbb84b5377e8788395e9c27d9ecda', - 'wss://relay.mostr.pub' - ], - [ - 'e', - 'f9472913904ab7e9da008dcb2d85fd4af2d2993ada483d00c646d0c4481d031d', - 'wss://relay.mostr.pub', - 'reply' - ], - ['mostr', 'https://poa.st/objects/dc50684b-6364-4264-ab16-49f4622f05ea'] - ] + ['p', 'a8c21fcd8aa1f4befba14d72fc7a012397732d30d8b3131af912642f3c726f52', 'wss://relay.mostr.pub'], + ['p', '003d7fd21fd09ff7f6f63a75daf194dd99feefbe6919cc376b7359d5090aa9a6', 'wss://relay.mostr.pub'], + ['p', '2f6fbe452edd3987d3c67f3b034c03ec5bcf4d054c521c3a954686f89f03212e', 'wss://relay.mostr.pub'], + ['p', '44c7c74668ff222b0e0b30579c49fc6e22dafcdeaad091036c947f9856590f1e', 'wss://relay.mostr.pub'], + ['p', 'c5cf39149caebda4cdd61771c51f6ba91ef5645919004e5c4998a4ea69f00512', 'wss://relay.mostr.pub'], + ['p', '094d44bb1e812696c57f57ad1c0c707812dedbe72c07e538b80639032c236a9e', 'wss://relay.mostr.pub'], + ['p', 'a1ba0ac9b6ec098f726a3c11ec654df4a32cbb84b5377e8788395e9c27d9ecda', 'wss://relay.mostr.pub'], + ['e', 'f9472913904ab7e9da008dcb2d85fd4af2d2993ada483d00c646d0c4481d031d', 'wss://relay.mostr.pub', 'reply'], + ['mostr', 'https://poa.st/objects/dc50684b-6364-4264-ab16-49f4622f05ea'], + ], } expect(parse(event)).toEqual({ mentions: [], profiles: [ { - pubkey: - 'a8c21fcd8aa1f4befba14d72fc7a012397732d30d8b3131af912642f3c726f52', - relays: ['wss://relay.mostr.pub'] + pubkey: 'a8c21fcd8aa1f4befba14d72fc7a012397732d30d8b3131af912642f3c726f52', + relays: ['wss://relay.mostr.pub'], }, { - pubkey: - '003d7fd21fd09ff7f6f63a75daf194dd99feefbe6919cc376b7359d5090aa9a6', - relays: ['wss://relay.mostr.pub'] + pubkey: '003d7fd21fd09ff7f6f63a75daf194dd99feefbe6919cc376b7359d5090aa9a6', + relays: ['wss://relay.mostr.pub'], }, { - pubkey: - '2f6fbe452edd3987d3c67f3b034c03ec5bcf4d054c521c3a954686f89f03212e', - relays: ['wss://relay.mostr.pub'] + pubkey: '2f6fbe452edd3987d3c67f3b034c03ec5bcf4d054c521c3a954686f89f03212e', + relays: ['wss://relay.mostr.pub'], }, { - pubkey: - '44c7c74668ff222b0e0b30579c49fc6e22dafcdeaad091036c947f9856590f1e', - relays: ['wss://relay.mostr.pub'] + pubkey: '44c7c74668ff222b0e0b30579c49fc6e22dafcdeaad091036c947f9856590f1e', + relays: ['wss://relay.mostr.pub'], }, { - pubkey: - 'c5cf39149caebda4cdd61771c51f6ba91ef5645919004e5c4998a4ea69f00512', - relays: ['wss://relay.mostr.pub'] + pubkey: 'c5cf39149caebda4cdd61771c51f6ba91ef5645919004e5c4998a4ea69f00512', + relays: ['wss://relay.mostr.pub'], }, { - pubkey: - '094d44bb1e812696c57f57ad1c0c707812dedbe72c07e538b80639032c236a9e', - relays: ['wss://relay.mostr.pub'] + pubkey: '094d44bb1e812696c57f57ad1c0c707812dedbe72c07e538b80639032c236a9e', + relays: ['wss://relay.mostr.pub'], }, { - pubkey: - 'a1ba0ac9b6ec098f726a3c11ec654df4a32cbb84b5377e8788395e9c27d9ecda', - relays: ['wss://relay.mostr.pub'] - } + pubkey: 'a1ba0ac9b6ec098f726a3c11ec654df4a32cbb84b5377e8788395e9c27d9ecda', + relays: ['wss://relay.mostr.pub'], + }, ], reply: { id: 'f9472913904ab7e9da008dcb2d85fd4af2d2993ada483d00c646d0c4481d031d', - relays: ['wss://relay.mostr.pub'] + relays: ['wss://relay.mostr.pub'], }, - root: undefined + root: undefined, }) }) }) diff --git a/nip10.ts b/nip10.ts index e9fd21e..87c4cb4 100644 --- a/nip10.ts +++ b/nip10.ts @@ -1,5 +1,5 @@ -import type {Event} from './event.ts' -import type {EventPointer, ProfilePointer} from './nip19.ts' +import type { Event } from './event.ts' +import type { EventPointer, ProfilePointer } from './nip19.ts' export type NIP10Result = { /** @@ -28,7 +28,7 @@ export function parse(event: Pick): NIP10Result { reply: undefined, root: undefined, mentions: [], - profiles: [] + profiles: [], } const eTags: string[][] = [] @@ -41,7 +41,7 @@ export function parse(event: Pick): NIP10Result { if (tag[0] === 'p' && tag[1]) { result.profiles.push({ pubkey: tag[1], - relays: tag[2] ? [tag[2]] : [] + relays: tag[2] ? [tag[2]] : [], }) } } @@ -49,16 +49,11 @@ export function parse(event: Pick): NIP10Result { for (let eTagIndex = 0; eTagIndex < eTags.length; eTagIndex++) { const eTag = eTags[eTagIndex] - const [_, eTagEventId, eTagRelayUrl, eTagMarker] = eTag as [ - string, - string, - undefined | string, - undefined | string - ] + const [_, eTagEventId, eTagRelayUrl, eTagMarker] = eTag as [string, string, undefined | string, undefined | string] const eventPointer: EventPointer = { id: eTagEventId, - relays: eTagRelayUrl ? [eTagRelayUrl] : [] + relays: eTagRelayUrl ? [eTagRelayUrl] : [], } const isFirstETag = eTagIndex === 0 diff --git a/nip13.test.ts b/nip13.test.ts index 85b1ccb..e10e2ff 100644 --- a/nip13.test.ts +++ b/nip13.test.ts @@ -1,4 +1,4 @@ -import {getPow} from './nip13.ts' +import { getPow } from './nip13.ts' test('identifies proof-of-work difficulty', async () => { const id = '000006d8c378af1779d2feebc7603a125d99eca0ccf1085959b307f64e5dd358' diff --git a/nip13.ts b/nip13.ts index 6adf1d2..654df22 100644 --- a/nip13.ts +++ b/nip13.ts @@ -1,4 +1,4 @@ -import {hexToBytes} from '@noble/hashes/utils' +import { hexToBytes } from '@noble/hashes/utils' /** Get POW difficulty from a Nostr hex ID. */ export function getPow(id: string): number { @@ -34,7 +34,7 @@ function msb(b: number) { } // eslint-disable-next-line no-cond-assign - while (b >>= 1) { + while ((b >>= 1)) { n++ } diff --git a/nip18.test.ts b/nip18.test.ts index 3a01c0f..e813abd 100644 --- a/nip18.test.ts +++ b/nip18.test.ts @@ -1,13 +1,12 @@ -import {finishEvent, Kind} from './event.ts' -import {getPublicKey} from './keys.ts' -import {finishRepostEvent, getRepostedEventPointer, getRepostedEvent} from './nip18.ts' -import {buildEvent} from './test-helpers.ts' +import { finishEvent, Kind } from './event.ts' +import { getPublicKey } from './keys.ts' +import { finishRepostEvent, getRepostedEventPointer, getRepostedEvent } from './nip18.ts' +import { buildEvent } from './test-helpers.ts' const relayUrl = 'https://relay.example.com' describe('finishRepostEvent + getRepostedEventPointer + getRepostedEvent', () => { - const privateKey = - 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' + const privateKey = 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' const publicKey = getPublicKey(privateKey) @@ -16,30 +15,25 @@ describe('finishRepostEvent + getRepostedEventPointer + getRepostedEvent', () => kind: Kind.Text, tags: [ ['e', 'replied event id'], - ['p', 'replied event pubkey'] + ['p', 'replied event pubkey'], ], content: 'Replied to a post', - created_at: 1617932115 + created_at: 1617932115, }, - privateKey + privateKey, ) it('should create a signed event from a minimal template', () => { const template = { - created_at: 1617932115 + created_at: 1617932115, } - const event = finishRepostEvent( - template, - repostedEvent, - relayUrl, - privateKey - ) + const event = finishRepostEvent(template, repostedEvent, relayUrl, privateKey) expect(event.kind).toEqual(Kind.Repost) expect(event.tags).toEqual([ ['e', repostedEvent.id, relayUrl], - ['p', repostedEvent.pubkey] + ['p', repostedEvent.pubkey], ]) expect(event.content).toEqual(JSON.stringify(repostedEvent)) expect(event.created_at).toEqual(template.created_at) @@ -62,21 +56,16 @@ describe('finishRepostEvent + getRepostedEventPointer + getRepostedEvent', () => const template = { tags: [['nonstandard', 'tag']], content: '' as const, - created_at: 1617932115 + created_at: 1617932115, } - const event = finishRepostEvent( - template, - repostedEvent, - relayUrl, - privateKey - ) + const event = finishRepostEvent(template, repostedEvent, relayUrl, privateKey) expect(event.kind).toEqual(Kind.Repost) expect(event.tags).toEqual([ ['nonstandard', 'tag'], ['e', repostedEvent.id, relayUrl], - ['p', repostedEvent.pubkey] + ['p', repostedEvent.pubkey], ]) expect(event.content).toEqual('') expect(event.created_at).toEqual(template.created_at) diff --git a/nip18.ts b/nip18.ts index 8b63bb6..3a7e6da 100644 --- a/nip18.ts +++ b/nip18.ts @@ -1,5 +1,5 @@ -import {Event, finishEvent, Kind, verifySignature} from './event.ts' -import {EventPointer} from './nip19.ts' +import { Event, finishEvent, Kind, verifySignature } from './event.ts' +import { EventPointer } from './nip19.ts' export type RepostEventTemplate = { /** @@ -13,7 +13,7 @@ export type RepostEventTemplate = { * Any other content will be ignored and replaced with the stringified JSON of the reposted event. * @default Stringified JSON of the reposted event */ - content?: ''; + content?: '' created_at: number } @@ -24,16 +24,15 @@ export function finishRepostEvent( relayUrl: string, privateKey: string, ): Event { - return finishEvent({ - kind: Kind.Repost, - tags: [ - ...(t.tags ?? []), - [ 'e', reposted.id, relayUrl ], - [ 'p', reposted.pubkey ], - ], - content: t.content === '' ? '' : JSON.stringify(reposted), - created_at: t.created_at, - }, privateKey) + return finishEvent( + { + kind: Kind.Repost, + tags: [...(t.tags ?? []), ['e', reposted.id, relayUrl], ['p', reposted.pubkey]], + content: t.content === '' ? '' : JSON.stringify(reposted), + created_at: t.created_at, + }, + privateKey, + ) } export function getRepostedEventPointer(event: Event): undefined | EventPointer { @@ -61,16 +60,19 @@ export function getRepostedEventPointer(event: Event): undefined | Event return { id: lastETag[1], - relays: [ lastETag[2], lastPTag?.[2] ].filter((x): x is string => typeof x === 'string'), + relays: [lastETag[2], lastPTag?.[2]].filter((x): x is string => typeof x === 'string'), author: lastPTag?.[1], } } export type GetRepostedEventOptions = { - skipVerification?: boolean, -}; + skipVerification?: boolean +} -export function getRepostedEvent(event: Event, { skipVerification }: GetRepostedEventOptions = {}): undefined | Event { +export function getRepostedEvent( + event: Event, + { skipVerification }: GetRepostedEventOptions = {}, +): undefined | Event { const pointer = getRepostedEventPointer(event) if (pointer === undefined || event.content === '') { diff --git a/nip19.test.ts b/nip19.test.ts index 73420b3..472ebb9 100644 --- a/nip19.test.ts +++ b/nip19.test.ts @@ -1,4 +1,4 @@ -import {generatePrivateKey, getPublicKey} from './keys.ts' +import { generatePrivateKey, getPublicKey } from './keys.ts' import { decode, naddrEncode, @@ -14,7 +14,7 @@ test('encode and decode nsec', () => { let sk = generatePrivateKey() let nsec = nsecEncode(sk) expect(nsec).toMatch(/nsec1\w+/) - let {type, data} = decode(nsec) + let { type, data } = decode(nsec) expect(type).toEqual('nsec') expect(data).toEqual(sk) }) @@ -23,20 +23,17 @@ test('encode and decode npub', () => { let pk = getPublicKey(generatePrivateKey()) let npub = npubEncode(pk) expect(npub).toMatch(/npub1\w+/) - let {type, data} = decode(npub) + let { type, data } = decode(npub) expect(type).toEqual('npub') expect(data).toEqual(pk) }) test('encode and decode nprofile', () => { let pk = getPublicKey(generatePrivateKey()) - let relays = [ - 'wss://relay.nostr.example.mydomain.example.com', - 'wss://nostr.banana.com' - ] - let nprofile = nprofileEncode({pubkey: pk, relays}) + let relays = ['wss://relay.nostr.example.mydomain.example.com', 'wss://nostr.banana.com'] + let nprofile = nprofileEncode({ pubkey: pk, relays }) expect(nprofile).toMatch(/nprofile1\w+/) - let {type, data} = decode(nprofile) + let { type, data } = decode(nprofile) expect(type).toEqual('nprofile') const pointer = data as ProfilePointer expect(pointer.pubkey).toEqual(pk) @@ -48,31 +45,24 @@ test('decode nprofile without relays', () => { expect( decode( nprofileEncode({ - pubkey: - '97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322', - relays: [] - }) - ).data - ).toHaveProperty( - 'pubkey', - '97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322' - ) + pubkey: '97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322', + relays: [], + }), + ).data, + ).toHaveProperty('pubkey', '97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322') }) test('encode and decode naddr', () => { let pk = getPublicKey(generatePrivateKey()) - let relays = [ - 'wss://relay.nostr.example.mydomain.example.com', - 'wss://nostr.banana.com' - ] + let relays = ['wss://relay.nostr.example.mydomain.example.com', 'wss://nostr.banana.com'] let naddr = naddrEncode({ pubkey: pk, relays, kind: 30023, - identifier: 'banana' + identifier: 'banana', }) expect(naddr).toMatch(/naddr1\w+/) - let {type, data} = decode(naddr) + let { type, data } = decode(naddr) expect(type).toEqual('naddr') const pointer = data as AddressPointer expect(pointer.pubkey).toEqual(pk) @@ -83,31 +73,25 @@ test('encode and decode naddr', () => { }) test('decode naddr from habla.news', () => { - let {type, data} = decode( - 'naddr1qq98yetxv4ex2mnrv4esygrl54h466tz4v0re4pyuavvxqptsejl0vxcmnhfl60z3rth2xkpjspsgqqqw4rsf34vl5' + let { type, data } = decode( + 'naddr1qq98yetxv4ex2mnrv4esygrl54h466tz4v0re4pyuavvxqptsejl0vxcmnhfl60z3rth2xkpjspsgqqqw4rsf34vl5', ) expect(type).toEqual('naddr') const pointer = data as AddressPointer - expect(pointer.pubkey).toEqual( - '7fa56f5d6962ab1e3cd424e758c3002b8665f7b0d8dcee9fe9e288d7751ac194' - ) + expect(pointer.pubkey).toEqual('7fa56f5d6962ab1e3cd424e758c3002b8665f7b0d8dcee9fe9e288d7751ac194') expect(pointer.kind).toEqual(30023) expect(pointer.identifier).toEqual('references') }) test('decode naddr from go-nostr with different TLV ordering', () => { - let {type, data} = decode( - 'naddr1qqrxyctwv9hxzq3q80cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsxpqqqp65wqfwwaehxw309aex2mrp0yhxummnw3ezuetcv9khqmr99ekhjer0d4skjm3wv4uxzmtsd3jjucm0d5q3vamnwvaz7tmwdaehgu3wvfskuctwvyhxxmmd0zfmwx' + let { type, data } = decode( + 'naddr1qqrxyctwv9hxzq3q80cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsxpqqqp65wqfwwaehxw309aex2mrp0yhxummnw3ezuetcv9khqmr99ekhjer0d4skjm3wv4uxzmtsd3jjucm0d5q3vamnwvaz7tmwdaehgu3wvfskuctwvyhxxmmd0zfmwx', ) expect(type).toEqual('naddr') const pointer = data as AddressPointer - expect(pointer.pubkey).toEqual( - '3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d' - ) - expect(pointer.relays).toContain( - 'wss://relay.nostr.example.mydomain.example.com' - ) + expect(pointer.pubkey).toEqual('3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d') + expect(pointer.relays).toContain('wss://relay.nostr.example.mydomain.example.com') expect(pointer.relays).toContain('wss://nostr.banana.com') expect(pointer.kind).toEqual(30023) expect(pointer.identifier).toEqual('banana') @@ -117,7 +101,7 @@ test('encode and decode nrelay', () => { let url = 'wss://relay.nostr.example' let nrelay = nrelayEncode(url) expect(nrelay).toMatch(/nrelay1\w+/) - let {type, data} = decode(nrelay) + let { type, data } = decode(nrelay) expect(type).toEqual('nrelay') expect(data).toEqual(url) }) diff --git a/nip19.ts b/nip19.ts index 8f402f4..fa83ff0 100644 --- a/nip19.ts +++ b/nip19.ts @@ -1,7 +1,7 @@ -import {bytesToHex, concatBytes, hexToBytes} from '@noble/hashes/utils' -import {bech32} from '@scure/base' +import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils' +import { bech32 } from '@scure/base' -import {utf8Decoder, utf8Encoder} from './utils.ts' +import { utf8Decoder, utf8Encoder } from './utils.ts' const Bech32MaxSize = 5000 @@ -9,8 +9,7 @@ const Bech32MaxSize = 5000 * Bech32 regex. * @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32 */ -export const BECH32_REGEX = - /[\x21-\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/ +export const BECH32_REGEX = /[\x21-\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/ export type ProfilePointer = { pubkey: string // hex @@ -52,7 +51,7 @@ export type DecodeResult = { export function decode(nip19: `${Prefix}1${string}`): DecodeValue export function decode(nip19: string): DecodeResult export function decode(nip19: string): DecodeResult { - let {prefix, words} = bech32.decode(nip19, Bech32MaxSize) + let { prefix, words } = bech32.decode(nip19, Bech32MaxSize) let data = new Uint8Array(bech32.fromWords(words)) switch (prefix) { @@ -65,24 +64,23 @@ export function decode(nip19: string): DecodeResult { type: 'nprofile', data: { pubkey: bytesToHex(tlv[0][0]), - relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [] - } + relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [], + }, } } case 'nevent': { let tlv = parseTLV(data) if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nevent') if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes') - if (tlv[2] && tlv[2][0].length !== 32) - throw new Error('TLV 2 should be 32 bytes') + if (tlv[2] && tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes') return { type: 'nevent', data: { id: bytesToHex(tlv[0][0]), relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [], - author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : undefined - } + author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : undefined, + }, } } @@ -100,8 +98,8 @@ export function decode(nip19: string): DecodeResult { identifier: utf8Decoder.decode(tlv[0][0]), pubkey: bytesToHex(tlv[2][0]), kind: parseInt(bytesToHex(tlv[3][0]), 16), - relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [] - } + relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [], + }, } } @@ -111,21 +109,21 @@ export function decode(nip19: string): DecodeResult { return { type: 'nrelay', - data: utf8Decoder.decode(tlv[0][0]) + data: utf8Decoder.decode(tlv[0][0]), } } case 'nsec': case 'npub': case 'note': - return {type: prefix, data: bytesToHex(data)} + return { type: prefix, data: bytesToHex(data) } default: throw new Error(`unknown prefix ${prefix}`) } } -type TLV = {[t: number]: Uint8Array[]} +type TLV = { [t: number]: Uint8Array[] } function parseTLV(data: Uint8Array): TLV { let result: TLV = {} @@ -168,7 +166,7 @@ function encodeBytes(prefix: Prefix, hex: string): `${Pre export function nprofileEncode(profile: ProfilePointer): `nprofile1${string}` { let data = encodeTLV({ 0: [hexToBytes(profile.pubkey)], - 1: (profile.relays || []).map(url => utf8Encoder.encode(url)) + 1: (profile.relays || []).map(url => utf8Encoder.encode(url)), }) return encodeBech32('nprofile', data) } @@ -177,7 +175,7 @@ export function neventEncode(event: EventPointer): `nevent1${string}` { let data = encodeTLV({ 0: [hexToBytes(event.id)], 1: (event.relays || []).map(url => utf8Encoder.encode(url)), - 2: event.author ? [hexToBytes(event.author)] : [] + 2: event.author ? [hexToBytes(event.author)] : [], }) return encodeBech32('nevent', data) } @@ -190,14 +188,14 @@ export function naddrEncode(addr: AddressPointer): `naddr1${string}` { 0: [utf8Encoder.encode(addr.identifier)], 1: (addr.relays || []).map(url => utf8Encoder.encode(url)), 2: [hexToBytes(addr.pubkey)], - 3: [new Uint8Array(kind)] + 3: [new Uint8Array(kind)], }) return encodeBech32('naddr', data) } export function nrelayEncode(url: string): `nrelay1${string}` { let data = encodeTLV({ - 0: [utf8Encoder.encode(url)] + 0: [utf8Encoder.encode(url)], }) return encodeBech32('nrelay', data) } diff --git a/nip21.test.ts b/nip21.test.ts index a985170..50be537 100644 --- a/nip21.test.ts +++ b/nip21.test.ts @@ -1,41 +1,23 @@ -import {test as testRegex, parse} from './nip21.ts' +import { test as testRegex, parse } from './nip21.ts' test('test()', () => { - expect( - testRegex( - 'nostr:npub108pv4cg5ag52nq082kd5leu9ffrn2gdg6g4xdwatn73y36uzplmq9uyev6' - ) - ).toBe(true) - expect( - testRegex( - 'nostr:note1gmtnz6q2m55epmlpe3semjdcq987av3jvx4emmjsa8g3s9x7tg4sclreky' - ) - ).toBe(true) - expect( - testRegex( - ' nostr:npub108pv4cg5ag52nq082kd5leu9ffrn2gdg6g4xdwatn73y36uzplmq9uyev6' - ) - ).toBe(false) + expect(testRegex('nostr:npub108pv4cg5ag52nq082kd5leu9ffrn2gdg6g4xdwatn73y36uzplmq9uyev6')).toBe(true) + expect(testRegex('nostr:note1gmtnz6q2m55epmlpe3semjdcq987av3jvx4emmjsa8g3s9x7tg4sclreky')).toBe(true) + expect(testRegex(' nostr:npub108pv4cg5ag52nq082kd5leu9ffrn2gdg6g4xdwatn73y36uzplmq9uyev6')).toBe(false) expect(testRegex('nostr:')).toBe(false) - expect( - testRegex( - 'nostr:npub108pv4cg5ag52nQq082kd5leu9ffrn2gdg6g4xdwatn73y36uzplmq9uyev6' - ) - ).toBe(false) + expect(testRegex('nostr:npub108pv4cg5ag52nQq082kd5leu9ffrn2gdg6g4xdwatn73y36uzplmq9uyev6')).toBe(false) expect(testRegex('gggggg')).toBe(false) }) test('parse', () => { - const result = parse( - 'nostr:note1gmtnz6q2m55epmlpe3semjdcq987av3jvx4emmjsa8g3s9x7tg4sclreky' - ) + const result = parse('nostr:note1gmtnz6q2m55epmlpe3semjdcq987av3jvx4emmjsa8g3s9x7tg4sclreky') expect(result).toEqual({ uri: 'nostr:note1gmtnz6q2m55epmlpe3semjdcq987av3jvx4emmjsa8g3s9x7tg4sclreky', value: 'note1gmtnz6q2m55epmlpe3semjdcq987av3jvx4emmjsa8g3s9x7tg4sclreky', decoded: { type: 'note', - data: '46d731680add2990efe1cc619dc9b8014feeb23261ab9dee50e9d11814de5a2b' - } + data: '46d731680add2990efe1cc619dc9b8014feeb23261ab9dee50e9d11814de5a2b', + }, }) }) diff --git a/nip21.ts b/nip21.ts index 2ff80f2..3bb0280 100644 --- a/nip21.ts +++ b/nip21.ts @@ -1,14 +1,11 @@ -import {BECH32_REGEX, decode, type DecodeResult} from './nip19.ts' +import { BECH32_REGEX, decode, type DecodeResult } from './nip19.ts' /** Nostr URI regex, eg `nostr:npub1...` */ export const NOSTR_URI_REGEX = new RegExp(`nostr:(${BECH32_REGEX.source})`) /** Test whether the value is a Nostr URI. */ export function test(value: unknown): value is `nostr:${string}` { - return ( - typeof value === 'string' && - new RegExp(`^${NOSTR_URI_REGEX.source}$`).test(value) - ) + return typeof value === 'string' && new RegExp(`^${NOSTR_URI_REGEX.source}$`).test(value) } /** Parsed Nostr URI data. */ @@ -28,6 +25,6 @@ export function parse(uri: string): NostrURI { return { uri: match[0] as `nostr:${string}`, value: match[1], - decoded: decode(match[1]) + decoded: decode(match[1]), } } diff --git a/nip25.test.ts b/nip25.test.ts index 7a43ba6..d397b82 100644 --- a/nip25.test.ts +++ b/nip25.test.ts @@ -1,10 +1,9 @@ -import {finishEvent, Kind} from './event.ts' -import {getPublicKey} from './keys.ts' -import {finishReactionEvent, getReactedEventPointer} from './nip25.ts' +import { finishEvent, Kind } from './event.ts' +import { getPublicKey } from './keys.ts' +import { finishReactionEvent, getReactedEventPointer } from './nip25.ts' describe('finishReactionEvent + getReactedEventPointer', () => { - const privateKey = - 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' + const privateKey = 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' const publicKey = getPublicKey(privateKey) @@ -13,17 +12,17 @@ describe('finishReactionEvent + getReactedEventPointer', () => { kind: Kind.Text, tags: [ ['e', 'replied event id'], - ['p', 'replied event pubkey'] + ['p', 'replied event pubkey'], ], content: 'Replied to a post', - created_at: 1617932115 + created_at: 1617932115, }, - privateKey + privateKey, ) it('should create a signed event from a minimal template', () => { const template = { - created_at: 1617932115 + created_at: 1617932115, } const event = finishReactionEvent(template, reactedEvent, privateKey) @@ -33,7 +32,7 @@ describe('finishReactionEvent + getReactedEventPointer', () => { ['e', 'replied event id'], ['p', 'replied event pubkey'], ['e', '0ecdbd4dba0652afb19e5f638257a41552a37995a4438ef63de658443f8d16b1'], - ['p', '6af0f9de588f2c53cedcba26c5e2402e0d0aa64ec7b47c9f8d97b5bc562bab5f'] + ['p', '6af0f9de588f2c53cedcba26c5e2402e0d0aa64ec7b47c9f8d97b5bc562bab5f'], ]) expect(event.content).toEqual('+') expect(event.created_at).toEqual(template.created_at) @@ -51,7 +50,7 @@ describe('finishReactionEvent + getReactedEventPointer', () => { const template = { tags: [['nonstandard', 'tag']], content: '👍', - created_at: 1617932115 + created_at: 1617932115, } const event = finishReactionEvent(template, reactedEvent, privateKey) @@ -62,7 +61,7 @@ describe('finishReactionEvent + getReactedEventPointer', () => { ['e', 'replied event id'], ['p', 'replied event pubkey'], ['e', '0ecdbd4dba0652afb19e5f638257a41552a37995a4438ef63de658443f8d16b1'], - ['p', '6af0f9de588f2c53cedcba26c5e2402e0d0aa64ec7b47c9f8d97b5bc562bab5f'] + ['p', '6af0f9de588f2c53cedcba26c5e2402e0d0aa64ec7b47c9f8d97b5bc562bab5f'], ]) expect(event.content).toEqual('👍') expect(event.created_at).toEqual(template.created_at) diff --git a/nip25.ts b/nip25.ts index 2fa3925..5e10c47 100644 --- a/nip25.ts +++ b/nip25.ts @@ -1,6 +1,6 @@ -import {Event, finishEvent, Kind} from './event.ts' +import { Event, finishEvent, Kind } from './event.ts' -import type {EventPointer} from './nip19.ts' +import type { EventPointer } from './nip19.ts' export type ReactionEventTemplate = { /** @@ -21,21 +21,17 @@ export function finishReactionEvent( reacted: Event, privateKey: string, ): Event { - const inheritedTags = reacted.tags.filter( - (tag) => tag.length >= 2 && (tag[0] === 'e' || tag[0] === 'p'), - ) + const inheritedTags = reacted.tags.filter(tag => tag.length >= 2 && (tag[0] === 'e' || tag[0] === 'p')) - return finishEvent({ - ...t, - kind: Kind.Reaction, - tags: [ - ...(t.tags ?? []), - ...inheritedTags, - ['e', reacted.id], - ['p', reacted.pubkey], - ], - content: t.content ?? '+', - }, privateKey) + return finishEvent( + { + ...t, + kind: Kind.Reaction, + tags: [...(t.tags ?? []), ...inheritedTags, ['e', reacted.id], ['p', reacted.pubkey]], + content: t.content ?? '+', + }, + privateKey, + ) } export function getReactedEventPointer(event: Event): undefined | EventPointer { @@ -63,7 +59,7 @@ export function getReactedEventPointer(event: Event): undefined | EventP return { id: lastETag[1], - relays: [ lastETag[2], lastPTag[2] ].filter((x) => x !== undefined), + relays: [lastETag[2], lastPTag[2]].filter(x => x !== undefined), author: lastPTag[1], } } diff --git a/nip26.test.ts b/nip26.test.ts index 23d8644..9bc7020 100644 --- a/nip26.test.ts +++ b/nip26.test.ts @@ -1,13 +1,12 @@ -import {getPublicKey, generatePrivateKey} from './keys.ts' -import {getDelegator, createDelegation} from './nip26.ts' -import {buildEvent} from './test-helpers.ts' +import { getPublicKey, generatePrivateKey } from './keys.ts' +import { getDelegator, createDelegation } from './nip26.ts' +import { buildEvent } from './test-helpers.ts' test('parse good delegation from NIP', async () => { expect( getDelegator({ id: 'a080fd288b60ac2225ff2e2d815291bd730911e583e177302cc949a15dc2b2dc', - pubkey: - '62903b1ff41559daf9ee98ef1ae67cc52f301bb5ce26d14baba3052f649c3f49', + pubkey: '62903b1ff41559daf9ee98ef1ae67cc52f301bb5ce26d14baba3052f649c3f49', created_at: 1660896109, kind: 1, tags: [ @@ -15,12 +14,12 @@ test('parse good delegation from NIP', async () => { 'delegation', '86f0689bd48dcd19c67a19d994f938ee34f251d8c39976290955ff585f2db42e', 'kind=1&created_at>1640995200', - 'c33c88ba78ec3c760e49db591ac5f7b129e3887c8af7729795e85a0588007e5ac89b46549232d8f918eefd73e726cb450135314bfda419c030d0b6affe401ec1' - ] + 'c33c88ba78ec3c760e49db591ac5f7b129e3887c8af7729795e85a0588007e5ac89b46549232d8f918eefd73e726cb450135314bfda419c030d0b6affe401ec1', + ], ], content: 'Hello world', - sig: 'cd4a3cd20dc61dcbc98324de561a07fd23b3d9702115920c0814b5fb822cc5b7c5bcdaf3fa326d24ed50c5b9c8214d66c75bae34e3a84c25e4d122afccb66eb6' - }) + sig: 'cd4a3cd20dc61dcbc98324de561a07fd23b3d9702115920c0814b5fb822cc5b7c5bcdaf3fa326d24ed50c5b9c8214d66c75bae34e3a84c25e4d122afccb66eb6', + }), ).toEqual('86f0689bd48dcd19c67a19d994f938ee34f251d8c39976290955ff585f2db42e') }) @@ -28,8 +27,7 @@ test('parse bad delegations', async () => { expect( getDelegator({ id: 'a080fd288b60ac2225ff2e2d815291bd730911e583e177302cc949a15dc2b2dc', - pubkey: - '62903b1ff41559daf9ee98ef1ae67cc52f301bb5ce26d14baba3052f649c3f49', + pubkey: '62903b1ff41559daf9ee98ef1ae67cc52f301bb5ce26d14baba3052f649c3f49', created_at: 1660896109, kind: 1, tags: [ @@ -37,19 +35,18 @@ test('parse bad delegations', async () => { 'delegation', '86f0689bd48dcd19c67a19d994f938ee34f251d8c39976290955ff585f2db42f', 'kind=1&created_at>1640995200', - 'c33c88ba78ec3c760e49db591ac5f7b129e3887c8af7729795e85a0588007e5ac89b46549232d8f918eefd73e726cb450135314bfda419c030d0b6affe401ec1' - ] + 'c33c88ba78ec3c760e49db591ac5f7b129e3887c8af7729795e85a0588007e5ac89b46549232d8f918eefd73e726cb450135314bfda419c030d0b6affe401ec1', + ], ], content: 'Hello world', - sig: 'cd4a3cd20dc61dcbc98324de561a07fd23b3d9702115920c0814b5fb822cc5b7c5bcdaf3fa326d24ed50c5b9c8214d66c75bae34e3a84c25e4d122afccb66eb6' - }) + sig: 'cd4a3cd20dc61dcbc98324de561a07fd23b3d9702115920c0814b5fb822cc5b7c5bcdaf3fa326d24ed50c5b9c8214d66c75bae34e3a84c25e4d122afccb66eb6', + }), ).toEqual(null) expect( getDelegator({ id: 'a080fd288b60ac2225ff2e2d815291bd730911e583e177302cc949a15dc2b2dc', - pubkey: - '62903b1ff41559daf9ee98ef1ae67cc52f301bb5ce26d14baba3052f649c3f49', + pubkey: '62903b1ff41559daf9ee98ef1ae67cc52f301bb5ce26d14baba3052f649c3f49', created_at: 1660896109, kind: 1, tags: [ @@ -57,19 +54,18 @@ test('parse bad delegations', async () => { 'delegation', '86f0689bd48dcd19c67a19d994f938ee34f251d8c39976290955ff585f2db42e', 'kind=1&created_at>1740995200', - 'c33c88ba78ec3c760e49db591ac5f7b129e3887c8af7729795e85a0588007e5ac89b46549232d8f918eefd73e726cb450135314bfda419c030d0b6affe401ec1' - ] + 'c33c88ba78ec3c760e49db591ac5f7b129e3887c8af7729795e85a0588007e5ac89b46549232d8f918eefd73e726cb450135314bfda419c030d0b6affe401ec1', + ], ], content: 'Hello world', - sig: 'cd4a3cd20dc61dcbc98324de561a07fd23b3d9702115920c0814b5fb822cc5b7c5bcdaf3fa326d24ed50c5b9c8214d66c75bae34e3a84c25e4d122afccb66eb6' - }) + sig: 'cd4a3cd20dc61dcbc98324de561a07fd23b3d9702115920c0814b5fb822cc5b7c5bcdaf3fa326d24ed50c5b9c8214d66c75bae34e3a84c25e4d122afccb66eb6', + }), ).toEqual(null) expect( getDelegator({ id: 'a080fd288b60ac2225ff2e2d815291bd730911e583e177302cc949a15dc2b2dc', - pubkey: - '62903b1ff41559daf9ee98ef1ae67c152f301bb5ce26d14baba3052f649c3f49', + pubkey: '62903b1ff41559daf9ee98ef1ae67c152f301bb5ce26d14baba3052f649c3f49', created_at: 1660896109, kind: 1, tags: [ @@ -77,12 +73,12 @@ test('parse bad delegations', async () => { 'delegation', '86f0689bd48dcd19c67a19d994f938ee34f251d8c39976290955ff585f2db42e', 'kind=1&created_at>1640995200', - 'c33c88ba78ec3c760e49db591ac5f7b129e3887c8af7729795e85a0588007e5ac89b46549232d8f918eefd73e726cb450135314bfda419c030d0b6affe401ec1' - ] + 'c33c88ba78ec3c760e49db591ac5f7b129e3887c8af7729795e85a0588007e5ac89b46549232d8f918eefd73e726cb450135314bfda419c030d0b6affe401ec1', + ], ], content: 'Hello world', - sig: 'cd4a3cd20dc61dcbc98324de561a07fd23b3d9702115920c0814b5fb822cc5b7c5bcdaf3fa326d24ed50c5b9c8214d66c75bae34e3a84c25e4d122afccb66eb6' - }) + sig: 'cd4a3cd20dc61dcbc98324de561a07fd23b3d9702115920c0814b5fb822cc5b7c5bcdaf3fa326d24ed50c5b9c8214d66c75bae34e3a84c25e4d122afccb66eb6', + }), ).toEqual(null) }) @@ -91,7 +87,7 @@ test('create and verify delegation', async () => { let pk1 = getPublicKey(sk1) let sk2 = generatePrivateKey() let pk2 = getPublicKey(sk2) - let delegation = createDelegation(sk1, {pubkey: pk2, kind: 1}) + let delegation = createDelegation(sk1, { pubkey: pk2, kind: 1 }) expect(delegation).toHaveProperty('from', pk1) expect(delegation).toHaveProperty('to', pk2) expect(delegation).toHaveProperty('cond', 'kind=1') diff --git a/nip26.ts b/nip26.ts index b9fdfcc..4ba46db 100644 --- a/nip26.ts +++ b/nip26.ts @@ -1,11 +1,11 @@ -import {schnorr} from '@noble/curves/secp256k1' -import {bytesToHex} from '@noble/hashes/utils' -import {sha256} from '@noble/hashes/sha256' +import { schnorr } from '@noble/curves/secp256k1' +import { bytesToHex } from '@noble/hashes/utils' +import { sha256 } from '@noble/hashes/sha256' -import {utf8Encoder} from './utils.ts' -import {getPublicKey} from './keys.ts' +import { utf8Encoder } from './utils.ts' +import { getPublicKey } from './keys.ts' -import type {Event} from './event.ts' +import type { Event } from './event.ts' export type Parameters = { pubkey: string // the key to whom the delegation will be given @@ -21,32 +21,24 @@ export type Delegation = { sig: string } -export function createDelegation( - privateKey: string, - parameters: Parameters -): Delegation { +export function createDelegation(privateKey: string, parameters: Parameters): Delegation { let conditions = [] if ((parameters.kind || -1) >= 0) conditions.push(`kind=${parameters.kind}`) if (parameters.until) conditions.push(`created_at<${parameters.until}`) if (parameters.since) conditions.push(`created_at>${parameters.since}`) let cond = conditions.join('&') - if (cond === '') - throw new Error('refusing to create a delegation without any conditions') + if (cond === '') throw new Error('refusing to create a delegation without any conditions') - let sighash = sha256( - utf8Encoder.encode(`nostr:delegation:${parameters.pubkey}:${cond}`) - ) + let sighash = sha256(utf8Encoder.encode(`nostr:delegation:${parameters.pubkey}:${cond}`)) - let sig = bytesToHex( - schnorr.sign(sighash, privateKey) - ) + let sig = bytesToHex(schnorr.sign(sighash, privateKey)) return { from: getPublicKey(privateKey), to: parameters.pubkey, cond, - sig + sig, } } @@ -65,27 +57,14 @@ export function getDelegator(event: Event): string | null { let [key, operator, value] = conditions[i].split(/\b/) // the supported conditions are just 'kind' and 'created_at' for now - if (key === 'kind' && operator === '=' && event.kind === parseInt(value)) - continue - else if ( - key === 'created_at' && - operator === '<' && - event.created_at < parseInt(value) - ) - continue - else if ( - key === 'created_at' && - operator === '>' && - event.created_at > parseInt(value) - ) - continue + if (key === 'kind' && operator === '=' && event.kind === parseInt(value)) continue + else if (key === 'created_at' && operator === '<' && event.created_at < parseInt(value)) continue + else if (key === 'created_at' && operator === '>' && event.created_at > parseInt(value)) continue else return null // invalid condition } // check signature - let sighash = sha256( - utf8Encoder.encode(`nostr:delegation:${event.pubkey}:${cond}`) - ) + let sighash = sha256(utf8Encoder.encode(`nostr:delegation:${event.pubkey}:${cond}`)) if (!schnorr.verify(sig, sighash, pubkey)) return null return pubkey diff --git a/nip27.test.ts b/nip27.test.ts index 134d23a..18e61aa 100644 --- a/nip27.test.ts +++ b/nip27.test.ts @@ -1,8 +1,8 @@ -import {matchAll, replaceAll} from './nip27.ts' +import { matchAll, replaceAll } from './nip27.ts' test('matchAll', () => { const result = matchAll( - 'Hello nostr:npub108pv4cg5ag52nq082kd5leu9ffrn2gdg6g4xdwatn73y36uzplmq9uyev6!\n\nnostr:note1gmtnz6q2m55epmlpe3semjdcq987av3jvx4emmjsa8g3s9x7tg4sclreky' + 'Hello nostr:npub108pv4cg5ag52nq082kd5leu9ffrn2gdg6g4xdwatn73y36uzplmq9uyev6!\n\nnostr:note1gmtnz6q2m55epmlpe3semjdcq987av3jvx4emmjsa8g3s9x7tg4sclreky', ) expect([...result]).toEqual([ @@ -11,40 +11,40 @@ test('matchAll', () => { value: 'npub108pv4cg5ag52nq082kd5leu9ffrn2gdg6g4xdwatn73y36uzplmq9uyev6', decoded: { type: 'npub', - data: '79c2cae114ea28a981e7559b4fe7854a473521a8d22a66bbab9fa248eb820ff6' + data: '79c2cae114ea28a981e7559b4fe7854a473521a8d22a66bbab9fa248eb820ff6', }, start: 6, - end: 75 + end: 75, }, { uri: 'nostr:note1gmtnz6q2m55epmlpe3semjdcq987av3jvx4emmjsa8g3s9x7tg4sclreky', value: 'note1gmtnz6q2m55epmlpe3semjdcq987av3jvx4emmjsa8g3s9x7tg4sclreky', decoded: { type: 'note', - data: '46d731680add2990efe1cc619dc9b8014feeb23261ab9dee50e9d11814de5a2b' + data: '46d731680add2990efe1cc619dc9b8014feeb23261ab9dee50e9d11814de5a2b', }, start: 78, - end: 147 - } + end: 147, + }, ]) }) test('matchAll with an invalid nip19', () => { const result = matchAll( - 'Hello nostr:npub129tvj896hqqkljerxkccpj9flshwnw999v9uwn9lfmwlj8vnzwgq9y5llnpub1rujdpkd8mwezrvpqd2rx2zphfaztqrtsfg6w3vdnlj!\n\nnostr:note1gmtnz6q2m55epmlpe3semjdcq987av3jvx4emmjsa8g3s9x7tg4sclreky' + 'Hello nostr:npub129tvj896hqqkljerxkccpj9flshwnw999v9uwn9lfmwlj8vnzwgq9y5llnpub1rujdpkd8mwezrvpqd2rx2zphfaztqrtsfg6w3vdnlj!\n\nnostr:note1gmtnz6q2m55epmlpe3semjdcq987av3jvx4emmjsa8g3s9x7tg4sclreky', ) expect([...result]).toEqual([ { decoded: { data: '46d731680add2990efe1cc619dc9b8014feeb23261ab9dee50e9d11814de5a2b', - type: 'note' + type: 'note', }, end: 193, start: 124, uri: 'nostr:note1gmtnz6q2m55epmlpe3semjdcq987av3jvx4emmjsa8g3s9x7tg4sclreky', - value: 'note1gmtnz6q2m55epmlpe3semjdcq987av3jvx4emmjsa8g3s9x7tg4sclreky' - } + value: 'note1gmtnz6q2m55epmlpe3semjdcq987av3jvx4emmjsa8g3s9x7tg4sclreky', + }, ]) }) @@ -52,7 +52,7 @@ test('replaceAll', () => { const content = 'Hello nostr:npub108pv4cg5ag52nq082kd5leu9ffrn2gdg6g4xdwatn73y36uzplmq9uyev6!\n\nnostr:note1gmtnz6q2m55epmlpe3semjdcq987av3jvx4emmjsa8g3s9x7tg4sclreky' - const result = replaceAll(content, ({decoded, value}) => { + const result = replaceAll(content, ({ decoded, value }) => { switch (decoded.type) { case 'npub': return '@alex' diff --git a/nip27.ts b/nip27.ts index fac7d59..c63804b 100644 --- a/nip27.ts +++ b/nip27.ts @@ -1,5 +1,5 @@ -import {decode} from './nip19.ts' -import {NOSTR_URI_REGEX, type NostrURI} from './nip21.ts' +import { decode } from './nip19.ts' +import { NOSTR_URI_REGEX, type NostrURI } from './nip21.ts' /** Regex to find NIP-21 URIs inside event content. */ export const regex = () => new RegExp(`\\b${NOSTR_URI_REGEX.source}\\b`, 'g') @@ -13,7 +13,7 @@ export interface NostrURIMatch extends NostrURI { } /** Find and decode all NIP-21 URIs. */ -export function * matchAll(content: string): Iterable { +export function* matchAll(content: string): Iterable { const matches = content.matchAll(regex()) for (const match of matches) { @@ -25,7 +25,7 @@ export function * matchAll(content: string): Iterable { value, decoded: decode(value), start: match.index!, - end: match.index! + uri.length + end: match.index! + uri.length, } } catch (_e) { // do nothing @@ -52,15 +52,12 @@ export function * matchAll(content: string): Iterable { * }) * ``` */ -export function replaceAll( - content: string, - replacer: (match: NostrURI) => string -): string { +export function replaceAll(content: string, replacer: (match: NostrURI) => string): string { return content.replaceAll(regex(), (uri, value: string) => { return replacer({ uri: uri as `nostr:${string}`, value, - decoded: decode(value) + decoded: decode(value), }) }) } diff --git a/nip28.test.ts b/nip28.test.ts index a850371..cee94f5 100644 --- a/nip28.test.ts +++ b/nip28.test.ts @@ -1,5 +1,5 @@ -import {Kind} from './event.ts' -import {getPublicKey} from './keys.ts' +import { Kind } from './event.ts' +import { getPublicKey } from './keys.ts' import { channelCreateEvent, channelMetadataEvent, @@ -7,24 +7,23 @@ import { channelHideMessageEvent, channelMuteUserEvent, ChannelMetadata, - ChannelMessageEventTemplate + ChannelMessageEventTemplate, } from './nip28.ts' -const privateKey = - 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' +const privateKey = 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' const publicKey = getPublicKey(privateKey) describe('NIP-28 Functions', () => { const channelMetadata: ChannelMetadata = { name: 'Test Channel', about: 'This is a test channel', - picture: 'https://example.com/picture.jpg' + picture: 'https://example.com/picture.jpg', } it('channelCreateEvent should create an event with given template', () => { const template = { content: channelMetadata, - created_at: 1617932115 + created_at: 1617932115, } const event = channelCreateEvent(template, privateKey) @@ -37,7 +36,7 @@ describe('NIP-28 Functions', () => { const template = { channel_create_event_id: 'channel creation event id', content: channelMetadata, - created_at: 1617932115 + created_at: 1617932115, } const event = channelMetadataEvent(template, privateKey) @@ -54,17 +53,12 @@ describe('NIP-28 Functions', () => { channel_create_event_id: 'channel creation event id', relay_url: 'https://relay.example.com', content: 'Hello, world!', - created_at: 1617932115 + created_at: 1617932115, } const event = channelMessageEvent(template, privateKey) expect(event.kind).toEqual(Kind.ChannelMessage) - expect(event.tags[0]).toEqual([ - 'e', - template.channel_create_event_id, - template.relay_url, - 'root' - ]) + expect(event.tags[0]).toEqual(['e', template.channel_create_event_id, template.relay_url, 'root']) expect(event.content).toEqual(template.content) expect(event.pubkey).toEqual(publicKey) expect(typeof event.id).toEqual('string') @@ -77,23 +71,13 @@ describe('NIP-28 Functions', () => { reply_to_channel_message_event_id: 'channel message event id', relay_url: 'https://relay.example.com', content: 'Hello, world!', - created_at: 1617932115 + created_at: 1617932115, } const event = channelMessageEvent(template, privateKey) expect(event.kind).toEqual(Kind.ChannelMessage) - expect(event.tags).toContainEqual([ - 'e', - template.channel_create_event_id, - template.relay_url, - 'root' - ]) - expect(event.tags).toContainEqual([ - 'e', - template.reply_to_channel_message_event_id, - template.relay_url, - 'reply' - ]) + expect(event.tags).toContainEqual(['e', template.channel_create_event_id, template.relay_url, 'root']) + expect(event.tags).toContainEqual(['e', template.reply_to_channel_message_event_id, template.relay_url, 'reply']) expect(event.content).toEqual(template.content) expect(event.pubkey).toEqual(publicKey) expect(typeof event.id).toEqual('string') @@ -103,8 +87,8 @@ describe('NIP-28 Functions', () => { it('channelHideMessageEvent should create a signed event with given template', () => { const template = { channel_message_event_id: 'channel message event id', - content: {reason: 'Inappropriate content'}, - created_at: 1617932115 + content: { reason: 'Inappropriate content' }, + created_at: 1617932115, } const event = channelHideMessageEvent(template, privateKey) @@ -118,9 +102,9 @@ describe('NIP-28 Functions', () => { it('channelMuteUserEvent should create a signed event with given template', () => { const template = { - content: {reason: 'Spamming'}, + content: { reason: 'Spamming' }, created_at: 1617932115, - pubkey_to_mute: 'pubkey to mute' + pubkey_to_mute: 'pubkey to mute', } const event = channelMuteUserEvent(template, privateKey) diff --git a/nip28.ts b/nip28.ts index 2d53bc2..fba812f 100644 --- a/nip28.ts +++ b/nip28.ts @@ -1,4 +1,4 @@ -import {Event, finishEvent, Kind} from './event.ts' +import { Event, finishEvent, Kind } from './event.ts' export interface ChannelMetadata { name: string @@ -32,13 +32,13 @@ export interface ChannelMessageEventTemplate { export interface ChannelHideMessageEventTemplate { channel_message_event_id: string - content: string | {reason: string} + content: string | { reason: string } created_at: number tags?: string[][] } export interface ChannelMuteUserEventTemplate { - content: string | {reason: string} + content: string | { reason: string } created_at: number pubkey_to_mute: string tags?: string[][] @@ -46,7 +46,7 @@ export interface ChannelMuteUserEventTemplate { export const channelCreateEvent = ( t: ChannelCreateEventTemplate, - privateKey: string + privateKey: string, ): Event | undefined => { let content: string if (typeof t.content === 'object') { @@ -62,15 +62,15 @@ export const channelCreateEvent = ( kind: Kind.ChannelCreation, tags: [...(t.tags ?? [])], content: content, - created_at: t.created_at + created_at: t.created_at, }, - privateKey + privateKey, ) } export const channelMetadataEvent = ( t: ChannelMetadataEventTemplate, - privateKey: string + privateKey: string, ): Event | undefined => { let content: string if (typeof t.content === 'object') { @@ -86,16 +86,13 @@ export const channelMetadataEvent = ( kind: Kind.ChannelMetadata, tags: [['e', t.channel_create_event_id], ...(t.tags ?? [])], content: content, - created_at: t.created_at + created_at: t.created_at, }, - privateKey + privateKey, ) } -export const channelMessageEvent = ( - t: ChannelMessageEventTemplate, - privateKey: string -): Event => { +export const channelMessageEvent = (t: ChannelMessageEventTemplate, privateKey: string): Event => { const tags = [['e', t.channel_create_event_id, t.relay_url, 'root']] if (t.reply_to_channel_message_event_id) { @@ -107,16 +104,16 @@ export const channelMessageEvent = ( kind: Kind.ChannelMessage, tags: [...tags, ...(t.tags ?? [])], content: t.content, - created_at: t.created_at + created_at: t.created_at, }, - privateKey + privateKey, ) } /* "e" tag should be the kind 42 event to hide */ export const channelHideMessageEvent = ( t: ChannelHideMessageEventTemplate, - privateKey: string + privateKey: string, ): Event | undefined => { let content: string if (typeof t.content === 'object') { @@ -132,15 +129,15 @@ export const channelHideMessageEvent = ( kind: Kind.ChannelHideMessage, tags: [['e', t.channel_message_event_id], ...(t.tags ?? [])], content: content, - created_at: t.created_at + created_at: t.created_at, }, - privateKey + privateKey, ) } export const channelMuteUserEvent = ( t: ChannelMuteUserEventTemplate, - privateKey: string + privateKey: string, ): Event | undefined => { let content: string if (typeof t.content === 'object') { @@ -156,8 +153,8 @@ export const channelMuteUserEvent = ( kind: Kind.ChannelMuteUser, tags: [['p', t.pubkey_to_mute], ...(t.tags ?? [])], content: content, - created_at: t.created_at + created_at: t.created_at, }, - privateKey + privateKey, ) } diff --git a/nip39.test.ts b/nip39.test.ts index ac7142e..ac31a69 100644 --- a/nip39.test.ts +++ b/nip39.test.ts @@ -1,6 +1,6 @@ import fetch from 'node-fetch' -import {useFetchImplementation, validateGithub} from './nip39.ts' +import { useFetchImplementation, validateGithub } from './nip39.ts' test('validate github claim', async () => { useFetchImplementation(fetch) @@ -8,7 +8,7 @@ test('validate github claim', async () => { let result = await validateGithub( 'npub1gcxzte5zlkncx26j68ez60fzkvtkm9e0vrwdcvsjakxf9mu9qewqlfnj5z', 'vitorpamplona', - 'cf19e2d1d7f8dac6348ad37b35ec8421' + 'cf19e2d1d7f8dac6348ad37b35ec8421', ) expect(result).toBe(true) }) diff --git a/nip39.ts b/nip39.ts index 9a94af7..73237f8 100644 --- a/nip39.ts +++ b/nip39.ts @@ -8,19 +8,10 @@ export function useFetchImplementation(fetchImplementation: any) { _fetch = fetchImplementation } -export async function validateGithub( - pubkey: string, - username: string, - proof: string -): Promise { +export async function validateGithub(pubkey: string, username: string, proof: string): Promise { try { - let res = await ( - await _fetch(`https://gist.github.com/${username}/${proof}/raw`) - ).text() - return ( - res === - `Verifying that I control the following Nostr public key: ${pubkey}` - ) + let res = await (await _fetch(`https://gist.github.com/${username}/${proof}/raw`)).text() + return res === `Verifying that I control the following Nostr public key: ${pubkey}` } catch (_) { return false } diff --git a/nip42.test.ts b/nip42.test.ts index 9ee6bee..53adb2b 100644 --- a/nip42.test.ts +++ b/nip42.test.ts @@ -1,23 +1,23 @@ import 'websocket-polyfill' -import {finishEvent} from './event.ts' -import {generatePrivateKey} from './keys.ts' -import {authenticate} from './nip42.ts' -import {relayInit} from './relay.ts' +import { finishEvent } from './event.ts' +import { generatePrivateKey } from './keys.ts' +import { authenticate } from './nip42.ts' +import { relayInit } from './relay.ts' test('auth flow', () => { const relay = relayInit('wss://nostr.kollider.xyz') relay.connect() const sk = generatePrivateKey() - return new Promise((resolve) => { + return new Promise(resolve => { relay.on('auth', async challenge => { await expect( authenticate({ challenge, relay, - sign: (e) => finishEvent(e, sk) - }) + sign: e => finishEvent(e, sk), + }), ).rejects.toBeTruthy() relay.close() resolve() diff --git a/nip42.ts b/nip42.ts index 369545b..167d6e3 100644 --- a/nip42.ts +++ b/nip42.ts @@ -1,5 +1,5 @@ -import {Kind, type EventTemplate, type Event} from './event.ts' -import {Relay} from './relay.ts' +import { Kind, type EventTemplate, type Event } from './event.ts' +import { Relay } from './relay.ts' /** * Authenticate via NIP-42 flow. @@ -13,22 +13,20 @@ import {Relay} from './relay.ts' export const authenticate = async ({ challenge, relay, - sign + sign, }: { challenge: string relay: Relay - sign: ( - e: EventTemplate - ) => Promise> | Event + sign: (e: EventTemplate) => Promise> | Event }): Promise => { const e: EventTemplate = { kind: Kind.ClientAuth, created_at: Math.floor(Date.now() / 1000), tags: [ ['relay', relay.url], - ['challenge', challenge] + ['challenge', challenge], ], - content: '' + content: '', } return relay.auth(await sign(e)) } diff --git a/nip44.test.ts b/nip44.test.ts index 1bf348b..a9a89e6 100644 --- a/nip44.test.ts +++ b/nip44.test.ts @@ -1,8 +1,8 @@ import crypto from 'node:crypto' -import {hexToBytes} from '@noble/hashes/utils' +import { hexToBytes } from '@noble/hashes/utils' -import {encrypt, decrypt, getSharedSecret} from './nip44.ts' -import {getPublicKey, generatePrivateKey} from './keys.ts' +import { encrypt, decrypt, getSharedSecret } from './nip44.ts' +import { getPublicKey, generatePrivateKey } from './keys.ts' // @ts-ignore // eslint-disable-next-line no-undef diff --git a/nip44.ts b/nip44.ts index d526d2a..dd75f85 100644 --- a/nip44.ts +++ b/nip44.ts @@ -1,10 +1,10 @@ -import {base64} from '@scure/base' -import {randomBytes} from '@noble/hashes/utils' -import {secp256k1} from '@noble/curves/secp256k1' -import {sha256} from '@noble/hashes/sha256' -import {xchacha20} from '@noble/ciphers/chacha' +import { base64 } from '@scure/base' +import { randomBytes } from '@noble/hashes/utils' +import { secp256k1 } from '@noble/curves/secp256k1' +import { sha256 } from '@noble/hashes/sha256' +import { xchacha20 } from '@noble/ciphers/chacha' -import {utf8Decoder, utf8Encoder} from './utils.ts' +import { utf8Decoder, utf8Encoder } from './utils.ts' export const getSharedSecret = (privkey: string, pubkey: string): Uint8Array => sha256(secp256k1.getSharedSecret(privkey, '02' + pubkey).subarray(1, 33)) diff --git a/nip57.test.ts b/nip57.test.ts index 9df9883..4990f07 100644 --- a/nip57.test.ts +++ b/nip57.test.ts @@ -1,17 +1,11 @@ -import {finishEvent} from './event.ts' -import {getPublicKey, generatePrivateKey} from './keys.ts' -import { - getZapEndpoint, - makeZapReceipt, - makeZapRequest, - useFetchImplementation, - validateZapRequest, -} from './nip57.ts' -import {buildEvent} from './test-helpers.ts' +import { finishEvent } from './event.ts' +import { getPublicKey, generatePrivateKey } from './keys.ts' +import { getZapEndpoint, makeZapReceipt, makeZapRequest, useFetchImplementation, validateZapRequest } from './nip57.ts' +import { buildEvent } from './test-helpers.ts' describe('getZapEndpoint', () => { test('returns null if neither lud06 nor lud16 is present', async () => { - const metadata = buildEvent({kind: 0, content: '{}'}) + const metadata = buildEvent({ kind: 0, content: '{}' }) const result = await getZapEndpoint(metadata) expect(result).toBeNull() @@ -21,28 +15,22 @@ describe('getZapEndpoint', () => { const fetchImplementation = jest.fn(() => Promise.reject(new Error())) useFetchImplementation(fetchImplementation) - const metadata = buildEvent({kind: 0, content: '{"lud16": "name@domain"}'}) + const metadata = buildEvent({ kind: 0, content: '{"lud16": "name@domain"}' }) const result = await getZapEndpoint(metadata) expect(result).toBeNull() - expect(fetchImplementation).toHaveBeenCalledWith( - 'https://domain/.well-known/lnurlp/name' - ) + expect(fetchImplementation).toHaveBeenCalledWith('https://domain/.well-known/lnurlp/name') }) test('returns null if the response does not allow Nostr payments', async () => { - const fetchImplementation = jest.fn(() => - Promise.resolve({json: () => ({allowsNostr: false})}) - ) + const fetchImplementation = jest.fn(() => Promise.resolve({ json: () => ({ allowsNostr: false }) })) useFetchImplementation(fetchImplementation) - const metadata = buildEvent({kind: 0, content: '{"lud16": "name@domain"}'}) + const metadata = buildEvent({ kind: 0, content: '{"lud16": "name@domain"}' }) const result = await getZapEndpoint(metadata) expect(result).toBeNull() - expect(fetchImplementation).toHaveBeenCalledWith( - 'https://domain/.well-known/lnurlp/name' - ) + expect(fetchImplementation).toHaveBeenCalledWith('https://domain/.well-known/lnurlp/name') }) test('returns the callback URL if the response allows Nostr payments', async () => { @@ -51,19 +39,17 @@ describe('getZapEndpoint', () => { json: () => ({ allowsNostr: true, nostrPubkey: 'pubkey', - callback: 'callback' - }) - }) + callback: 'callback', + }), + }), ) useFetchImplementation(fetchImplementation) - const metadata = buildEvent({kind: 0, content: '{"lud16": "name@domain"}'}) + const metadata = buildEvent({ kind: 0, content: '{"lud16": "name@domain"}' }) const result = await getZapEndpoint(metadata) expect(result).toBe('callback') - expect(fetchImplementation).toHaveBeenCalledWith( - 'https://domain/.well-known/lnurlp/name' - ) + expect(fetchImplementation).toHaveBeenCalledWith('https://domain/.well-known/lnurlp/name') }) }) @@ -75,8 +61,8 @@ describe('makeZapRequest', () => { profile: 'profile', event: null, relays: [], - comment: '' - }) + comment: '', + }), ).toThrow() }) @@ -87,8 +73,8 @@ describe('makeZapRequest', () => { event: null, amount: 100, relays: [], - comment: '' - }) + comment: '', + }), ).toThrow() }) @@ -98,7 +84,7 @@ describe('makeZapRequest', () => { event: 'event', amount: 100, relays: ['relay1', 'relay2'], - comment: 'comment' + comment: 'comment', }) expect(result.kind).toBe(9734) expect(result.created_at).toBeCloseTo(Date.now() / 1000, 0) @@ -107,8 +93,8 @@ describe('makeZapRequest', () => { expect.arrayContaining([ ['p', 'profile'], ['amount', '100'], - ['relays', 'relay1', 'relay2'] - ]) + ['relays', 'relay1', 'relay2'], + ]), ) expect(result.tags).toContainEqual(['e', 'event']) }) @@ -116,9 +102,7 @@ describe('makeZapRequest', () => { describe('validateZapRequest', () => { test('returns an error message for invalid JSON', () => { - expect(validateZapRequest('invalid JSON')).toBe( - 'Invalid zap request JSON.' - ) + expect(validateZapRequest('invalid JSON')).toBe('Invalid zap request JSON.') }) test('returns an error message if the Zap request is not a valid Nostr event', () => { @@ -129,13 +113,11 @@ describe('validateZapRequest', () => { tags: [ ['p', 'profile'], ['amount', '100'], - ['relays', 'relay1', 'relay2'] - ] + ['relays', 'relay1', 'relay2'], + ], } - expect(validateZapRequest(JSON.stringify(zapRequest))).toBe( - 'Zap request is not a valid Nostr event.' - ) + expect(validateZapRequest(JSON.stringify(zapRequest))).toBe('Zap request is not a valid Nostr event.') }) test('returns an error message if the signature on the Zap request is invalid', () => { @@ -150,13 +132,11 @@ describe('validateZapRequest', () => { tags: [ ['p', publicKey], ['amount', '100'], - ['relays', 'relay1', 'relay2'] - ] + ['relays', 'relay1', 'relay2'], + ], } - expect(validateZapRequest(JSON.stringify(zapRequest))).toBe( - 'Invalid signature on zap request.' - ) + expect(validateZapRequest(JSON.stringify(zapRequest))).toBe('Invalid signature on zap request.') }) test('returns an error message if the Zap request does not have a "p" tag', () => { @@ -169,15 +149,13 @@ describe('validateZapRequest', () => { content: 'content', tags: [ ['amount', '100'], - ['relays', 'relay1', 'relay2'] - ] + ['relays', 'relay1', 'relay2'], + ], }, - privateKey + privateKey, ) - expect(validateZapRequest(JSON.stringify(zapRequest))).toBe( - "Zap request doesn't have a 'p' tag." - ) + expect(validateZapRequest(JSON.stringify(zapRequest))).toBe("Zap request doesn't have a 'p' tag.") }) test('returns an error message if the "p" tag on the Zap request is not valid hex', () => { @@ -191,15 +169,13 @@ describe('validateZapRequest', () => { tags: [ ['p', 'invalid hex'], ['amount', '100'], - ['relays', 'relay1', 'relay2'] - ] + ['relays', 'relay1', 'relay2'], + ], }, - privateKey + privateKey, ) - expect(validateZapRequest(JSON.stringify(zapRequest))).toBe( - "Zap request 'p' tag is not valid hex." - ) + expect(validateZapRequest(JSON.stringify(zapRequest))).toBe("Zap request 'p' tag is not valid hex.") }) test('returns an error message if the "e" tag on the Zap request is not valid hex', () => { @@ -215,15 +191,13 @@ describe('validateZapRequest', () => { ['p', publicKey], ['e', 'invalid hex'], ['amount', '100'], - ['relays', 'relay1', 'relay2'] - ] + ['relays', 'relay1', 'relay2'], + ], }, - privateKey + privateKey, ) - expect(validateZapRequest(JSON.stringify(zapRequest))).toBe( - "Zap request 'e' tag is not valid hex." - ) + expect(validateZapRequest(JSON.stringify(zapRequest))).toBe("Zap request 'e' tag is not valid hex.") }) test('returns an error message if the Zap request does not have a relays tag', () => { @@ -237,15 +211,13 @@ describe('validateZapRequest', () => { content: 'content', tags: [ ['p', publicKey], - ['amount', '100'] - ] + ['amount', '100'], + ], }, - privateKey + privateKey, ) - expect(validateZapRequest(JSON.stringify(zapRequest))).toBe( - "Zap request doesn't have a 'relays' tag." - ) + expect(validateZapRequest(JSON.stringify(zapRequest))).toBe("Zap request doesn't have a 'relays' tag.") }) test('returns null for a valid Zap request', () => { @@ -260,10 +232,10 @@ describe('validateZapRequest', () => { tags: [ ['p', publicKey], ['amount', '100'], - ['relays', 'relay1', 'relay2'] - ] + ['relays', 'relay1', 'relay2'], + ], }, - privateKey + privateKey, ) expect(validateZapRequest(JSON.stringify(zapRequest))).toBeNull() @@ -284,17 +256,17 @@ describe('makeZapReceipt', () => { tags: [ ['p', publicKey], ['amount', '100'], - ['relays', 'relay1', 'relay2'] - ] + ['relays', 'relay1', 'relay2'], + ], }, - privateKey - ) + privateKey, + ), ) const preimage = 'preimage' const bolt11 = 'bolt11' const paidAt = new Date() - const result = makeZapReceipt({zapRequest, preimage, bolt11, paidAt}) + const result = makeZapReceipt({ zapRequest, preimage, bolt11, paidAt }) expect(result.kind).toBe(9735) expect(result.created_at).toBeCloseTo(paidAt.getTime() / 1000, 0) @@ -318,16 +290,16 @@ describe('makeZapReceipt', () => { tags: [ ['p', publicKey], ['amount', '100'], - ['relays', 'relay1', 'relay2'] - ] + ['relays', 'relay1', 'relay2'], + ], }, - privateKey - ) + privateKey, + ), ) const bolt11 = 'bolt11' const paidAt = new Date() - const result = makeZapReceipt({zapRequest, bolt11, paidAt}) + const result = makeZapReceipt({ zapRequest, bolt11, paidAt }) expect(result.kind).toBe(9735) expect(result.created_at).toBeCloseTo(paidAt.getTime() / 1000, 0) diff --git a/nip57.ts b/nip57.ts index 6c424f9..94fd488 100644 --- a/nip57.ts +++ b/nip57.ts @@ -1,13 +1,7 @@ -import {bech32} from '@scure/base' +import { bech32 } from '@scure/base' -import { - Kind, - validateEvent, - verifySignature, - type Event, - type EventTemplate, -} from './event.ts' -import {utf8Decoder} from './utils.ts' +import { Kind, validateEvent, verifySignature, type Event, type EventTemplate } from './event.ts' +import { utf8Decoder } from './utils.ts' var _fetch: any @@ -19,14 +13,12 @@ export function useFetchImplementation(fetchImplementation: any) { _fetch = fetchImplementation } -export async function getZapEndpoint( - metadata: Event -): Promise { +export async function getZapEndpoint(metadata: Event): Promise { try { let lnurl: string = '' - let {lud06, lud16} = JSON.parse(metadata.content) + let { lud06, lud16 } = JSON.parse(metadata.content) if (lud06) { - let {words} = bech32.decode(lud06, 1000) + let { words } = bech32.decode(lud06, 1000) let data = bech32.fromWords(words) lnurl = utf8Decoder.decode(data) } else if (lud16) { @@ -54,7 +46,7 @@ export function makeZapRequest({ event, amount, relays, - comment = '' + comment = '', }: { profile: string event: string | null @@ -72,8 +64,8 @@ export function makeZapRequest({ tags: [ ['p', profile], ['amount', amount.toString()], - ['relays', ...relays] - ] + ['relays', ...relays], + ], } if (event) { @@ -92,19 +84,16 @@ export function validateZapRequest(zapRequestString: string): string | null { return 'Invalid zap request JSON.' } - if (!validateEvent(zapRequest)) - return 'Zap request is not a valid Nostr event.' + if (!validateEvent(zapRequest)) return 'Zap request is not a valid Nostr event.' if (!verifySignature(zapRequest)) return 'Invalid signature on zap request.' let p = zapRequest.tags.find(([t, v]) => t === 'p' && v) if (!p) return "Zap request doesn't have a 'p' tag." - if (!p[1].match(/^[a-f0-9]{64}$/)) - return "Zap request 'p' tag is not valid hex." + if (!p[1].match(/^[a-f0-9]{64}$/)) return "Zap request 'p' tag is not valid hex." let e = zapRequest.tags.find(([t, v]) => t === 'e' && v) - if (e && !e[1].match(/^[a-f0-9]{64}$/)) - return "Zap request 'e' tag is not valid hex." + if (e && !e[1].match(/^[a-f0-9]{64}$/)) return "Zap request 'e' tag is not valid hex." let relays = zapRequest.tags.find(([t, v]) => t === 'relays' && v) if (!relays) return "Zap request doesn't have a 'relays' tag." @@ -116,7 +105,7 @@ export function makeZapReceipt({ zapRequest, preimage, bolt11, - paidAt + paidAt, }: { zapRequest: string preimage?: string @@ -124,19 +113,13 @@ export function makeZapReceipt({ paidAt: Date }): EventTemplate { let zr: Event = JSON.parse(zapRequest) - let tagsFromZapRequest = zr.tags.filter( - ([t]) => t === 'e' || t === 'p' || t === 'a' - ) + let tagsFromZapRequest = zr.tags.filter(([t]) => t === 'e' || t === 'p' || t === 'a') let zap: EventTemplate = { kind: 9735, created_at: Math.round(paidAt.getTime() / 1000), content: '', - tags: [ - ...tagsFromZapRequest, - ['bolt11', bolt11], - ['description', zapRequest] - ] + tags: [...tagsFromZapRequest, ['bolt11', bolt11], ['description', zapRequest]], } if (preimage) { diff --git a/nip98.test.ts b/nip98.test.ts index 034f8f1..5a637a1 100644 --- a/nip98.test.ts +++ b/nip98.test.ts @@ -1,14 +1,12 @@ -import {getToken, unpackEventFromToken, validateEvent, validateToken} from './nip98.ts' -import {Event, Kind, finishEvent} from './event.ts' -import {generatePrivateKey, getPublicKey} from './keys.ts' +import { getToken, unpackEventFromToken, validateEvent, validateToken } from './nip98.ts' +import { Event, Kind, finishEvent } from './event.ts' +import { generatePrivateKey, getPublicKey } from './keys.ts' const sk = generatePrivateKey() describe('getToken', () => { test('getToken GET returns without authorization scheme', async () => { - let result = await getToken('http://test.com', 'get', e => - finishEvent(e, sk) - ) + let result = await getToken('http://test.com', 'get', e => finishEvent(e, sk)) const decodedResult: Event = await unpackEventFromToken(result) @@ -18,14 +16,12 @@ describe('getToken', () => { expect(decodedResult.pubkey).toBe(getPublicKey(sk)) expect(decodedResult.tags).toStrictEqual([ ['u', 'http://test.com'], - ['method', 'get'] + ['method', 'get'], ]) }) test('getToken POST returns token without authorization scheme', async () => { - let result = await getToken('http://test.com', 'post', e => - finishEvent(e, sk) - ) + let result = await getToken('http://test.com', 'post', e => finishEvent(e, sk)) const decodedResult: Event = await unpackEventFromToken(result) @@ -35,19 +31,14 @@ describe('getToken', () => { expect(decodedResult.pubkey).toBe(getPublicKey(sk)) expect(decodedResult.tags).toStrictEqual([ ['u', 'http://test.com'], - ['method', 'post'] + ['method', 'post'], ]) }) test('getToken GET returns token WITH authorization scheme', async () => { const authorizationScheme = 'Nostr ' - let result = await getToken( - 'http://test.com', - 'post', - e => finishEvent(e, sk), - true - ) + let result = await getToken('http://test.com', 'post', e => finishEvent(e, sk), true) expect(result.startsWith(authorizationScheme)).toBe(true) @@ -59,7 +50,7 @@ describe('getToken', () => { expect(decodedResult.pubkey).toBe(getPublicKey(sk)) expect(decodedResult.tags).toStrictEqual([ ['u', 'http://test.com'], - ['method', 'post'] + ['method', 'post'], ]) }) @@ -81,21 +72,14 @@ describe('getToken', () => { describe('validateToken', () => { test('validateToken returns true for valid token without authorization scheme', async () => { - const validToken = await getToken('http://test.com', 'get', e => - finishEvent(e, sk) - ) + const validToken = await getToken('http://test.com', 'get', e => finishEvent(e, sk)) const result = await validateToken(validToken, 'http://test.com', 'get') expect(result).toBe(true) }) test('validateToken returns true for valid token with authorization scheme', async () => { - const validToken = await getToken( - 'http://test.com', - 'get', - e => finishEvent(e, sk), - true - ) + const validToken = await getToken('http://test.com', 'get', e => finishEvent(e, sk), true) const result = await validateToken(validToken, 'http://test.com', 'get') expect(result).toBe(true) @@ -112,30 +96,21 @@ describe('validateToken', () => { }) test('validateToken throws an error for a wrong url', async () => { - const validToken = await getToken('http://test.com', 'get', e => - finishEvent(e, sk) - ) + const validToken = await getToken('http://test.com', 'get', e => finishEvent(e, sk)) const result = validateToken(validToken, 'http://wrong-test.com', 'get') await expect(result).rejects.toThrow(Error) }) test('validateToken throws an error for a wrong method', async () => { - const validToken = await getToken('http://test.com', 'get', e => - finishEvent(e, sk) - ) + const validToken = await getToken('http://test.com', 'get', e => finishEvent(e, sk)) const result = validateToken(validToken, 'http://test.com', 'post') await expect(result).rejects.toThrow(Error) }) test('validateEvent returns true for valid decoded token with authorization scheme', async () => { - const validToken = await getToken( - 'http://test.com', - 'get', - e => finishEvent(e, sk), - true - ) + const validToken = await getToken('http://test.com', 'get', e => finishEvent(e, sk), true) const decodedResult: Event = await unpackEventFromToken(validToken) const result = await validateEvent(decodedResult, 'http://test.com', 'get') @@ -143,12 +118,7 @@ describe('validateToken', () => { }) test('validateEvent throws an error for a wrong url', async () => { - const validToken = await getToken( - 'http://test.com', - 'get', - e => finishEvent(e, sk), - true - ) + const validToken = await getToken('http://test.com', 'get', e => finishEvent(e, sk), true) const decodedResult: Event = await unpackEventFromToken(validToken) const result = validateEvent(decodedResult, 'http://wrong-test.com', 'get') @@ -156,12 +126,7 @@ describe('validateToken', () => { }) test('validateEvent throws an error for a wrong method', async () => { - const validToken = await getToken( - 'http://test.com', - 'get', - e => finishEvent(e, sk), - true - ) + const validToken = await getToken('http://test.com', 'get', e => finishEvent(e, sk), true) const decodedResult: Event = await unpackEventFromToken(validToken) const result = validateEvent(decodedResult, 'http://test.com', 'post') diff --git a/nip98.ts b/nip98.ts index f7a79e7..3e78ec6 100644 --- a/nip98.ts +++ b/nip98.ts @@ -1,12 +1,6 @@ -import {base64} from '@scure/base' -import { - Event, - EventTemplate, - Kind, - getBlankEvent, - verifySignature -} from './event' -import {utf8Decoder, utf8Encoder} from './utils' +import { base64 } from '@scure/base' +import { Event, EventTemplate, Kind, getBlankEvent, verifySignature } from './event' +import { utf8Decoder, utf8Encoder } from './utils' const _authorizationScheme = 'Nostr ' @@ -20,31 +14,23 @@ const _authorizationScheme = 'Nostr ' export async function getToken( loginUrl: string, httpMethod: string, - sign: ( - e: EventTemplate - ) => Promise> | Event, - includeAuthorizationScheme: boolean = false + sign: (e: EventTemplate) => Promise> | Event, + includeAuthorizationScheme: boolean = false, ): Promise { - if (!loginUrl || !httpMethod) - throw new Error('Missing loginUrl or httpMethod') + if (!loginUrl || !httpMethod) throw new Error('Missing loginUrl or httpMethod') const event = getBlankEvent(Kind.HttpAuth) event.tags = [ ['u', loginUrl], - ['method', httpMethod] + ['method', httpMethod], ] event.created_at = Math.round(new Date().getTime() / 1000) const signedEvent = await sign(event) - const authorizationScheme = includeAuthorizationScheme - ? _authorizationScheme - : '' - return ( - authorizationScheme + - base64.encode(utf8Encoder.encode(JSON.stringify(signedEvent))) - ) + const authorizationScheme = includeAuthorizationScheme ? _authorizationScheme : '' + return authorizationScheme + base64.encode(utf8Encoder.encode(JSON.stringify(signedEvent))) } /** @@ -53,13 +39,13 @@ export async function getToken( * @example * await nip98.validateToken('Nostr base64token', 'https://example.com/login', 'post') */ -export async function validateToken( - token: string, - url: string, - method: string -): Promise { - const event = await unpackEventFromToken(token).catch((error) => { throw(error) }) - const valid = await validateEvent(event, url, method).catch((error) => { throw(error) }) +export async function validateToken(token: string, url: string, method: string): Promise { + const event = await unpackEventFromToken(token).catch(error => { + throw error + }) + const valid = await validateEvent(event, url, method).catch(error => { + throw error + }) return valid } @@ -80,11 +66,7 @@ export async function unpackEventFromToken(token: string): Promise { return event } -export async function validateEvent( - event: Event, - url: string, - method: string -): Promise { +export async function validateEvent(event: Event, url: string, method: string): Promise { if (!event) { throw new Error('Invalid nostr event') } @@ -110,10 +92,7 @@ export async function validateEvent( } const methodTag = event.tags.find(t => t[0] === 'method') - if ( - methodTag?.length !== 1 && - methodTag?.[1].toLowerCase() !== method.toLowerCase() - ) { + if (methodTag?.length !== 1 && methodTag?.[1].toLowerCase() !== method.toLowerCase()) { throw new Error('Invalid nostr event, method tag invalid') } diff --git a/pool.test.ts b/pool.test.ts index c6de68e..6c1d59f 100644 --- a/pool.test.ts +++ b/pool.test.ts @@ -1,8 +1,8 @@ import 'websocket-polyfill' -import {finishEvent, type Event} from './event.ts' -import {generatePrivateKey, getPublicKey} from './keys.ts' -import {SimplePool} from './pool.ts' +import { finishEvent, type Event } from './event.ts' +import { generatePrivateKey, getPublicKey } from './keys.ts' +import { SimplePool } from './pool.ts' let pool = new SimplePool() @@ -11,23 +11,18 @@ let relays = [ 'wss://relay.nostr.bg/', 'wss://nostr.fmt.wiz.biz/', 'wss://relay.nostr.band/', - 'wss://nos.lol/' + 'wss://nos.lol/', ] afterAll(() => { - pool.close([ - ...relays, - 'wss://nostr.wine', - 'wss://offchain.pub', - 'wss://eden.nostr.land' - ]) + pool.close([...relays, 'wss://nostr.wine', 'wss://offchain.pub', 'wss://eden.nostr.land']) }) test('removing duplicates when querying', async () => { let priv = generatePrivateKey() let pub = getPublicKey(priv) - let sub = pool.sub(relays, [{authors: [pub]}]) + let sub = pool.sub(relays, [{ authors: [pub] }]) let received: Event[] = [] sub.on('event', event => { @@ -37,12 +32,15 @@ test('removing duplicates when querying', async () => { received.push(event) }) - let event = finishEvent({ - created_at: Math.round(Date.now() / 1000), - content: 'test', - kind: 22345, - tags: [] - }, priv) + let event = finishEvent( + { + created_at: Math.round(Date.now() / 1000), + content: 'test', + kind: 22345, + tags: [], + }, + priv, + ) pool.publish(relays, event) @@ -55,8 +53,8 @@ test('same with double querying', async () => { let priv = generatePrivateKey() let pub = getPublicKey(priv) - let sub1 = pool.sub(relays, [{authors: [pub]}]) - let sub2 = pool.sub(relays, [{authors: [pub]}]) + let sub1 = pool.sub(relays, [{ authors: [pub] }]) + let sub2 = pool.sub(relays, [{ authors: [pub] }]) let received: Event[] = [] @@ -68,12 +66,15 @@ test('same with double querying', async () => { received.push(event) }) - let event = finishEvent({ - created_at: Math.round(Date.now() / 1000), - content: 'test2', - kind: 22346, - tags: [] - }, priv) + let event = finishEvent( + { + created_at: Math.round(Date.now() / 1000), + content: 'test2', + kind: 22346, + tags: [], + }, + priv, + ) pool.publish(relays, event) @@ -84,13 +85,10 @@ test('same with double querying', async () => { test('get()', async () => { let event = await pool.get(relays, { - ids: ['d7dd5eb3ab747e16f8d0212d53032ea2a7cadef53837e5a6c66d42849fcb9027'] + ids: ['d7dd5eb3ab747e16f8d0212d53032ea2a7cadef53837e5a6c66d42849fcb9027'], }) - expect(event).toHaveProperty( - 'id', - 'd7dd5eb3ab747e16f8d0212d53032ea2a7cadef53837e5a6c66d42849fcb9027' - ) + expect(event).toHaveProperty('id', 'd7dd5eb3ab747e16f8d0212d53032ea2a7cadef53837e5a6c66d42849fcb9027') }) test('list()', async () => { @@ -98,13 +96,11 @@ test('list()', async () => { [...relays, 'wss://offchain.pub', 'wss://eden.nostr.land'], [ { - authors: [ - '3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d' - ], + authors: ['3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d'], kinds: [1], - limit: 2 - } - ] + limit: 2, + }, + ], ) // the actual received number will be greater than 2, but there will be no duplicates @@ -112,27 +108,21 @@ test('list()', async () => { events .map(evt => evt.id) // @ts-ignore ??? - .reduce((acc, n) => (acc.indexOf(n) !== -1 ? acc : [...acc, n]), []) - .length + .reduce((acc, n) => (acc.indexOf(n) !== -1 ? acc : [...acc, n]), []).length, ) - let relaysForAllEvents = events - .map(event => pool.seenOn(event.id)) - .reduce((acc, n) => acc.concat(n), []) + let relaysForAllEvents = events.map(event => pool.seenOn(event.id)).reduce((acc, n) => acc.concat(n), []) expect(relaysForAllEvents.length).toBeGreaterThanOrEqual(events.length) }) test('seenOnEnabled: false', async () => { - const poolWithoutSeenOn = new SimplePool({seenOnEnabled: false}) + const poolWithoutSeenOn = new SimplePool({ seenOnEnabled: false }) const event = await poolWithoutSeenOn.get(relays, { - ids: ['d7dd5eb3ab747e16f8d0212d53032ea2a7cadef53837e5a6c66d42849fcb9027'] + ids: ['d7dd5eb3ab747e16f8d0212d53032ea2a7cadef53837e5a6c66d42849fcb9027'], }) - expect(event).toHaveProperty( - 'id', - 'd7dd5eb3ab747e16f8d0212d53032ea2a7cadef53837e5a6c66d42849fcb9027' - ) + expect(event).toHaveProperty('id', 'd7dd5eb3ab747e16f8d0212d53032ea2a7cadef53837e5a6c66d42849fcb9027') const relaysForEvent = poolWithoutSeenOn.seenOn(event!.id) diff --git a/pool.ts b/pool.ts index 990b9e0..7076360 100644 --- a/pool.ts +++ b/pool.ts @@ -1,13 +1,8 @@ -import { - relayInit, - type Relay, - type Sub, - type SubscriptionOptions -} from './relay.ts' -import {normalizeURL} from './utils.ts' +import { relayInit, type Relay, type Sub, type SubscriptionOptions } from './relay.ts' +import { normalizeURL } from './utils.ts' -import type {Event} from './event.ts' -import {matchFilters, type Filter} from './filter.ts' +import type { Event } from './event.ts' +import { matchFilters, type Filter } from './filter.ts' type BatchedRequest = { filters: Filter[] @@ -17,9 +12,9 @@ type BatchedRequest = { } export class SimplePool { - private _conn: {[url: string]: Relay} - private _seenOn: {[id: string]: Set} = {} // a map of all events we've seen in each relay - private batchedByKey: {[batchKey: string]: BatchedRequest[]} = {} + private _conn: { [url: string]: Relay } + private _seenOn: { [id: string]: Set } = {} // a map of all events we've seen in each relay + private batchedByKey: { [batchKey: string]: BatchedRequest[] } = {} private eoseSubTimeout: number private getTimeout: number @@ -32,7 +27,7 @@ export class SimplePool { getTimeout?: number seenOnEnabled?: boolean batchInterval?: number - } = {} + } = {}, ) { this._conn = {} this.eoseSubTimeout = options.eoseSubTimeout || 3400 @@ -54,7 +49,7 @@ export class SimplePool { if (!this._conn[nm]) { this._conn[nm] = relayInit(nm, { getTimeout: this.getTimeout * 0.9, - listTimeout: this.getTimeout * 0.9 + listTimeout: this.getTimeout * 0.9, }) } @@ -63,13 +58,9 @@ export class SimplePool { return relay } - sub( - relays: string[], - filters: Filter[], - opts?: SubscriptionOptions - ): Sub { + sub(relays: string[], filters: Filter[], opts?: SubscriptionOptions): Sub { let _knownIds: Set = new Set() - let modifiedOpts = {...(opts || {})} + let modifiedOpts = { ...(opts || {}) } modifiedOpts.alreadyHaveEvent = (id, url) => { if (opts?.alreadyHaveEvent?.(id, url)) { return true @@ -142,9 +133,8 @@ export class SimplePool { off(type, cb) { if (type === 'event') { eventListeners.delete(cb) - } else if (type === 'eose') - eoseListeners.delete(cb as () => void | Promise) - } + } else if (type === 'eose') eoseListeners.delete(cb as () => void | Promise) + }, } return greaterSub @@ -153,7 +143,7 @@ export class SimplePool { get( relays: string[], filter: Filter, - opts?: SubscriptionOptions + opts?: SubscriptionOptions, ): Promise | null> { return new Promise(resolve => { let sub = this.sub(relays, [filter], opts) @@ -172,7 +162,7 @@ export class SimplePool { list( relays: string[], filters: Filter[], - opts?: SubscriptionOptions + opts?: SubscriptionOptions, ): Promise[]> { return new Promise(resolve => { let events: Event[] = [] @@ -193,7 +183,7 @@ export class SimplePool { batchedList( batchKey: string, relays: string[], - filters: Filter[] + filters: Filter[], ): Promise[]> { return new Promise(resolve => { if (!this.batchedByKey[batchKey]) { @@ -202,8 +192,8 @@ export class SimplePool { filters, relays, resolve, - events: [] - } + events: [], + }, ] setTimeout(() => { @@ -219,9 +209,7 @@ export class SimplePool { const sub = this.sub(relays, filters) sub.on('event', event => { - batchedRequests.forEach( - br => matchFilters(br.filters, event) && br.events.push(event) - ) + batchedRequests.forEach(br => matchFilters(br.filters, event) && br.events.push(event)) }) sub.on('eose', () => { sub.unsub() @@ -236,7 +224,7 @@ export class SimplePool { filters, relays, resolve, - events: [] + events: [], }) } }) diff --git a/references.test.ts b/references.test.ts index 038acdc..1b2a0b8 100644 --- a/references.test.ts +++ b/references.test.ts @@ -1,25 +1,12 @@ -import {parseReferences} from './references.ts' -import {buildEvent} from './test-helpers.ts' +import { parseReferences } from './references.ts' +import { buildEvent } from './test-helpers.ts' test('parse mentions', () => { let evt = buildEvent({ tags: [ - [ - 'p', - 'c9d556c6d3978d112d30616d0d20aaa81410e3653911dd67787b5aaf9b36ade8', - 'wss://nostr.com' - ], - [ - 'e', - 'a84c5de86efc2ec2cff7bad077c4171e09146b633b7ad117fffe088d9579ac33', - 'wss://other.com', - 'reply' - ], - [ - 'e', - '31d7c2875b5fc8e6f9c8f9dc1f84de1b6b91d1947ea4c59225e55c325d330fa8', - '' - ] + ['p', 'c9d556c6d3978d112d30616d0d20aaa81410e3653911dd67787b5aaf9b36ade8', 'wss://nostr.com'], + ['e', 'a84c5de86efc2ec2cff7bad077c4171e09146b633b7ad117fffe088d9579ac33', 'wss://other.com', 'reply'], + ['e', '31d7c2875b5fc8e6f9c8f9dc1f84de1b6b91d1947ea4c59225e55c325d330fa8', ''], ], content: 'hello #[0], have you seen #[2]? it was made by nostr:nprofile1qqsvc6ulagpn7kwrcwdqgp797xl7usumqa6s3kgcelwq6m75x8fe8yc5usxdg on nostr:nevent1qqsvc6ulagpn7kwrcwdqgp797xl7usumqa6s3kgcelwq6m75x8fe8ychxp5v4! broken #[3]', @@ -29,33 +16,31 @@ test('parse mentions', () => { { text: '#[0]', profile: { - pubkey: - 'c9d556c6d3978d112d30616d0d20aaa81410e3653911dd67787b5aaf9b36ade8', - relays: ['wss://nostr.com'] - } + pubkey: 'c9d556c6d3978d112d30616d0d20aaa81410e3653911dd67787b5aaf9b36ade8', + relays: ['wss://nostr.com'], + }, }, { text: '#[2]', event: { id: '31d7c2875b5fc8e6f9c8f9dc1f84de1b6b91d1947ea4c59225e55c325d330fa8', - relays: [] - } + relays: [], + }, }, { text: 'nostr:nprofile1qqsvc6ulagpn7kwrcwdqgp797xl7usumqa6s3kgcelwq6m75x8fe8yc5usxdg', profile: { - pubkey: - 'cc6b9fea033f59c3c39a0407c5f1bfee439b077508d918cfdc0d6fd431d39393', - relays: [] - } + pubkey: 'cc6b9fea033f59c3c39a0407c5f1bfee439b077508d918cfdc0d6fd431d39393', + relays: [], + }, }, { text: 'nostr:nevent1qqsvc6ulagpn7kwrcwdqgp797xl7usumqa6s3kgcelwq6m75x8fe8ychxp5v4', event: { id: 'cc6b9fea033f59c3c39a0407c5f1bfee439b077508d918cfdc0d6fd431d39393', relays: [], - author: undefined - } - } + author: undefined, + }, + }, ]) }) diff --git a/references.ts b/references.ts index b548ee2..2ceb511 100644 --- a/references.ts +++ b/references.ts @@ -1,11 +1,6 @@ -import { - decode, - type AddressPointer, - type ProfilePointer, - type EventPointer, -} from './nip19.ts' +import { decode, type AddressPointer, type ProfilePointer, type EventPointer } from './nip19.ts' -import type {Event} from './event.ts' +import type { Event } from './event.ts' type Reference = { text: string @@ -14,8 +9,7 @@ type Reference = { address?: AddressPointer } -const mentionRegex = - /\bnostr:((note|npub|naddr|nevent|nprofile)1\w+)\b|#\[(\d+)\]/g +const mentionRegex = /\bnostr:((note|npub|naddr|nevent|nprofile)1\w+)\b|#\[(\d+)\]/g export function parseReferences(evt: Event): Reference[] { let references: Reference[] = [] @@ -23,40 +17,40 @@ export function parseReferences(evt: Event): Reference[] { if (ref[2]) { // it's a NIP-27 mention try { - let {type, data} = decode(ref[1]) + let { type, data } = decode(ref[1]) switch (type) { case 'npub': { references.push({ text: ref[0], - profile: {pubkey: data as string, relays: []} + profile: { pubkey: data as string, relays: [] }, }) break } case 'nprofile': { references.push({ text: ref[0], - profile: data as ProfilePointer + profile: data as ProfilePointer, }) break } case 'note': { references.push({ text: ref[0], - event: {id: data as string, relays: []} + event: { id: data as string, relays: [] }, }) break } case 'nevent': { references.push({ text: ref[0], - event: data as EventPointer + event: data as EventPointer, }) break } case 'naddr': { references.push({ text: ref[0], - address: data as AddressPointer + address: data as AddressPointer, }) break } @@ -74,14 +68,14 @@ export function parseReferences(evt: Event): Reference[] { case 'p': { references.push({ text: ref[0], - profile: {pubkey: tag[1], relays: tag[2] ? [tag[2]] : []} + profile: { pubkey: tag[1], relays: tag[2] ? [tag[2]] : [] }, }) break } case 'e': { references.push({ text: ref[0], - event: {id: tag[1], relays: tag[2] ? [tag[2]] : []} + event: { id: tag[1], relays: tag[2] ? [tag[2]] : [] }, }) break } @@ -94,8 +88,8 @@ export function parseReferences(evt: Event): Reference[] { identifier, pubkey, kind: parseInt(kind, 10), - relays: tag[2] ? [tag[2]] : [] - } + relays: tag[2] ? [tag[2]] : [], + }, }) } catch (err) { /***/ diff --git a/relay.test.ts b/relay.test.ts index 96d088a..27f3218 100644 --- a/relay.test.ts +++ b/relay.test.ts @@ -1,8 +1,8 @@ import 'websocket-polyfill' -import {finishEvent} from './event.ts' -import {generatePrivateKey, getPublicKey} from './keys.ts' -import {relayInit} from './relay.ts' +import { finishEvent } from './event.ts' +import { generatePrivateKey, getPublicKey } from './keys.ts' +import { relayInit } from './relay.ts' let relay = relayInit('wss://relay.damus.io/') @@ -23,7 +23,7 @@ test('connectivity', () => { relay.on('error', () => { resolve(false) }) - }) + }), ).resolves.toBe(true) }) @@ -33,14 +33,11 @@ test('querying', async () => { let sub = relay.sub([ { - ids: ['d7dd5eb3ab747e16f8d0212d53032ea2a7cadef53837e5a6c66d42849fcb9027'] - } + ids: ['d7dd5eb3ab747e16f8d0212d53032ea2a7cadef53837e5a6c66d42849fcb9027'], + }, ]) sub.on('event', event => { - expect(event).toHaveProperty( - 'id', - 'd7dd5eb3ab747e16f8d0212d53032ea2a7cadef53837e5a6c66d42849fcb9027' - ) + expect(event).toHaveProperty('id', 'd7dd5eb3ab747e16f8d0212d53032ea2a7cadef53837e5a6c66d42849fcb9027') resolve1(true) }) sub.on('eose', () => { @@ -53,7 +50,7 @@ test('querying', async () => { }), new Promise(resolve => { resolve2 = resolve - }) + }), ]) expect(t1).toEqual(true) @@ -62,24 +59,19 @@ test('querying', async () => { test('get()', async () => { let event = await relay.get({ - ids: ['d7dd5eb3ab747e16f8d0212d53032ea2a7cadef53837e5a6c66d42849fcb9027'] + ids: ['d7dd5eb3ab747e16f8d0212d53032ea2a7cadef53837e5a6c66d42849fcb9027'], }) - expect(event).toHaveProperty( - 'id', - 'd7dd5eb3ab747e16f8d0212d53032ea2a7cadef53837e5a6c66d42849fcb9027' - ) + expect(event).toHaveProperty('id', 'd7dd5eb3ab747e16f8d0212d53032ea2a7cadef53837e5a6c66d42849fcb9027') }) test('list()', async () => { let events = await relay.list([ { - authors: [ - '3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d' - ], + authors: ['3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d'], kinds: [1], - limit: 2 - } + limit: 2, + }, ]) expect(events.length).toEqual(2) @@ -94,8 +86,8 @@ test('listening (twice) and publishing', async () => { let sub = relay.sub([ { kinds: [27572], - authors: [pk] - } + authors: [pk], + }, ]) sub.on('event', event => { @@ -111,12 +103,15 @@ test('listening (twice) and publishing', async () => { resolve2(true) }) - let event = finishEvent({ - kind: 27572, - created_at: Math.floor(Date.now() / 1000), - tags: [], - content: 'nostr-tools test suite' - }, sk) + let event = finishEvent( + { + kind: 27572, + created_at: Math.floor(Date.now() / 1000), + tags: [], + content: 'nostr-tools test suite', + }, + sk, + ) relay.publish(event) return expect( @@ -126,7 +121,7 @@ test('listening (twice) and publishing', async () => { }), new Promise(resolve => { resolve2 = resolve - }) - ]) + }), + ]), ).resolves.toEqual([true, true]) }) diff --git a/relay.ts b/relay.ts index 018ca10..1c160c7 100644 --- a/relay.ts +++ b/relay.ts @@ -1,9 +1,9 @@ /* global WebSocket */ -import {verifySignature, validateEvent, type Event} from './event.ts' -import {matchFilters, type Filter} from './filter.ts' -import {getHex64, getSubscriptionId} from './fakejson.ts' -import {MessageQueue} from './utils.ts' +import { verifySignature, validateEvent, type Event } from './event.ts' +import { matchFilters, type Filter } from './filter.ts' +import { getHex64, getSubscriptionId } from './fakejson.ts' +import { MessageQueue } from './utils.ts' type RelayEvent = { connect: () => void | Promise @@ -25,47 +25,20 @@ export type Relay = { status: number connect: () => Promise close: () => void - sub: ( - filters: Filter[], - opts?: SubscriptionOptions - ) => Sub - list: ( - filters: Filter[], - opts?: SubscriptionOptions - ) => Promise[]> - get: ( - filter: Filter, - opts?: SubscriptionOptions - ) => Promise | null> - count: ( - filters: Filter[], - opts?: SubscriptionOptions - ) => Promise + sub: (filters: Filter[], opts?: SubscriptionOptions) => Sub + list: (filters: Filter[], opts?: SubscriptionOptions) => Promise[]> + get: (filter: Filter, opts?: SubscriptionOptions) => Promise | null> + count: (filters: Filter[], opts?: SubscriptionOptions) => Promise publish: (event: Event) => Promise auth: (event: Event) => Promise - off: ( - event: T, - listener: U - ) => void - on: ( - event: T, - listener: U - ) => void + off: (event: T, listener: U) => void + on: (event: T, listener: U) => void } export type Sub = { - sub: ( - filters: Filter[], - opts: SubscriptionOptions - ) => Sub + sub: (filters: Filter[], opts: SubscriptionOptions) => Sub unsub: () => void - on: , U extends SubEvent[T]>( - event: T, - listener: U - ) => void - off: , U extends SubEvent[T]>( - event: T, - listener: U - ) => void + on: , U extends SubEvent[T]>(event: T, listener: U) => void + off: , U extends SubEvent[T]>(event: T, listener: U) => void } export type SubscriptionOptions = { @@ -75,12 +48,12 @@ export type SubscriptionOptions = { alreadyHaveEvent?: null | ((id: string, relay: string) => boolean) } -const newListeners = (): {[TK in keyof RelayEvent]: RelayEvent[TK][]} => ({ +const newListeners = (): { [TK in keyof RelayEvent]: RelayEvent[TK][] } => ({ connect: [], disconnect: [], error: [], notice: [], - auth: [] + auth: [], }) export function relayInit( @@ -89,15 +62,15 @@ export function relayInit( getTimeout?: number listTimeout?: number countTimeout?: number - } = {} + } = {}, ): Relay { - let {listTimeout = 3000, getTimeout = 3000, countTimeout = 3000} = options + let { listTimeout = 3000, getTimeout = 3000, countTimeout = 3000 } = options var ws: WebSocket - var openSubs: {[id: string]: {filters: Filter[]} & SubscriptionOptions} = {} + var openSubs: { [id: string]: { filters: Filter[] } & SubscriptionOptions } = {} var listeners = newListeners() var subListeners: { - [subid: string]: {[TK in keyof SubEvent]: SubEvent[TK][]} + [subid: string]: { [TK in keyof SubEvent]: SubEvent[TK][] } } = {} var pubListeners: { [eventid: string]: { @@ -153,11 +126,7 @@ export function relayInit( let subid = getSubscriptionId(json) if (subid) { let so = openSubs[subid] - if ( - so && - so.alreadyHaveEvent && - so.alreadyHaveEvent(getHex64(json, 'id'), url) - ) { + if (so && so.alreadyHaveEvent && so.alreadyHaveEvent(getHex64(json, 'id'), url)) { return } } @@ -203,7 +172,7 @@ export function relayInit( let ok: boolean = data[2] let reason: string = data[3] || '' if (id in pubListeners) { - let {resolve, reject} = pubListeners[id] + let { resolve, reject } = pubListeners[id] if (ok) resolve(null) else reject(new Error(reason)) } @@ -258,8 +227,8 @@ export function relayInit( verb = 'REQ', skipVerification = false, alreadyHaveEvent = null, - id = Math.random().toString().slice(2) - }: SubscriptionOptions = {} + id = Math.random().toString().slice(2), + }: SubscriptionOptions = {}, ): Sub => { let subid = id @@ -267,7 +236,7 @@ export function relayInit( id: subid, filters, skipVerification, - alreadyHaveEvent + alreadyHaveEvent, } trySend([verb, subid, ...filters]) @@ -276,7 +245,7 @@ export function relayInit( sub(newFilters || filters, { skipVerification: newOpts.skipVerification || skipVerification, alreadyHaveEvent: newOpts.alreadyHaveEvent || alreadyHaveEvent, - id: subid + id: subid, }), unsub: () => { delete openSubs[subid] @@ -287,7 +256,7 @@ export function relayInit( subListeners[subid] = subListeners[subid] || { event: [], count: [], - eose: [] + eose: [], } subListeners[subid][type].push(cb) }, @@ -295,7 +264,7 @@ export function relayInit( let listeners = subListeners[subid] let idx = listeners[type].indexOf(cb) if (idx >= 0) listeners[type].splice(idx, 1) - } + }, } } @@ -308,27 +277,21 @@ export function relayInit( let id = event.id trySend([type, event]) - pubListeners[id] = {resolve, reject} + pubListeners[id] = { resolve, reject } }) } return { url, sub, - on: ( - type: T, - cb: U - ): void => { + on: (type: T, cb: U): void => { listeners[type].push(cb) if (type === 'connect' && ws?.readyState === 1) { // i would love to know why we need this ;(cb as () => void)() } }, - off: ( - type: T, - cb: U - ): void => { + off: (type: T, cb: U): void => { let index = listeners[type].indexOf(cb) if (index !== -1) listeners[type].splice(index, 1) }, @@ -364,7 +327,7 @@ export function relayInit( }), count: (filters: Filter[]): Promise => new Promise(resolve => { - let s = sub(filters, {...sub, verb: 'COUNT'}) + let s = sub(filters, { ...sub, verb: 'COUNT' }) let timeout = setTimeout(() => { s.unsub() resolve(null) @@ -392,6 +355,6 @@ export function relayInit( }, get status() { return ws?.readyState ?? 3 - } + }, } } diff --git a/test-helpers.ts b/test-helpers.ts index 04e7045..98a8bab 100644 --- a/test-helpers.ts +++ b/test-helpers.ts @@ -1,4 +1,4 @@ -import type {Event} from './event.ts' +import type { Event } from './event.ts' type EventParams = Partial> @@ -12,6 +12,6 @@ export function buildEvent(params: EventParams): Event< content: '', tags: [], sig: '', - ...params + ...params, } } diff --git a/utils.test.ts b/utils.test.ts index 7ad3d3b..c14bcdf 100644 --- a/utils.test.ts +++ b/utils.test.ts @@ -1,101 +1,109 @@ -import {buildEvent} from './test-helpers.ts' -import { - MessageQueue, - insertEventIntoAscendingList, - insertEventIntoDescendingList, -} from './utils.ts' +import { buildEvent } from './test-helpers.ts' +import { MessageQueue, insertEventIntoAscendingList, insertEventIntoDescendingList } from './utils.ts' -import type {Event} from './event.ts' +import type { Event } from './event.ts' describe('inserting into a desc sorted list of events', () => { test('insert into an empty list', async () => { const list0: Event[] = [] - expect( - insertEventIntoDescendingList(list0, buildEvent({id: 'abc', created_at: 10})) - ).toHaveLength(1) + expect(insertEventIntoDescendingList(list0, buildEvent({ id: 'abc', created_at: 10 }))).toHaveLength(1) }) test('insert in the beginning of a list', async () => { - const list0 = [buildEvent({created_at: 20}), buildEvent({created_at: 10})] - const list1 = insertEventIntoDescendingList(list0, buildEvent({ - id: 'abc', - created_at: 30 - })) + const list0 = [buildEvent({ created_at: 20 }), buildEvent({ created_at: 10 })] + const list1 = insertEventIntoDescendingList( + list0, + buildEvent({ + id: 'abc', + created_at: 30, + }), + ) expect(list1).toHaveLength(3) expect(list1[0].id).toBe('abc') }) test('insert in the beginning of a list with same created_at', async () => { - const list0 = [ - buildEvent({created_at: 30}), - buildEvent({created_at: 20}), - buildEvent({created_at: 10}), - ] - const list1 = insertEventIntoDescendingList(list0, buildEvent({ - id: 'abc', - created_at: 30 - })) + const list0 = [buildEvent({ created_at: 30 }), buildEvent({ created_at: 20 }), buildEvent({ created_at: 10 })] + const list1 = insertEventIntoDescendingList( + list0, + buildEvent({ + id: 'abc', + created_at: 30, + }), + ) expect(list1).toHaveLength(4) expect(list1[0].id).toBe('abc') }) test('insert in the middle of a list', async () => { const list0 = [ - buildEvent({created_at: 30}), - buildEvent({created_at: 20}), - buildEvent({created_at: 10}), - buildEvent({created_at: 1}), + buildEvent({ created_at: 30 }), + buildEvent({ created_at: 20 }), + buildEvent({ created_at: 10 }), + buildEvent({ created_at: 1 }), ] - const list1 = insertEventIntoDescendingList(list0, buildEvent({ - id: 'abc', - created_at: 15 - })) + const list1 = insertEventIntoDescendingList( + list0, + buildEvent({ + id: 'abc', + created_at: 15, + }), + ) expect(list1).toHaveLength(5) expect(list1[2].id).toBe('abc') }) test('insert in the end of a list', async () => { const list0 = [ - buildEvent({created_at: 20}), - buildEvent({created_at: 20}), - buildEvent({created_at: 20}), - buildEvent({created_at: 20}), - buildEvent({created_at: 10}), + buildEvent({ created_at: 20 }), + buildEvent({ created_at: 20 }), + buildEvent({ created_at: 20 }), + buildEvent({ created_at: 20 }), + buildEvent({ created_at: 10 }), ] - const list1 = insertEventIntoDescendingList(list0, buildEvent({ - id: 'abc', - created_at: 5 - })) + const list1 = insertEventIntoDescendingList( + list0, + buildEvent({ + id: 'abc', + created_at: 5, + }), + ) expect(list1).toHaveLength(6) expect(list1.slice(-1)[0].id).toBe('abc') }) test('insert in the last-to-end of a list with same created_at', async () => { const list0: Event[] = [ - buildEvent({created_at: 20}), - buildEvent({created_at: 20}), - buildEvent({created_at: 20}), - buildEvent({created_at: 20}), - buildEvent({created_at: 10}), + buildEvent({ created_at: 20 }), + buildEvent({ created_at: 20 }), + buildEvent({ created_at: 20 }), + buildEvent({ created_at: 20 }), + buildEvent({ created_at: 10 }), ] - const list1 = insertEventIntoDescendingList(list0, buildEvent({ - id: 'abc', - created_at: 10 - })) + const list1 = insertEventIntoDescendingList( + list0, + buildEvent({ + id: 'abc', + created_at: 10, + }), + ) expect(list1).toHaveLength(6) expect(list1.slice(-2)[0].id).toBe('abc') }) test('do not insert duplicates', async () => { const list0 = [ - buildEvent({created_at: 20}), - buildEvent({created_at: 20}), - buildEvent({created_at: 10, id: 'abc'}), + buildEvent({ created_at: 20 }), + buildEvent({ created_at: 20 }), + buildEvent({ created_at: 10, id: 'abc' }), ] - const list1 = insertEventIntoDescendingList(list0, buildEvent({ - id: 'abc', - created_at: 10 - })) + const list1 = insertEventIntoDescendingList( + list0, + buildEvent({ + id: 'abc', + created_at: 10, + }), + ) expect(list1).toHaveLength(3) }) }) @@ -103,92 +111,104 @@ describe('inserting into a desc sorted list of events', () => { describe('inserting into a asc sorted list of events', () => { test('insert into an empty list', async () => { const list0: Event[] = [] - expect( - insertEventIntoAscendingList(list0, buildEvent({id: 'abc', created_at: 10})) - ).toHaveLength(1) + expect(insertEventIntoAscendingList(list0, buildEvent({ id: 'abc', created_at: 10 }))).toHaveLength(1) }) test('insert in the beginning of a list', async () => { - const list0 = [buildEvent({created_at: 10}), buildEvent({created_at: 20})] - const list1 = insertEventIntoAscendingList(list0, buildEvent({ - id: 'abc', - created_at: 1 - })) + const list0 = [buildEvent({ created_at: 10 }), buildEvent({ created_at: 20 })] + const list1 = insertEventIntoAscendingList( + list0, + buildEvent({ + id: 'abc', + created_at: 1, + }), + ) expect(list1).toHaveLength(3) expect(list1[0].id).toBe('abc') }) test('insert in the beginning of a list with same created_at', async () => { - const list0 = [ - buildEvent({created_at: 10}), - buildEvent({created_at: 20}), - buildEvent({created_at: 30}), - ] - const list1 = insertEventIntoAscendingList(list0, buildEvent({ - id: 'abc', - created_at: 10 - })) + const list0 = [buildEvent({ created_at: 10 }), buildEvent({ created_at: 20 }), buildEvent({ created_at: 30 })] + const list1 = insertEventIntoAscendingList( + list0, + buildEvent({ + id: 'abc', + created_at: 10, + }), + ) expect(list1).toHaveLength(4) expect(list1[0].id).toBe('abc') }) test('insert in the middle of a list', async () => { const list0 = [ - buildEvent({created_at: 10}), - buildEvent({created_at: 20}), - buildEvent({created_at: 30}), - buildEvent({created_at: 40}), + buildEvent({ created_at: 10 }), + buildEvent({ created_at: 20 }), + buildEvent({ created_at: 30 }), + buildEvent({ created_at: 40 }), ] - const list1 = insertEventIntoAscendingList(list0, buildEvent({ - id: 'abc', - created_at: 25 - })) + const list1 = insertEventIntoAscendingList( + list0, + buildEvent({ + id: 'abc', + created_at: 25, + }), + ) expect(list1).toHaveLength(5) expect(list1[2].id).toBe('abc') }) test('insert in the end of a list', async () => { const list0 = [ - buildEvent({created_at: 20}), - buildEvent({created_at: 20}), - buildEvent({created_at: 20}), - buildEvent({created_at: 20}), - buildEvent({created_at: 40}), + buildEvent({ created_at: 20 }), + buildEvent({ created_at: 20 }), + buildEvent({ created_at: 20 }), + buildEvent({ created_at: 20 }), + buildEvent({ created_at: 40 }), ] - const list1 = insertEventIntoAscendingList(list0, buildEvent({ - id: 'abc', - created_at: 50 - })) + const list1 = insertEventIntoAscendingList( + list0, + buildEvent({ + id: 'abc', + created_at: 50, + }), + ) expect(list1).toHaveLength(6) expect(list1.slice(-1)[0].id).toBe('abc') }) test('insert in the last-to-end of a list with same created_at', async () => { const list0 = [ - buildEvent({created_at: 20}), - buildEvent({created_at: 20}), - buildEvent({created_at: 20}), - buildEvent({created_at: 20}), - buildEvent({created_at: 30}), + buildEvent({ created_at: 20 }), + buildEvent({ created_at: 20 }), + buildEvent({ created_at: 20 }), + buildEvent({ created_at: 20 }), + buildEvent({ created_at: 30 }), ] - const list1 = insertEventIntoAscendingList(list0, buildEvent({ - id: 'abc', - created_at: 30 - })) + const list1 = insertEventIntoAscendingList( + list0, + buildEvent({ + id: 'abc', + created_at: 30, + }), + ) expect(list1).toHaveLength(6) expect(list1.slice(-2)[0].id).toBe('abc') }) test('do not insert duplicates', async () => { const list0 = [ - buildEvent({created_at: 20}), - buildEvent({created_at: 20}), - buildEvent({created_at: 30, id: 'abc'}), + buildEvent({ created_at: 20 }), + buildEvent({ created_at: 20 }), + buildEvent({ created_at: 30, id: 'abc' }), ] - const list1 = insertEventIntoAscendingList(list0, buildEvent({ - id: 'abc', - created_at: 30 - })) + const list1 = insertEventIntoAscendingList( + list0, + buildEvent({ + id: 'abc', + created_at: 30, + }), + ) expect(list1).toHaveLength(3) }) }) diff --git a/utils.ts b/utils.ts index 86e9eb2..cae4d5f 100644 --- a/utils.ts +++ b/utils.ts @@ -1,4 +1,4 @@ -import type {Event} from './event.ts' +import type { Event } from './event.ts' export const utf8Decoder = new TextDecoder('utf-8') export const utf8Encoder = new TextEncoder() @@ -7,11 +7,7 @@ export function normalizeURL(url: string): string { let p = new URL(url) p.pathname = p.pathname.replace(/\/+/g, '/') if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1) - if ( - (p.port === '80' && p.protocol === 'ws:') || - (p.port === '443' && p.protocol === 'wss:') - ) - p.port = '' + if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = '' p.searchParams.sort() p.hash = '' return p.toString() @@ -20,10 +16,7 @@ export function normalizeURL(url: string): string { // // fast insert-into-sorted-array functions adapted from https://github.com/terrymorse58/fast-sorted-array // -export function insertEventIntoDescendingList( - sortedArray: Event[], - event: Event -) { +export function insertEventIntoDescendingList(sortedArray: Event[], event: Event) { let start = 0 let end = sortedArray.length - 1 let midPoint @@ -55,20 +48,13 @@ export function insertEventIntoDescendingList( // insert when num is NOT already in (no duplicates) if (sortedArray[position]?.id !== event.id) { - return [ - ...sortedArray.slice(0, position), - event, - ...sortedArray.slice(position) - ] + return [...sortedArray.slice(0, position), event, ...sortedArray.slice(position)] } return sortedArray } -export function insertEventIntoAscendingList( - sortedArray: Event[], - event: Event -) { +export function insertEventIntoAscendingList(sortedArray: Event[], event: Event) { let start = 0 let end = sortedArray.length - 1 let midPoint @@ -100,11 +86,7 @@ export function insertEventIntoAscendingList( // insert when num is NOT already in (no duplicates) if (sortedArray[position]?.id !== event.id) { - return [ - ...sortedArray.slice(0, position), - event, - ...sortedArray.slice(position) - ] + return [...sortedArray.slice(0, position), event, ...sortedArray.slice(position)] } return sortedArray From 48767d382db430aba943ec35853c22be7f16e16c Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Thu, 31 Aug 2023 13:45:24 -0500 Subject: [PATCH 13/16] relay.test: increase querying timeout to 10s --- relay.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/relay.test.ts b/relay.test.ts index 27f3218..7db69cc 100644 --- a/relay.test.ts +++ b/relay.test.ts @@ -55,7 +55,7 @@ test('querying', async () => { expect(t1).toEqual(true) expect(t2).toEqual(true) -}) +}, 10000) test('get()', async () => { let event = await relay.get({ From 5977d68ec218b36b2bccbc21e48253ea74d189f3 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Thu, 31 Aug 2023 13:47:16 -0500 Subject: [PATCH 14/16] nip98.test: remove outdated/failing test --- nip98.test.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/nip98.test.ts b/nip98.test.ts index 5a637a1..1b636b2 100644 --- a/nip98.test.ts +++ b/nip98.test.ts @@ -54,11 +54,6 @@ describe('getToken', () => { ]) }) - test('getToken unknown method throws an error', async () => { - const result = getToken('http://test.com', 'fake', e => finishEvent(e, sk)) - await expect(result).rejects.toThrow(Error) - }) - test('getToken missing loginUrl throws an error', async () => { const result = getToken('', 'get', e => finishEvent(e, sk)) await expect(result).rejects.toThrow(Error) From e7aa23cb1d592156ceb1652ba98384bce114cf9f Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Thu, 31 Aug 2023 13:51:17 -0500 Subject: [PATCH 15/16] README: add a note about typescript 5.0 --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c463175..e1f7497 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,8 @@ This package is only providing lower-level functionality. If you want an easy-to npm install nostr-tools # or yarn add nostr-tools ``` +If using TypeScript, this package requires TypeScript >= 5.0. + ## Usage ### Generating a private key and a public key From cf465606194d1bb4522914310a8f45fe53b02cc5 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Thu, 31 Aug 2023 13:52:56 -0500 Subject: [PATCH 16/16] ci: ensure `just` is available to the runner --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0ccc2e7..402c7ef 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,5 +23,6 @@ jobs: - uses: actions/setup-node@v3 with: node-version: 18 + - uses: extractions/setup-just@v1 - run: just install-dependencies - run: just lint