Convert worker to ESM (#500)
* Convert worker to ESM
To use ESM for the worker, I created a package.json file in worker/ with `{ type: "module" }` as its sole content.
I then rewrote every import to use ESM syntax.
I also tried to set `{ type: "module" }` in the root package.json file to also use ESM in next.config.js.
However, this resulted in a weird problem: default imports were now getting imported as objects in this shape: `{ default: <defaultImport> }`.
Afaik, this should only be the case if you use "import * as foo from 'bar'" syntax: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#default_import
This is fixed by not using `{ type: "module" }` for some reason. However, then, next.config.js also doesn't support ESM import syntax anymore.
The documentation says that if you want to use ESM, you can use next.config.mjs: https://nextjs.org/docs/pages/api-reference/next-config-js
But I didn't want to use MJS extension since I don't have any experience with it. For example, not sure if it's good style to mix JS with MJS etc. So I kept the CJS import syntax there.
* Ignore worker/ during linting
I wasn't able to fix the following errors:
/home/runner/work/stacker.news/stacker.news/worker/auction.js:0:0: Parsing error: No Babel config file detected for /home/runner/work/stacker.news/stacker.news/worker/auction.js. Either disable config file checking with requireConfigFile: false, or configure Babel so that it can find the config files. (null)
/home/runner/work/stacker.news/stacker.news/worker/earn.js:0:0: Parsing error: No Babel config file detected for /home/runner/work/stacker.news/stacker.news/worker/earn.js. Either disable config file checking with requireConfigFile: false, or configure Babel so that it can find the config files. (null)
/home/runner/work/stacker.news/stacker.news/worker/index.js:0:0: Parsing error: No Babel config file detected for /home/runner/work/stacker.news/stacker.news/worker/index.js. Either disable config file checking with requireConfigFile: false, or configure Babel so that it can find the config files. (null)
/home/runner/work/stacker.news/stacker.news/worker/nostr.js:0:0: Parsing error: No Babel config file detected for /home/runner/work/stacker.news/stacker.news/worker/nostr.js. Either disable config file checking with requireConfigFile: false, or configure Babel so that it can find the config files. (null)
/home/runner/work/stacker.news/stacker.news/worker/ots.js:0:0: Parsing error: No Babel config file detected for /home/runner/work/stacker.news/stacker.news/worker/ots.js. Either disable config file checking with requireConfigFile: false, or configure Babel so that it can find the config files. (null)
/home/runner/work/stacker.news/stacker.news/worker/repin.js:0:0: Parsing error: No Babel config file detected for /home/runner/work/stacker.news/stacker.news/worker/repin.js. Either disable config file checking with requireConfigFile: false, or configure Babel so that it can find the config files. (null)
/home/runner/work/stacker.news/stacker.news/worker/search.js:0:0: Parsing error: No Babel config file detected for /home/runner/work/stacker.news/stacker.news/worker/search.js. Either disable config file checking with requireConfigFile: false, or configure Babel so that it can find the config files. (null)
/home/runner/work/stacker.news/stacker.news/worker/streak.js:0:0: Parsing error: No Babel config file detected for /home/runner/work/stacker.news/stacker.news/worker/streak.js. Either disable config file checking with requireConfigFile: false, or configure Babel so that it can find the config files. (null)
/home/runner/work/stacker.news/stacker.news/worker/trust.js:0:0: Parsing error: No Babel config file detected for /home/runner/work/stacker.news/stacker.news/worker/trust.js. Either disable config file checking with requireConfigFile: false, or configure Babel so that it can find the config files. (null)
/home/runner/work/stacker.news/stacker.news/worker/views.js:0:0: Parsing error: No Babel config file detected for /home/runner/work/stacker.news/stacker.news/worker/views.js. Either disable config file checking with requireConfigFile: false, or configure Babel so that it can find the config files. (null)
/home/runner/work/stacker.news/stacker.news/worker/wallet.js:0:0: Parsing error: No Babel config file detected for /home/runner/work/stacker.news/stacker.news/worker/wallet.js. Either disable config file checking with requireConfigFile: false, or configure Babel so that it can find the config files. (null)
I tried to tell babel where to find the babel config file (.babelrc), specifying the babel config in worker/package.json under "babel", using babel.config.json etc. to no avail.
However, afaict, we don't need babel for the worker since it won't run in a browser. Babel is only used to transpile code to target browsers.
But it still would be nice to lint the worker code with standard.
But we can figure this out later.
* Fix worker imports from lib/ and api/
This fixes the issue that we can't use `{ "type": "module" }` in the root package.json since it breaks the app with this error:
app | TypeError: next_auth_providers_credentials__WEBPACK_IMPORTED_MODULE_2__ is not a function
app | at eval (webpack-internal:///./pages/api/auth/[...nextauth].js:218:20)
app | at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
app | LND GRPC connection successful
app | - error pages/api/auth/[...nextauth].js (139:2) @ CredentialsProvider
app | - error Error [TypeError]: next_auth_providers_credentials__WEBPACK_IMPORTED_MODULE_2__ is not a function
app | at eval (webpack-internal:///./pages/api/auth/[...nextauth].js:218:20) {
app | digest: undefined
app | }
app | 137 |
app | 138 | const providers = [
app | > 139 | CredentialsProvider({
app | | ^
app | 140 | id: 'lightning',
app | 141 | name: 'Lightning',
app | 142 | credentials: {
app | TypeError: next_auth_providers_credentials__WEBPACK_IMPORTED_MODULE_2__ is not a function
app | at eval (webpack-internal:///./pages/api/auth/[...nextauth].js:218:20)
app | at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
build but we need to tell the worker that the files are MJS, else we get this error:
worker | file:///app/worker/wallet.js:3
worker | import { datePivot } from '../lib/time.js'
worker | ^^^^^^^^^
worker | SyntaxError: Named export 'datePivot' not found. The requested module '../lib/time.js' is a CommonJS module, which may not support all module.exports as named exports.
worker | CommonJS modules can always be imported via the default export, for example using:
worker |
worker | import pkg from '../lib/time.js';
worker | const { datePivot } = pkg;
worker |
worker | at ModuleJob._instantiate (node:internal/modules/esm/module_job:124:21)
worker | at async ModuleJob.run (node:internal/modules/esm/module_job:190:5)
worker |
worker | Node.js v18.17.0
worker |
worker exited with code 1
* Fix global not defined in browser context
* Also ignore api/ and lib/ during linting
I did not want to do this but I was not able to fix this error in any other way I tried:
/home/ekzyis/programming/stacker.news/api/lnd/index.js:0:0: Parsing error: No Babel config file detected for /home/ekzyis/programming/stacker.news/api/lnd/index.js. Either disable config file checking with requ
ireConfigFile: false, or configure Babel so that it can find the config files. (null)
Did not want to look deeper into all this standard, eslint, babel configuration stuff ...
---------
Co-authored-by: ekzyis <ek@stacker.news>
Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com>
2023-09-24 01:19:35 +00:00
|
|
|
import { getInvoice } from 'ln-service'
|
|
|
|
import { Relay, signId, calculateId, getPublicKey } from 'nostr'
|
2023-02-14 22:58:12 +00:00
|
|
|
|
|
|
|
const nostrOptions = { startAfter: 5, retryLimit: 21, retryBackoff: true }
|
|
|
|
|
2023-11-21 23:32:22 +00:00
|
|
|
export async function nip57 ({ data: { hash }, boss, lnd, models }) {
|
|
|
|
let inv, lnInv
|
|
|
|
try {
|
|
|
|
lnInv = await getInvoice({ id: hash, lnd })
|
|
|
|
inv = await models.invoice.findUnique({
|
|
|
|
where: {
|
|
|
|
hash
|
|
|
|
}
|
|
|
|
})
|
|
|
|
} catch (err) {
|
|
|
|
console.log(err)
|
|
|
|
// on lnd related errors, we manually retry which so we don't exponentially backoff
|
|
|
|
await boss.send('nip57', { hash }, nostrOptions)
|
|
|
|
return
|
|
|
|
}
|
2023-02-14 22:58:12 +00:00
|
|
|
|
2024-02-16 18:27:15 +00:00
|
|
|
// check if invoice still exists since JIT invoices get deleted after usage
|
2023-11-21 23:32:22 +00:00
|
|
|
if (!inv) return
|
2023-08-31 02:48:49 +00:00
|
|
|
|
2023-11-21 23:32:22 +00:00
|
|
|
try {
|
|
|
|
// if parsing fails it's not a zap
|
|
|
|
console.log('zapping', inv.desc)
|
|
|
|
const desc = JSON.parse(inv.desc)
|
|
|
|
const ptag = desc.tags.filter(t => t?.length >= 2 && t[0] === 'p')[0]
|
|
|
|
const etag = desc.tags.filter(t => t?.length >= 2 && t[0] === 'e')[0]
|
|
|
|
const atag = desc.tags.filter(t => t?.length >= 2 && t[0] === 'a')[0]
|
|
|
|
const relays = desc.tags.find(t => t?.length >= 2 && t[0] === 'relays').slice(1)
|
2023-02-14 22:58:12 +00:00
|
|
|
|
2023-11-21 23:32:22 +00:00
|
|
|
const tags = [ptag]
|
|
|
|
if (etag) tags.push(etag)
|
|
|
|
if (atag) tags.push(atag)
|
|
|
|
tags.push(['bolt11', lnInv.request])
|
|
|
|
tags.push(['description', inv.desc])
|
|
|
|
tags.push(['preimage', lnInv.secret])
|
2023-02-14 22:58:12 +00:00
|
|
|
|
2023-11-21 23:32:22 +00:00
|
|
|
const e = {
|
|
|
|
kind: 9735,
|
|
|
|
pubkey: getPublicKey(process.env.NOSTR_PRIVATE_KEY),
|
|
|
|
created_at: Math.floor(new Date(lnInv.confirmed_at).getTime() / 1000),
|
|
|
|
content: '',
|
|
|
|
tags
|
|
|
|
}
|
|
|
|
e.id = await calculateId(e)
|
|
|
|
e.sig = await signId(process.env.NOSTR_PRIVATE_KEY, e.id)
|
2023-02-14 22:58:12 +00:00
|
|
|
|
2023-11-21 23:32:22 +00:00
|
|
|
console.log('zap note', e, relays)
|
|
|
|
await Promise.allSettled(
|
|
|
|
relays.map(r => new Promise((resolve, reject) => {
|
|
|
|
const timeout = 1000
|
|
|
|
const relay = Relay(r)
|
2023-02-14 22:58:12 +00:00
|
|
|
|
2023-11-21 23:32:22 +00:00
|
|
|
function timedout () {
|
|
|
|
relay.close()
|
|
|
|
console.log('failed to send to', r)
|
|
|
|
reject(new Error('relay timeout'))
|
|
|
|
}
|
2023-02-14 22:58:12 +00:00
|
|
|
|
2023-11-21 23:32:22 +00:00
|
|
|
let timer = setTimeout(timedout, timeout)
|
2023-02-14 22:58:12 +00:00
|
|
|
|
2023-11-21 23:32:22 +00:00
|
|
|
relay.on('open', () => {
|
|
|
|
clearTimeout(timer)
|
|
|
|
timer = setTimeout(timedout, timeout)
|
|
|
|
relay.send(['EVENT', e])
|
|
|
|
})
|
2023-02-14 22:58:12 +00:00
|
|
|
|
2023-11-21 23:32:22 +00:00
|
|
|
relay.on('ok', () => {
|
|
|
|
clearTimeout(timer)
|
|
|
|
relay.close()
|
|
|
|
console.log('sent zap to', r)
|
|
|
|
resolve()
|
|
|
|
})
|
|
|
|
})))
|
|
|
|
} catch (e) {
|
|
|
|
console.log(e)
|
2023-02-14 22:58:12 +00:00
|
|
|
}
|
|
|
|
}
|