Merge pull request 'sigit-issue-30' (#1) from sigit-issue-30 into master
Reviewed-on: https://git.sigit.io/sig/dvm/pulls/1
This commit is contained in:
commit
772e73f48d
16
.prettierrc
16
.prettierrc
@ -1,13 +1,7 @@
|
|||||||
{
|
{
|
||||||
"singleQuote": true,
|
"trailingComma": "none",
|
||||||
"trailingComma": "all",
|
"tabWidth": 2,
|
||||||
"tabWidth": 4,
|
"semi": false,
|
||||||
"overrides": [
|
"singleQuote": true,
|
||||||
{
|
"endOfLine": "auto"
|
||||||
"files": ["*.ts", "*.mts"],
|
|
||||||
"options": {
|
|
||||||
"parser": "typescript"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
213
package-lock.json
generated
213
package-lock.json
generated
@ -9,7 +9,7 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nostr-dev-kit/ndk": "^0.7.5",
|
"@nostr-dev-kit/ndk": "^0.8.1",
|
||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"file-type": "^18.5.0",
|
"file-type": "^18.5.0",
|
||||||
@ -29,7 +29,7 @@
|
|||||||
"eslint-config-prettier": "~8.8",
|
"eslint-config-prettier": "~8.8",
|
||||||
"eslint-plugin-jest": "~27.2",
|
"eslint-plugin-jest": "~27.2",
|
||||||
"jest": "~29.5",
|
"jest": "~29.5",
|
||||||
"prettier": "~2.8",
|
"prettier": "3.2.5",
|
||||||
"rimraf": "~5.0",
|
"rimraf": "~5.0",
|
||||||
"ts-api-utils": "~0.0.44",
|
"ts-api-utils": "~0.0.44",
|
||||||
"ts-jest": "~29.1",
|
"ts-jest": "~29.1",
|
||||||
@ -1644,9 +1644,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@nostr-dev-kit/ndk": {
|
"node_modules/@nostr-dev-kit/ndk": {
|
||||||
"version": "0.7.7",
|
"version": "0.8.23",
|
||||||
"resolved": "https://registry.npmjs.org/@nostr-dev-kit/ndk/-/ndk-0.7.7.tgz",
|
"resolved": "https://registry.npmjs.org/@nostr-dev-kit/ndk/-/ndk-0.8.23.tgz",
|
||||||
"integrity": "sha512-IRTW16q40zzuSBkpYpDUcZJRrbw26JTeicfZN6O/2Gw7D2w6Pe42VqFwpbcP9xOnFPEGP2eNV6SwXQ3y0tjBtw==",
|
"integrity": "sha512-wX/9Cl02gCR0Kz25C/1xxGO47K13Ve1x8IISbkF/M3RTTXftYBvzB7bL8qwLaFaeqb02cMU0YVL+oKDrYzH/Ng==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@noble/hashes": "^1.3.1",
|
"@noble/hashes": "^1.3.1",
|
||||||
"@noble/secp256k1": "^2.0.0",
|
"@noble/secp256k1": "^2.0.0",
|
||||||
@ -1663,10 +1663,9 @@
|
|||||||
"eventemitter3": "^5.0.1",
|
"eventemitter3": "^5.0.1",
|
||||||
"light-bolt11-decoder": "^3.0.0",
|
"light-bolt11-decoder": "^3.0.0",
|
||||||
"node-fetch": "^3.3.1",
|
"node-fetch": "^3.3.1",
|
||||||
"nostr-tools": "^1.11.2",
|
"nostr-tools": "^1.14.0",
|
||||||
"tsd": "^0.28.1",
|
"tsd": "^0.28.1",
|
||||||
"utf8-buffer": "^1.0.0",
|
"utf8-buffer": "^1.0.0"
|
||||||
"websocket-polyfill": "^0.0.3"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@pkgjs/parseargs": {
|
"node_modules/@pkgjs/parseargs": {
|
||||||
@ -2552,18 +2551,6 @@
|
|||||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/bufferutil": {
|
|
||||||
"version": "4.0.8",
|
|
||||||
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz",
|
|
||||||
"integrity": "sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==",
|
|
||||||
"hasInstallScript": true,
|
|
||||||
"dependencies": {
|
|
||||||
"node-gyp-build": "^4.3.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.14.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/call-bind": {
|
"node_modules/call-bind": {
|
||||||
"version": "1.0.7",
|
"version": "1.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
|
||||||
@ -2792,18 +2779,6 @@
|
|||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/d": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz",
|
|
||||||
"integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==",
|
|
||||||
"dependencies": {
|
|
||||||
"es5-ext": "^0.10.64",
|
|
||||||
"type": "^2.7.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/data-uri-to-buffer": {
|
"node_modules/data-uri-to-buffer": {
|
||||||
"version": "4.0.1",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
|
||||||
@ -3177,43 +3152,6 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/es5-ext": {
|
|
||||||
"version": "0.10.64",
|
|
||||||
"resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz",
|
|
||||||
"integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==",
|
|
||||||
"hasInstallScript": true,
|
|
||||||
"dependencies": {
|
|
||||||
"es6-iterator": "^2.0.3",
|
|
||||||
"es6-symbol": "^3.1.3",
|
|
||||||
"esniff": "^2.0.1",
|
|
||||||
"next-tick": "^1.1.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/es6-iterator": {
|
|
||||||
"version": "2.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
|
|
||||||
"integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
|
|
||||||
"dependencies": {
|
|
||||||
"d": "1",
|
|
||||||
"es5-ext": "^0.10.35",
|
|
||||||
"es6-symbol": "^3.1.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/es6-symbol": {
|
|
||||||
"version": "3.1.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz",
|
|
||||||
"integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==",
|
|
||||||
"dependencies": {
|
|
||||||
"d": "^1.0.2",
|
|
||||||
"ext": "^1.7.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/esbuild": {
|
"node_modules/esbuild": {
|
||||||
"version": "0.17.19",
|
"version": "0.17.19",
|
||||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz",
|
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz",
|
||||||
@ -3561,20 +3499,6 @@
|
|||||||
"node": ">=14.17"
|
"node": ">=14.17"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/esniff": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz",
|
|
||||||
"integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==",
|
|
||||||
"dependencies": {
|
|
||||||
"d": "^1.0.1",
|
|
||||||
"es5-ext": "^0.10.62",
|
|
||||||
"event-emitter": "^0.3.5",
|
|
||||||
"type": "^2.7.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/espree": {
|
"node_modules/espree": {
|
||||||
"version": "9.6.1",
|
"version": "9.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
|
||||||
@ -3658,15 +3582,6 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/event-emitter": {
|
|
||||||
"version": "0.3.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
|
|
||||||
"integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==",
|
|
||||||
"dependencies": {
|
|
||||||
"d": "1",
|
|
||||||
"es5-ext": "~0.10.14"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/eventemitter3": {
|
"node_modules/eventemitter3": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
|
||||||
@ -3720,14 +3635,6 @@
|
|||||||
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
|
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ext": {
|
|
||||||
"version": "1.7.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz",
|
|
||||||
"integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==",
|
|
||||||
"dependencies": {
|
|
||||||
"type": "^2.7.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/fast-deep-equal": {
|
"node_modules/fast-deep-equal": {
|
||||||
"version": "3.1.3",
|
"version": "3.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||||
@ -4702,11 +4609,6 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/is-typedarray": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="
|
|
||||||
},
|
|
||||||
"node_modules/is-unicode-supported": {
|
"node_modules/is-unicode-supported": {
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
|
||||||
@ -5884,11 +5786,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz",
|
||||||
"integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g=="
|
"integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g=="
|
||||||
},
|
},
|
||||||
"node_modules/next-tick": {
|
|
||||||
"version": "1.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz",
|
|
||||||
"integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ=="
|
|
||||||
},
|
|
||||||
"node_modules/nice-try": {
|
"node_modules/nice-try": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
|
||||||
@ -5929,16 +5826,6 @@
|
|||||||
"url": "https://opencollective.com/node-fetch"
|
"url": "https://opencollective.com/node-fetch"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/node-gyp-build": {
|
|
||||||
"version": "4.8.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz",
|
|
||||||
"integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==",
|
|
||||||
"bin": {
|
|
||||||
"node-gyp-build": "bin.js",
|
|
||||||
"node-gyp-build-optional": "optional.js",
|
|
||||||
"node-gyp-build-test": "build-test.js"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/node-int64": {
|
"node_modules/node-int64": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
|
||||||
@ -6578,15 +6465,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prettier": {
|
"node_modules/prettier": {
|
||||||
"version": "2.8.8",
|
"version": "3.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz",
|
||||||
"integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
|
"integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"prettier": "bin-prettier.js"
|
"prettier": "bin/prettier.cjs"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10.13.0"
|
"node": ">=14"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||||
@ -7659,11 +7546,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz",
|
||||||
"integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w=="
|
"integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w=="
|
||||||
},
|
},
|
||||||
"node_modules/tstl": {
|
|
||||||
"version": "2.5.16",
|
|
||||||
"resolved": "https://registry.npmjs.org/tstl/-/tstl-2.5.16.tgz",
|
|
||||||
"integrity": "sha512-+O2ybLVLKcBwKm4HymCEwZIT0PpwS3gCYnxfSDEjJEKADvIFruaQjd3m7CAKNU1c7N3X3WjVz87re7TA2A5FUw=="
|
|
||||||
},
|
|
||||||
"node_modules/tsutils": {
|
"node_modules/tsutils": {
|
||||||
"version": "3.21.0",
|
"version": "3.21.0",
|
||||||
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
|
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
|
||||||
@ -7683,11 +7565,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||||
},
|
},
|
||||||
"node_modules/type": {
|
|
||||||
"version": "2.7.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz",
|
|
||||||
"integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw=="
|
|
||||||
},
|
|
||||||
"node_modules/type-check": {
|
"node_modules/type-check": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
||||||
@ -7788,14 +7665,6 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typedarray-to-buffer": {
|
|
||||||
"version": "3.1.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
|
|
||||||
"integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
|
|
||||||
"dependencies": {
|
|
||||||
"is-typedarray": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/typescript": {
|
"node_modules/typescript": {
|
||||||
"version": "5.0.4",
|
"version": "5.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz",
|
||||||
@ -7866,18 +7735,6 @@
|
|||||||
"punycode": "^2.1.0"
|
"punycode": "^2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/utf-8-validate": {
|
|
||||||
"version": "5.0.10",
|
|
||||||
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz",
|
|
||||||
"integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==",
|
|
||||||
"hasInstallScript": true,
|
|
||||||
"dependencies": {
|
|
||||||
"node-gyp-build": "^4.3.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.14.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/utf8-buffer": {
|
"node_modules/utf8-buffer": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/utf8-buffer/-/utf8-buffer-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/utf8-buffer/-/utf8-buffer-1.0.0.tgz",
|
||||||
@ -7931,44 +7788,6 @@
|
|||||||
"node": ">= 14"
|
"node": ">= 14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/websocket": {
|
|
||||||
"version": "1.0.34",
|
|
||||||
"resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz",
|
|
||||||
"integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"bufferutil": "^4.0.1",
|
|
||||||
"debug": "^2.2.0",
|
|
||||||
"es5-ext": "^0.10.50",
|
|
||||||
"typedarray-to-buffer": "^3.1.5",
|
|
||||||
"utf-8-validate": "^5.0.2",
|
|
||||||
"yaeti": "^0.0.6"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=4.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/websocket-polyfill": {
|
|
||||||
"version": "0.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/websocket-polyfill/-/websocket-polyfill-0.0.3.tgz",
|
|
||||||
"integrity": "sha512-pF3kR8Uaoau78MpUmFfzbIRxXj9PeQrCuPepGE6JIsfsJ/o/iXr07Q2iQNzKSSblQJ0FiGWlS64N4pVSm+O3Dg==",
|
|
||||||
"dependencies": {
|
|
||||||
"tstl": "^2.0.7",
|
|
||||||
"websocket": "^1.0.28"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/websocket/node_modules/debug": {
|
|
||||||
"version": "2.6.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
|
||||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
|
||||||
"dependencies": {
|
|
||||||
"ms": "2.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/websocket/node_modules/ms": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
|
||||||
},
|
|
||||||
"node_modules/which": {
|
"node_modules/which": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
@ -8086,14 +7905,6 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/yaeti": {
|
|
||||||
"version": "0.0.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz",
|
|
||||||
"integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10.32"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/yallist": {
|
"node_modules/yallist": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
||||||
|
114
package.json
114
package.json
@ -1,58 +1,60 @@
|
|||||||
{
|
{
|
||||||
"name": "data-vending-machine-skeleton",
|
"name": "data-vending-machine-skeleton",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"description": "nostr data vending machine skeleton",
|
"description": "nostr data vending machine skeleton",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "~19"
|
"node": "~19"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"nostr",
|
"nostr",
|
||||||
"ai",
|
"ai",
|
||||||
"bitcoin"
|
"bitcoin"
|
||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "~29.5",
|
"@types/jest": "~29.5",
|
||||||
"@types/node": "~18",
|
"@types/node": "~18",
|
||||||
"@typescript-eslint/eslint-plugin": "~5.59",
|
"@typescript-eslint/eslint-plugin": "~5.59",
|
||||||
"@typescript-eslint/parser": "~5.59",
|
"@typescript-eslint/parser": "~5.59",
|
||||||
"eslint": "~8.38",
|
"eslint": "~8.38",
|
||||||
"eslint-config-prettier": "~8.8",
|
"eslint-config-prettier": "~8.8",
|
||||||
"eslint-plugin-jest": "~27.2",
|
"eslint-plugin-jest": "~27.2",
|
||||||
"jest": "~29.5",
|
"jest": "~29.5",
|
||||||
"prettier": "~2.8",
|
"prettier": "3.2.5",
|
||||||
"rimraf": "~5.0",
|
"rimraf": "~5.0",
|
||||||
"ts-api-utils": "~0.0.44",
|
"ts-api-utils": "~0.0.44",
|
||||||
"ts-jest": "~29.1",
|
"ts-jest": "~29.1",
|
||||||
"typescript": "~5.0"
|
"typescript": "~5.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node build/src/main.js",
|
"start": "node build/src/main.js",
|
||||||
"clean": "rimraf coverage build tmp",
|
"clean": "rimraf coverage build tmp",
|
||||||
"_prebuild": "npm run lint",
|
"_prebuild": "npm run lint",
|
||||||
"build": "tsc -p tsconfig.json",
|
"build": "tsc -p tsconfig.json",
|
||||||
"build:watch": "tsc -w -p tsconfig.json",
|
"build:watch": "tsc -w -p tsconfig.json",
|
||||||
"build:release": "npm run clean && tsc -p tsconfig.release.json",
|
"build:release": "npm run clean && tsc -p tsconfig.release.json",
|
||||||
"lint": "eslint . --ext .ts --ext .mts",
|
"lint": "eslint . --ext .ts --ext .mts",
|
||||||
"test": "jest --coverage",
|
"test": "jest --coverage",
|
||||||
"prettier": "prettier --config .prettierrc --write .",
|
"prettier": "prettier --config .prettierrc --write .",
|
||||||
"test:watch": "jest --watch"
|
"test:watch": "jest --watch",
|
||||||
},
|
"formatter:check": "prettier --check \"src/**/*.{ts,tsx,js,jsx,html,css,sass,less,yml,md,graphql}\"",
|
||||||
"author": "pablof7z",
|
"formatter:fix": "prettier --write \"src/**/*.{ts,tsx,js,jsx,html,css,sass,less,yml,md,graphql}\""
|
||||||
"license": "MIT",
|
},
|
||||||
"dependencies": {
|
"author": "pablof7z",
|
||||||
"@nostr-dev-kit/ndk": "^0.8.1",
|
"license": "MIT",
|
||||||
"axios": "^1.4.0",
|
"dependencies": {
|
||||||
"debug": "^4.3.4",
|
"@nostr-dev-kit/ndk": "^0.8.1",
|
||||||
"file-type": "^18.5.0",
|
"axios": "^1.4.0",
|
||||||
"form-data": "^4.0.0",
|
"debug": "^4.3.4",
|
||||||
"form-data-encoder": "^3.0.0",
|
"file-type": "^18.5.0",
|
||||||
"formdata-node": "^5.0.1",
|
"form-data": "^4.0.0",
|
||||||
"light-bolt11-decoder": "^3.0.0",
|
"form-data-encoder": "^3.0.0",
|
||||||
"lnbits": "^1.1.5",
|
"formdata-node": "^5.0.1",
|
||||||
"tslib": "~2.5"
|
"light-bolt11-decoder": "^3.0.0",
|
||||||
},
|
"lnbits": "^1.1.5",
|
||||||
"volta": {
|
"tslib": "~2.5"
|
||||||
"node": "18.12.1"
|
},
|
||||||
}
|
"volta": {
|
||||||
|
"node": "18.12.1"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
12
pnpm-lock.yaml
generated
12
pnpm-lock.yaml
generated
@ -64,8 +64,8 @@ importers:
|
|||||||
specifier: ~29.5
|
specifier: ~29.5
|
||||||
version: 29.5.0(@types/node@18.16.19)
|
version: 29.5.0(@types/node@18.16.19)
|
||||||
prettier:
|
prettier:
|
||||||
specifier: ~2.8
|
specifier: 3.2.5
|
||||||
version: 2.8.8
|
version: 3.2.5
|
||||||
rimraf:
|
rimraf:
|
||||||
specifier: ~5.0
|
specifier: ~5.0
|
||||||
version: 5.0.1
|
version: 5.0.1
|
||||||
@ -2171,9 +2171,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
|
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
|
|
||||||
prettier@2.8.8:
|
prettier@3.2.5:
|
||||||
resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==}
|
resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==}
|
||||||
engines: {node: '>=10.13.0'}
|
engines: {node: '>=14'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
pretty-format@29.6.1:
|
pretty-format@29.6.1:
|
||||||
@ -5246,7 +5246,7 @@ snapshots:
|
|||||||
|
|
||||||
prelude-ls@1.2.1: {}
|
prelude-ls@1.2.1: {}
|
||||||
|
|
||||||
prettier@2.8.8: {}
|
prettier@3.2.5: {}
|
||||||
|
|
||||||
pretty-format@29.6.1:
|
pretty-format@29.6.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -1,37 +1,37 @@
|
|||||||
import { NDKPrivateKeySigner } from '@nostr-dev-kit/ndk';
|
import { NDKPrivateKeySigner } from '@nostr-dev-kit/ndk'
|
||||||
import fs from 'fs';
|
import fs from 'fs'
|
||||||
import { log, configFile } from '../main.js';
|
import { log, configFile } from '../main.js'
|
||||||
|
|
||||||
type IConfig = {
|
type IConfig = {
|
||||||
key: string;
|
key: string
|
||||||
discount?: number;
|
discount?: number
|
||||||
undercut?: number;
|
undercut?: number
|
||||||
processWithoutPaymentLimit?: number;
|
processWithoutPaymentLimit?: number
|
||||||
serveResultsWithoutPaymentLimit?: number;
|
serveResultsWithoutPaymentLimit?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getConfig(): IConfig {
|
export function getConfig(): IConfig {
|
||||||
let config: IConfig;
|
let config: IConfig
|
||||||
|
|
||||||
if (fs.existsSync(configFile)) {
|
if (fs.existsSync(configFile)) {
|
||||||
config = JSON.parse(fs.readFileSync(configFile, 'utf8'));
|
config = JSON.parse(fs.readFileSync(configFile, 'utf8'))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!config) {
|
||||||
|
log('Generating new config')
|
||||||
|
config = {
|
||||||
|
key: NDKPrivateKeySigner.generate().privateKey
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!config) {
|
const signer = NDKPrivateKeySigner.generate()
|
||||||
log('Generating new config')
|
config.key = signer.privateKey
|
||||||
config = {
|
|
||||||
key: NDKPrivateKeySigner.generate().privateKey,
|
|
||||||
};
|
|
||||||
|
|
||||||
const signer = NDKPrivateKeySigner.generate();
|
saveConfig(config)
|
||||||
config.key = signer.privateKey;
|
}
|
||||||
|
|
||||||
saveConfig(config);
|
return config
|
||||||
}
|
|
||||||
|
|
||||||
return config;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function saveConfig(config: IConfig) {
|
export function saveConfig(config: IConfig) {
|
||||||
fs.writeFileSync(configFile, JSON.stringify(config));
|
fs.writeFileSync(configFile, JSON.stringify(config))
|
||||||
}
|
}
|
||||||
|
@ -1,43 +1,43 @@
|
|||||||
import { NDKEvent } from '@nostr-dev-kit/ndk';
|
import { NDKEvent } from '@nostr-dev-kit/ndk'
|
||||||
import { log } from '../main.js';
|
import { log } from '../main.js'
|
||||||
import axios from 'axios';
|
import axios from 'axios'
|
||||||
|
|
||||||
export async function blockChainBlockNumberJob(
|
export async function blockChainBlockNumberJob(
|
||||||
event: NDKEvent,
|
event: NDKEvent
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
log('New blockChain-block-number job', event.rawEvent());
|
log('New blockChain-block-number job', event.rawEvent())
|
||||||
|
|
||||||
const input = event.tagValue('i');
|
const input = event.tagValue('i')
|
||||||
|
|
||||||
const blockChainUrl = `https://blockchain.info/blocks/${input}?format=json`;
|
const blockChainUrl = `https://blockchain.info/blocks/${input}?format=json`
|
||||||
|
|
||||||
const output = await axios
|
const output = await axios
|
||||||
.get(blockChainUrl)
|
.get(blockChainUrl)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
const closestObject = findClosestObject(res.data, input);
|
const closestObject = findClosestObject(res.data, input)
|
||||||
return closestObject.block_index.toString();
|
return closestObject.block_index.toString()
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log('err in blockChain request :>> ', err);
|
console.log('err in blockChain request :>> ', err)
|
||||||
return Promise.reject(err);
|
return Promise.reject(err)
|
||||||
});
|
})
|
||||||
|
|
||||||
return output;
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: define type for array
|
// todo: define type for array
|
||||||
// Function to find the object with the closest timestamp
|
// Function to find the object with the closest timestamp
|
||||||
function findClosestObject(array, timestamp) {
|
function findClosestObject(array, timestamp) {
|
||||||
let closestObject = null;
|
let closestObject = null
|
||||||
let minDifference = Infinity;
|
let minDifference = Infinity
|
||||||
|
|
||||||
array.forEach((obj) => {
|
array.forEach((obj) => {
|
||||||
const difference = Math.abs(obj.time - timestamp);
|
const difference = Math.abs(obj.time - timestamp)
|
||||||
if (difference < minDifference) {
|
if (difference < minDifference) {
|
||||||
minDifference = difference;
|
minDifference = difference
|
||||||
closestObject = obj;
|
closestObject = obj
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
return closestObject;
|
return closestObject
|
||||||
}
|
}
|
||||||
|
57
src/job-types/relay-info.ts
Normal file
57
src/job-types/relay-info.ts
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import { NDKEvent } from '@nostr-dev-kit/ndk'
|
||||||
|
import { log } from '../main.js'
|
||||||
|
import axios from 'axios'
|
||||||
|
import { RelayInfo } from '../types/index.js'
|
||||||
|
|
||||||
|
export const relayInfoJob = async (event: NDKEvent): Promise<string> => {
|
||||||
|
log('New relay-info job', event.rawEvent())
|
||||||
|
|
||||||
|
const input: string = event.tagValue('i')
|
||||||
|
|
||||||
|
let relays: string[] = []
|
||||||
|
|
||||||
|
try {
|
||||||
|
const relaysArr = JSON.parse(input)
|
||||||
|
|
||||||
|
// input is a string containing an array of strings representing multiple relay URIs
|
||||||
|
relays = relaysArr
|
||||||
|
} catch (err) {
|
||||||
|
// input is a string containing a string representing single relay URI
|
||||||
|
|
||||||
|
relays.push(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
const prefixes = { wss: 'wss://', https: 'https://', http: 'http://' }
|
||||||
|
const headers = {
|
||||||
|
headers: { Accept: 'application/nostr+json' }
|
||||||
|
}
|
||||||
|
|
||||||
|
const requests = relays.map((relay) => {
|
||||||
|
if (relay.startsWith(prefixes.wss)) {
|
||||||
|
relay = relay.replace(prefixes.wss, '')
|
||||||
|
}
|
||||||
|
|
||||||
|
return axios
|
||||||
|
.get<RelayInfo>((relay = `${prefixes.https}${relay}`), headers)
|
||||||
|
.catch(() => {
|
||||||
|
return axios
|
||||||
|
.get<RelayInfo>(`${prefixes.http}${relay}`, headers)
|
||||||
|
.catch(() => undefined)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
let responses = await Promise.all(requests)
|
||||||
|
responses = responses.filter((response) => response !== undefined)
|
||||||
|
|
||||||
|
const relaysInfo: { [key: string]: RelayInfo } = {}
|
||||||
|
|
||||||
|
responses.forEach((response) => {
|
||||||
|
const relayURI = response.config.url
|
||||||
|
.replace(prefixes.https, prefixes.wss)
|
||||||
|
.replace(prefixes.http, prefixes.wss)
|
||||||
|
|
||||||
|
relaysInfo[relayURI] = response.data
|
||||||
|
})
|
||||||
|
|
||||||
|
return Promise.resolve(JSON.stringify(relaysInfo))
|
||||||
|
}
|
@ -1,142 +1,144 @@
|
|||||||
import { NDKEvent, type NostrEvent } from '@nostr-dev-kit/ndk';
|
import { NDKEvent, type NostrEvent } from '@nostr-dev-kit/ndk'
|
||||||
import axios from 'axios';
|
import axios from 'axios'
|
||||||
import FormData from 'form-data';
|
import FormData from 'form-data'
|
||||||
import { log } from '../main.js';
|
import { log } from '../main.js'
|
||||||
import { fetchFileFromInput } from '../utils/fetch-file-from-input.js';
|
import { fetchFileFromInput } from '../utils/fetch-file-from-input.js'
|
||||||
import { ndk } from '../main.js';
|
import { ndk } from '../main.js'
|
||||||
// import { fileTypeFromFile, type FileTypeResult } from 'file-type';
|
// import { fileTypeFromFile, type FileTypeResult } from 'file-type';
|
||||||
import { exec } from 'child_process';
|
import { exec } from 'child_process'
|
||||||
import fs from 'fs';
|
import fs from 'fs'
|
||||||
import { createInvoice } from '../utils/lnbits.js';
|
import { createInvoice } from '../utils/lnbits.js'
|
||||||
|
|
||||||
export async function speechToTextJob(event: NDKEvent): Promise<string> {
|
export async function speechToTextJob(event: NDKEvent): Promise<string> {
|
||||||
log("New speech-to-text job", event.rawEvent());
|
log('New speech-to-text job', event.rawEvent())
|
||||||
|
|
||||||
// fetch the input file
|
// fetch the input file
|
||||||
const file = await fetchFile(event);
|
const file = await fetchFile(event)
|
||||||
log(`file: ${file}`);
|
log(`file: ${file}`)
|
||||||
|
|
||||||
if (!file) {
|
if (!file) {
|
||||||
return undefined;
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if file exists
|
// check if file exists
|
||||||
// if (!fs.existsSync(file)) {
|
// if (!fs.existsSync(file)) {
|
||||||
// log(`file does not exist: ${file}`);
|
// log(`file does not exist: ${file}`);
|
||||||
// return undefined;
|
// return undefined;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// let fileType: FileTypeResult;
|
// let fileType: FileTypeResult;
|
||||||
|
|
||||||
// try {
|
// try {
|
||||||
// fileType = await fileTypeFromFile(file);
|
// fileType = await fileTypeFromFile(file);
|
||||||
// log(`fileType: ${fileType}`);
|
// log(`fileType: ${fileType}`);
|
||||||
// } catch (error) {
|
// } catch (error) {
|
||||||
// log(error);
|
// log(error);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
const whisperCommand = (resolve: any, file: string) => {
|
const whisperCommand = (resolve: any, file: string) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
if (!fs.existsSync(file)) {
|
||||||
|
log(`file does not exist: ${file}`)
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
const formData = new FormData()
|
||||||
|
const a = fs.createReadStream(file)
|
||||||
|
console.log({ a })
|
||||||
|
|
||||||
if (!fs.existsSync(file)) {
|
formData.append('file', a)
|
||||||
log(`file does not exist: ${file}`);
|
formData.append('model', 'whisper-1')
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
const formData = new FormData();
|
|
||||||
const a = fs.createReadStream(file);
|
|
||||||
console.log({a});
|
|
||||||
|
|
||||||
formData.append('file', a);
|
axios
|
||||||
formData.append('model', 'whisper-1');
|
.post('http://127.0.0.1:10111/v1/audio/transcriptions', formData, {
|
||||||
|
headers: {
|
||||||
|
Authorization: 'Bearer fsdfdsf',
|
||||||
|
...formData.getHeaders()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
const { text } = response.data
|
||||||
|
console.log({ text })
|
||||||
|
resolve(text)
|
||||||
|
// Handle response
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log({ error })
|
||||||
|
// Handle error
|
||||||
|
})
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
|
||||||
axios.post('http://127.0.0.1:10111/v1/audio/transcriptions', formData, {
|
// const input = event.tagValue('i');
|
||||||
headers: {
|
const range = event.getMatchingTags('param').find((tag) => tag[1] === 'range')
|
||||||
'Authorization': 'Bearer fsdfdsf',
|
return new Promise((resolve) => whisperCommand(resolve, file))
|
||||||
...formData.getHeaders(),
|
|
||||||
},
|
|
||||||
}).then(response => {
|
|
||||||
const { text } = response.data;
|
|
||||||
console.log({text});
|
|
||||||
resolve(text);
|
|
||||||
// Handle response
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.log({error});
|
|
||||||
// Handle error
|
|
||||||
});
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
// const input = event.tagValue('i');
|
if (range) {
|
||||||
const range = event.getMatchingTags('param').find((tag) => tag[1] === 'range');
|
return new Promise((resolve) => {
|
||||||
return new Promise((resolve) => whisperCommand(resolve, file));
|
const startTime = range[2]
|
||||||
|
const endTime = range[3]
|
||||||
if (range) {
|
const randomName = Math.random().toString(36).substring(7) + '.mp3'
|
||||||
return new Promise((resolve) => {
|
const command = `ffmpeg -ss ${startTime} -to ${endTime} -i ${file} -vn -acodec copy ${randomName}`
|
||||||
const startTime = range[2];
|
console.log({ startTime, endTime, randomName, command })
|
||||||
const endTime = range[3];
|
exec(command, (error, stderr, stdout) => {
|
||||||
const randomName = Math.random().toString(36).substring(7)+'.mp3';
|
console.log('ffmpeg', { error, stderr, stdout })
|
||||||
const command = `ffmpeg -ss ${startTime} -to ${endTime} -i ${file} -vn -acodec copy ${randomName}`;
|
|
||||||
console.log({startTime, endTime, randomName, command});
|
|
||||||
exec(command, (error, stderr, stdout) => {
|
|
||||||
console.log('ffmpeg', {error, stderr, stdout});
|
|
||||||
|
|
||||||
whisperCommand(resolve, randomName);
|
whisperCommand(resolve, randomName)
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
} else {
|
} else {
|
||||||
return new Promise((resolve) => whisperCommand(resolve, file));
|
return new Promise((resolve) => whisperCommand(resolve, file))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ICompleteParams {
|
interface ICompleteParams {
|
||||||
output: string;
|
output: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function addAmount(event: NDKEvent, amount: number, includeInvoice = true): Promise<void> {
|
export async function addAmount(
|
||||||
const tag = ['amount', amount.toString()];
|
event: NDKEvent,
|
||||||
|
amount: number,
|
||||||
|
includeInvoice = true
|
||||||
|
): Promise<void> {
|
||||||
|
const tag = ['amount', amount.toString()]
|
||||||
|
|
||||||
if (includeInvoice) {
|
if (includeInvoice) {
|
||||||
const invoice = await createInvoice(amount / 1000);
|
const invoice = await createInvoice(amount / 1000)
|
||||||
tag.push(invoice.payment_request);
|
tag.push(invoice.payment_request)
|
||||||
}
|
}
|
||||||
|
|
||||||
event.tags.push(tag);
|
event.tags.push(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function complete(
|
export async function complete(
|
||||||
jobRequest: NDKEvent,
|
jobRequest: NDKEvent,
|
||||||
amount: number,
|
amount: number,
|
||||||
completeParams: ICompleteParams,
|
completeParams: ICompleteParams,
|
||||||
includeInvoice?: boolean
|
includeInvoice?: boolean
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const jobResult = new NDKEvent(ndk, {
|
const jobResult = new NDKEvent(ndk, {
|
||||||
kind: 68002,
|
kind: 68002,
|
||||||
content: completeParams.output,
|
content: completeParams.output,
|
||||||
tags: [
|
tags: [['status', 'success']]
|
||||||
[ 'status', 'success' ]
|
} as NostrEvent)
|
||||||
]
|
|
||||||
} as NostrEvent);
|
|
||||||
|
|
||||||
if (amount > 0) {
|
if (amount > 0) {
|
||||||
await addAmount(jobResult, amount, includeInvoice);
|
await addAmount(jobResult, amount, includeInvoice)
|
||||||
}
|
}
|
||||||
jobResult.tag(jobRequest);
|
jobResult.tag(jobRequest)
|
||||||
|
|
||||||
|
await jobResult.sign()
|
||||||
|
log(jobResult.rawEvent())
|
||||||
|
|
||||||
await jobResult.sign();
|
await jobResult.publish()
|
||||||
log(jobResult.rawEvent());
|
return jobResult
|
||||||
|
|
||||||
await jobResult.publish();
|
|
||||||
return jobResult;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchFile(event: NDKEvent): Promise<string> {
|
export async function fetchFile(event: NDKEvent): Promise<string> {
|
||||||
const inputTags = event.getMatchingTags("i");
|
const inputTags = event.getMatchingTags('i')
|
||||||
|
|
||||||
if (inputTags.length !== 1) {
|
if (inputTags.length !== 1) {
|
||||||
throw new Error(`Incorrect number of inputs: ${inputTags.length}`);
|
throw new Error(`Incorrect number of inputs: ${inputTags.length}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
return fetchFileFromInput(inputTags[0]);
|
return fetchFileFromInput(inputTags[0])
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { NDKEvent } from '@nostr-dev-kit/ndk';
|
import { NDKEvent } from '@nostr-dev-kit/ndk'
|
||||||
import { validateJobRequest } from '../validations/index.js';
|
import { validateJobRequest } from '../validations/index.js'
|
||||||
import { inProgress } from '../jobs/reactions/in-progress.js';
|
import { inProgress } from '../jobs/reactions/in-progress.js'
|
||||||
|
|
||||||
export async function onNewSummarizationJob(event: NDKEvent): Promise<void> {
|
export async function onNewSummarizationJob(event: NDKEvent): Promise<void> {
|
||||||
console.log("New summarization job");
|
console.log('New summarization job')
|
||||||
|
|
||||||
await validateJobRequest(event);
|
await validateJobRequest(event)
|
||||||
|
|
||||||
inProgress(event);
|
inProgress(event)
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
import { NDKEvent } from '@nostr-dev-kit/ndk';
|
import { NDKEvent } from '@nostr-dev-kit/ndk'
|
||||||
import { log } from '../main.js';
|
import { log } from '../main.js'
|
||||||
import { getConfig } from '../config/index.js';
|
import { getConfig } from '../config/index.js'
|
||||||
|
|
||||||
export async function priceJob(event: NDKEvent): Promise<number> {
|
export async function priceJob(event: NDKEvent): Promise<number> {
|
||||||
const config = getConfig();
|
const config = getConfig()
|
||||||
const bidTag = event.tagValue('bid');
|
const bidTag = event.tagValue('bid')
|
||||||
let bidAmount = bidTag ? parseInt(bidTag) : 1001 * 1000;
|
let bidAmount = bidTag ? parseInt(bidTag) : 1001 * 1000
|
||||||
|
|
||||||
if (config.discount) {
|
if (config.discount) {
|
||||||
bidAmount = bidAmount * config.discount;
|
bidAmount = bidAmount * config.discount
|
||||||
}
|
}
|
||||||
|
|
||||||
log(`bid amount: ${bidAmount} (${config.discount??'no'} discount)`);
|
log(`bid amount: ${bidAmount} (${config.discount ?? 'no'} discount)`)
|
||||||
|
|
||||||
return bidAmount;
|
return bidAmount
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,17 @@
|
|||||||
import { NDKEvent } from '@nostr-dev-kit/ndk';
|
import { NDKEvent } from '@nostr-dev-kit/ndk'
|
||||||
import { log, ndk } from '../../main.js';
|
import { log, ndk } from '../../main.js'
|
||||||
|
|
||||||
export async function inProgress(event: NDKEvent): Promise<NDKEvent> {
|
export async function inProgress(event: NDKEvent): Promise<NDKEvent> {
|
||||||
log("marking job as in progress");
|
log('marking job as in progress')
|
||||||
|
|
||||||
const reactEvent = new NDKEvent(ndk, {
|
const reactEvent = new NDKEvent(ndk, {
|
||||||
kind: 68003,
|
kind: 68003,
|
||||||
content: "👍",
|
content: '👍',
|
||||||
tags: [
|
tags: [['status', 'started']]
|
||||||
[ "status", "started" ],
|
})
|
||||||
]
|
|
||||||
})
|
|
||||||
|
|
||||||
reactEvent.tag(event, "job");
|
reactEvent.tag(event, 'job')
|
||||||
await reactEvent.sign();
|
await reactEvent.sign()
|
||||||
await reactEvent.publish();
|
await reactEvent.publish()
|
||||||
return reactEvent;
|
return reactEvent
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,23 @@
|
|||||||
import { NDKEvent, NDKTag } from '@nostr-dev-kit/ndk';
|
import { NDKEvent, NDKTag } from '@nostr-dev-kit/ndk'
|
||||||
import { log, ndk } from '../../main.js';
|
import { log, ndk } from '../../main.js'
|
||||||
|
|
||||||
export async function publishStatus(
|
export async function publishStatus(
|
||||||
event: NDKEvent,
|
event: NDKEvent,
|
||||||
status: string,
|
status: string,
|
||||||
extraTags: NDKTag[] = []): Promise<NDKEvent> {
|
extraTags: NDKTag[] = []
|
||||||
log("marking job as finished");
|
): Promise<NDKEvent> {
|
||||||
|
log('marking job as finished')
|
||||||
|
|
||||||
const reactEvent = new NDKEvent(ndk, {
|
const reactEvent = new NDKEvent(ndk, {
|
||||||
kind: 68003,
|
kind: 68003,
|
||||||
content: "👍",
|
content: '👍',
|
||||||
tags: [
|
tags: [['status', status], ...extraTags]
|
||||||
[ "status", status ],
|
})
|
||||||
...extraTags
|
|
||||||
]
|
|
||||||
})
|
|
||||||
|
|
||||||
console.log({extraTags})
|
console.log({ extraTags })
|
||||||
|
|
||||||
reactEvent.tag(event, "job");
|
reactEvent.tag(event, 'job')
|
||||||
await reactEvent.sign();
|
await reactEvent.sign()
|
||||||
await reactEvent.publish();
|
await reactEvent.publish()
|
||||||
return reactEvent;
|
return reactEvent
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { NDKPrivateKeySigner } from '@nostr-dev-kit/ndk';
|
import { NDKPrivateKeySigner } from '@nostr-dev-kit/ndk'
|
||||||
import { getConfig } from './config/index.js';
|
import { getConfig } from './config/index.js'
|
||||||
|
|
||||||
export default function getSigner(): NDKPrivateKeySigner {
|
export default function getSigner(): NDKPrivateKeySigner {
|
||||||
const config = getConfig();
|
const config = getConfig()
|
||||||
|
|
||||||
return new NDKPrivateKeySigner(config.key!);
|
return new NDKPrivateKeySigner(config.key!)
|
||||||
}
|
}
|
||||||
|
431
src/main.ts
431
src/main.ts
@ -1,240 +1,249 @@
|
|||||||
import NDK, { NDKEvent } from '@nostr-dev-kit/ndk';
|
import NDK, { NDKEvent } from '@nostr-dev-kit/ndk'
|
||||||
import debug from 'debug';
|
import debug from 'debug'
|
||||||
import { onNewSummarizationJob } from './job-types/summarization.js';
|
import { onNewSummarizationJob } from './job-types/summarization.js'
|
||||||
import { complete, speechToTextJob } from './job-types/speech-to-text.js';
|
import { complete, speechToTextJob } from './job-types/speech-to-text.js'
|
||||||
import getSigner from './local-signer.js';
|
import getSigner from './local-signer.js'
|
||||||
import { requirePayment, validateJobRequest } from './validations/index.js';
|
import { requirePayment, validateJobRequest } from './validations/index.js'
|
||||||
import { inProgress } from './jobs/reactions/in-progress.js';
|
import { inProgress } from './jobs/reactions/in-progress.js'
|
||||||
import { publishStatus } from './jobs/reactions/status.js';
|
import { publishStatus } from './jobs/reactions/status.js'
|
||||||
import { priceJob } from './jobs/price.js';
|
import { priceJob } from './jobs/price.js'
|
||||||
import { getConfig } from './config/index.js';
|
import { getConfig } from './config/index.js'
|
||||||
import { decode } from 'light-bolt11-decoder';
|
import { decode } from 'light-bolt11-decoder'
|
||||||
import { checkInvoiceStatus } from './utils/lnbits.js';
|
import { checkInvoiceStatus } from './utils/lnbits.js'
|
||||||
import { blockChainBlockNumberJob } from './job-types/blockChain-block-number.js';
|
import { blockChainBlockNumberJob } from './job-types/blockChain-block-number.js'
|
||||||
|
import { relayInfoJob } from './job-types/relay-info.js'
|
||||||
|
import { JobType, JobTypes } from './types/index.js'
|
||||||
|
|
||||||
export const log = debug('fool-me-once-dvm');
|
export const log = debug('fool-me-once-dvm')
|
||||||
|
|
||||||
export const configFile =
|
export const configFile =
|
||||||
process.argv[2] || `${process.env.HOME}/.fool-me-once.json`;
|
process.argv[2] || `${process.env.HOME}/.fool-me-once.json`
|
||||||
|
|
||||||
log('configFile', { configFile });
|
log('configFile', { configFile })
|
||||||
|
|
||||||
export const ndk = new NDK({
|
export const ndk = new NDK({
|
||||||
explicitRelayUrls: [
|
explicitRelayUrls: [
|
||||||
'wss://relay.damus.io',
|
'wss://relay.damus.io',
|
||||||
'wss://relay.primal.net',
|
'wss://relay.primal.net',
|
||||||
'wss://relayable.org',
|
'wss://relayable.org'
|
||||||
],
|
],
|
||||||
signer: getSigner(),
|
signer: getSigner()
|
||||||
});
|
})
|
||||||
await ndk.connect(2000);
|
await ndk.connect(2000)
|
||||||
log('connected');
|
log('connected')
|
||||||
|
|
||||||
const subs = ndk.subscribe(
|
const subs = ndk.subscribe(
|
||||||
{
|
{
|
||||||
kinds: [68001 as number],
|
kinds: [68001 as number],
|
||||||
since: Math.floor(Date.now() / 1000),
|
since: Math.floor(Date.now() / 1000),
|
||||||
'#j': ['summarize', 'explain'],
|
'#j': [JobTypes.Summarize, JobTypes.Explain]
|
||||||
},
|
},
|
||||||
{ closeOnEose: false },
|
{ closeOnEose: false }
|
||||||
);
|
)
|
||||||
|
|
||||||
const speechToTextSub = ndk.subscribe(
|
const speechToTextSub = ndk.subscribe(
|
||||||
{
|
{
|
||||||
kinds: [68001 as number],
|
kinds: [68001 as number],
|
||||||
since: Math.floor(Date.now() / 1000),
|
since: Math.floor(Date.now() / 1000),
|
||||||
'#j': ['speech-to-text'],
|
'#j': [JobTypes.SpeechToText]
|
||||||
},
|
},
|
||||||
{ closeOnEose: false },
|
{ closeOnEose: false }
|
||||||
);
|
)
|
||||||
|
|
||||||
const blockChainBlockNumberSub = ndk.subscribe(
|
const blockChainBlockNumberSub = ndk.subscribe(
|
||||||
{
|
{
|
||||||
kinds: [68001 as number],
|
kinds: [68001 as number],
|
||||||
since: Math.floor(Date.now() / 1000),
|
since: Math.floor(Date.now() / 1000),
|
||||||
'#j': ['blockChain-block-number'],
|
'#j': [JobTypes.BlockChainBlockNumber]
|
||||||
},
|
},
|
||||||
{ closeOnEose: false },
|
{ closeOnEose: false }
|
||||||
);
|
)
|
||||||
|
const relayInfoSub = ndk.subscribe(
|
||||||
|
{
|
||||||
|
kinds: [68001 as number],
|
||||||
|
since: Math.floor(Date.now() / 1000),
|
||||||
|
'#j': [JobTypes.RelayInfo]
|
||||||
|
},
|
||||||
|
{ closeOnEose: false }
|
||||||
|
)
|
||||||
|
|
||||||
subs.on('event', (e) => processJobEvent(e, 'summarize'));
|
subs.on('event', (e) => processJobEvent(e, JobTypes.Summarize))
|
||||||
speechToTextSub.on('event', (e) => processJobEvent(e, 'speech-to-text'));
|
speechToTextSub.on('event', (e) => processJobEvent(e, JobTypes.SpeechToText))
|
||||||
blockChainBlockNumberSub.on('event', (e) =>
|
blockChainBlockNumberSub.on('event', (e) =>
|
||||||
processJobEvent(e, 'blockChain-block-number'),
|
processJobEvent(e, JobTypes.BlockChainBlockNumber)
|
||||||
);
|
)
|
||||||
|
relayInfoSub.on('event', (e) => processJobEvent(e, JobTypes.RelayInfo))
|
||||||
|
|
||||||
type JobType =
|
const freeJobs: string[] = [JobTypes.BlockChainBlockNumber, JobTypes.RelayInfo]
|
||||||
| 'summarize'
|
|
||||||
| 'explain'
|
|
||||||
| 'speech-to-text'
|
|
||||||
| 'blockChain-block-number';
|
|
||||||
|
|
||||||
async function processJobEvent(event: NDKEvent, type: JobType): Promise<void> {
|
async function processJobEvent(event: NDKEvent, type: JobType): Promise<void> {
|
||||||
const config = getConfig();
|
const config = getConfig()
|
||||||
let jobAmount =
|
let jobAmount = freeJobs.includes(type) ? 0 : await priceJob(event)
|
||||||
type === 'blockChain-block-number' ? 0 : await priceJob(event);
|
let output: any
|
||||||
let output: any;
|
let payReqEvent: NDKEvent
|
||||||
let payReqEvent: NDKEvent;
|
let paidAmount = 0
|
||||||
let paidAmount = 0;
|
|
||||||
|
|
||||||
const waitForPaymentBeforeProcessing = (): boolean => {
|
const waitForPaymentBeforeProcessing = (): boolean => {
|
||||||
const processWithoutPaymentLimit =
|
const processWithoutPaymentLimit = config.processWithoutPaymentLimit ?? 500
|
||||||
config.processWithoutPaymentLimit ?? 500;
|
log('waitForPaymentBeforeProcessing', {
|
||||||
log('waitForPaymentBeforeProcessing', {
|
jobAmount,
|
||||||
jobAmount,
|
processWithoutPaymentLimit
|
||||||
processWithoutPaymentLimit,
|
})
|
||||||
});
|
return jobAmount && jobAmount > processWithoutPaymentLimit * 1000
|
||||||
return jobAmount && jobAmount > processWithoutPaymentLimit * 1000;
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const waitForPaymentBeforePublishingResult = (): boolean => {
|
const waitForPaymentBeforePublishingResult = (): boolean => {
|
||||||
const serveResultsWithoutPaymentLimit =
|
const serveResultsWithoutPaymentLimit =
|
||||||
config.serveResultsWithoutPaymentLimit ?? 1000;
|
config.serveResultsWithoutPaymentLimit ?? 1000
|
||||||
log('waitForPaymentBeforeProcessing', { jobAmount });
|
log('waitForPaymentBeforeProcessing', { jobAmount })
|
||||||
return jobAmount && jobAmount > serveResultsWithoutPaymentLimit * 1000;
|
return jobAmount && jobAmount > serveResultsWithoutPaymentLimit * 1000
|
||||||
};
|
}
|
||||||
|
|
||||||
const missingAmount = (): number => jobAmount - paidAmount;
|
const missingAmount = (): number => jobAmount - paidAmount
|
||||||
|
|
||||||
const reqPayment = async (): Promise<void> => {
|
const reqPayment = async (): Promise<void> => {
|
||||||
payReqEvent = await requirePayment(event, missingAmount(), true);
|
payReqEvent = await requirePayment(event, missingAmount(), true)
|
||||||
|
|
||||||
if (config.undercut) {
|
if (config.undercut) {
|
||||||
startUndercutting();
|
startUndercutting()
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const startUndercutting = async (): Promise<void> => {
|
|
||||||
const undercutSub = ndk.subscribe(
|
|
||||||
{
|
|
||||||
kinds: [68002 as number, 68003 as number],
|
|
||||||
...event.filter(),
|
|
||||||
},
|
|
||||||
{ closeOnEose: false, groupable: false },
|
|
||||||
);
|
|
||||||
undercutSub.on('event', async (e) => {
|
|
||||||
if (e.pubkey === payReqEvent.pubkey) return;
|
|
||||||
|
|
||||||
// check if this is a payment request
|
|
||||||
const amountValue = e.tagValue('amount');
|
|
||||||
if (!amountValue) return;
|
|
||||||
|
|
||||||
log(`found someone else's bid`, amountValue);
|
|
||||||
|
|
||||||
// check if it's more-or-less than the current bid
|
|
||||||
const amount = parseInt(amountValue);
|
|
||||||
if (amount > jobAmount) return;
|
|
||||||
|
|
||||||
// if so, undercut
|
|
||||||
jobAmount = Math.round(amount * config.undercut);
|
|
||||||
log(`undercutting to ${jobAmount}`);
|
|
||||||
setTimeout(async () => {
|
|
||||||
payReqEvent = await requirePayment(event, jobAmount, true);
|
|
||||||
}, 5000);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const waitForPaymentViaZap = (payReqEvent, resolve, reject) => {
|
|
||||||
const zapmon = ndk.subscribe(
|
|
||||||
{
|
|
||||||
kinds: [68002, 9735],
|
|
||||||
...payReqEvent.filter(),
|
|
||||||
},
|
|
||||||
{ closeOnEose: false },
|
|
||||||
);
|
|
||||||
zapmon.on('event', (e) => {
|
|
||||||
log(`received a ${e.kind} for the payment request`, e.rawEvent());
|
|
||||||
|
|
||||||
// TODO: validate amount, zapper, etc
|
|
||||||
if (e.kind === 9735) {
|
|
||||||
// TODO: This needs to check the actual zap
|
|
||||||
paidAmount = jobAmount;
|
|
||||||
|
|
||||||
// zapmon.close();
|
|
||||||
resolve();
|
|
||||||
} else if (e.kind === 68003) {
|
|
||||||
zapmon.stop();
|
|
||||||
reject();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const waitForPaymentViaLNInvoice = (payReqEvent, resolve) => {
|
|
||||||
const amountTag = payReqEvent.getMatchingTags('amount')[0];
|
|
||||||
const bolt11 = amountTag[2];
|
|
||||||
|
|
||||||
if (!bolt11) return;
|
|
||||||
|
|
||||||
const invoice = decode(bolt11);
|
|
||||||
const pr = invoice.payment_hash;
|
|
||||||
log({ invoice });
|
|
||||||
log({ pr });
|
|
||||||
|
|
||||||
const checkInterval = setInterval(() => {
|
|
||||||
checkInvoiceStatus(invoice).then((status) => {
|
|
||||||
if (status.paid) {
|
|
||||||
log('invoice paid');
|
|
||||||
paidAmount = jobAmount;
|
|
||||||
clearInterval(checkInterval);
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, 2000);
|
|
||||||
};
|
|
||||||
|
|
||||||
const waitForPayment = async (payReqEvent: NDKEvent): Promise<void> => {
|
|
||||||
log('waitForPayment');
|
|
||||||
const promise = new Promise<void>((resolve, reject) => {
|
|
||||||
waitForPaymentViaZap(payReqEvent, resolve, reject);
|
|
||||||
waitForPaymentViaLNInvoice(payReqEvent, resolve);
|
|
||||||
});
|
|
||||||
|
|
||||||
return promise;
|
|
||||||
};
|
|
||||||
|
|
||||||
const startProcessing = async () => {
|
|
||||||
log('startProcessing');
|
|
||||||
await inProgress(event);
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case 'summarize': {
|
|
||||||
output = await onNewSummarizationJob(event);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'speech-to-text': {
|
|
||||||
output = await speechToTextJob(event);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'blockChain-block-number': {
|
|
||||||
output = await blockChainBlockNumberJob(event);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const publishResult = (): void => {
|
|
||||||
log('publishResult');
|
|
||||||
complete(event, missingAmount(), { output });
|
|
||||||
};
|
|
||||||
|
|
||||||
await validateJobRequest(event);
|
|
||||||
|
|
||||||
if (jobAmount > paidAmount && waitForPaymentBeforeProcessing()) {
|
|
||||||
await reqPayment();
|
|
||||||
await waitForPayment(payReqEvent);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await startProcessing();
|
const startUndercutting = async (): Promise<void> => {
|
||||||
|
const undercutSub = ndk.subscribe(
|
||||||
|
{
|
||||||
|
kinds: [68002 as number, 68003 as number],
|
||||||
|
...event.filter()
|
||||||
|
},
|
||||||
|
{ closeOnEose: false, groupable: false }
|
||||||
|
)
|
||||||
|
undercutSub.on('event', async (e) => {
|
||||||
|
if (e.pubkey === payReqEvent.pubkey) return
|
||||||
|
|
||||||
await publishStatus(event, 'finished').catch((err) =>
|
// check if this is a payment request
|
||||||
console.log('err :>> ', err),
|
const amountValue = e.tagValue('amount')
|
||||||
);
|
if (!amountValue) return
|
||||||
|
|
||||||
if (jobAmount > paidAmount && waitForPaymentBeforePublishingResult()) {
|
log(`found someone else's bid`, amountValue)
|
||||||
await reqPayment();
|
|
||||||
await waitForPayment(payReqEvent);
|
// check if it's more-or-less than the current bid
|
||||||
log(`done with wait for publish`);
|
const amount = parseInt(amountValue)
|
||||||
|
if (amount > jobAmount) return
|
||||||
|
|
||||||
|
// if so, undercut
|
||||||
|
jobAmount = Math.round(amount * config.undercut)
|
||||||
|
log(`undercutting to ${jobAmount}`)
|
||||||
|
setTimeout(async () => {
|
||||||
|
payReqEvent = await requirePayment(event, jobAmount, true)
|
||||||
|
}, 5000)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const waitForPaymentViaZap = (payReqEvent, resolve, reject) => {
|
||||||
|
const zapmon = ndk.subscribe(
|
||||||
|
{
|
||||||
|
kinds: [68002, 9735],
|
||||||
|
...payReqEvent.filter()
|
||||||
|
},
|
||||||
|
{ closeOnEose: false }
|
||||||
|
)
|
||||||
|
zapmon.on('event', (e) => {
|
||||||
|
log(`received a ${e.kind} for the payment request`, e.rawEvent())
|
||||||
|
|
||||||
|
// TODO: validate amount, zapper, etc
|
||||||
|
if (e.kind === 9735) {
|
||||||
|
// TODO: This needs to check the actual zap
|
||||||
|
paidAmount = jobAmount
|
||||||
|
|
||||||
|
// zapmon.close();
|
||||||
|
resolve()
|
||||||
|
} else if (e.kind === 68003) {
|
||||||
|
zapmon.stop()
|
||||||
|
reject()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const waitForPaymentViaLNInvoice = (payReqEvent, resolve) => {
|
||||||
|
const amountTag = payReqEvent.getMatchingTags('amount')[0]
|
||||||
|
const bolt11 = amountTag[2]
|
||||||
|
|
||||||
|
if (!bolt11) return
|
||||||
|
|
||||||
|
const invoice = decode(bolt11)
|
||||||
|
const pr = invoice.payment_hash
|
||||||
|
log({ invoice })
|
||||||
|
log({ pr })
|
||||||
|
|
||||||
|
const checkInterval = setInterval(() => {
|
||||||
|
checkInvoiceStatus(invoice).then((status) => {
|
||||||
|
if (status.paid) {
|
||||||
|
log('invoice paid')
|
||||||
|
paidAmount = jobAmount
|
||||||
|
clearInterval(checkInterval)
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, 2000)
|
||||||
|
}
|
||||||
|
|
||||||
|
const waitForPayment = async (payReqEvent: NDKEvent): Promise<void> => {
|
||||||
|
log('waitForPayment')
|
||||||
|
const promise = new Promise<void>((resolve, reject) => {
|
||||||
|
waitForPaymentViaZap(payReqEvent, resolve, reject)
|
||||||
|
waitForPaymentViaLNInvoice(payReqEvent, resolve)
|
||||||
|
})
|
||||||
|
|
||||||
|
return promise
|
||||||
|
}
|
||||||
|
|
||||||
|
const startProcessing = async () => {
|
||||||
|
log('startProcessing')
|
||||||
|
await inProgress(event)
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case JobTypes.Summarize: {
|
||||||
|
output = await onNewSummarizationJob(event)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case JobTypes.SpeechToText: {
|
||||||
|
output = await speechToTextJob(event)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case JobTypes.BlockChainBlockNumber: {
|
||||||
|
output = await blockChainBlockNumberJob(event)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case JobTypes.RelayInfo: {
|
||||||
|
output = await relayInfoJob(event)
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await publishResult();
|
const publishResult = (): void => {
|
||||||
|
log('publishResult')
|
||||||
|
complete(event, missingAmount(), { output })
|
||||||
|
}
|
||||||
|
|
||||||
|
await validateJobRequest(event)
|
||||||
|
|
||||||
|
if (jobAmount > paidAmount && waitForPaymentBeforeProcessing()) {
|
||||||
|
await reqPayment()
|
||||||
|
await waitForPayment(payReqEvent)
|
||||||
|
}
|
||||||
|
|
||||||
|
await startProcessing()
|
||||||
|
|
||||||
|
await publishStatus(event, 'finished').catch((err) =>
|
||||||
|
console.log('err :>> ', err)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (jobAmount > paidAmount && waitForPaymentBeforePublishingResult()) {
|
||||||
|
await reqPayment()
|
||||||
|
await waitForPayment(payReqEvent)
|
||||||
|
log(`done with wait for publish`)
|
||||||
|
}
|
||||||
|
|
||||||
|
await publishResult()
|
||||||
}
|
}
|
||||||
|
2
src/types/index.ts
Normal file
2
src/types/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from './relay.js'
|
||||||
|
export * from './job.js'
|
14
src/types/job.ts
Normal file
14
src/types/job.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
export type JobType =
|
||||||
|
| 'summarize'
|
||||||
|
| 'explain'
|
||||||
|
| 'speech-to-text'
|
||||||
|
| 'blockChain-block-number'
|
||||||
|
| 'relay-info'
|
||||||
|
|
||||||
|
export enum JobTypes {
|
||||||
|
Summarize = 'summarize',
|
||||||
|
Explain = 'explain',
|
||||||
|
SpeechToText = 'speech-to-text',
|
||||||
|
BlockChainBlockNumber = 'blockChain-block-number',
|
||||||
|
RelayInfo = 'relay-info'
|
||||||
|
}
|
9
src/types/relay.ts
Normal file
9
src/types/relay.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export interface RelayInfo {
|
||||||
|
name: string
|
||||||
|
description: string
|
||||||
|
pubkey: string
|
||||||
|
contact: string
|
||||||
|
supported_nips: number[]
|
||||||
|
software: string
|
||||||
|
version: string
|
||||||
|
}
|
@ -1,28 +1,28 @@
|
|||||||
import { NDKTag } from '@nostr-dev-kit/ndk';
|
import { NDKTag } from '@nostr-dev-kit/ndk'
|
||||||
import axios from 'axios';
|
import axios from 'axios'
|
||||||
import fs from 'fs';
|
import fs from 'fs'
|
||||||
|
|
||||||
export async function fetchFileFromInput(input: NDKTag): Promise<string> {
|
export async function fetchFileFromInput(input: NDKTag): Promise<string> {
|
||||||
switch (input[2]) {
|
switch (input[2]) {
|
||||||
case 'url': {
|
case 'url': {
|
||||||
const url = input[1];
|
const url = input[1]
|
||||||
const fileExtension = url.split('.').pop();
|
const fileExtension = url.split('.').pop()
|
||||||
|
|
||||||
// download the file
|
// download the file
|
||||||
// save it to the local filesystem
|
// save it to the local filesystem
|
||||||
// return the path to the file
|
// return the path to the file
|
||||||
const response = await axios.get(url, {
|
const response = await axios.get(url, {
|
||||||
responseType: 'stream'
|
responseType: 'stream'
|
||||||
});
|
})
|
||||||
|
|
||||||
const randomName = Math.random().toString(36).substring(7);
|
const randomName = Math.random().toString(36).substring(7)
|
||||||
const path = `./${randomName}.${fileExtension}`;
|
const path = `./${randomName}.${fileExtension}`
|
||||||
|
|
||||||
await response.data.pipe(fs.createWriteStream(path));
|
await response.data.pipe(fs.createWriteStream(path))
|
||||||
|
|
||||||
return path;
|
return path
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return undefined;
|
return undefined
|
||||||
}
|
}
|
||||||
|
@ -1,38 +1,38 @@
|
|||||||
import _LNBits from "lnbits";
|
import _LNBits from 'lnbits'
|
||||||
|
|
||||||
let LNBits: any;
|
let LNBits: any
|
||||||
|
|
||||||
if (_LNBits.default) {
|
if (_LNBits.default) {
|
||||||
LNBits = _LNBits.default;
|
LNBits = _LNBits.default
|
||||||
} else {
|
} else {
|
||||||
LNBits = _LNBits;
|
LNBits = _LNBits
|
||||||
}
|
}
|
||||||
|
|
||||||
function getWallet (): any {
|
function getWallet(): any {
|
||||||
return LNBits({
|
return LNBits({
|
||||||
adminKey: "",
|
adminKey: '',
|
||||||
invoiceReadKey: 'bfbcb5b116c04179bc618ab78265a939',
|
invoiceReadKey: 'bfbcb5b116c04179bc618ab78265a939',
|
||||||
endpoint: 'https://legend.lnbits.com'
|
endpoint: 'https://legend.lnbits.com'
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createInvoice(amount: number): Promise<any> {
|
export async function createInvoice(amount: number): Promise<any> {
|
||||||
const { wallet } = getWallet();
|
const { wallet } = getWallet()
|
||||||
|
|
||||||
const newInvoice = await wallet.createInvoice({
|
const newInvoice = await wallet.createInvoice({
|
||||||
amount: amount,
|
amount: amount,
|
||||||
memo: 'data vending machine',
|
memo: 'data vending machine',
|
||||||
out: false,
|
out: false
|
||||||
});
|
})
|
||||||
|
|
||||||
return newInvoice;
|
return newInvoice
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function checkInvoiceStatus(invoice): Promise<any> {
|
export async function checkInvoiceStatus(invoice): Promise<any> {
|
||||||
const { wallet } = getWallet();
|
const { wallet } = getWallet()
|
||||||
const invoiceStatus = await wallet.checkInvoice({
|
const invoiceStatus = await wallet.checkInvoice({
|
||||||
payment_hash: invoice.payment_hash,
|
payment_hash: invoice.payment_hash
|
||||||
});
|
})
|
||||||
|
|
||||||
return invoiceStatus;
|
return invoiceStatus
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { NDKEvent } from '@nostr-dev-kit/ndk';
|
import { NDKEvent } from '@nostr-dev-kit/ndk'
|
||||||
|
|
||||||
export default async function validateExpiration(event: NDKEvent) {
|
export default async function validateExpiration(event: NDKEvent) {
|
||||||
const expTag = event.tagValue('exp');
|
const expTag = event.tagValue('exp')
|
||||||
const timeNow = Math.floor(Date.now() / 1000);
|
const timeNow = Math.floor(Date.now() / 1000)
|
||||||
|
|
||||||
if (expTag && parseInt(expTag) < timeNow - 10) {
|
if (expTag && parseInt(expTag) < timeNow - 10) {
|
||||||
throw new Error('Job expired');
|
throw new Error('Job expired')
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1,40 +1,42 @@
|
|||||||
import { NDKEvent, type NostrEvent } from '@nostr-dev-kit/ndk';
|
import { NDKEvent, type NostrEvent } from '@nostr-dev-kit/ndk'
|
||||||
import validateExpiration from './expiration.js';
|
import validateExpiration from './expiration.js'
|
||||||
import validateRequester from './requester.js';
|
import validateRequester from './requester.js'
|
||||||
import validateNoRecentResults from './no-recent-results.js';
|
import validateNoRecentResults from './no-recent-results.js'
|
||||||
import { ndk } from '../main.js';
|
import { ndk } from '../main.js'
|
||||||
import { addAmount } from '../job-types/speech-to-text.js';
|
import { addAmount } from '../job-types/speech-to-text.js'
|
||||||
|
|
||||||
export async function validateJobRequest(event: NDKEvent): Promise<void> {
|
export async function validateJobRequest(event: NDKEvent): Promise<void> {
|
||||||
await validateExpiration(event);
|
await validateExpiration(event)
|
||||||
await validateRequester(event);
|
await validateRequester(event)
|
||||||
await validateNoRecentResults(event);
|
await validateNoRecentResults(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function requirePayment(event: NDKEvent, amount?: number, publish?: boolean): Promise<NDKEvent> {
|
export async function requirePayment(
|
||||||
if (!amount) {
|
event: NDKEvent,
|
||||||
const bidTag = event.tagValue('bid');
|
amount?: number,
|
||||||
amount = bidTag ? parseInt(bidTag) : undefined;
|
publish?: boolean
|
||||||
}
|
): Promise<NDKEvent> {
|
||||||
|
if (!amount) {
|
||||||
|
const bidTag = event.tagValue('bid')
|
||||||
|
amount = bidTag ? parseInt(bidTag) : undefined
|
||||||
|
}
|
||||||
|
|
||||||
if (!amount) {
|
if (!amount) {
|
||||||
throw new Error("No amount specified");
|
throw new Error('No amount specified')
|
||||||
}
|
}
|
||||||
|
|
||||||
const payReq = new NDKEvent(ndk, {
|
const payReq = new NDKEvent(ndk, {
|
||||||
kind: 68003,
|
kind: 68003,
|
||||||
content: "`Please pay for this job`",
|
content: '`Please pay for this job`',
|
||||||
tags: [
|
tags: [['status', 'payment-required']]
|
||||||
["status", "payment-required"],
|
} as NostrEvent)
|
||||||
]
|
await addAmount(payReq, amount)
|
||||||
} as NostrEvent);
|
payReq.tag(event, 'job')
|
||||||
await addAmount(payReq, amount);
|
|
||||||
payReq.tag(event, "job");
|
|
||||||
|
|
||||||
await payReq.sign();
|
await payReq.sign()
|
||||||
console.log(payReq.rawEvent());
|
console.log(payReq.rawEvent())
|
||||||
|
|
||||||
if (publish !== false) await payReq.publish();
|
if (publish !== false) await payReq.publish()
|
||||||
|
|
||||||
return payReq;
|
return payReq
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,18 @@
|
|||||||
import { NDKEvent } from '@nostr-dev-kit/ndk';
|
import { NDKEvent } from '@nostr-dev-kit/ndk'
|
||||||
import { ndk } from '../main.js';
|
import { ndk } from '../main.js'
|
||||||
|
|
||||||
export default async function validateNoRecentResults(event: NDKEvent): Promise<void> {
|
export default async function validateNoRecentResults(
|
||||||
const results = ndk.fetchEvents({
|
event: NDKEvent
|
||||||
kinds: [68002 as number],
|
): Promise<void> {
|
||||||
"#e": [event.id],
|
const results = ndk.fetchEvents(
|
||||||
}, { groupable: false })
|
{
|
||||||
|
kinds: [68002 as number],
|
||||||
|
'#e': [event.id]
|
||||||
|
},
|
||||||
|
{ groupable: false }
|
||||||
|
)
|
||||||
|
|
||||||
if (results.length > 0) {
|
if (results.length > 0) {
|
||||||
throw new Error(`This job already has ${results.length} results`);
|
throw new Error(`This job already has ${results.length} results`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
import { NDKEvent } from '@nostr-dev-kit/ndk';
|
import { NDKEvent } from '@nostr-dev-kit/ndk'
|
||||||
|
|
||||||
export default async function validateRequester(event: NDKEvent): Promise<void> {
|
export default async function validateRequester(
|
||||||
if (event) { /* empty */ }
|
event: NDKEvent
|
||||||
}
|
): Promise<void> {
|
||||||
|
if (event) {
|
||||||
|
/* empty */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user