diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index cef9a77..0000000 --- a/.eslintrc.json +++ /dev/null @@ -1,151 +0,0 @@ -{ - "root": true, - "parserOptions": { - "ecmaVersion": 9, - "ecmaFeatures": { - "jsx": true - }, - "sourceType": "module", - "allowImportExportEverywhere": false - }, - - "env": { - "es6": true, - "node": true - }, - - "globals": { - "document": false, - "navigator": false, - "window": false, - "location": false, - "URL": false, - "URLSearchParams": false, - "fetch": false, - "EventSource": false, - "localStorage": false, - "sessionStorage": false, - "BigInt": false - }, - - "rules": { - "accessor-pairs": 2, - "arrow-spacing": [2, {"before": true, "after": true}], - "block-spacing": [2, "always"], - "brace-style": [2, "1tbs", {"allowSingleLine": true}], - "comma-dangle": 0, - "comma-spacing": [2, {"before": false, "after": true}], - "comma-style": [2, "last"], - "constructor-super": 2, - "curly": [0, "multi-line"], - "dot-location": [2, "property"], - "eol-last": 2, - "eqeqeq": [2, "allow-null"], - "generator-star-spacing": [2, {"before": true, "after": true}], - "handle-callback-err": [2, "^(err|error)$"], - "indent": 0, - "jsx-quotes": [2, "prefer-double"], - "key-spacing": [2, {"beforeColon": false, "afterColon": true}], - "keyword-spacing": [2, {"before": true, "after": true}], - "new-cap": 0, - "new-parens": 0, - "no-array-constructor": 2, - "no-caller": 2, - "no-class-assign": 2, - "no-cond-assign": 2, - "no-const-assign": 2, - "no-control-regex": 0, - "no-debugger": 0, - "no-delete-var": 2, - "no-dupe-args": 2, - "no-dupe-class-members": 2, - "no-dupe-keys": 2, - "no-duplicate-case": 2, - "no-empty-character-class": 2, - "no-empty-pattern": 2, - "no-eval": 0, - "no-ex-assign": 2, - "no-extend-native": 2, - "no-extra-bind": 2, - "no-extra-boolean-cast": 2, - "no-extra-parens": [2, "functions"], - "no-fallthrough": 2, - "no-floating-decimal": 2, - "no-func-assign": 2, - "no-implied-eval": 2, - "no-inner-declarations": [0, "functions"], - "no-invalid-regexp": 2, - "no-irregular-whitespace": 2, - "no-iterator": 2, - "no-label-var": 2, - "no-labels": [2, {"allowLoop": false, "allowSwitch": false}], - "no-lone-blocks": 2, - "no-mixed-spaces-and-tabs": 2, - "no-multi-spaces": 2, - "no-multi-str": 2, - "no-multiple-empty-lines": [2, {"max": 2}], - "no-native-reassign": 2, - "no-negated-in-lhs": 2, - "no-new": 0, - "no-new-func": 2, - "no-new-object": 2, - "no-new-require": 2, - "no-new-symbol": 2, - "no-new-wrappers": 2, - "no-obj-calls": 2, - "no-octal": 2, - "no-octal-escape": 2, - "no-path-concat": 0, - "no-proto": 2, - "no-redeclare": 2, - "no-regex-spaces": 2, - "no-return-assign": 0, - "no-self-assign": 2, - "no-self-compare": 2, - "no-sequences": 2, - "no-shadow-restricted-names": 2, - "no-spaced-func": 2, - "no-sparse-arrays": 2, - "no-this-before-super": 2, - "no-throw-literal": 2, - "no-trailing-spaces": 2, - "no-undef": 2, - "no-undef-init": 2, - "no-unexpected-multiline": 2, - "no-unneeded-ternary": [2, {"defaultAssignment": false}], - "no-unreachable": 2, - "no-unused-vars": [ - 2, - {"vars": "local", "args": "none", "varsIgnorePattern": "^_"} - ], - "no-useless-call": 2, - "no-useless-constructor": 2, - "no-with": 2, - "one-var": [0, {"initialized": "never"}], - "operator-linebreak": [ - 2, - "after", - {"overrides": {"?": "before", ":": "before"}} - ], - "padded-blocks": [2, "never"], - "quotes": [ - 2, - "single", - {"avoidEscape": true, "allowTemplateLiterals": true} - ], - "semi": [2, "never"], - "semi-spacing": [2, {"before": false, "after": true}], - "space-before-blocks": [2, "always"], - "space-before-function-paren": 0, - "space-in-parens": [2, "never"], - "space-infix-ops": 2, - "space-unary-ops": [2, {"words": true, "nonwords": false}], - "spaced-comment": 0, - "template-curly-spacing": [2, "never"], - "use-isnan": 2, - "valid-typeof": 2, - "wrap-iife": [2, "any"], - "yield-star-spacing": [2, "both"], - "yoda": [0] - } -} diff --git a/.gitignore b/.gitignore index 57db901..3c3629e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,61 +1 @@ -package-lock.json -yarn.lock - -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (http://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# Typescript v1 declaration files -typings/ - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env +node_modules diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..6f4247a --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +26 diff --git a/.oxlintrc.json b/.oxlintrc.json new file mode 100644 index 0000000..661f932 --- /dev/null +++ b/.oxlintrc.json @@ -0,0 +1,94 @@ +{ + "plugins": [ + "import", + "jsdoc", + "node", + "oxc", + "promise", + "unicorn" + ], + "categories": { + "correctness": "warn", + "suspicious": "warn", + "perf": "warn", + "pedantic": "warn" + }, + "rules": { + "eslint/array-callback-return": ["warn", { "checkForEach": true }], + "eslint/eqeqeq": ["warn", "always", {"null": "ignore"}], + "eslint/func-style": ["off", "expression"], + "eslint/guard-for-in": "warn", + "eslint/no-duplicate-imports": ["warn", { "includeExports": true }], + "eslint/no-empty": "warn", + "eslint/no-empty-function": "warn", + "eslint/no-iterator": "warn", + "eslint/no-lone-blocks": "warn", + "eslint/no-multi-assign": "warn", + "eslint/no-multi-str": "warn", + "eslint/no-nested-ternary": "warn", + "eslint/no-new-func": "warn", + "eslint/no-proto": "warn", + "eslint/no-return-assign": ["warn", "always"], + "eslint/no-script-url": "warn", + "eslint/no-unused-expressions": "warn", + "eslint/no-var": "warn", + "eslint/no-void": "warn", + "eslint/prefer-exponentiation-operator": "warn", + "eslint/prefer-numeric-literals": "warn", + "eslint/prefer-object-has-own": "warn", + "eslint/prefer-object-spread": "warn", + "eslint/prefer-spread": "warn", + "eslint/yoda": "warn", + "eslint/max-depth": "off", + "eslint/max-classes-per-file": "off", + "eslint/max-lines": "off", + "eslint/max-lines-per-function": "off", + "eslint/max-nested-callbacks": "off", + "eslint/new-cap": "off", + "eslint/radix": "off", + "import/consistent-type-specifier-style": "warn", + "import/exports-last": "warn", + "import/first": "warn", + "import/group-exports": "warn", + "import/no-amd": "warn", + "import/no-commonjs": "warn", + "import/no-cycle": "warn", + "import/no-dynamic-require": "warn", + "import/no-mutable-exports": "warn", + "import/no-named-default": "warn", + "import/no-webpack-loader-syntax": "warn", + "import/unambiguous": "warn", + "import/max-dependencies": "off", + "jsdoc/check-access": "warn", + "jsdoc/empty-tags": "warn", + "jsdoc/require-param-description": "off", + "jsdoc/require-returns-description": "off", + "node/no-new-require": "warn", + "oxc/bad-bitwise-operator": "warn", + "oxc/no-barrel-file": "warn", + "promise/prefer-await-to-callbacks": "warn", + "promise/prefer-await-to-then": "warn", + "promise/spec-only": "warn", + "unicorn/no-abusive-eslint-disable": "warn", + "unicorn/no-anonymous-default-export": "warn", + "unicorn/no-array-for-each": "warn", + "unicorn/no-array-method-this-argument": "warn", + "unicorn/no-array-reduce": "warn", + "unicorn/no-document-cookie": "warn", + "unicorn/no-length-as-slice-end": "warn", + "unicorn/no-nested-ternary": "warn", + "unicorn/prefer-array-index-of": "warn", + "unicorn/prefer-global-this": "warn", + "unicorn/prefer-modern-math-apis": "warn", + "unicorn/prefer-node-protocol": "warn", + "unicorn/prefer-number-properties": "warn", + "unicorn/prefer-object-from-entries": "warn" + }, + "env": { + "node": true, + "builtin": true + }, + "ignorePatterns": [ + "node_modules/*" + ] +} diff --git a/.prettierrc.yaml b/.prettierrc.yaml deleted file mode 100644 index 16c878e..0000000 --- a/.prettierrc.yaml +++ /dev/null @@ -1,10 +0,0 @@ -semi: false -arrowParens: avoid -insertPragma: false -printWidth: 80 -proseWrap: preserve -singleQuote: true -trailingComma: none -useTabs: false -jsxBracketSameLine: false -bracketSpacing: false diff --git a/README.md b/README.md index 242eb58..f2b2860 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A lightweight and naïve library for decoding lightning network payment requests It doesn't recover payee from signature, doesn't check signature, doesn't parse fallback addresses and doesn't do any encoding -- therefore dependencies are very minimal (no libsecp256k1 here). -Code derived from [bolt11](https://npmjs.com/package/bolt11), which has the full functionality but it's a pain to run in browsers. +Code derived from [bolt11](https://npmjs.com/package/bolt11), which has the full functionality, but it's a pain to run in browsers. Spits out "sections" of the invoice, in a way that is used to make visualizations like https://bolt11.org/. diff --git a/bolt11.d.ts b/bolt11.d.ts deleted file mode 100644 index 74fd82a..0000000 --- a/bolt11.d.ts +++ /dev/null @@ -1,89 +0,0 @@ -declare module "light-bolt11-decoder" { - type NetworkSection = { - name: 'coin_network'; - letters: string; - value?: { - bech32: string; - pubKeyHash: number; - scriptHash: number; - validWitnessVersions: number[]; - }; - }; - - type FeatureBits = { - option_data_loss_protect: string; - initial_routing_sync: string; - option_upfront_shutdown_script: string; - gossip_queries: string; - var_onion_optin: string; - gossip_queries_ex: string; - option_static_remotekey: string; - payment_secret: string; - basic_mpp: string; - option_support_large_channel: string; - extra_bits: { - start_bit: number; - bits: unknown[]; - has_required: boolean; - }; - }; - - type RouteHint = { - pubkey: string; - short_channel_id: string; - fee_base_msat: number; - fee_proportional_millionths: number; - cltv_expiry_delta: number; - }; - - type RouteHintSection = { - name: "route_hint"; - tag: "r"; - letters: string; - value: RouteHint[]; - }; - - type FeatureBitsSection = { - name: "feature_bits"; - tag: "9"; - letters: string; - value: FeatureBits; - }; - - type Section = - | { name: "paymentRequest"; value: string } - | { name: "expiry"; value: number } - | { name: "checksum"; letters: string } - | NetworkSection - | { name: "amount"; letters: string; value: string } - | { name: "separator"; letters: string } - | { name: "timestamp"; letters: string; value: number } - | { name: "payment_hash"; tag: "p"; letters: string; value: string } - | { name: "description"; tag: "d"; letters: string; value: string } - | { name: "payment_secret"; tag: "s"; letters: string; value: string } - | { - name: "min_final_cltv_expiry"; - tag: "c"; - letters: string; - value: number; - } - | FeatureBitsSection - | RouteHintSection - | { name: "signature"; letters: string; value: string }; - - type PaymentJSON = { - paymentRequest: string; - sections: Section[]; - expiry: number; - route_hints: RouteHint[][]; - }; - - type DecodedInvoice = { - paymentRequest: string; - sections: Section[]; - expiry: number; - route_hints: RouteHint[][]; - }; - - function decode(invoice: string): DecodedInvoice; -} diff --git a/bolt11.js b/bolt11.js index d1897ea..c402a85 100644 --- a/bolt11.js +++ b/bolt11.js @@ -1,6 +1,66 @@ -const {bech32, hex, utf8} = require('@scure/base') +import {bech32, hex, utf8} from '@scure/base' + +/** + * + * @typedef {{bech32: string, pubKeyHash: number, scriptHash: number, validWitnessVersions: number[]}} Network + * + * @typedef {{ + * name: 'coin_network', + * letters: string, + * value?: Network + * }} NetworkSection + * + * @typedef {{ + * option_data_loss_protect: string, + * initial_routing_sync: string, + * option_upfront_shutdown_script: string, + * gossip_queries: string, + * var_onion_optin: string, + * gossip_queries_ex: string, + * option_static_remotekey: string, + * payment_secret: string, + * basic_mpp: string, + * option_support_large_channel: string, + * extra_bits: { + * start_bit: number, + * bits: unknown[], + * has_required: boolean + * } + * }} FeatureBits + * + * @typedef {{ pubkey: string, short_channel_id: string, fee_base_msat: number, fee_proportional_millionths: number, cltv_expiry_delta: number }} RouteHint + * @typedef {{ name: "route_hint", tag: "r", letters: string, value: RouteHint[] }} RouteHintSection + * @typedef {{ name: "feature_bits", tag: "9", letters: string, value: FeatureBits }} FeatureBitsSection + * + * @typedef { + * | { name: "paymentRequest", value: string } + * | { name: "expiry", value: number } + * | { name: "checksum", letters: string } + * | NetworkSection + * | { name: "amount", letters: string; value: string } + * | { name: "separator", letters: string } + * | { name: "timestamp", letters: string, value: number } + * | { name: "payment_hash", tag: "p", letters: string, value: string } + * | { name: "description", tag: "d", letters: string, value: string } + * | { name: "payment_secret", tag: "s", letters: string, value: string } + * | { + * name: "min_final_cltv_expiry", + * tag: "c", + * letters: string, + * value: number + * } + * | FeatureBitsSection + * | RouteHintSection + * | { name: "signature", letters: string, value: string } + * | { name: "lightning_network", letters: string } + * } Section + * + * @typedef {{ paymentRequest: string, sections: Section[], expiry: number, route_hints: RouteHint[][] }} DecodedInvoice + * + */ // defaults for encode; default timestamp is current time at call +/** @type {Network} */ const DEFAULTNETWORK = { // default network is bitcoin bech32: 'bc', @@ -8,31 +68,35 @@ const DEFAULTNETWORK = { scriptHash: 0x05, validWitnessVersions: [0] } +/** @type {Network} */ const TESTNETWORK = { bech32: 'tb', pubKeyHash: 0x6f, scriptHash: 0xc4, validWitnessVersions: [0] } +/** @type {Network} */ const SIGNETNETWORK = { bech32: 'tbs', pubKeyHash: 0x6f, scriptHash: 0xc4, validWitnessVersions: [0] } +/** @type {Network} */ const REGTESTNETWORK = { bech32: 'bcrt', pubKeyHash: 0x6f, scriptHash: 0xc4, validWitnessVersions: [0] } +/** @type {Network} */ const SIMNETWORK = { bech32: 'sb', pubKeyHash: 0x3f, scriptHash: 0x7b, validWitnessVersions: [0] } - +/** @type {string[]} */ const FEATUREBIT_ORDER = [ 'option_data_loss_protect', 'initial_routing_sync', @@ -92,38 +156,50 @@ const TAGPARSERS = { 5: featureBitsParser // keep feature bits as array of 5 bit words } +/** + * + * @param {string} tagCode + * @returns {function(*): {tagCode: number, words: `unknown1${string}`}} + */ function getUnknownParser(tagCode) { return words => ({ - tagCode: parseInt(tagCode), + tagCode: Number.parseInt(tagCode), words: bech32.encode('unknown', words, Number.MAX_SAFE_INTEGER) }) } +/** + * + * @param {number[]} words + * @returns {*} + */ function wordsToIntBE(words) { - return words.reverse().reduce((total, item, index) => { - return total + item * Math.pow(32, index) - }, 0) + return words.toReversed().reduce((total, item, index) => total + item * (32**index), 0) } -// first convert from words to buffer, trimming padding where necessary -// parse in 51 byte chunks. See encoder for details. +/** + * First convert from words to buffer, trimming padding where necessary + * parse in 51 byte chunks. See encoder for details. + * @param {number[]} words + * @returns {*[]} + */ function routingInfoParser(words) { const routes = [] - let pubkey, - shortChannelId, - feeBaseMSats, - feeProportionalMillionths, - cltvExpiryDelta + let pubkey + let shortChannelId + let feeBaseMSats + let feeProportionalMillionths + let cltvExpiryDelta let routesBuffer = bech32.fromWordsUnsafe(words) while (routesBuffer.length > 0) { pubkey = hex.encode(routesBuffer.slice(0, 33)) // 33 bytes shortChannelId = hex.encode(routesBuffer.slice(33, 41)) // 8 bytes - feeBaseMSats = parseInt(hex.encode(routesBuffer.slice(41, 45)), 16) // 4 bytes - feeProportionalMillionths = parseInt( + feeBaseMSats = Number.parseInt(hex.encode(routesBuffer.slice(41, 45)), 16) // 4 bytes + feeProportionalMillionths = Number.parseInt( hex.encode(routesBuffer.slice(45, 49)), 16 ) // 4 bytes - cltvExpiryDelta = parseInt(hex.encode(routesBuffer.slice(49, 51)), 16) // 2 bytes + cltvExpiryDelta = Number.parseInt(hex.encode(routesBuffer.slice(49, 51)), 16) // 2 bytes routesBuffer = routesBuffer.slice(51) @@ -138,10 +214,15 @@ function routingInfoParser(words) { return routes } +/** + * + * @param {Uint8Array} words + * @returns {{}} + */ function featureBitsParser(words) { const bools = words .slice() - .reverse() + .toReversed() .map(word => [ !!(word & 0b1), !!(word & 0b10), @@ -150,23 +231,22 @@ function featureBitsParser(words) { !!(word & 0b10000) ]) .reduce((finalArr, itemArr) => finalArr.concat(itemArr), []) - while (bools.length < FEATUREBIT_ORDER.length * 2) { + while (bools.length < FEATUREBIT_ORDER.length * 2) bools.push(false) - } const featureBits = {} - FEATUREBIT_ORDER.forEach((featureName, index) => { + for (const featureName of FEATUREBIT_ORDER) { + const index = FEATUREBIT_ORDER.indexOf(featureName); let status - if (bools[index * 2]) { + if (bools[index * 2]) status = 'required' - } else if (bools[index * 2 + 1]) { + else if (bools[index * 2 + 1]) status = 'supported' - } else { + else status = 'unsupported' - } featureBits[featureName] = status - }) + } const extraBits = bools.slice(FEATUREBIT_ORDER.length * 2) featureBits.extra_bits = { @@ -174,7 +254,7 @@ function featureBitsParser(words) { bits: extraBits, has_required: extraBits.reduce( (result, bit, index) => - index % 2 !== 0 ? result || false : result || bit, + index % 2 === 0 ? result || bit : result || false, false ) } @@ -182,18 +262,23 @@ function featureBitsParser(words) { return featureBits } +/** + * + * @param {string} hrpString + * @param {boolean} outputString + * @returns {string|bigint} + */ function hrpToMillisat(hrpString, outputString) { let divisor, value - if (hrpString.slice(-1).match(/^[munp]$/)) { + if (/^[munp]$/.test(hrpString.slice(-1))) { divisor = hrpString.slice(-1) value = hrpString.slice(0, -1) - } else if (hrpString.slice(-1).match(/^[^munp0-9]$/)) { + } else if (/^[^munp0-9]$/.test(hrpString.slice(-1))) throw new Error('Not a valid multiplier for the amount') - } else { + else value = hrpString - } - if (!value.match(/^\d+$/)) + if (!/^\d+$/.test(value)) throw new Error('Not a valid human readable amount') const valueBN = BigInt(value) @@ -205,31 +290,36 @@ function hrpToMillisat(hrpString, outputString) { if ( (divisor === 'p' && !(valueBN % BigInt(10) === BigInt(0))) || millisatoshisBN > MAX_MILLISATS - ) { + ) throw new Error('Amount is outside of valid range') - } return outputString ? millisatoshisBN.toString() : millisatoshisBN } -// decode will only have extra comments that aren't covered in encode comments. -// also if anything is hard to read I'll comment. +/** + * Decode will only have extra comments that aren't covered in encode comments. + * Also, if anything is hard to read I'll comment. + * @param {string} paymentRequest + * @param {Network=} network + * @returns {DecodedInvoice} + */ function decode(paymentRequest, network) { if (typeof paymentRequest !== 'string') throw new Error('Lightning Payment Request must be string') if (paymentRequest.slice(0, 2).toLowerCase() !== 'ln') throw new Error('Not a proper lightning payment request') + /** @type {Section[]} */ const sections = [] const decoded = bech32.decode(paymentRequest, Number.MAX_SAFE_INTEGER) - paymentRequest = paymentRequest.toLowerCase() + const paymentRequest_lower = paymentRequest.toLowerCase() const prefix = decoded.prefix let words = decoded.words - let letters = paymentRequest.slice(prefix.length + 1) + let letters = paymentRequest_lower.slice(prefix.length + 1) let sigWords = words.slice(-104) words = words.slice(0, -104) - // Without reverse lookups, can't say that the multipier at the end must + // Without reverse lookups, can't say that the multiplier at the end must // have a number before it, so instead we parse, and if the second group // doesn't have anything, there's a good chance the last letter of the // coin type got captured by the third group, so just re-regex without @@ -237,9 +327,8 @@ function decode(paymentRequest, network) { let prefixMatches = prefix.match(/^ln(\S+?)(\d*)([a-zA-Z]?)$/) if (prefixMatches && !prefixMatches[2]) prefixMatches = prefix.match(/^ln(\S+)$/) - if (!prefixMatches) { + if (!prefixMatches) throw new Error('Not a proper lightning payment request') - } // "ln" section sections.push({ @@ -250,7 +339,16 @@ function decode(paymentRequest, network) { // "bc" section const bech32Prefix = prefixMatches[1] let coinNetwork - if (!network) { + if (network) { + if ( + network.bech32 === undefined || + network.pubKeyHash === undefined || + network.scriptHash === undefined || + !Array.isArray(network.validWitnessVersions) + ) + throw new Error('Invalid network') + coinNetwork = network + } else { switch (bech32Prefix) { case DEFAULTNETWORK.bech32: coinNetwork = DEFAULTNETWORK @@ -268,19 +366,10 @@ function decode(paymentRequest, network) { coinNetwork = SIMNETWORK break } - } else { - if ( - network.bech32 === undefined || - network.pubKeyHash === undefined || - network.scriptHash === undefined || - !Array.isArray(network.validWitnessVersions) - ) - throw new Error('Invalid network') - coinNetwork = network } - if (!coinNetwork || coinNetwork.bech32 !== bech32Prefix) { + if (!coinNetwork || coinNetwork.bech32 !== bech32Prefix) throw new Error('Unknown coin bech32 prefix') - } + sections.push({ name: 'coin_network', letters: bech32Prefix, @@ -298,9 +387,8 @@ function decode(paymentRequest, network) { letters: prefixMatches[2] + prefixMatches[3], value: millisatoshis }) - } else { + } else millisatoshis = null - } // "1" separator sections.push({ @@ -318,7 +406,10 @@ function decode(paymentRequest, network) { }) letters = letters.slice(7) - let tagName, parser, tagLength, tagWords + let tagName + let parser + let tagLength + let tagWords // we have no tag count to go on, so just keep hacking off words // until we have none. while (words.length > 0) { @@ -371,10 +462,9 @@ function decode(paymentRequest, network) { } for (let name in TAGCODES) { - if (name === 'route_hint') { + if (name === 'route_hint') // route hints can be multiple, so this won't work for them continue - } Object.defineProperty(result, name, { get() { @@ -385,13 +475,18 @@ function decode(paymentRequest, network) { return result + /** + * + * @param {string} name + * @returns {*|undefined} + */ function getValue(name) { let section = sections.find(s => s.name === name) return section ? section.value : undefined } } -module.exports = { +export { decode, hrpToMillisat } diff --git a/examples/.gitignore b/examples/.gitignore deleted file mode 100644 index 2bce25e..0000000 --- a/examples/.gitignore +++ /dev/null @@ -1 +0,0 @@ -demo.build.js diff --git a/examples/.oxlintrc.json b/examples/.oxlintrc.json new file mode 100644 index 0000000..8515eaf --- /dev/null +++ b/examples/.oxlintrc.json @@ -0,0 +1,95 @@ +{ + "plugins": [ + "import", + "jsdoc", + "node", + "oxc", + "promise", + "unicorn" + ], + "categories": { + "correctness": "warn", + "suspicious": "warn", + "perf": "warn", + "pedantic": "warn" + }, + "rules": { + "eslint/array-callback-return": ["warn", { "checkForEach": true }], + "eslint/eqeqeq": ["warn", "always", {"null": "ignore"}], + "eslint/func-style": ["off", "expression"], + "eslint/guard-for-in": "warn", + "eslint/no-duplicate-imports": ["warn", { "includeExports": true }], + "eslint/no-empty": "warn", + "eslint/no-empty-function": "warn", + "eslint/no-iterator": "warn", + "eslint/no-lone-blocks": "warn", + "eslint/no-multi-assign": "warn", + "eslint/no-multi-str": "warn", + "eslint/no-nested-ternary": "warn", + "eslint/no-new-func": "warn", + "eslint/no-proto": "warn", + "eslint/no-return-assign": ["warn", "always"], + "eslint/no-script-url": "warn", + "eslint/no-unused-expressions": "warn", + "eslint/no-var": "warn", + "eslint/no-void": "warn", + "eslint/prefer-exponentiation-operator": "warn", + "eslint/prefer-numeric-literals": "warn", + "eslint/prefer-object-has-own": "warn", + "eslint/prefer-object-spread": "warn", + "eslint/prefer-spread": "warn", + "eslint/yoda": "warn", + "eslint/max-depth": "off", + "eslint/max-classes-per-file": "off", + "eslint/max-lines": "off", + "eslint/max-lines-per-function": "off", + "eslint/max-nested-callbacks": "off", + "eslint/new-cap": "off", + "eslint/radix": "off", + "import/consistent-type-specifier-style": "warn", + "import/exports-last": "warn", + "import/first": "warn", + "import/group-exports": "warn", + "import/no-amd": "warn", + "import/no-commonjs": "warn", + "import/no-cycle": "warn", + "import/no-dynamic-require": "warn", + "import/no-mutable-exports": "warn", + "import/no-named-default": "warn", + "import/no-webpack-loader-syntax": "warn", + "import/unambiguous": "warn", + "import/max-dependencies": "off", + "jsdoc/check-access": "warn", + "jsdoc/empty-tags": "warn", + "jsdoc/require-param-description": "off", + "jsdoc/require-returns-description": "off", + "node/no-new-require": "warn", + "oxc/bad-bitwise-operator": "warn", + "oxc/no-barrel-file": "warn", + "promise/prefer-await-to-callbacks": "warn", + "promise/prefer-await-to-then": "warn", + "promise/spec-only": "warn", + "unicorn/no-abusive-eslint-disable": "warn", + "unicorn/no-anonymous-default-export": "warn", + "unicorn/no-array-for-each": "warn", + "unicorn/no-array-method-this-argument": "warn", + "unicorn/no-array-reduce": "warn", + "unicorn/no-document-cookie": "warn", + "unicorn/no-length-as-slice-end": "warn", + "unicorn/no-nested-ternary": "warn", + "unicorn/prefer-array-index-of": "warn", + "unicorn/prefer-global-this": "warn", + "unicorn/prefer-modern-math-apis": "warn", + "unicorn/prefer-node-protocol": "warn", + "unicorn/prefer-number-properties": "warn", + "unicorn/prefer-object-from-entries": "warn" + }, + "env": { + "builtin": true, + "browser": true, + "node": true + }, + "ignorePatterns": [ + "node_modules/*" + ] +} diff --git a/examples/build.js b/examples/build.js deleted file mode 100755 index 52bf337..0000000 --- a/examples/build.js +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env node - -const esbuild = require('esbuild') -const nodeGlobals = require('@esbuild-plugins/node-globals-polyfill').default - -esbuild - .build({ - entryPoints: ['demo.jsx'], - outfile: 'demo.build.js', - bundle: true, - plugins: [nodeGlobals({buffer: true})], - define: { - window: 'self', - global: 'self' - }, - sourcemap: 'inline' - }) - .then(() => console.log('build success.')) diff --git a/examples/demo.jsx b/examples/demo.jsx deleted file mode 100644 index 501d216..0000000 --- a/examples/demo.jsx +++ /dev/null @@ -1,121 +0,0 @@ -import {decode} from 'light-bolt11-decoder' -import React, {useState} from 'react' -import {render} from 'react-dom' -import useComputedState from 'use-computed-state' -import styled, {css} from 'styled-components' - -const TAGCOLORS = { - lightning_network: 'rgb(31, 31, 40)', - coin_network: 'rgb(27, 51, 93)', - amount: 'rgb(0, 110, 98)', - separator: 'rgb(31, 31, 40)', - timestamp: 'rgb(181, 10, 11)', - payment_hash: 'rgb(71, 105, 169)', - description: 'rgb(41, 131, 11)', - description_hash: 'rgb(41, 131, 11)', - payment_secret: 'rgb(92, 25, 75)', - expiry: 'rgb(181, 10, 11)', - metadata: 'rgb(86, 25, 24)', - feature_bits: 'rgb(57, 118, 179)', - payee: 'rgb(51, 44, 138)', - unknown_tag: 'rgb(37, 15, 45)', - min_final_cltv_expiry: 'rgb(119, 34, 32)', - fallback_address: 'rgb(27, 51, 93)', - route_hint: 'rgb(131, 93, 233)', - signature: 'rgb(51, 44, 138)', - checksum: 'rgb(31, 31, 40)' -} - -function getTagColor(name) { - return TAGCOLORS[name] || 'rgb(0, 0, 0)' -} - -const Textarea = styled.textarea` - margin: 18px; - width: 90%; - height: 80px; -` - -const Row = styled.div`` - -const PaymentRequest = styled.div` - white-space: pre-wrap; - word-wrap: break-word; - word-break: break-all; -` - -const Section = styled.span` - font-family: monospace; - font-size: 25px; - - ${props => { - console.log(props) - - return css` - background-color: ${getTagColor(props.name) - .replace('rgb', 'rgba') - .replace(')', ', 0.2)')}; - ` - }} - - &:hover { - color: white; - - ${props => - css` - background-color: ${getTagColor(props.name)}; - `} - } -` - -const Info = styled.div` - margin: 8px; - padding: 8px; - color: white; - - ${props => - css` - background-color: ${getTagColor(props.name)}; - `} -` - -function Demo() { - const [pr, setPR] = useState( - 'lnbc120n1p39wfrtpp5n24pj26fpl0p9dsyxx47ttklcazd7z87pkmru4geca6n6kz4409qdpzve5kzar2v9nr5gpqw3hjqsrvde68scn0wssp5mqr9mkd94jm5z65x94msas8hqhcuc96tqtre3wqkrm305tcvzgmqxqy9gcqcqzys9qrsgqrzjqtx3k77yrrav9hye7zar2rtqlfkytl094dsp0ms5majzth6gt7ca6uhdkxl983uywgqqqqqqqqqq86qqjqrzjq0h9s36s2kpql0a99c6k4zfq7chcx9sjnsund8damcl96qvc4833tx69gvk26e6efsqqqqlgqqqqpjqqjqrzjqd98kxkpyw0l9tyy8r8q57k7zpy9zjmh6sez752wj6gcumqnj3yxzhdsmg6qq56utgqqqqqqqqqqqeqqjqxahrxthcc8syrjyklsg57mzsqauargyc748lf8s2dezw5x7aww0j5v4k5wz9p5x4ax840h4q0qmgucglkesgzvvc22wwmqc756ec02qp34yg8p' - ) - const parsed = useComputedState(() => pr && decode(pr), [pr]) - const [info, setInfo] = useState(null) - - console.log(parsed) - - return ( - <> -
+ +
+ + diff --git a/examples/package.json b/examples/package.json index 1f87547..5019250 100644 --- a/examples/package.json +++ b/examples/package.json @@ -1,12 +1,14 @@ { + "name": "light-bolt11-decoder-example", + "type": "module", "dependencies": { - "@esbuild-plugins/node-globals-polyfill": "^0.1.1", - "buffer": "^6.0.3", - "esbuild": "^0.14.36", - "light-bolt11-decoder": "^2.0.0", - "react": "^18.0.0", - "react-dom": "^18.0.0", - "styled-components": "^5.3.5", - "use-computed-state": "^1.1.0" + "light-bolt11-decoder": "../" + }, + "devDependencies": { + "rolldown": "1.1.4" + }, + "scripts": { + "build": "rolldown example.js --file example.build.js", + "lint": "oxlint" } } diff --git a/examples/pnpm-lock.yaml b/examples/pnpm-lock.yaml new file mode 100644 index 0000000..92765d0 --- /dev/null +++ b/examples/pnpm-lock.yaml @@ -0,0 +1,253 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + light-bolt11-decoder: + specifier: ../ + version: link:.. + devDependencies: + rolldown: + specifier: 1.1.4 + version: 1.1.4 + +packages: + + '@emnapi/core@1.11.1': + resolution: {integrity: sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==} + + '@emnapi/runtime@1.11.1': + resolution: {integrity: sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==} + + '@emnapi/wasi-threads@1.2.2': + resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} + + '@napi-rs/wasm-runtime@1.1.6': + resolution: {integrity: sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 + + '@oxc-project/types@0.138.0': + resolution: {integrity: sha512-1a7ZKmrRTCoN1XMZ4L0PyyqrMnrNlLyPuOkdSX2MZg7IiIGRUyurNhAm73ptDOraoBcIordsIGKNPKUzy3ZmfA==} + + '@rolldown/binding-android-arm64@1.1.4': + resolution: {integrity: sha512-EZLpf/8y7GXkkra90ML47kzik/GMP3EMcE9bPyHmRfxLC6z9+aW5A8poCsoxjrT5GfEcNAAvWwUHjvP1pUQkfw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.1.4': + resolution: {integrity: sha512-aUi+HBvmYb7j8krl1+qJgkG8C17fO79gk3c+jPw4S8glRFc1DTija9S3EyaTSQUm5GJXYKDAsugBEhFHH2vYiQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.1.4': + resolution: {integrity: sha512-F7hHC3gwY11+vByKPRWqwGbeXWVgKmL+pTGCinaEhdihzBV2aQ0fvZOch9cXYUOKuKKq429HeYXOqQLc7wFCEg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.1.4': + resolution: {integrity: sha512-sI5yw+7s92SK6odiEhD5lKCBlWcpjHS5qyqpVQbZAJ0fIzEUXrmbl3DH2ybR3PZogulNJF+COLtmA8hUfvkCCQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.1.4': + resolution: {integrity: sha512-mCi0OKgEieFircrtVYmQAFGszRtMnZ6fpZAXrxanXAu7lqZcsK1E1RAaZNG0uKAnxox3B1f4EyQNnoyMfN1vAA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.1.4': + resolution: {integrity: sha512-B9Ial3Kv5sh0SHnB1g/QWcUQCEvCF6QKGAl4zXypYj65mVI+B4AhFBwPtSN7pDrJeIx8Z7zdy4ntx+wQABom7w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-arm64-musl@1.1.4': + resolution: {integrity: sha512-lZVym0PuHE1KZ22gmFTC15lAkrg9iTszR617oYRB/iPY1A56ywoJzVKOJBKaot5RiikCObmur6pogpse3gRcng==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rolldown/binding-linux-ppc64-gnu@1.1.4': + resolution: {integrity: sha512-t2DNiLJWNTbnEHyUzTumldML6ET4/g16467LZoDDJ3tSxGvguL5/NyC2lCsNKuyRycg9XeDQF5SSv+TNOhQEXg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-s390x-gnu@1.1.4': + resolution: {integrity: sha512-0WIRnL1Uw4BvTZRLQt+PVgo6ZKTJadlC2btP+/EOXv2f/DWbY0rEgl+y834mIVwP1FkTlWVTrGGJXf12lru7EQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-gnu@1.1.4': + resolution: {integrity: sha512-JWtGshGfX+oENAKonoNkqEJX+7hC8yfhi9GUyPX1VX4mdh1y5r+ZiJLR5XzAB0aoP6s/PcILsGjKq8O0mm24bw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-musl@1.1.4': + resolution: {integrity: sha512-rT6yQcxUuXs4CnbofqwHRRV0iem349rLMYpTjkgQGLjrY4ado/eDzwPZPTCgTOlF6Nkp8NEv70yLMTn6qkWxsQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rolldown/binding-openharmony-arm64@1.1.4': + resolution: {integrity: sha512-KXMGoboq5cyaCQjDA4GLuRiOwBQ0EyFnJoVViLeZ45/3rFItRODEr+NdsBcVpll40hhNArlm/speWGRvj08LzA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.1.4': + resolution: {integrity: sha512-5K83rb36oJiY7BCyE9zLZtGcPV4g5wvq+xwdO0XPIwDVZI8cyB/AUjkNXGb92/rnmezEkjMOpgY61rtwjQtFwg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.1.4': + resolution: {integrity: sha512-PnWBtw3TV5KOg69HQQDR0mnQuyCmSGR2pAB4DC1rPF808fgKeTUMj2EOEyKATpgiuxuR5APQmiDO7PDgEjTFSA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.1.4': + resolution: {integrity: sha512-M1lpniBePobTfsa7Ks9a199e1akxsXn+GYBUKsEzv3YFzOm1HJAMNwKI3qr0Zq+mxwx9gOZoTdP1yXRYsZUocQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + + '@tybys/wasm-util@0.10.3': + resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} + + rolldown@1.1.4: + resolution: {integrity: sha512-IjZYiLxZwpnhwhdBH2ugdTGVSdhCQUmLxLoqyjiL0JxYjyRst+5a0P3xfrTxJ5F638j4Mvvw5FAX5XE6eHpXbA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + +snapshots: + + '@emnapi/core@1.11.1': + dependencies: + '@emnapi/wasi-threads': 1.2.2 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.11.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.2': + dependencies: + tslib: 2.8.1 + optional: true + + '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': + dependencies: + '@emnapi/core': 1.11.1 + '@emnapi/runtime': 1.11.1 + '@tybys/wasm-util': 0.10.3 + optional: true + + '@oxc-project/types@0.138.0': {} + + '@rolldown/binding-android-arm64@1.1.4': + optional: true + + '@rolldown/binding-darwin-arm64@1.1.4': + optional: true + + '@rolldown/binding-darwin-x64@1.1.4': + optional: true + + '@rolldown/binding-freebsd-x64@1.1.4': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.1.4': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.1.4': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.1.4': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.1.4': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.1.4': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.1.4': + optional: true + + '@rolldown/binding-linux-x64-musl@1.1.4': + optional: true + + '@rolldown/binding-openharmony-arm64@1.1.4': + optional: true + + '@rolldown/binding-wasm32-wasi@1.1.4': + dependencies: + '@emnapi/core': 1.11.1 + '@emnapi/runtime': 1.11.1 + '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.1.4': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.1.4': + optional: true + + '@rolldown/pluginutils@1.0.1': {} + + '@tybys/wasm-util@0.10.3': + dependencies: + tslib: 2.8.1 + optional: true + + rolldown@1.1.4: + dependencies: + '@oxc-project/types': 0.138.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.1.4 + '@rolldown/binding-darwin-arm64': 1.1.4 + '@rolldown/binding-darwin-x64': 1.1.4 + '@rolldown/binding-freebsd-x64': 1.1.4 + '@rolldown/binding-linux-arm-gnueabihf': 1.1.4 + '@rolldown/binding-linux-arm64-gnu': 1.1.4 + '@rolldown/binding-linux-arm64-musl': 1.1.4 + '@rolldown/binding-linux-ppc64-gnu': 1.1.4 + '@rolldown/binding-linux-s390x-gnu': 1.1.4 + '@rolldown/binding-linux-x64-gnu': 1.1.4 + '@rolldown/binding-linux-x64-musl': 1.1.4 + '@rolldown/binding-openharmony-arm64': 1.1.4 + '@rolldown/binding-wasm32-wasi': 1.1.4 + '@rolldown/binding-win32-arm64-msvc': 1.1.4 + '@rolldown/binding-win32-x64-msvc': 1.1.4 + + tslib@2.8.1: + optional: true diff --git a/package.json b/package.json index 7f3cc8c..ce05ac9 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { "name": "light-bolt11-decoder", - "version": "3.2.0", + "version": "3.2.7", + "type": "module", "description": "decode lightning invoices without overhead (doesn't check signatures).", "main": "bolt11.js", - "types": "bolt11.d.ts", "repository": { "type": "git", "url": "git+https://github.com/fiatjaf/light-bolt11-decoder.git" @@ -19,12 +19,11 @@ ], "author": "fiatjaf", "license": "MIT", - "dependencies": { - "@scure/base": "1.1.1" + "scripts": { + "test": "node --test --experimental-test-coverage tests/basic.test.js", + "lint": "oxlint" }, - "devDependencies": { - "eslint": "^8.0.0", - "jest": "^29.4.3", - "prettier": "^2.4.1" + "dependencies": { + "@scure/base": "2.2.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..d3d9bff --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,22 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@scure/base': + specifier: 2.2.0 + version: 2.2.0 + +packages: + + '@scure/base@2.2.0': + resolution: {integrity: sha512-b8XEupJibegiXV+tDUseI8oLQc8ei3d/4Jkb2RpbHh3MfE054ov3uIz2dhFkB3FI8iwYkEh0gGCApkrYggkPNg==} + +snapshots: + + '@scure/base@2.2.0': {} diff --git a/tests/basic.test.js b/tests/basic.test.js index ed5e70d..fe18e0b 100644 --- a/tests/basic.test.js +++ b/tests/basic.test.js @@ -1,13 +1,14 @@ -/* eslint-env jest */ +import { describe, it } from 'node:test' +import assert from 'node:assert/strict' -const {decode} = require('..') +import {decode} from '../bolt11.js' describe('decoding', () => { it('should decode an invoice', () => { let inv = decode( 'lnbc20u1p3y0x3hpp5743k2g0fsqqxj7n8qzuhns5gmkk4djeejk3wkp64ppevgekvc0jsdqcve5kzar2v9nr5gpqd4hkuetesp5ez2g297jduwc20t6lmqlsg3man0vf2jfd8ar9fh8fhn2g8yttfkqxqy9gcqcqzys9qrsgqrzjqtx3k77yrrav9hye7zar2rtqlfkytl094dsp0ms5majzth6gt7ca6uhdkxl983uywgqqqqlgqqqvx5qqjqrzjqd98kxkpyw0l9tyy8r8q57k7zpy9zjmh6sez752wj6gcumqnj3yxzhdsmg6qq56utgqqqqqqqqqqqeqqjq7jd56882gtxhrjm03c93aacyfy306m4fq0tskf83c0nmet8zc2lxyyg3saz8x6vwcp26xnrlagf9semau3qm2glysp7sv95693fphvsp54l567' ) - expect(inv).toEqual({ + assert.deepEqual(inv, { paymentRequest: 'lnbc20u1p3y0x3hpp5743k2g0fsqqxj7n8qzuhns5gmkk4djeejk3wkp64ppevgekvc0jsdqcve5kzar2v9nr5gpqd4hkuetesp5ez2g297jduwc20t6lmqlsg3man0vf2jfd8ar9fh8fhn2g8yttfkqxqy9gcqcqzys9qrsgqrzjqtx3k77yrrav9hye7zar2rtqlfkytl094dsp0ms5majzth6gt7ca6uhdkxl983uywgqqqqlgqqqvx5qqjqrzjqd98kxkpyw0l9tyy8r8q57k7zpy9zjmh6sez752wj6gcumqnj3yxzhdsmg6qq56utgqqqqqqqqqqqeqqjq7jd56882gtxhrjm03c93aacyfy306m4fq0tskf83c0nmet8zc2lxyyg3saz8x6vwcp26xnrlagf9semau3qm2glysp7sv95693fphvsp54l567', sections: [ diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index 0967ef4..0000000 --- a/tsconfig.json +++ /dev/null @@ -1 +0,0 @@ -{}