mirror of
https://github.com/samuelthomas2774/nxapi.git
synced 2026-03-21 18:04:10 -05:00
Initial commit
This commit is contained in:
commit
fc217056e1
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
node_modules
|
||||
dist
|
||||
data
|
||||
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"files.associations": {
|
||||
"**/*/data/*": "json"
|
||||
}
|
||||
}
|
||||
3
bin/discord-switch-presence.js
Executable file
3
bin/discord-switch-presence.js
Executable file
|
|
@ -0,0 +1,3 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
import('../dist/cli.js').then(cli => cli.default.argv);
|
||||
887
package-lock.json
generated
Normal file
887
package-lock.json
generated
Normal file
|
|
@ -0,0 +1,887 @@
|
|||
{
|
||||
"name": "discord-switch-presence",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "discord-switch-presence",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"cli-table": "^0.3.11",
|
||||
"debug": "^4.3.3",
|
||||
"discord-rpc": "^4.0.1",
|
||||
"node-fetch": "^3.2.2",
|
||||
"node-persist": "^3.1.0",
|
||||
"read": "^1.0.7",
|
||||
"uuid": "^8.3.2",
|
||||
"yargs": "^17.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/cli-table": "^0.3.0",
|
||||
"@types/debug": "^4.1.7",
|
||||
"@types/discord-rpc": "^4.0.0",
|
||||
"@types/node": "^17.0.21",
|
||||
"@types/node-persist": "^3.1.2",
|
||||
"@types/read": "^0.0.29",
|
||||
"@types/uuid": "^8.3.4",
|
||||
"@types/yargs": "^17.0.9",
|
||||
"typescript": "^4.7.0-dev.20220308"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/cli-table": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/cli-table/-/cli-table-0.3.0.tgz",
|
||||
"integrity": "sha512-QnZUISJJXyhyD6L1e5QwXDV/A5i2W1/gl6D6YMc8u0ncPepbv/B4w3S+izVvtAg60m6h+JP09+Y/0zF2mojlFQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/debug": {
|
||||
"version": "4.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz",
|
||||
"integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/ms": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/discord-rpc": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/discord-rpc/-/discord-rpc-4.0.0.tgz",
|
||||
"integrity": "sha512-a5HiKOcBkB43g/lN6fBYw8FyGc6Ue9CYucxxHxXlELXpb1CxCa2NA2pGK2Ub88pi4uY5+HQeSFbYtH6DJtV3Qw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/ms": {
|
||||
"version": "0.7.31",
|
||||
"resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz",
|
||||
"integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "17.0.21",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz",
|
||||
"integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/node-persist": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/node-persist/-/node-persist-3.1.2.tgz",
|
||||
"integrity": "sha512-aLFUB1951wOfR+tZ4f3TudLPblo9+PfnduMh6feuOTijD0Q6YkMdqPXSgQIjI23FGmCuoZaIZ9x6cvEG/TdiSg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/read": {
|
||||
"version": "0.0.29",
|
||||
"resolved": "https://registry.npmjs.org/@types/read/-/read-0.0.29.tgz",
|
||||
"integrity": "sha512-TisW3O3OhpP8/ZwaiqV7kewh9gnoH7PfqHd4hkCM9ogiqWEagu43WXpHWqgPbltXhembYJDpYB3cVwUIOweHXg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/uuid": {
|
||||
"version": "8.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz",
|
||||
"integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/yargs": {
|
||||
"version": "17.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.9.tgz",
|
||||
"integrity": "sha512-Ci8+4/DOtkHRylcisKmVMtmVO5g7weUVCKcsu1sJvF1bn0wExTmbHmhFKj7AnEm0de800iovGhdSKzYnzbaHpg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/yargs-parser": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/yargs-parser": {
|
||||
"version": "21.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz",
|
||||
"integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/bindings": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
||||
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"file-uri-to-path": "1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cli-table": {
|
||||
"version": "0.3.11",
|
||||
"resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.11.tgz",
|
||||
"integrity": "sha512-IqLQi4lO0nIB4tcdTpN4LCB9FI3uqrJZK7RC515EnhZ6qBaglkIgICb1wjeAqpdoOabm1+SuQtkXIPdYC93jhQ==",
|
||||
"dependencies": {
|
||||
"colors": "1.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cliui": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
|
||||
"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
|
||||
"dependencies": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.0",
|
||||
"wrap-ansi": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dependencies": {
|
||||
"color-name": "~1.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"node_modules/colors": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz",
|
||||
"integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=",
|
||||
"engines": {
|
||||
"node": ">=0.1.90"
|
||||
}
|
||||
},
|
||||
"node_modules/data-uri-to-buffer": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz",
|
||||
"integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==",
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
}
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.3.3",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
|
||||
"integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
|
||||
"dependencies": {
|
||||
"ms": "2.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/discord-rpc": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/discord-rpc/-/discord-rpc-4.0.1.tgz",
|
||||
"integrity": "sha512-HOvHpbq5STRZJjQIBzwoKnQ0jHplbEWFWlPDwXXKm/bILh4nzjcg7mNqll0UY7RsjFoaXA7e/oYb/4lvpda2zA==",
|
||||
"dependencies": {
|
||||
"node-fetch": "^2.6.1",
|
||||
"ws": "^7.3.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"register-scheme": "github:devsnek/node-register-scheme"
|
||||
}
|
||||
},
|
||||
"node_modules/discord-rpc/node_modules/node-fetch": {
|
||||
"version": "2.6.7",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
|
||||
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"encoding": "^0.1.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"encoding": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
||||
},
|
||||
"node_modules/escalade": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
|
||||
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/fetch-blob": {
|
||||
"version": "3.1.4",
|
||||
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.1.4.tgz",
|
||||
"integrity": "sha512-Eq5Xv5+VlSrYWEqKrusxY1C3Hm/hjeAsCGVG3ft7pZahlUAChpGZT/Ms1WmSLnEAisEXszjzu/s+ce6HZB2VHA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/jimmywarting"
|
||||
},
|
||||
{
|
||||
"type": "paypal",
|
||||
"url": "https://paypal.me/jimmywarting"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"node-domexception": "^1.0.0",
|
||||
"web-streams-polyfill": "^3.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.20 || >= 14.13"
|
||||
}
|
||||
},
|
||||
"node_modules/file-uri-to-path": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
|
||||
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/formdata-polyfill": {
|
||||
"version": "4.0.10",
|
||||
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
|
||||
"integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
|
||||
"dependencies": {
|
||||
"fetch-blob": "^3.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/get-caller-file": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||
"engines": {
|
||||
"node": "6.* || 8.* || >= 10.*"
|
||||
}
|
||||
},
|
||||
"node_modules/is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"node_modules/mute-stream": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
|
||||
"integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA=="
|
||||
},
|
||||
"node_modules/node-addon-api": {
|
||||
"version": "1.7.2",
|
||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz",
|
||||
"integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/node-domexception": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
|
||||
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/jimmywarting"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://paypal.me/jimmywarting"
|
||||
}
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.2.tgz",
|
||||
"integrity": "sha512-Cwhq1JFIoon15wcIkFzubVNFE5GvXGV82pKf4knXXjvGmn7RJKcypeuqcVNZMGDZsAFWyIRya/anwAJr7TWJ7w==",
|
||||
"dependencies": {
|
||||
"data-uri-to-buffer": "^4.0.0",
|
||||
"fetch-blob": "^3.1.4",
|
||||
"formdata-polyfill": "^4.0.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/node-fetch"
|
||||
}
|
||||
},
|
||||
"node_modules/node-persist": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/node-persist/-/node-persist-3.1.0.tgz",
|
||||
"integrity": "sha512-/j+fd/u71wNgKf3V2bx4tnDm+3GvLnlCuvf2MXbJ3wern+67IAb6zN9Leu1tCWPlPNZ+v1hLSibVukkPK2HqJw==",
|
||||
"engines": {
|
||||
"node": ">=10.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/read": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz",
|
||||
"integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=",
|
||||
"dependencies": {
|
||||
"mute-stream": "~0.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/register-scheme": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "git+ssh://git@github.com/devsnek/node-register-scheme.git#e7cc9a63a1f512565da44cb57316d9fb10750e17",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"bindings": "^1.3.0",
|
||||
"node-addon-api": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "4.7.0-dev.20220308",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.0-dev.20220308.tgz",
|
||||
"integrity": "sha512-dWx2ETRQadrYmrtU4XDnjQsxPNzX1u3+/TWJZ8kU0gOwdyZQ8NrO5BSzhIwp5eqAGe8xdBg+xPDT9tI4mxLfjw==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/web-streams-polyfill": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.0.tgz",
|
||||
"integrity": "sha512-EqPmREeOzttaLRm5HS7io98goBgZ7IVz79aDvqjD0kYXLtFZTc0T/U6wHTPKyIjb+MdN7DFIIX6hgdBEpWmfPA==",
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
|
||||
},
|
||||
"node_modules/whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
|
||||
"dependencies": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "7.5.7",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz",
|
||||
"integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==",
|
||||
"engines": {
|
||||
"node": ">=8.3.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": "^5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs": {
|
||||
"version": "17.3.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz",
|
||||
"integrity": "sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==",
|
||||
"dependencies": {
|
||||
"cliui": "^7.0.2",
|
||||
"escalade": "^3.1.1",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"require-directory": "^2.1.1",
|
||||
"string-width": "^4.2.3",
|
||||
"y18n": "^5.0.5",
|
||||
"yargs-parser": "^21.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs-parser": {
|
||||
"version": "21.0.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz",
|
||||
"integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/cli-table": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/cli-table/-/cli-table-0.3.0.tgz",
|
||||
"integrity": "sha512-QnZUISJJXyhyD6L1e5QwXDV/A5i2W1/gl6D6YMc8u0ncPepbv/B4w3S+izVvtAg60m6h+JP09+Y/0zF2mojlFQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/debug": {
|
||||
"version": "4.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz",
|
||||
"integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/ms": "*"
|
||||
}
|
||||
},
|
||||
"@types/discord-rpc": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/discord-rpc/-/discord-rpc-4.0.0.tgz",
|
||||
"integrity": "sha512-a5HiKOcBkB43g/lN6fBYw8FyGc6Ue9CYucxxHxXlELXpb1CxCa2NA2pGK2Ub88pi4uY5+HQeSFbYtH6DJtV3Qw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/ms": {
|
||||
"version": "0.7.31",
|
||||
"resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz",
|
||||
"integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "17.0.21",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz",
|
||||
"integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/node-persist": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/node-persist/-/node-persist-3.1.2.tgz",
|
||||
"integrity": "sha512-aLFUB1951wOfR+tZ4f3TudLPblo9+PfnduMh6feuOTijD0Q6YkMdqPXSgQIjI23FGmCuoZaIZ9x6cvEG/TdiSg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/read": {
|
||||
"version": "0.0.29",
|
||||
"resolved": "https://registry.npmjs.org/@types/read/-/read-0.0.29.tgz",
|
||||
"integrity": "sha512-TisW3O3OhpP8/ZwaiqV7kewh9gnoH7PfqHd4hkCM9ogiqWEagu43WXpHWqgPbltXhembYJDpYB3cVwUIOweHXg==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/uuid": {
|
||||
"version": "8.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz",
|
||||
"integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/yargs": {
|
||||
"version": "17.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.9.tgz",
|
||||
"integrity": "sha512-Ci8+4/DOtkHRylcisKmVMtmVO5g7weUVCKcsu1sJvF1bn0wExTmbHmhFKj7AnEm0de800iovGhdSKzYnzbaHpg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/yargs-parser": "*"
|
||||
}
|
||||
},
|
||||
"@types/yargs-parser": {
|
||||
"version": "21.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz",
|
||||
"integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==",
|
||||
"dev": true
|
||||
},
|
||||
"ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"requires": {
|
||||
"color-convert": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"bindings": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
||||
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"file-uri-to-path": "1.0.0"
|
||||
}
|
||||
},
|
||||
"cli-table": {
|
||||
"version": "0.3.11",
|
||||
"resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.11.tgz",
|
||||
"integrity": "sha512-IqLQi4lO0nIB4tcdTpN4LCB9FI3uqrJZK7RC515EnhZ6qBaglkIgICb1wjeAqpdoOabm1+SuQtkXIPdYC93jhQ==",
|
||||
"requires": {
|
||||
"colors": "1.0.3"
|
||||
}
|
||||
},
|
||||
"cliui": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
|
||||
"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
|
||||
"requires": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.0",
|
||||
"wrap-ansi": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"requires": {
|
||||
"color-name": "~1.1.4"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"colors": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz",
|
||||
"integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs="
|
||||
},
|
||||
"data-uri-to-buffer": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz",
|
||||
"integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA=="
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.3.3",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
|
||||
"integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"discord-rpc": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/discord-rpc/-/discord-rpc-4.0.1.tgz",
|
||||
"integrity": "sha512-HOvHpbq5STRZJjQIBzwoKnQ0jHplbEWFWlPDwXXKm/bILh4nzjcg7mNqll0UY7RsjFoaXA7e/oYb/4lvpda2zA==",
|
||||
"requires": {
|
||||
"node-fetch": "^2.6.1",
|
||||
"register-scheme": "github:devsnek/node-register-scheme",
|
||||
"ws": "^7.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"node-fetch": {
|
||||
"version": "2.6.7",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
|
||||
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
|
||||
"requires": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
||||
},
|
||||
"escalade": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
|
||||
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="
|
||||
},
|
||||
"fetch-blob": {
|
||||
"version": "3.1.4",
|
||||
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.1.4.tgz",
|
||||
"integrity": "sha512-Eq5Xv5+VlSrYWEqKrusxY1C3Hm/hjeAsCGVG3ft7pZahlUAChpGZT/Ms1WmSLnEAisEXszjzu/s+ce6HZB2VHA==",
|
||||
"requires": {
|
||||
"node-domexception": "^1.0.0",
|
||||
"web-streams-polyfill": "^3.0.3"
|
||||
}
|
||||
},
|
||||
"file-uri-to-path": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
|
||||
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
|
||||
"optional": true
|
||||
},
|
||||
"formdata-polyfill": {
|
||||
"version": "4.0.10",
|
||||
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
|
||||
"integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
|
||||
"requires": {
|
||||
"fetch-blob": "^3.1.2"
|
||||
}
|
||||
},
|
||||
"get-caller-file": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"mute-stream": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
|
||||
"integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA=="
|
||||
},
|
||||
"node-addon-api": {
|
||||
"version": "1.7.2",
|
||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz",
|
||||
"integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==",
|
||||
"optional": true
|
||||
},
|
||||
"node-domexception": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
|
||||
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.2.tgz",
|
||||
"integrity": "sha512-Cwhq1JFIoon15wcIkFzubVNFE5GvXGV82pKf4knXXjvGmn7RJKcypeuqcVNZMGDZsAFWyIRya/anwAJr7TWJ7w==",
|
||||
"requires": {
|
||||
"data-uri-to-buffer": "^4.0.0",
|
||||
"fetch-blob": "^3.1.4",
|
||||
"formdata-polyfill": "^4.0.10"
|
||||
}
|
||||
},
|
||||
"node-persist": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/node-persist/-/node-persist-3.1.0.tgz",
|
||||
"integrity": "sha512-/j+fd/u71wNgKf3V2bx4tnDm+3GvLnlCuvf2MXbJ3wern+67IAb6zN9Leu1tCWPlPNZ+v1hLSibVukkPK2HqJw=="
|
||||
},
|
||||
"read": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz",
|
||||
"integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=",
|
||||
"requires": {
|
||||
"mute-stream": "~0.0.4"
|
||||
}
|
||||
},
|
||||
"register-scheme": {
|
||||
"version": "git+ssh://git@github.com/devsnek/node-register-scheme.git#e7cc9a63a1f512565da44cb57316d9fb10750e17",
|
||||
"from": "register-scheme@github:devsnek/node-register-scheme",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"bindings": "^1.3.0",
|
||||
"node-addon-api": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
|
||||
},
|
||||
"string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"requires": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.1"
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"requires": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.7.0-dev.20220308",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.0-dev.20220308.tgz",
|
||||
"integrity": "sha512-dWx2ETRQadrYmrtU4XDnjQsxPNzX1u3+/TWJZ8kU0gOwdyZQ8NrO5BSzhIwp5eqAGe8xdBg+xPDT9tI4mxLfjw==",
|
||||
"dev": true
|
||||
},
|
||||
"uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
|
||||
},
|
||||
"web-streams-polyfill": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.0.tgz",
|
||||
"integrity": "sha512-EqPmREeOzttaLRm5HS7io98goBgZ7IVz79aDvqjD0kYXLtFZTc0T/U6wHTPKyIjb+MdN7DFIIX6hgdBEpWmfPA=="
|
||||
},
|
||||
"webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
|
||||
},
|
||||
"whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
|
||||
"requires": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"requires": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"ws": {
|
||||
"version": "7.5.7",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz",
|
||||
"integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==",
|
||||
"requires": {}
|
||||
},
|
||||
"y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="
|
||||
},
|
||||
"yargs": {
|
||||
"version": "17.3.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz",
|
||||
"integrity": "sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==",
|
||||
"requires": {
|
||||
"cliui": "^7.0.2",
|
||||
"escalade": "^3.1.1",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"require-directory": "^2.1.1",
|
||||
"string-width": "^4.2.3",
|
||||
"y18n": "^5.0.5",
|
||||
"yargs-parser": "^21.0.0"
|
||||
}
|
||||
},
|
||||
"yargs-parser": {
|
||||
"version": "21.0.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz",
|
||||
"integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg=="
|
||||
}
|
||||
}
|
||||
}
|
||||
41
package.json
Normal file
41
package.json
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
"name": "discord-switch-presence",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"author": "Samuel Elliott",
|
||||
"main": "dist/index.js",
|
||||
"type": "module",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git@gitlab.fancy.org.uk:samuel/discord-switch-presence.git"
|
||||
},
|
||||
"bin": {
|
||||
"discord-switch-presence": "bin/discord-switch-presence.js"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"cli": "node bin/discord-switch-presence.js",
|
||||
"start": "node bin/discord-switch-presence.js presence"
|
||||
},
|
||||
"dependencies": {
|
||||
"cli-table": "^0.3.11",
|
||||
"debug": "^4.3.3",
|
||||
"discord-rpc": "^4.0.1",
|
||||
"node-fetch": "^3.2.2",
|
||||
"node-persist": "^3.1.0",
|
||||
"read": "^1.0.7",
|
||||
"uuid": "^8.3.2",
|
||||
"yargs": "^17.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/cli-table": "^0.3.0",
|
||||
"@types/debug": "^4.1.7",
|
||||
"@types/discord-rpc": "^4.0.0",
|
||||
"@types/node": "^17.0.21",
|
||||
"@types/node-persist": "^3.1.2",
|
||||
"@types/read": "^0.0.29",
|
||||
"@types/uuid": "^8.3.4",
|
||||
"@types/yargs": "^17.0.9",
|
||||
"typescript": "^4.7.0-dev.20220308"
|
||||
}
|
||||
}
|
||||
535
src/api.ts
Normal file
535
src/api.ts
Normal file
|
|
@ -0,0 +1,535 @@
|
|||
import fetch from 'node-fetch';
|
||||
import { v4 as uuidgen } from 'uuid';
|
||||
import { stringify as buildQueryString } from 'querystring';
|
||||
import createDebug from 'debug';
|
||||
|
||||
const debug = createDebug('api');
|
||||
|
||||
export default class ZncApi {
|
||||
constructor(
|
||||
private token: string
|
||||
) {}
|
||||
|
||||
protected async fetch<T = unknown>(url: string, method = 'GET', body?: string, headers?: object) {
|
||||
const response = await fetch('https://api-lp1.znc.srv.nintendo.net' + url, {
|
||||
method: method,
|
||||
body: body,
|
||||
headers: Object.assign({
|
||||
'X-Platform': 'Android',
|
||||
'X-ProductVersion': '2.0.0',
|
||||
'Authorization': 'Bearer ' + this.token,
|
||||
'Content-Type': 'application/json; charset=utf-8',
|
||||
'User-Agent': 'com.nintendo.znca/2.0.0(Android/8.0.0)',
|
||||
}, headers),
|
||||
});
|
||||
|
||||
const data = await response.json() as ZncResponse<T>;
|
||||
|
||||
if ('errorMessage' in data) {
|
||||
const error = new Error('[znc] ' + data.errorMessage);
|
||||
// @ts-expect-error
|
||||
error.response = response;
|
||||
// @ts-expect-error
|
||||
error.data = data;
|
||||
throw error;
|
||||
}
|
||||
if (data.status !== 0) {
|
||||
const error = new Error('[znc] Unknown error');
|
||||
// @ts-expect-error
|
||||
error.response = response;
|
||||
// @ts-expect-error
|
||||
error.data = data;
|
||||
throw error;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async getAnnouncements() {
|
||||
return this.fetch<Announcement[]>('/v1/Announcement/List', 'POST', '{"parameter":{}}');
|
||||
}
|
||||
|
||||
async getFriendList() {
|
||||
return this.fetch<Friends>('/v3/Friend/List', 'POST', '{"parameter":{}}');
|
||||
}
|
||||
|
||||
async getWebServices() {
|
||||
const uuid = uuidgen();
|
||||
|
||||
return this.fetch<WebService[]>('/v1/Game/ListWebServices', 'POST', JSON.stringify({
|
||||
requestId: uuid,
|
||||
}));
|
||||
}
|
||||
|
||||
async getActiveEvent() {
|
||||
return this.fetch<ActiveEvent>('/v1/Event/GetActiveEvent', 'POST', '{"parameter":{}}');
|
||||
}
|
||||
|
||||
async getCurrentUser() {
|
||||
return this.fetch<CurrentUser>('/v3/User/ShowSelf', 'POST', '{"parameter":{}}');
|
||||
}
|
||||
|
||||
async getWebServiceToken(id: string, nintendoAccountToken: string) {
|
||||
const uuid = uuidgen();
|
||||
const timestamp = '' + Math.floor(Date.now() / 1000);
|
||||
|
||||
const flapg = await ZncApi.flapg(nintendoAccountToken, timestamp, uuid, 'app');
|
||||
|
||||
const req = {
|
||||
id,
|
||||
registrationToken: flapg.p1,
|
||||
f: flapg.f,
|
||||
requestId: flapg.p3,
|
||||
timestamp: flapg.p2,
|
||||
};
|
||||
|
||||
return this.fetch<WebServiceToken>('/v2/Game/GetWebServiceToken', 'POST', JSON.stringify({
|
||||
parameter: req,
|
||||
}));
|
||||
}
|
||||
|
||||
static async createWithSessionToken(token: string) {
|
||||
const data = await this.loginWithSessionToken(token);
|
||||
|
||||
return {
|
||||
nso: new this(data.credential.accessToken),
|
||||
data,
|
||||
};
|
||||
}
|
||||
|
||||
async renewToken(token: string) {
|
||||
const data = await ZncApi.loginWithSessionToken(token);
|
||||
|
||||
this.token = data.credential.accessToken;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static async loginWithSessionToken(token: string) {
|
||||
const uuid = uuidgen();
|
||||
const timestamp = '' + Math.floor(Date.now() / 1000);
|
||||
|
||||
//
|
||||
// Nintendo Account token
|
||||
//
|
||||
|
||||
debug('[na] Getting Nintendo Account token');
|
||||
|
||||
const nintendoAccountTokenResponse = await fetch('https://accounts.nintendo.com/connect/1.0.0/api/token', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
client_id: '71b963c1b7b6d119',
|
||||
session_token: token,
|
||||
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer-session-token',
|
||||
}),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 8.0.0)',
|
||||
},
|
||||
});
|
||||
|
||||
const nintendoAccountToken = await nintendoAccountTokenResponse.json() as
|
||||
NintendoAccountToken | NintendoAccountError;
|
||||
|
||||
if ('errorCode' in nintendoAccountToken) {
|
||||
const error = new Error('[na] ' + nintendoAccountToken.detail);
|
||||
// @ts-expect-error
|
||||
error.response = nintendoAccountTokenResponse;
|
||||
// @ts-expect-error
|
||||
error.data = nintendoAccountToken;
|
||||
throw error;
|
||||
}
|
||||
|
||||
debug('[na] Got Nintendo Account token', nintendoAccountToken);
|
||||
|
||||
//
|
||||
// Nintendo Account user data
|
||||
//
|
||||
|
||||
debug('[na] Getting Nintendo Account user info');
|
||||
|
||||
const userResponse = await fetch('https://api.accounts.nintendo.com/2.0.0/users/me', {
|
||||
headers: {
|
||||
'Accept-Language': 'en-GB',
|
||||
'User-Agent': 'NASDKAPI; Android',
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
'Authorization': 'Bearer ' + nintendoAccountToken.access_token!,
|
||||
},
|
||||
});
|
||||
|
||||
const user = await userResponse.json() as NintendoAccountUser | NintendoAccountError;
|
||||
|
||||
if ('errorCode' in user) {
|
||||
const error = new Error('[na] ' + user.detail);
|
||||
// @ts-expect-error
|
||||
error.response = userResponse;
|
||||
// @ts-expect-error
|
||||
error.data = user;
|
||||
throw error;
|
||||
}
|
||||
|
||||
debug('[na] Got Nintendo Account user info', user);
|
||||
|
||||
//
|
||||
// Nintendo Switch Online app token
|
||||
//
|
||||
|
||||
const flapg = await this.flapg(nintendoAccountToken.id_token, timestamp, uuid, 'nso');
|
||||
|
||||
debug('[znc] Getting Nintendo Switch Online app token');
|
||||
|
||||
const response = await fetch('https://api-lp1.znc.srv.nintendo.net/v3/Account/Login', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
parameter: {
|
||||
naIdToken: flapg.p1,
|
||||
naBirthday: user.birthday,
|
||||
naCountry: user.country,
|
||||
language: user.language,
|
||||
timestamp: flapg.p2,
|
||||
requestId: flapg.p3,
|
||||
f: flapg.f,
|
||||
},
|
||||
}),
|
||||
headers: {
|
||||
'X-Platform': 'Android',
|
||||
'X-ProductVersion': '2.0.0',
|
||||
'Content-Type': 'application/json; charset=utf-8',
|
||||
'User-Agent': 'com.nintendo.znca/2.0.0(Android/8.0.0)',
|
||||
},
|
||||
});
|
||||
|
||||
const data = await response.json() as ZncResponse<AccountLogin>;
|
||||
|
||||
debug('[znc] Got Nintendo Switch Online app token', data);
|
||||
|
||||
if ('errorMessage' in data) {
|
||||
const error = new Error('[znc] ' + data.errorMessage);
|
||||
// @ts-expect-error
|
||||
error.response = response;
|
||||
// @ts-expect-error
|
||||
error.data = data;
|
||||
throw error;
|
||||
}
|
||||
if (data.status !== 0) {
|
||||
const error = new Error('[znc] Unknown error');
|
||||
// @ts-expect-error
|
||||
error.response = response;
|
||||
// @ts-expect-error
|
||||
error.data = data;
|
||||
throw error;
|
||||
}
|
||||
|
||||
return {
|
||||
uuid,
|
||||
timestamp,
|
||||
nintendoAccountToken,
|
||||
user,
|
||||
flapg,
|
||||
credential: data.result.webApiServerCredential,
|
||||
};
|
||||
}
|
||||
|
||||
static async getLoginHash(token: string, timestamp: string | number) {
|
||||
debug('[s2s] Getting login hash');
|
||||
|
||||
const response = await fetch('https://elifessler.com/s2s/api/gen2', {
|
||||
method: 'POST',
|
||||
body: buildQueryString({
|
||||
naIdToken: token,
|
||||
timestamp: '' + timestamp,
|
||||
}),
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'User-Agent': 'discord-switch-presence/1.0.0',
|
||||
},
|
||||
});
|
||||
|
||||
const data = await response.json() as LoginHashApiResponse | LoginHashApiError;
|
||||
|
||||
if ('error' in data) {
|
||||
const error = new Error('[s2s] ' + data.error);
|
||||
// @ts-expect-error
|
||||
error.response = response;
|
||||
// @ts-expect-error
|
||||
error.data = data;
|
||||
throw error;
|
||||
}
|
||||
|
||||
debug('[s2s] Got login hash "%s"', data.hash, data);
|
||||
|
||||
return data.hash;
|
||||
}
|
||||
|
||||
static async flapg(token: string, timestamp: string | number, guid: string, iid: 'nso' | 'app') {
|
||||
const hash = await this.getLoginHash(token, timestamp);
|
||||
|
||||
debug('[flapg] Getting f parameter', {
|
||||
token, timestamp, guid, iid,
|
||||
});
|
||||
|
||||
const response = await fetch('https://flapg.com/ika2/api/login?public', {
|
||||
headers: {
|
||||
'x-token': token,
|
||||
'x-time': '' + timestamp,
|
||||
'x-guid': guid,
|
||||
'x-hash': hash,
|
||||
'x-ver': '3',
|
||||
'x-iid': iid,
|
||||
},
|
||||
});
|
||||
|
||||
const data = await response.json() as FlapgApiResponse;
|
||||
|
||||
debug('[flapg] Got f parameter "%s"', data.result.f);
|
||||
|
||||
return data.result;
|
||||
}
|
||||
}
|
||||
|
||||
interface LoginHashApiResponse {
|
||||
hash: string;
|
||||
}
|
||||
interface LoginHashApiError {
|
||||
error: string;
|
||||
}
|
||||
|
||||
export interface FlapgApiResponse {
|
||||
result: {
|
||||
f: string;
|
||||
p1: string;
|
||||
p2: string;
|
||||
p3: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface NintendoAccountToken {
|
||||
scope: ['openid', 'user', 'user.birthday', 'user.mii', 'user.screenName'];
|
||||
token_type: 'Bearer';
|
||||
id_token: string;
|
||||
access_token?: string;
|
||||
expires_in: 900;
|
||||
}
|
||||
|
||||
export interface NintendoAccountUser {
|
||||
emailOptedIn: boolean;
|
||||
language: string;
|
||||
country: string;
|
||||
timezone: {
|
||||
name: string;
|
||||
id: string;
|
||||
utcOffsetSeconds: number;
|
||||
utcOffset: string;
|
||||
};
|
||||
region: null;
|
||||
nickname: string;
|
||||
clientFriendsOptedIn: boolean;
|
||||
mii: {
|
||||
favoriteColor: string;
|
||||
id: string;
|
||||
updatedAt: number;
|
||||
coreData: {
|
||||
'4': string;
|
||||
}
|
||||
clientId: '1cfe3a55ed8924d9';
|
||||
imageUriTemplate: string;
|
||||
storeData: {
|
||||
'3': string;
|
||||
};
|
||||
imageOrigin: string;
|
||||
etag: string;
|
||||
type: 'profile';
|
||||
};
|
||||
isChild: boolean;
|
||||
eachEmailOptedIn: {
|
||||
survey: {
|
||||
updatedAt: number;
|
||||
optedIn: boolean;
|
||||
};
|
||||
deals: {
|
||||
updatedAt: number;
|
||||
optedIn: boolean;
|
||||
};
|
||||
};
|
||||
updatedAt: number;
|
||||
candidateMiis: unknown[];
|
||||
id: string;
|
||||
createdAt: number;
|
||||
emailVerified: boolean;
|
||||
analyticsPermissions: {
|
||||
internalAnalysis: {
|
||||
updatedAt: number;
|
||||
permitted: boolean;
|
||||
};
|
||||
targetMarketing: {
|
||||
updatedAt: number;
|
||||
permitted: boolean;
|
||||
};
|
||||
};
|
||||
emailOptedInUpdatedAt: number;
|
||||
birthday: string;
|
||||
screenName: string;
|
||||
gender: string;
|
||||
analyticsOptedInUpdatedAt: number;
|
||||
analyticsOptedIn: boolean;
|
||||
clientFriendsOptedInUpdatedAt: number;
|
||||
}
|
||||
|
||||
interface NintendoAccountError {
|
||||
errorCode: string;
|
||||
detail: string;
|
||||
instance: string;
|
||||
title: string;
|
||||
status: number;
|
||||
type: string;
|
||||
}
|
||||
|
||||
interface ZncSuccessResponse<T = unknown> {
|
||||
status: 0;
|
||||
result: T;
|
||||
correlationId: string;
|
||||
}
|
||||
|
||||
interface ZncErrorResponse {
|
||||
status: number;
|
||||
errorMessage: string;
|
||||
correlationId: string;
|
||||
}
|
||||
|
||||
type ZncResponse<T = unknown> = ZncSuccessResponse<T> | ZncErrorResponse;
|
||||
|
||||
export interface AccountLogin {
|
||||
user: {
|
||||
id: number;
|
||||
nsaId: string;
|
||||
imageUri: string;
|
||||
name: string;
|
||||
supportId: string;
|
||||
isChildRestricted: boolean;
|
||||
etag: string;
|
||||
links: {
|
||||
nintendoAccount: {
|
||||
membership: {
|
||||
active: boolean;
|
||||
};
|
||||
};
|
||||
friendCode: {
|
||||
regenerable: boolean;
|
||||
regenerableAt: number;
|
||||
id: string;
|
||||
};
|
||||
};
|
||||
permissions: {
|
||||
presence: string;
|
||||
};
|
||||
presence: Presence;
|
||||
};
|
||||
webApiServerCredential: {
|
||||
accessToken: string;
|
||||
expiresIn: number;
|
||||
};
|
||||
firebaseCredential: {
|
||||
accessToken: string;
|
||||
expiresIn: number;
|
||||
};
|
||||
}
|
||||
|
||||
interface Announcement {
|
||||
announcementId: number;
|
||||
priority: number;
|
||||
forceDisplayEndDate: number;
|
||||
distributionDate: number;
|
||||
title: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
interface Friends {
|
||||
friends: Friend[];
|
||||
}
|
||||
|
||||
interface Friend {
|
||||
id: number;
|
||||
nsaId: string;
|
||||
imageUri: string;
|
||||
name: string;
|
||||
isFriend: boolean;
|
||||
isFavoriteFriend: boolean;
|
||||
isServiceUser: boolean;
|
||||
friendCreatedAt: number;
|
||||
presence: Presence;
|
||||
}
|
||||
|
||||
export interface Presence {
|
||||
state: PresenceState;
|
||||
updatedAt: number;
|
||||
logoutAt: number;
|
||||
game: Game | {};
|
||||
}
|
||||
|
||||
export enum PresenceState {
|
||||
OFFLINE = 'OFFLINE',
|
||||
INACTIVE = 'INACTIVE',
|
||||
ONLINE = 'ONLINE',
|
||||
}
|
||||
|
||||
export interface Game {
|
||||
name: string;
|
||||
imageUri: string;
|
||||
shopUri: string;
|
||||
totalPlayTime: number;
|
||||
firstPlayedAt: number;
|
||||
sysDescription: string;
|
||||
}
|
||||
|
||||
interface WebService {
|
||||
id: number;
|
||||
uri: string;
|
||||
customAttributes: WebServiceAttribute[];
|
||||
whiteList: string[];
|
||||
name: string;
|
||||
imageUri: string;
|
||||
}
|
||||
|
||||
interface WebServiceAttribute {
|
||||
attrValue: string;
|
||||
attrKey: string;
|
||||
}
|
||||
|
||||
interface ActiveEvent {
|
||||
// ??
|
||||
}
|
||||
|
||||
interface CurrentUser {
|
||||
id: number;
|
||||
nsaId: string;
|
||||
imageUri: string;
|
||||
name: string;
|
||||
supportId: string;
|
||||
isChildRestricted: boolean;
|
||||
etag: string;
|
||||
links: {
|
||||
nintendoAccount: {
|
||||
membership: {
|
||||
active: {
|
||||
active: boolean;
|
||||
};
|
||||
};
|
||||
};
|
||||
friendCode: {
|
||||
regenerable: boolean;
|
||||
regenerableAt: number;
|
||||
id: string;
|
||||
};
|
||||
};
|
||||
permissions: {
|
||||
presence: string;
|
||||
};
|
||||
presence: Presence;
|
||||
}
|
||||
|
||||
interface WebServiceToken {
|
||||
accessToken: string;
|
||||
expiresIn: number;
|
||||
}
|
||||
358
src/cli.ts
Normal file
358
src/cli.ts
Normal file
|
|
@ -0,0 +1,358 @@
|
|||
import Yargs from 'yargs';
|
||||
import ZncApi, { AccountLogin, FlapgApiResponse, Game, NintendoAccountToken, NintendoAccountUser, Presence, PresenceState } from './api.js';
|
||||
import persist from 'node-persist';
|
||||
import * as path from 'path';
|
||||
// @ts-expect-error
|
||||
import Table from 'cli-table/lib/index.js';
|
||||
import DiscordRPC from 'discord-rpc';
|
||||
import titles, { defaultTitle } from './titles.js';
|
||||
import * as util from 'util';
|
||||
import createDebug from 'debug';
|
||||
|
||||
const debug = createDebug('cli');
|
||||
|
||||
interface SavedToken {
|
||||
uuid: string;
|
||||
timestamp: string;
|
||||
nintendoAccountToken: NintendoAccountToken;
|
||||
user: NintendoAccountUser;
|
||||
flapg: FlapgApiResponse['result'];
|
||||
credential: AccountLogin['webApiServerCredential'];
|
||||
|
||||
expires_at: number;
|
||||
}
|
||||
|
||||
async function initStorage(dir = path.join(import.meta.url.substr(7), '..', '..', 'data')) {
|
||||
const storage = persist.create({
|
||||
dir,
|
||||
stringify: data => JSON.stringify(data, null, 4) + '\n',
|
||||
});
|
||||
await storage.init();
|
||||
return storage;
|
||||
}
|
||||
|
||||
async function getToken(storage: persist.LocalStorage, token: string) {
|
||||
if (!token) {
|
||||
console.error('No token set. Set a Nintendo Account session token using the `--token` option or by running `discord-switch-presence token`.');
|
||||
throw new Error('Invalid token');
|
||||
}
|
||||
|
||||
const existingToken: SavedToken | undefined = await storage.getItem('NsoToken.' + token);
|
||||
|
||||
if (!existingToken || existingToken.expires_at <= Date.now()) {
|
||||
debug('Authenticating to znc with session token');
|
||||
|
||||
const data = await ZncApi.createWithSessionToken(token);
|
||||
|
||||
const existingToken: SavedToken = {
|
||||
...data.data,
|
||||
expires_at: Date.now() + (data.data.credential.expiresIn * 1000),
|
||||
};
|
||||
|
||||
await storage.setItem('NsoToken.' + token, existingToken);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
debug('Using existing token');
|
||||
|
||||
return {
|
||||
nso: new ZncApi(existingToken.credential.accessToken),
|
||||
data: existingToken,
|
||||
};
|
||||
}
|
||||
|
||||
const yargs = Yargs(process.argv.slice(2));
|
||||
|
||||
yargs.option('data-path', {
|
||||
describe: 'Data storage path',
|
||||
type: 'string',
|
||||
default: path.join(import.meta.url.substr(7), '..', '..', 'data'),
|
||||
});
|
||||
|
||||
yargs.command('token [token]', 'Set the default Nintendo Account session token', yargs => {
|
||||
yargs.option('token', {
|
||||
describe: 'Nintendo Account session token (it is recommended this is not set and you enter it interactively)',
|
||||
type: 'string',
|
||||
requiresArg: false,
|
||||
});
|
||||
yargs.option('auth', {
|
||||
describe: 'Authenticate immediately',
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
});
|
||||
}, async argv => {
|
||||
// @ts-expect-error
|
||||
const storage = await initStorage(argv.dataPath);
|
||||
|
||||
let token = argv.token as string | undefined;
|
||||
|
||||
if (!token) {
|
||||
const read = await import('read');
|
||||
// @ts-expect-error
|
||||
const prompt = util.promisify(read.default as typeof read);
|
||||
|
||||
token = await prompt({
|
||||
prompt: `Token: `,
|
||||
silent: true,
|
||||
output: process.stderr,
|
||||
});
|
||||
}
|
||||
|
||||
await storage.setItem('SessionToken', token);
|
||||
|
||||
if (argv.auth) {
|
||||
const {nso, data} = await getToken(storage, token);
|
||||
|
||||
console.log('Authenticated as Nintendo Account %s (%s)', data.user.screenName, data.user.nickname);
|
||||
} else {
|
||||
console.log('Saved token');
|
||||
}
|
||||
});
|
||||
|
||||
yargs.command('user', 'Get the authenticated Nintendo Account', yargs => {
|
||||
yargs.option('token', {
|
||||
describe: 'Nintendo Account session token',
|
||||
type: 'string',
|
||||
requiresArg: false,
|
||||
});
|
||||
}, async argv => {
|
||||
// @ts-expect-error
|
||||
const storage = await initStorage(argv.dataPath);
|
||||
|
||||
const token: string = (argv.token as string) || await storage.getItem('SessionToken');
|
||||
const {nso, data} = await getToken(storage, token);
|
||||
|
||||
console.log('Nintendo Account', data.user);
|
||||
});
|
||||
|
||||
yargs.command('friends', 'List Nintendo Switch friends', yargs => {
|
||||
yargs.option('token', {
|
||||
describe: 'Nintendo Account session token',
|
||||
type: 'string',
|
||||
requiresArg: false,
|
||||
});
|
||||
}, async argv => {
|
||||
console.log('Listing friends');
|
||||
|
||||
// @ts-expect-error
|
||||
const storage = await initStorage(argv.dataPath);
|
||||
|
||||
const token: string = (argv.token as string) || await storage.getItem('SessionToken');
|
||||
const {nso, data} = await getToken(storage, token);
|
||||
|
||||
const announcements = await nso.getAnnouncements();
|
||||
const friends = await nso.getFriendList();
|
||||
const webservices = await nso.getWebServices();
|
||||
const activeevent = await nso.getActiveEvent();
|
||||
|
||||
const table = new Table({
|
||||
head: [
|
||||
'ID',
|
||||
'NA ID',
|
||||
'Name',
|
||||
'Status',
|
||||
'Favourite?',
|
||||
'Added at',
|
||||
],
|
||||
});
|
||||
|
||||
for (const friend of friends.result.friends) {
|
||||
const hours = 'name' in friend.presence.game ? Math.floor(friend.presence.game.totalPlayTime / 60) : 0;
|
||||
const minutes = 'name' in friend.presence.game ? friend.presence.game.totalPlayTime - (hours * 60) : 0;
|
||||
|
||||
table.push([
|
||||
friend.id,
|
||||
friend.nsaId,
|
||||
friend.name,
|
||||
friend.presence.state === PresenceState.ONLINE ?
|
||||
'name' in friend.presence.game ?
|
||||
'Playing ' + friend.presence.game.name +
|
||||
'; played for ' + (hours || !minutes ? hours + ' hour' + (hours === 1 ? '' : 's') : '') +
|
||||
(minutes ? ', ' + minutes + ' minute' + (minutes === 1 ? '' : 's'): '') +
|
||||
' since ' + new Date(friend.presence.game.firstPlayedAt * 1000).toLocaleDateString('en-GB') :
|
||||
'Online' :
|
||||
friend.presence.logoutAt ?
|
||||
'Last seen ' + new Date(friend.presence.logoutAt * 1000).toISOString() :
|
||||
'Offline',
|
||||
friend.isFavoriteFriend ? 'Yes' : 'No',
|
||||
new Date(friend.friendCreatedAt * 1000).toISOString(),
|
||||
]);
|
||||
}
|
||||
|
||||
console.log(table.toString());
|
||||
});
|
||||
|
||||
function getDiscordPresence(game: Game): {
|
||||
id: string;
|
||||
title: string | undefined;
|
||||
presence: DiscordRPC.Presence;
|
||||
showTimestamp?: boolean;
|
||||
} {
|
||||
const match = game.shopUri.match(/^https:\/\/ec\.nintendo\.com\/apps\/([0-9a-f]{16})\//);
|
||||
|
||||
const titleid = match?.[1];
|
||||
const title = titles.find(t => t.id === titleid) || defaultTitle;
|
||||
|
||||
const hours = Math.floor(game.totalPlayTime / 60);
|
||||
const minutes = game.totalPlayTime - (hours * 60);
|
||||
|
||||
const text = [];
|
||||
|
||||
if (title.titleName === true) text.push(game.name);
|
||||
else if (title.titleName) text.push(title.titleName);
|
||||
|
||||
if (hours >= 1) text.push('Played for ' + hours + ' hour' + (hours === 1 ? '' : 's') +
|
||||
(minutes ? ', ' + minutes + ' minute' + (minutes === 1 ? '' : 's'): '') +
|
||||
' since ' + new Date(game.firstPlayedAt * 1000).toLocaleDateString('en-GB'));
|
||||
|
||||
return {
|
||||
id: title.client || defaultTitle.client,
|
||||
title: titleid,
|
||||
presence: {
|
||||
details: text[0],
|
||||
state: text[1],
|
||||
largeImageKey: title.largeImageKey,
|
||||
smallImageKey: title.smallImageKey,
|
||||
},
|
||||
showTimestamp: title.showTimestamp,
|
||||
};
|
||||
}
|
||||
|
||||
yargs.command('presence', 'Start Discord Rich Presence', yargs => {
|
||||
yargs.option('token', {
|
||||
describe: 'Nintendo Account session token',
|
||||
type: 'string',
|
||||
requiresArg: false,
|
||||
});
|
||||
yargs.option('friend-naid', {
|
||||
describe: 'Friend\'s Nintendo Account ID',
|
||||
type: 'string',
|
||||
requiresArg: false,
|
||||
});
|
||||
}, async argv => {
|
||||
// @ts-expect-error
|
||||
const storage = await initStorage(argv.dataPath);
|
||||
|
||||
const token: string = (argv.token as string) || await storage.getItem('SessionToken');
|
||||
const {nso, data} = await getToken(storage, token);
|
||||
|
||||
let rpc: {client: DiscordRPC.Client, id: string} | null = null;
|
||||
let title: {id: string; since: number} | null = null;
|
||||
let i = 0;
|
||||
|
||||
async function updatePresence(presence: Presence | null) {
|
||||
console.log('Presence', i++, presence);
|
||||
|
||||
if (presence?.state === PresenceState.ONLINE && 'name' in presence.game) {
|
||||
const discordpresence = getDiscordPresence(presence.game);
|
||||
|
||||
if (rpc && rpc.id !== discordpresence.id) {
|
||||
await rpc?.client.destroy();
|
||||
rpc = null;
|
||||
}
|
||||
|
||||
if (!rpc) {
|
||||
const client = new DiscordRPC.Client({transport: 'ipc'});
|
||||
await client.connect(discordpresence.id);
|
||||
rpc = {client, id: discordpresence.id};
|
||||
}
|
||||
|
||||
if (discordpresence.title) {
|
||||
if (discordpresence.title !== title?.id) {
|
||||
title = {id: discordpresence.title, since: Date.now()};
|
||||
}
|
||||
|
||||
if (discordpresence.showTimestamp) {
|
||||
discordpresence.presence.startTimestamp = title.since;
|
||||
}
|
||||
} else {
|
||||
title = null;
|
||||
}
|
||||
|
||||
rpc.client.setActivity(discordpresence.presence);
|
||||
}
|
||||
|
||||
if (!presence || presence.state !== PresenceState.ONLINE || !('name' in presence.game)) {
|
||||
if (rpc) {
|
||||
await rpc.client.destroy();
|
||||
rpc = null;
|
||||
}
|
||||
|
||||
title = null;
|
||||
}
|
||||
}
|
||||
|
||||
const announcements = await nso.getAnnouncements();
|
||||
const friends = await nso.getFriendList();
|
||||
const webservices = await nso.getWebServices();
|
||||
const activeevent = await nso.getActiveEvent();
|
||||
|
||||
if (argv.friendNaid) {
|
||||
const friend = friends.result.friends.find(f => f.nsaId === argv.friendNaid);
|
||||
|
||||
if (!friend) {
|
||||
throw new Error('User "' + argv.friendNaid + '" is not friends with this user');
|
||||
}
|
||||
|
||||
await updatePresence(friend.presence);
|
||||
} else {
|
||||
const user = await nso.getCurrentUser();
|
||||
|
||||
await updatePresence(user.result.presence);
|
||||
}
|
||||
|
||||
await new Promise(rs => setTimeout(rs, 30000));
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
if (argv.friendNaid) {
|
||||
await nso.getActiveEvent();
|
||||
await nso.getFriendList();
|
||||
await nso.getWebServices();
|
||||
|
||||
const friend = friends.result.friends.find(f => f.nsaId === argv.friendNaid);
|
||||
|
||||
if (!friend) {
|
||||
// Is the authenticated user no longer friends with this user?
|
||||
await updatePresence(null);
|
||||
continue;
|
||||
}
|
||||
|
||||
await updatePresence(friend.presence);
|
||||
} else {
|
||||
const user = await nso.getCurrentUser();
|
||||
|
||||
await updatePresence(user.result.presence);
|
||||
}
|
||||
|
||||
await new Promise(rs => setTimeout(rs, 30000));
|
||||
} catch (err) {
|
||||
// @ts-expect-error
|
||||
if (err?.data?.status === 9404) {
|
||||
// Token expired
|
||||
debug('Renewing token');
|
||||
|
||||
const data = await nso.renewToken(token);
|
||||
|
||||
const existingToken: SavedToken = {
|
||||
...data,
|
||||
expires_at: Date.now() + (data.credential.expiresIn * 1000),
|
||||
};
|
||||
|
||||
await storage.setItem('NsoToken.' + token, existingToken);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
yargs
|
||||
.scriptName('discord-switch-presence')
|
||||
.demandCommand()
|
||||
.help()
|
||||
// .version(false)
|
||||
.showHelpOnFail(false, 'Specify --help for available options');
|
||||
|
||||
export default yargs;
|
||||
115
src/titles.ts
Normal file
115
src/titles.ts
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
interface Title {
|
||||
id: string;
|
||||
client: string;
|
||||
titleName?: string | true;
|
||||
largeImageKey?: string;
|
||||
smallImageKey?: string;
|
||||
showTimestamp?: boolean;
|
||||
}
|
||||
|
||||
export const defaultTitle: Title = {
|
||||
id: '0000000000000000',
|
||||
client: '950883021165330493',
|
||||
titleName: true,
|
||||
largeImageKey: 'nintendoswitch',
|
||||
};
|
||||
|
||||
const titles: Title[] = [
|
||||
{
|
||||
// Splatoon 2 [Europe]
|
||||
id: '0100f8f0000a2000',
|
||||
client: '950886725398429726',
|
||||
largeImageKey: '0100f8f0000a2000',
|
||||
},
|
||||
{
|
||||
// Splatoon 2 [The Americas]
|
||||
id: '01003bc0000a0000',
|
||||
client: '950886725398429726',
|
||||
largeImageKey: '0100f8f0000a2000',
|
||||
},
|
||||
{
|
||||
// Splatoon 2 [Japan]
|
||||
id: '01003c700009c000',
|
||||
client: '950886725398429726',
|
||||
largeImageKey: '01003c700009c000',
|
||||
},
|
||||
|
||||
{
|
||||
// Super Smash Bros. Ultimate
|
||||
id: '01006a800016e000',
|
||||
client: '950894516104212490',
|
||||
largeImageKey: '01006a800016e000',
|
||||
},
|
||||
|
||||
{
|
||||
// Mario Kart 8 Deluxe
|
||||
id: '0100152000022000',
|
||||
client: '950905573149409280',
|
||||
largeImageKey: '0100152000022000',
|
||||
},
|
||||
|
||||
{
|
||||
// Super Mario Odyssey
|
||||
id: '0100000000010000',
|
||||
client: '950905939899351050',
|
||||
largeImageKey: '0100000000010000',
|
||||
},
|
||||
|
||||
{
|
||||
// Minecraft
|
||||
id: '0100d71004694000',
|
||||
client: '950906152391168020',
|
||||
largeImageKey: '0100d71004694000',
|
||||
},
|
||||
{
|
||||
// Minecraft: Nintendo Switch Edition
|
||||
id: '01006bd001e06000',
|
||||
client: '950906152391168020',
|
||||
largeImageKey: '01006bd001e06000',
|
||||
},
|
||||
|
||||
{
|
||||
// Nintendo Entertainment System - Nintendo Switch Online
|
||||
id: '0100d870045b6000',
|
||||
client: '950907272438104064',
|
||||
titleName: 'Nintendo Entertainment System',
|
||||
largeImageKey: '0100d870045b6000',
|
||||
},
|
||||
{
|
||||
// Super Nintendo Entertainment System - Nintendo Switch Online
|
||||
id: '01008d300c50c000',
|
||||
client: '950907272438104064',
|
||||
titleName: 'Super Nintendo Entertainment System',
|
||||
largeImageKey: '01008d300c50c000',
|
||||
},
|
||||
{
|
||||
// Nintendo 64 - Nintendo Switch Online
|
||||
id: '0100c9a00ece6000',
|
||||
client: '950907272438104064',
|
||||
titleName: 'Nintendo 64',
|
||||
largeImageKey: '0100c9a00ece6000',
|
||||
},
|
||||
{
|
||||
// SEGA Mega Drive - Nintendo Switch Online
|
||||
id: '0100b3c014bda000',
|
||||
client: '950907272438104064',
|
||||
titleName: 'SEGA Mega Drive',
|
||||
largeImageKey: '0100b3c014bda000',
|
||||
},
|
||||
|
||||
{
|
||||
// Animal Crossing: New Horizons
|
||||
id: '01006f8002326000',
|
||||
client: '950908097235415079',
|
||||
largeImageKey: '01006f8002326000',
|
||||
},
|
||||
{
|
||||
// Animal Crossing: New Horizons Island Transfer Tool
|
||||
id: '0100f38011cfe000',
|
||||
client: '950908097235415079',
|
||||
titleName: 'Island Transfer Tool',
|
||||
largeImageKey: '0100f38011cfe000',
|
||||
},
|
||||
];
|
||||
|
||||
export default titles;
|
||||
11
tsconfig.json
Normal file
11
tsconfig.json
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"target": "es2015",
|
||||
"module": "es2022",
|
||||
"moduleResolution": "node12",
|
||||
"declaration": true,
|
||||
"rootDir": "src",
|
||||
"outDir": "dist"
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user