Compare commits
4 Commits
54fedbc528
...
772e73f48d
Author | SHA1 | Date | |
---|---|---|---|
|
772e73f48d | ||
|
eba2472f2f | ||
|
d67d53b172 | ||
|
946b50261e |
16
.prettierrc
16
.prettierrc
@ -1,13 +1,7 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"tabWidth": 4,
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts", "*.mts"],
|
||||
"options": {
|
||||
"parser": "typescript"
|
||||
}
|
||||
}
|
||||
]
|
||||
"trailingComma": "none",
|
||||
"tabWidth": 2,
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"endOfLine": "auto"
|
||||
}
|
||||
|
213
package-lock.json
generated
213
package-lock.json
generated
@ -9,7 +9,7 @@
|
||||
"version": "0.1.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@nostr-dev-kit/ndk": "^0.7.5",
|
||||
"@nostr-dev-kit/ndk": "^0.8.1",
|
||||
"axios": "^1.4.0",
|
||||
"debug": "^4.3.4",
|
||||
"file-type": "^18.5.0",
|
||||
@ -29,7 +29,7 @@
|
||||
"eslint-config-prettier": "~8.8",
|
||||
"eslint-plugin-jest": "~27.2",
|
||||
"jest": "~29.5",
|
||||
"prettier": "~2.8",
|
||||
"prettier": "3.2.5",
|
||||
"rimraf": "~5.0",
|
||||
"ts-api-utils": "~0.0.44",
|
||||
"ts-jest": "~29.1",
|
||||
@ -1644,9 +1644,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@nostr-dev-kit/ndk": {
|
||||
"version": "0.7.7",
|
||||
"resolved": "https://registry.npmjs.org/@nostr-dev-kit/ndk/-/ndk-0.7.7.tgz",
|
||||
"integrity": "sha512-IRTW16q40zzuSBkpYpDUcZJRrbw26JTeicfZN6O/2Gw7D2w6Pe42VqFwpbcP9xOnFPEGP2eNV6SwXQ3y0tjBtw==",
|
||||
"version": "0.8.23",
|
||||
"resolved": "https://registry.npmjs.org/@nostr-dev-kit/ndk/-/ndk-0.8.23.tgz",
|
||||
"integrity": "sha512-wX/9Cl02gCR0Kz25C/1xxGO47K13Ve1x8IISbkF/M3RTTXftYBvzB7bL8qwLaFaeqb02cMU0YVL+oKDrYzH/Ng==",
|
||||
"dependencies": {
|
||||
"@noble/hashes": "^1.3.1",
|
||||
"@noble/secp256k1": "^2.0.0",
|
||||
@ -1663,10 +1663,9 @@
|
||||
"eventemitter3": "^5.0.1",
|
||||
"light-bolt11-decoder": "^3.0.0",
|
||||
"node-fetch": "^3.3.1",
|
||||
"nostr-tools": "^1.11.2",
|
||||
"nostr-tools": "^1.14.0",
|
||||
"tsd": "^0.28.1",
|
||||
"utf8-buffer": "^1.0.0",
|
||||
"websocket-polyfill": "^0.0.3"
|
||||
"utf8-buffer": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@pkgjs/parseargs": {
|
||||
@ -2552,18 +2551,6 @@
|
||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
||||
"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": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
|
||||
@ -2792,18 +2779,6 @@
|
||||
"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": {
|
||||
"version": "4.0.1",
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"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": {
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz",
|
||||
@ -3561,20 +3499,6 @@
|
||||
"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": {
|
||||
"version": "9.6.1",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
|
||||
@ -3658,15 +3582,6 @@
|
||||
"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": {
|
||||
"version": "5.0.1",
|
||||
"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_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": {
|
||||
"version": "3.1.3",
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"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": {
|
||||
"version": "0.1.0",
|
||||
"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",
|
||||
"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": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
|
||||
@ -5929,16 +5826,6 @@
|
||||
"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": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
|
||||
@ -6578,15 +6465,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "2.8.8",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
|
||||
"integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
|
||||
"version": "3.2.5",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz",
|
||||
"integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"prettier": "bin-prettier.js"
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||
@ -7659,11 +7546,6 @@
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz",
|
||||
"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": {
|
||||
"version": "3.21.0",
|
||||
"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",
|
||||
"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": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
||||
@ -7788,14 +7665,6 @@
|
||||
"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": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz",
|
||||
@ -7866,18 +7735,6 @@
|
||||
"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": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/utf8-buffer/-/utf8-buffer-1.0.0.tgz",
|
||||
@ -7931,44 +7788,6 @@
|
||||
"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": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
@ -8086,14 +7905,6 @@
|
||||
"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": {
|
||||
"version": "3.1.1",
|
||||
"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",
|
||||
"version": "0.1.0",
|
||||
"description": "nostr data vending machine skeleton",
|
||||
"type": "module",
|
||||
"engines": {
|
||||
"node": "~19"
|
||||
},
|
||||
"keywords": [
|
||||
"nostr",
|
||||
"ai",
|
||||
"bitcoin"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@types/jest": "~29.5",
|
||||
"@types/node": "~18",
|
||||
"@typescript-eslint/eslint-plugin": "~5.59",
|
||||
"@typescript-eslint/parser": "~5.59",
|
||||
"eslint": "~8.38",
|
||||
"eslint-config-prettier": "~8.8",
|
||||
"eslint-plugin-jest": "~27.2",
|
||||
"jest": "~29.5",
|
||||
"prettier": "~2.8",
|
||||
"rimraf": "~5.0",
|
||||
"ts-api-utils": "~0.0.44",
|
||||
"ts-jest": "~29.1",
|
||||
"typescript": "~5.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node build/src/main.js",
|
||||
"clean": "rimraf coverage build tmp",
|
||||
"_prebuild": "npm run lint",
|
||||
"build": "tsc -p tsconfig.json",
|
||||
"build:watch": "tsc -w -p tsconfig.json",
|
||||
"build:release": "npm run clean && tsc -p tsconfig.release.json",
|
||||
"lint": "eslint . --ext .ts --ext .mts",
|
||||
"test": "jest --coverage",
|
||||
"prettier": "prettier --config .prettierrc --write .",
|
||||
"test:watch": "jest --watch"
|
||||
},
|
||||
"author": "pablof7z",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@nostr-dev-kit/ndk": "^0.8.1",
|
||||
"axios": "^1.4.0",
|
||||
"debug": "^4.3.4",
|
||||
"file-type": "^18.5.0",
|
||||
"form-data": "^4.0.0",
|
||||
"form-data-encoder": "^3.0.0",
|
||||
"formdata-node": "^5.0.1",
|
||||
"light-bolt11-decoder": "^3.0.0",
|
||||
"lnbits": "^1.1.5",
|
||||
"tslib": "~2.5"
|
||||
},
|
||||
"volta": {
|
||||
"node": "18.12.1"
|
||||
}
|
||||
"name": "data-vending-machine-skeleton",
|
||||
"version": "0.1.0",
|
||||
"description": "nostr data vending machine skeleton",
|
||||
"type": "module",
|
||||
"engines": {
|
||||
"node": "~19"
|
||||
},
|
||||
"keywords": [
|
||||
"nostr",
|
||||
"ai",
|
||||
"bitcoin"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@types/jest": "~29.5",
|
||||
"@types/node": "~18",
|
||||
"@typescript-eslint/eslint-plugin": "~5.59",
|
||||
"@typescript-eslint/parser": "~5.59",
|
||||
"eslint": "~8.38",
|
||||
"eslint-config-prettier": "~8.8",
|
||||
"eslint-plugin-jest": "~27.2",
|
||||
"jest": "~29.5",
|
||||
"prettier": "3.2.5",
|
||||
"rimraf": "~5.0",
|
||||
"ts-api-utils": "~0.0.44",
|
||||
"ts-jest": "~29.1",
|
||||
"typescript": "~5.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node build/src/main.js",
|
||||
"clean": "rimraf coverage build tmp",
|
||||
"_prebuild": "npm run lint",
|
||||
"build": "tsc -p tsconfig.json",
|
||||
"build:watch": "tsc -w -p tsconfig.json",
|
||||
"build:release": "npm run clean && tsc -p tsconfig.release.json",
|
||||
"lint": "eslint . --ext .ts --ext .mts",
|
||||
"test": "jest --coverage",
|
||||
"prettier": "prettier --config .prettierrc --write .",
|
||||
"test:watch": "jest --watch",
|
||||
"formatter:check": "prettier --check \"src/**/*.{ts,tsx,js,jsx,html,css,sass,less,yml,md,graphql}\"",
|
||||
"formatter:fix": "prettier --write \"src/**/*.{ts,tsx,js,jsx,html,css,sass,less,yml,md,graphql}\""
|
||||
},
|
||||
"author": "pablof7z",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@nostr-dev-kit/ndk": "^0.8.1",
|
||||
"axios": "^1.4.0",
|
||||
"debug": "^4.3.4",
|
||||
"file-type": "^18.5.0",
|
||||
"form-data": "^4.0.0",
|
||||
"form-data-encoder": "^3.0.0",
|
||||
"formdata-node": "^5.0.1",
|
||||
"light-bolt11-decoder": "^3.0.0",
|
||||
"lnbits": "^1.1.5",
|
||||
"tslib": "~2.5"
|
||||
},
|
||||
"volta": {
|
||||
"node": "18.12.1"
|
||||
}
|
||||
}
|
||||
|
@ -64,8 +64,8 @@ importers:
|
||||
specifier: ~29.5
|
||||
version: 29.5.0(@types/node@18.16.19)
|
||||
prettier:
|
||||
specifier: ~2.8
|
||||
version: 2.8.8
|
||||
specifier: 3.2.5
|
||||
version: 3.2.5
|
||||
rimraf:
|
||||
specifier: ~5.0
|
||||
version: 5.0.1
|
||||
@ -2171,9 +2171,9 @@ packages:
|
||||
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
|
||||
prettier@2.8.8:
|
||||
resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
prettier@3.2.5:
|
||||
resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==}
|
||||
engines: {node: '>=14'}
|
||||
hasBin: true
|
||||
|
||||
pretty-format@29.6.1:
|
||||
@ -5246,7 +5246,7 @@ snapshots:
|
||||
|
||||
prelude-ls@1.2.1: {}
|
||||
|
||||
prettier@2.8.8: {}
|
||||
prettier@3.2.5: {}
|
||||
|
||||
pretty-format@29.6.1:
|
||||
dependencies:
|
||||
|
@ -1,37 +1,37 @@
|
||||
import { NDKPrivateKeySigner } from '@nostr-dev-kit/ndk';
|
||||
import fs from 'fs';
|
||||
import { log, configFile } from '../main.js';
|
||||
import { NDKPrivateKeySigner } from '@nostr-dev-kit/ndk'
|
||||
import fs from 'fs'
|
||||
import { log, configFile } from '../main.js'
|
||||
|
||||
type IConfig = {
|
||||
key: string;
|
||||
discount?: number;
|
||||
undercut?: number;
|
||||
processWithoutPaymentLimit?: number;
|
||||
serveResultsWithoutPaymentLimit?: number;
|
||||
key: string
|
||||
discount?: number
|
||||
undercut?: number
|
||||
processWithoutPaymentLimit?: number
|
||||
serveResultsWithoutPaymentLimit?: number
|
||||
}
|
||||
|
||||
export function getConfig(): IConfig {
|
||||
let config: IConfig;
|
||||
let config: IConfig
|
||||
|
||||
if (fs.existsSync(configFile)) {
|
||||
config = JSON.parse(fs.readFileSync(configFile, 'utf8'));
|
||||
if (fs.existsSync(configFile)) {
|
||||
config = JSON.parse(fs.readFileSync(configFile, 'utf8'))
|
||||
}
|
||||
|
||||
if (!config) {
|
||||
log('Generating new config')
|
||||
config = {
|
||||
key: NDKPrivateKeySigner.generate().privateKey
|
||||
}
|
||||
|
||||
if (!config) {
|
||||
log('Generating new config')
|
||||
config = {
|
||||
key: NDKPrivateKeySigner.generate().privateKey,
|
||||
};
|
||||
const signer = NDKPrivateKeySigner.generate()
|
||||
config.key = signer.privateKey
|
||||
|
||||
const signer = NDKPrivateKeySigner.generate();
|
||||
config.key = signer.privateKey;
|
||||
saveConfig(config)
|
||||
}
|
||||
|
||||
saveConfig(config);
|
||||
}
|
||||
|
||||
return config;
|
||||
return config
|
||||
}
|
||||
|
||||
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 { log } from '../main.js';
|
||||
import axios from 'axios';
|
||||
import { NDKEvent } from '@nostr-dev-kit/ndk'
|
||||
import { log } from '../main.js'
|
||||
import axios from 'axios'
|
||||
|
||||
export async function blockChainBlockNumberJob(
|
||||
event: NDKEvent,
|
||||
event: NDKEvent
|
||||
): 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
|
||||
.get(blockChainUrl)
|
||||
.then((res) => {
|
||||
const closestObject = findClosestObject(res.data, input);
|
||||
return closestObject.block_index.toString();
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log('err in blockChain request :>> ', err);
|
||||
return Promise.reject(err);
|
||||
});
|
||||
const output = await axios
|
||||
.get(blockChainUrl)
|
||||
.then((res) => {
|
||||
const closestObject = findClosestObject(res.data, input)
|
||||
return closestObject.block_index.toString()
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log('err in blockChain request :>> ', err)
|
||||
return Promise.reject(err)
|
||||
})
|
||||
|
||||
return output;
|
||||
return output
|
||||
}
|
||||
|
||||
// todo: define type for array
|
||||
// Function to find the object with the closest timestamp
|
||||
function findClosestObject(array, timestamp) {
|
||||
let closestObject = null;
|
||||
let minDifference = Infinity;
|
||||
let closestObject = null
|
||||
let minDifference = Infinity
|
||||
|
||||
array.forEach((obj) => {
|
||||
const difference = Math.abs(obj.time - timestamp);
|
||||
if (difference < minDifference) {
|
||||
minDifference = difference;
|
||||
closestObject = obj;
|
||||
}
|
||||
});
|
||||
array.forEach((obj) => {
|
||||
const difference = Math.abs(obj.time - timestamp)
|
||||
if (difference < minDifference) {
|
||||
minDifference = difference
|
||||
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 axios from 'axios';
|
||||
import FormData from 'form-data';
|
||||
import { log } from '../main.js';
|
||||
import { fetchFileFromInput } from '../utils/fetch-file-from-input.js';
|
||||
import { ndk } from '../main.js';
|
||||
import { NDKEvent, type NostrEvent } from '@nostr-dev-kit/ndk'
|
||||
import axios from 'axios'
|
||||
import FormData from 'form-data'
|
||||
import { log } from '../main.js'
|
||||
import { fetchFileFromInput } from '../utils/fetch-file-from-input.js'
|
||||
import { ndk } from '../main.js'
|
||||
// import { fileTypeFromFile, type FileTypeResult } from 'file-type';
|
||||
import { exec } from 'child_process';
|
||||
import fs from 'fs';
|
||||
import { createInvoice } from '../utils/lnbits.js';
|
||||
import { exec } from 'child_process'
|
||||
import fs from 'fs'
|
||||
import { createInvoice } from '../utils/lnbits.js'
|
||||
|
||||
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
|
||||
const file = await fetchFile(event);
|
||||
log(`file: ${file}`);
|
||||
// fetch the input file
|
||||
const file = await fetchFile(event)
|
||||
log(`file: ${file}`)
|
||||
|
||||
if (!file) {
|
||||
return undefined;
|
||||
}
|
||||
if (!file) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
// check if file exists
|
||||
// if (!fs.existsSync(file)) {
|
||||
// log(`file does not exist: ${file}`);
|
||||
// return undefined;
|
||||
// }
|
||||
// check if file exists
|
||||
// if (!fs.existsSync(file)) {
|
||||
// log(`file does not exist: ${file}`);
|
||||
// return undefined;
|
||||
// }
|
||||
|
||||
// let fileType: FileTypeResult;
|
||||
// let fileType: FileTypeResult;
|
||||
|
||||
// try {
|
||||
// fileType = await fileTypeFromFile(file);
|
||||
// log(`fileType: ${fileType}`);
|
||||
// } catch (error) {
|
||||
// log(error);
|
||||
// }
|
||||
// try {
|
||||
// fileType = await fileTypeFromFile(file);
|
||||
// log(`fileType: ${fileType}`);
|
||||
// } catch (error) {
|
||||
// log(error);
|
||||
// }
|
||||
|
||||
const whisperCommand = (resolve: any, file: string) => {
|
||||
setTimeout(() => {
|
||||
const whisperCommand = (resolve: any, file: string) => {
|
||||
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)) {
|
||||
log(`file does not exist: ${file}`);
|
||||
return undefined;
|
||||
}
|
||||
const formData = new FormData();
|
||||
const a = fs.createReadStream(file);
|
||||
console.log({a});
|
||||
formData.append('file', a)
|
||||
formData.append('model', 'whisper-1')
|
||||
|
||||
formData.append('file', a);
|
||||
formData.append('model', 'whisper-1');
|
||||
axios
|
||||
.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, {
|
||||
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);
|
||||
}
|
||||
// const input = event.tagValue('i');
|
||||
const range = event.getMatchingTags('param').find((tag) => tag[1] === 'range')
|
||||
return new Promise((resolve) => whisperCommand(resolve, file))
|
||||
|
||||
// const input = event.tagValue('i');
|
||||
const range = event.getMatchingTags('param').find((tag) => tag[1] === 'range');
|
||||
return new Promise((resolve) => whisperCommand(resolve, file));
|
||||
if (range) {
|
||||
return new Promise((resolve) => {
|
||||
const startTime = range[2]
|
||||
const endTime = range[3]
|
||||
const randomName = Math.random().toString(36).substring(7) + '.mp3'
|
||||
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 })
|
||||
|
||||
if (range) {
|
||||
return new Promise((resolve) => {
|
||||
const startTime = range[2];
|
||||
const endTime = range[3];
|
||||
const randomName = Math.random().toString(36).substring(7)+'.mp3';
|
||||
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);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
return new Promise((resolve) => whisperCommand(resolve, file));
|
||||
}
|
||||
whisperCommand(resolve, randomName)
|
||||
})
|
||||
})
|
||||
} else {
|
||||
return new Promise((resolve) => whisperCommand(resolve, file))
|
||||
}
|
||||
}
|
||||
|
||||
interface ICompleteParams {
|
||||
output: string;
|
||||
output: string
|
||||
}
|
||||
|
||||
export async function addAmount(event: NDKEvent, amount: number, includeInvoice = true): Promise<void> {
|
||||
const tag = ['amount', amount.toString()];
|
||||
export async function addAmount(
|
||||
event: NDKEvent,
|
||||
amount: number,
|
||||
includeInvoice = true
|
||||
): Promise<void> {
|
||||
const tag = ['amount', amount.toString()]
|
||||
|
||||
if (includeInvoice) {
|
||||
const invoice = await createInvoice(amount / 1000);
|
||||
tag.push(invoice.payment_request);
|
||||
}
|
||||
if (includeInvoice) {
|
||||
const invoice = await createInvoice(amount / 1000)
|
||||
tag.push(invoice.payment_request)
|
||||
}
|
||||
|
||||
event.tags.push(tag);
|
||||
event.tags.push(tag)
|
||||
}
|
||||
|
||||
export async function complete(
|
||||
jobRequest: NDKEvent,
|
||||
amount: number,
|
||||
completeParams: ICompleteParams,
|
||||
includeInvoice?: boolean
|
||||
jobRequest: NDKEvent,
|
||||
amount: number,
|
||||
completeParams: ICompleteParams,
|
||||
includeInvoice?: boolean
|
||||
): Promise<void> {
|
||||
const jobResult = new NDKEvent(ndk, {
|
||||
kind: 68002,
|
||||
content: completeParams.output,
|
||||
tags: [
|
||||
[ 'status', 'success' ]
|
||||
]
|
||||
} as NostrEvent);
|
||||
const jobResult = new NDKEvent(ndk, {
|
||||
kind: 68002,
|
||||
content: completeParams.output,
|
||||
tags: [['status', 'success']]
|
||||
} as NostrEvent)
|
||||
|
||||
if (amount > 0) {
|
||||
await addAmount(jobResult, amount, includeInvoice);
|
||||
}
|
||||
jobResult.tag(jobRequest);
|
||||
if (amount > 0) {
|
||||
await addAmount(jobResult, amount, includeInvoice)
|
||||
}
|
||||
jobResult.tag(jobRequest)
|
||||
|
||||
await jobResult.sign()
|
||||
log(jobResult.rawEvent())
|
||||
|
||||
await jobResult.sign();
|
||||
log(jobResult.rawEvent());
|
||||
|
||||
await jobResult.publish();
|
||||
return jobResult;
|
||||
await jobResult.publish()
|
||||
return jobResult
|
||||
}
|
||||
|
||||
export async function fetchFile(event: NDKEvent): Promise<string> {
|
||||
const inputTags = event.getMatchingTags("i");
|
||||
const inputTags = event.getMatchingTags('i')
|
||||
|
||||
if (inputTags.length !== 1) {
|
||||
throw new Error(`Incorrect number of inputs: ${inputTags.length}`);
|
||||
}
|
||||
if (inputTags.length !== 1) {
|
||||
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 { validateJobRequest } from '../validations/index.js';
|
||||
import { inProgress } from '../jobs/reactions/in-progress.js';
|
||||
import { NDKEvent } from '@nostr-dev-kit/ndk'
|
||||
import { validateJobRequest } from '../validations/index.js'
|
||||
import { inProgress } from '../jobs/reactions/in-progress.js'
|
||||
|
||||
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 { log } from '../main.js';
|
||||
import { getConfig } from '../config/index.js';
|
||||
import { NDKEvent } from '@nostr-dev-kit/ndk'
|
||||
import { log } from '../main.js'
|
||||
import { getConfig } from '../config/index.js'
|
||||
|
||||
export async function priceJob(event: NDKEvent): Promise<number> {
|
||||
const config = getConfig();
|
||||
const bidTag = event.tagValue('bid');
|
||||
let bidAmount = bidTag ? parseInt(bidTag) : 1001 * 1000;
|
||||
const config = getConfig()
|
||||
const bidTag = event.tagValue('bid')
|
||||
let bidAmount = bidTag ? parseInt(bidTag) : 1001 * 1000
|
||||
|
||||
if (config.discount) {
|
||||
bidAmount = bidAmount * config.discount;
|
||||
}
|
||||
if (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 { log, ndk } from '../../main.js';
|
||||
import { NDKEvent } from '@nostr-dev-kit/ndk'
|
||||
import { log, ndk } from '../../main.js'
|
||||
|
||||
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, {
|
||||
kind: 68003,
|
||||
content: "👍",
|
||||
tags: [
|
||||
[ "status", "started" ],
|
||||
]
|
||||
})
|
||||
const reactEvent = new NDKEvent(ndk, {
|
||||
kind: 68003,
|
||||
content: '👍',
|
||||
tags: [['status', 'started']]
|
||||
})
|
||||
|
||||
reactEvent.tag(event, "job");
|
||||
await reactEvent.sign();
|
||||
await reactEvent.publish();
|
||||
return reactEvent;
|
||||
reactEvent.tag(event, 'job')
|
||||
await reactEvent.sign()
|
||||
await reactEvent.publish()
|
||||
return reactEvent
|
||||
}
|
||||
|
@ -1,25 +1,23 @@
|
||||
import { NDKEvent, NDKTag } from '@nostr-dev-kit/ndk';
|
||||
import { log, ndk } from '../../main.js';
|
||||
import { NDKEvent, NDKTag } from '@nostr-dev-kit/ndk'
|
||||
import { log, ndk } from '../../main.js'
|
||||
|
||||
export async function publishStatus(
|
||||
event: NDKEvent,
|
||||
status: string,
|
||||
extraTags: NDKTag[] = []): Promise<NDKEvent> {
|
||||
log("marking job as finished");
|
||||
event: NDKEvent,
|
||||
status: string,
|
||||
extraTags: NDKTag[] = []
|
||||
): Promise<NDKEvent> {
|
||||
log('marking job as finished')
|
||||
|
||||
const reactEvent = new NDKEvent(ndk, {
|
||||
kind: 68003,
|
||||
content: "👍",
|
||||
tags: [
|
||||
[ "status", status ],
|
||||
...extraTags
|
||||
]
|
||||
})
|
||||
const reactEvent = new NDKEvent(ndk, {
|
||||
kind: 68003,
|
||||
content: '👍',
|
||||
tags: [['status', status], ...extraTags]
|
||||
})
|
||||
|
||||
console.log({extraTags})
|
||||
console.log({ extraTags })
|
||||
|
||||
reactEvent.tag(event, "job");
|
||||
await reactEvent.sign();
|
||||
await reactEvent.publish();
|
||||
return reactEvent;
|
||||
reactEvent.tag(event, 'job')
|
||||
await reactEvent.sign()
|
||||
await reactEvent.publish()
|
||||
return reactEvent
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { NDKPrivateKeySigner } from '@nostr-dev-kit/ndk';
|
||||
import { getConfig } from './config/index.js';
|
||||
import { NDKPrivateKeySigner } from '@nostr-dev-kit/ndk'
|
||||
import { getConfig } from './config/index.js'
|
||||
|
||||
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 debug from 'debug';
|
||||
import { onNewSummarizationJob } from './job-types/summarization.js';
|
||||
import { complete, speechToTextJob } from './job-types/speech-to-text.js';
|
||||
import getSigner from './local-signer.js';
|
||||
import { requirePayment, validateJobRequest } from './validations/index.js';
|
||||
import { inProgress } from './jobs/reactions/in-progress.js';
|
||||
import { publishStatus } from './jobs/reactions/status.js';
|
||||
import { priceJob } from './jobs/price.js';
|
||||
import { getConfig } from './config/index.js';
|
||||
import { decode } from 'light-bolt11-decoder';
|
||||
import { checkInvoiceStatus } from './utils/lnbits.js';
|
||||
import { blockChainBlockNumberJob } from './job-types/blockChain-block-number.js';
|
||||
import NDK, { NDKEvent } from '@nostr-dev-kit/ndk'
|
||||
import debug from 'debug'
|
||||
import { onNewSummarizationJob } from './job-types/summarization.js'
|
||||
import { complete, speechToTextJob } from './job-types/speech-to-text.js'
|
||||
import getSigner from './local-signer.js'
|
||||
import { requirePayment, validateJobRequest } from './validations/index.js'
|
||||
import { inProgress } from './jobs/reactions/in-progress.js'
|
||||
import { publishStatus } from './jobs/reactions/status.js'
|
||||
import { priceJob } from './jobs/price.js'
|
||||
import { getConfig } from './config/index.js'
|
||||
import { decode } from 'light-bolt11-decoder'
|
||||
import { checkInvoiceStatus } from './utils/lnbits.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 =
|
||||
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({
|
||||
explicitRelayUrls: [
|
||||
'wss://relay.damus.io',
|
||||
'wss://relay.primal.net',
|
||||
'wss://relayable.org',
|
||||
],
|
||||
signer: getSigner(),
|
||||
});
|
||||
await ndk.connect(2000);
|
||||
log('connected');
|
||||
explicitRelayUrls: [
|
||||
'wss://relay.damus.io',
|
||||
'wss://relay.primal.net',
|
||||
'wss://relayable.org'
|
||||
],
|
||||
signer: getSigner()
|
||||
})
|
||||
await ndk.connect(2000)
|
||||
log('connected')
|
||||
|
||||
const subs = ndk.subscribe(
|
||||
{
|
||||
kinds: [68001 as number],
|
||||
since: Math.floor(Date.now() / 1000),
|
||||
'#j': ['summarize', 'explain'],
|
||||
},
|
||||
{ closeOnEose: false },
|
||||
);
|
||||
{
|
||||
kinds: [68001 as number],
|
||||
since: Math.floor(Date.now() / 1000),
|
||||
'#j': [JobTypes.Summarize, JobTypes.Explain]
|
||||
},
|
||||
{ closeOnEose: false }
|
||||
)
|
||||
|
||||
const speechToTextSub = ndk.subscribe(
|
||||
{
|
||||
kinds: [68001 as number],
|
||||
since: Math.floor(Date.now() / 1000),
|
||||
'#j': ['speech-to-text'],
|
||||
},
|
||||
{ closeOnEose: false },
|
||||
);
|
||||
{
|
||||
kinds: [68001 as number],
|
||||
since: Math.floor(Date.now() / 1000),
|
||||
'#j': [JobTypes.SpeechToText]
|
||||
},
|
||||
{ closeOnEose: false }
|
||||
)
|
||||
|
||||
const blockChainBlockNumberSub = ndk.subscribe(
|
||||
{
|
||||
kinds: [68001 as number],
|
||||
since: Math.floor(Date.now() / 1000),
|
||||
'#j': ['blockChain-block-number'],
|
||||
},
|
||||
{ closeOnEose: false },
|
||||
);
|
||||
{
|
||||
kinds: [68001 as number],
|
||||
since: Math.floor(Date.now() / 1000),
|
||||
'#j': [JobTypes.BlockChainBlockNumber]
|
||||
},
|
||||
{ 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'));
|
||||
speechToTextSub.on('event', (e) => processJobEvent(e, 'speech-to-text'));
|
||||
subs.on('event', (e) => processJobEvent(e, JobTypes.Summarize))
|
||||
speechToTextSub.on('event', (e) => processJobEvent(e, JobTypes.SpeechToText))
|
||||
blockChainBlockNumberSub.on('event', (e) =>
|
||||
processJobEvent(e, 'blockChain-block-number'),
|
||||
);
|
||||
processJobEvent(e, JobTypes.BlockChainBlockNumber)
|
||||
)
|
||||
relayInfoSub.on('event', (e) => processJobEvent(e, JobTypes.RelayInfo))
|
||||
|
||||
type JobType =
|
||||
| 'summarize'
|
||||
| 'explain'
|
||||
| 'speech-to-text'
|
||||
| 'blockChain-block-number';
|
||||
const freeJobs: string[] = [JobTypes.BlockChainBlockNumber, JobTypes.RelayInfo]
|
||||
|
||||
async function processJobEvent(event: NDKEvent, type: JobType): Promise<void> {
|
||||
const config = getConfig();
|
||||
let jobAmount =
|
||||
type === 'blockChain-block-number' ? 0 : await priceJob(event);
|
||||
let output: any;
|
||||
let payReqEvent: NDKEvent;
|
||||
let paidAmount = 0;
|
||||
const config = getConfig()
|
||||
let jobAmount = freeJobs.includes(type) ? 0 : await priceJob(event)
|
||||
let output: any
|
||||
let payReqEvent: NDKEvent
|
||||
let paidAmount = 0
|
||||
|
||||
const waitForPaymentBeforeProcessing = (): boolean => {
|
||||
const processWithoutPaymentLimit =
|
||||
config.processWithoutPaymentLimit ?? 500;
|
||||
log('waitForPaymentBeforeProcessing', {
|
||||
jobAmount,
|
||||
processWithoutPaymentLimit,
|
||||
});
|
||||
return jobAmount && jobAmount > processWithoutPaymentLimit * 1000;
|
||||
};
|
||||
const waitForPaymentBeforeProcessing = (): boolean => {
|
||||
const processWithoutPaymentLimit = config.processWithoutPaymentLimit ?? 500
|
||||
log('waitForPaymentBeforeProcessing', {
|
||||
jobAmount,
|
||||
processWithoutPaymentLimit
|
||||
})
|
||||
return jobAmount && jobAmount > processWithoutPaymentLimit * 1000
|
||||
}
|
||||
|
||||
const waitForPaymentBeforePublishingResult = (): boolean => {
|
||||
const serveResultsWithoutPaymentLimit =
|
||||
config.serveResultsWithoutPaymentLimit ?? 1000;
|
||||
log('waitForPaymentBeforeProcessing', { jobAmount });
|
||||
return jobAmount && jobAmount > serveResultsWithoutPaymentLimit * 1000;
|
||||
};
|
||||
const waitForPaymentBeforePublishingResult = (): boolean => {
|
||||
const serveResultsWithoutPaymentLimit =
|
||||
config.serveResultsWithoutPaymentLimit ?? 1000
|
||||
log('waitForPaymentBeforeProcessing', { jobAmount })
|
||||
return jobAmount && jobAmount > serveResultsWithoutPaymentLimit * 1000
|
||||
}
|
||||
|
||||
const missingAmount = (): number => jobAmount - paidAmount;
|
||||
const missingAmount = (): number => jobAmount - paidAmount
|
||||
|
||||
const reqPayment = async (): Promise<void> => {
|
||||
payReqEvent = await requirePayment(event, missingAmount(), true);
|
||||
const reqPayment = async (): Promise<void> => {
|
||||
payReqEvent = await requirePayment(event, missingAmount(), true)
|
||||
|
||||
if (config.undercut) {
|
||||
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);
|
||||
if (config.undercut) {
|
||||
startUndercutting()
|
||||
}
|
||||
}
|
||||
|
||||
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) =>
|
||||
console.log('err :>> ', err),
|
||||
);
|
||||
// check if this is a payment request
|
||||
const amountValue = e.tagValue('amount')
|
||||
if (!amountValue) return
|
||||
|
||||
if (jobAmount > paidAmount && waitForPaymentBeforePublishingResult()) {
|
||||
await reqPayment();
|
||||
await waitForPayment(payReqEvent);
|
||||
log(`done with wait for publish`);
|
||||
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 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 axios from 'axios';
|
||||
import fs from 'fs';
|
||||
import { NDKTag } from '@nostr-dev-kit/ndk'
|
||||
import axios from 'axios'
|
||||
import fs from 'fs'
|
||||
|
||||
export async function fetchFileFromInput(input: NDKTag): Promise<string> {
|
||||
switch (input[2]) {
|
||||
case 'url': {
|
||||
const url = input[1];
|
||||
const fileExtension = url.split('.').pop();
|
||||
switch (input[2]) {
|
||||
case 'url': {
|
||||
const url = input[1]
|
||||
const fileExtension = url.split('.').pop()
|
||||
|
||||
// download the file
|
||||
// save it to the local filesystem
|
||||
// return the path to the file
|
||||
const response = await axios.get(url, {
|
||||
responseType: 'stream'
|
||||
});
|
||||
// download the file
|
||||
// save it to the local filesystem
|
||||
// return the path to the file
|
||||
const response = await axios.get(url, {
|
||||
responseType: 'stream'
|
||||
})
|
||||
|
||||
const randomName = Math.random().toString(36).substring(7);
|
||||
const path = `./${randomName}.${fileExtension}`;
|
||||
const randomName = Math.random().toString(36).substring(7)
|
||||
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) {
|
||||
LNBits = _LNBits.default;
|
||||
LNBits = _LNBits.default
|
||||
} else {
|
||||
LNBits = _LNBits;
|
||||
LNBits = _LNBits
|
||||
}
|
||||
|
||||
function getWallet (): any {
|
||||
return LNBits({
|
||||
adminKey: "",
|
||||
invoiceReadKey: 'bfbcb5b116c04179bc618ab78265a939',
|
||||
endpoint: 'https://legend.lnbits.com'
|
||||
});
|
||||
function getWallet(): any {
|
||||
return LNBits({
|
||||
adminKey: '',
|
||||
invoiceReadKey: 'bfbcb5b116c04179bc618ab78265a939',
|
||||
endpoint: 'https://legend.lnbits.com'
|
||||
})
|
||||
}
|
||||
|
||||
export async function createInvoice(amount: number): Promise<any> {
|
||||
const { wallet } = getWallet();
|
||||
const { wallet } = getWallet()
|
||||
|
||||
const newInvoice = await wallet.createInvoice({
|
||||
amount: amount,
|
||||
memo: 'data vending machine',
|
||||
out: false,
|
||||
});
|
||||
const newInvoice = await wallet.createInvoice({
|
||||
amount: amount,
|
||||
memo: 'data vending machine',
|
||||
out: false
|
||||
})
|
||||
|
||||
return newInvoice;
|
||||
return newInvoice
|
||||
}
|
||||
|
||||
export async function checkInvoiceStatus(invoice): Promise<any> {
|
||||
const { wallet } = getWallet();
|
||||
const invoiceStatus = await wallet.checkInvoice({
|
||||
payment_hash: invoice.payment_hash,
|
||||
});
|
||||
const { wallet } = getWallet()
|
||||
const invoiceStatus = await wallet.checkInvoice({
|
||||
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) {
|
||||
const expTag = event.tagValue('exp');
|
||||
const timeNow = Math.floor(Date.now() / 1000);
|
||||
const expTag = event.tagValue('exp')
|
||||
const timeNow = Math.floor(Date.now() / 1000)
|
||||
|
||||
if (expTag && parseInt(expTag) < timeNow - 10) {
|
||||
throw new Error('Job expired');
|
||||
}
|
||||
if (expTag && parseInt(expTag) < timeNow - 10) {
|
||||
throw new Error('Job expired')
|
||||
}
|
||||
|
||||
return
|
||||
return
|
||||
}
|
@ -1,40 +1,42 @@
|
||||
import { NDKEvent, type NostrEvent } from '@nostr-dev-kit/ndk';
|
||||
import validateExpiration from './expiration.js';
|
||||
import validateRequester from './requester.js';
|
||||
import validateNoRecentResults from './no-recent-results.js';
|
||||
import { ndk } from '../main.js';
|
||||
import { addAmount } from '../job-types/speech-to-text.js';
|
||||
import { NDKEvent, type NostrEvent } from '@nostr-dev-kit/ndk'
|
||||
import validateExpiration from './expiration.js'
|
||||
import validateRequester from './requester.js'
|
||||
import validateNoRecentResults from './no-recent-results.js'
|
||||
import { ndk } from '../main.js'
|
||||
import { addAmount } from '../job-types/speech-to-text.js'
|
||||
|
||||
export async function validateJobRequest(event: NDKEvent): Promise<void> {
|
||||
await validateExpiration(event);
|
||||
await validateRequester(event);
|
||||
await validateNoRecentResults(event);
|
||||
await validateExpiration(event)
|
||||
await validateRequester(event)
|
||||
await validateNoRecentResults(event)
|
||||
}
|
||||
|
||||
export async function requirePayment(event: NDKEvent, amount?: number, publish?: boolean): Promise<NDKEvent> {
|
||||
if (!amount) {
|
||||
const bidTag = event.tagValue('bid');
|
||||
amount = bidTag ? parseInt(bidTag) : undefined;
|
||||
}
|
||||
export async function requirePayment(
|
||||
event: NDKEvent,
|
||||
amount?: number,
|
||||
publish?: boolean
|
||||
): Promise<NDKEvent> {
|
||||
if (!amount) {
|
||||
const bidTag = event.tagValue('bid')
|
||||
amount = bidTag ? parseInt(bidTag) : undefined
|
||||
}
|
||||
|
||||
if (!amount) {
|
||||
throw new Error("No amount specified");
|
||||
}
|
||||
if (!amount) {
|
||||
throw new Error('No amount specified')
|
||||
}
|
||||
|
||||
const payReq = new NDKEvent(ndk, {
|
||||
kind: 68003,
|
||||
content: "`Please pay for this job`",
|
||||
tags: [
|
||||
["status", "payment-required"],
|
||||
]
|
||||
} as NostrEvent);
|
||||
await addAmount(payReq, amount);
|
||||
payReq.tag(event, "job");
|
||||
const payReq = new NDKEvent(ndk, {
|
||||
kind: 68003,
|
||||
content: '`Please pay for this job`',
|
||||
tags: [['status', 'payment-required']]
|
||||
} as NostrEvent)
|
||||
await addAmount(payReq, amount)
|
||||
payReq.tag(event, 'job')
|
||||
|
||||
await payReq.sign();
|
||||
console.log(payReq.rawEvent());
|
||||
await payReq.sign()
|
||||
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 { ndk } from '../main.js';
|
||||
import { NDKEvent } from '@nostr-dev-kit/ndk'
|
||||
import { ndk } from '../main.js'
|
||||
|
||||
export default async function validateNoRecentResults(event: NDKEvent): Promise<void> {
|
||||
const results = ndk.fetchEvents({
|
||||
kinds: [68002 as number],
|
||||
"#e": [event.id],
|
||||
}, { groupable: false })
|
||||
export default async function validateNoRecentResults(
|
||||
event: NDKEvent
|
||||
): Promise<void> {
|
||||
const results = ndk.fetchEvents(
|
||||
{
|
||||
kinds: [68002 as number],
|
||||
'#e': [event.id]
|
||||
},
|
||||
{ groupable: false }
|
||||
)
|
||||
|
||||
if (results.length > 0) {
|
||||
throw new Error(`This job already has ${results.length} results`);
|
||||
}
|
||||
if (results.length > 0) {
|
||||
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> {
|
||||
if (event) { /* empty */ }
|
||||
export default async function validateRequester(
|
||||
event: NDKEvent
|
||||
): Promise<void> {
|
||||
if (event) {
|
||||
/* empty */
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user