cln-ledger

CLN ledger accounting
git clone git://jb55.com/cln-ledger
Log | Files | Refs

commit eb6089fd397571037e5bfd15c50429557ba1d298
Author: William Casarin <jb55@jb55.com>
Date:   Sat, 27 May 2023 13:00:29 -0700

init commit

Diffstat:
A.gitignore | 12++++++++++++
Aindex.ts | 227+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apackage-lock.json | 387+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apackage.json | 20++++++++++++++++++++
Arun | 1+
Ashell.nix | 5+++++
Atsconfig.json | 22++++++++++++++++++++++
7 files changed, 674 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1,12 @@ +.build-result +.buildcmd +.direnv/ +.envrc +.rgignore +Makefile +events.txt +index.js +invoice_events.txt +node_modules/ +prices.db +test.ledger diff --git a/index.ts b/index.ts @@ -0,0 +1,227 @@ + +import fs from 'fs'; +import readline from 'readline'; +import assert from 'assert'; + +interface Zap { + kind: number; + content: string; + pubkey: string; + tags: string[][]; +} + +// Zap Types +interface ZapProfileType { + type: "profile" // profile + pubkey: string +} + +interface ZapEventType { + type: "event" + evid: string + pubkey: string +} + +type ZapType = ZapProfileType | ZapEventType + +// Descriptions +interface GenericDesc { + type: "generic" // generic + value: string +} + +interface LNDesc { + type: "lnurl" // lnurl + description: string + address: string +} + +interface ZapDesc { + type: "zap" // zap + zap_type: ZapType + zap: Zap +} + +type Description = LNDesc | GenericDesc | ZapDesc + +interface Posting { + account: string; + amount: string; +} + +interface Transaction { + date: Date; + description: Description; + postings: Posting[]; +} + +function description_string(desc: Description): string { + switch (desc.type) { + case "generic": + return desc.value + case "lnurl": + return desc.description + case "zap": + return "Zap" + } +} + +function determine_zap_type(zap: Zap): ZapType { + const etag = get_tag(zap.tags, "e") + const ptag = get_tag(zap.tags, "p") + + if (!ptag) + return null + + if (!etag) { + let profile_zap: ZapProfileType = { pubkey: ptag, type: "profile" } + return profile_zap + } + + let zap_ev: ZapEventType = { evid: etag, pubkey: ptag, type: "event" } + return zap_ev +} + +function get_tag(tags: string[][], key: string): string { + let v = tags.find(tag => tag[0] === key) + return v && v[1] +} + +function get_lnurl_description(json: string[][]): LNDesc { + const description = get_tag(json, "text/plain") + const address = get_tag(json, "text/identifier") + return { description, address, type: "lnurl" } +} + +function is_json(str: string): boolean { + return str[0] === '{' || (str[0] === '[' && str[1] === '[') +} + +function create_generic_desc(value: string): GenericDesc { + return { type: "generic", value } +} + +function determine_description(str: string): Description { + try { + let json + if (is_json(str) && (json = JSON.parse(str))) { + if (json.kind === 9734) { + let zaptype: ZapType = determine_zap_type(json) + let zap_desc: ZapDesc = { zap_type: zaptype, zap: json, type: "zap" } + return zap_desc + } else if (json.length > 0) { + return get_lnurl_description(json) + } + + return create_generic_desc(str) + } + + return create_generic_desc(str) + } catch(e) { + return create_generic_desc(str) + } +} + +function msat(val: number): string { + return `${val} msat` +} + +function classify_account(str: string):string { + if (str.includes("Damus Merch")) + return "merch:tshirt" + if (str.includes("Damus Hat")) + return "merch:hat" + if (str.includes("@tipjar")) + return "lnurl:jb55@sendsats.lol:tipjar" + return "unknown" +} + +function determine_postings(credit: number, debit: number, desc: Description): Posting[] { + let postings: Posting[] = [] + switch (desc.type) { + case "generic": + // todo: categorize + const is_credit = credit > 0 + const acct = is_credit? "income" : "expenses" + const amount = is_credit? credit : debit + const subacct = classify_account(desc.value) + postings.push({ account: `${acct}:${subacct}`, amount: msat(is_credit? -amount : amount) }) + postings.push({ account: `assets:cln`, amount: msat(is_credit? amount : -amount) }) + break + case "lnurl": + assert(debit === 0) + postings.push({ account: `income:lnurl:${desc.address}`, amount: msat(-credit) }) + postings.push({ account: `assets:cln`, amount: msat(credit) }) + break + case "zap": + assert(debit === 0) + switch (desc.zap_type.type) { + case 'profile': + postings.push({ account: `income:zap:profile:${desc.zap_type.pubkey}`, amount: msat(-credit) }) + break + case 'event': + // todo: attribute this to profile as well? + let evtype = desc.zap_type as ZapEventType + postings.push({ account: `income:zap:event:${evtype.evid}`, amount: msat(-credit) }) + break + } + postings.push({ account: `assets:cln`, amount: msat(credit) }) + break + } + + return postings +} + +async function process(filePath: string) { + const fileStream = fs.createReadStream(filePath); + + const rl = readline.createInterface({ + input: fileStream, + crlfDelay: Infinity + }); + + console.log("P 2022-07-22 msat 0.00000036 CAD") + + for await (const line of rl) { + let parts = line.split('\t'); + + if(parts.length !== 6) { + console.error(`Invalid line: ${line} ${parts.length} !== 5`); + continue; + } + + const credit = Number(parts[2]) + const debit = Number(parts[3]) + + if (credit === 0 && debit === 0) + continue + + const timestamp = Number(parts[4]) + const date = new Date(timestamp * 1000) + const description = determine_description(parts[5]) + const postings = determine_postings(credit, debit, description) + + // type,.tag,.credit_msat,.debit_msat,.timestamp,.description + let transaction: Transaction = { date, description, postings }; + console.log(transactionToLedger(transaction)); + } +} + +function format_date(date: Date): string { + const year = date.getFullYear(); + const month = (date.getMonth() + 1).toString().padStart(2, '0'); + const day = date.getDate().toString().padStart(2, '0'); + + return `${year}-${month}-${day}`; +} + +function transactionToLedger(transaction: Transaction): string { + const tx = `${format_date(transaction.date)} ${description_string(transaction.description)}\n` + return tx + transaction.postings.map(p => ` ${p.account} ${p.amount}`).join("\n") + "\n" +} + +async function main() { + await process('invoice_events.txt'); +} + +main().catch(console.error); diff --git a/package-lock.json b/package-lock.json @@ -0,0 +1,387 @@ +{ + "name": "accounting", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "accounting", + "version": "0.1.0", + "dependencies": { + "@types/node": "^20.2.5" + }, + "devDependencies": { + "tap": "~0.2.5", + "ts-node": "^10.9.1", + "typescript": "^5.0.4" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.2.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.5.tgz", + "integrity": "sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ==" + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/buffer-equal": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.2.tgz", + "integrity": "sha512-4hr0gS7+NK47X6WbA/okVFrN5qGh3WLT7N3hMRv7+hlkXnbUIdU2u05n6r0RQv6cq6xke06nVl70r0NW0WM2OQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/bunker": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/bunker/-/bunker-0.1.2.tgz", + "integrity": "sha512-YnahkcXBNT522S46k5LUA9P18lzvgkunbMl0qIJQ8oeRMQ+dAg3YI3k32q5TnO+AAUErFHO6R768To6jslgYmQ==", + "dev": true, + "dependencies": { + "burrito": ">=0.2.5 <0.3" + }, + "engines": { + "node": "*" + } + }, + "node_modules/burrito": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/burrito/-/burrito-0.2.12.tgz", + "integrity": "sha512-ZhhT5iVTAgzQ+s8rily7m45Swxe/cU3dVCHTzqmHVWD/cc0Ds3W4Q4MExbkevY+fm0Me3lEwpehIy6TH7p+ehw==", + "dev": true, + "dependencies": { + "traverse": "~0.5.1", + "uglify-js": "~1.1.1" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/burrito/node_modules/traverse": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.5.2.tgz", + "integrity": "sha512-PUBVcfB3RqgLpzgTRGNiqK4duqrDbgGa1bobbUtzUwLiBNAjZ7vd5eCOdBxqZ/Fgezagr9o69IxP2fZp41RGFA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/charm": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/charm/-/charm-0.1.2.tgz", + "integrity": "sha512-syedaZ9cPe7r3hoQA9twWYKu5AIyCswN5+szkmPBe9ccdLrj4bYaCnLVPTLd2kgVRc7+zoX4tyPgRnFKCj5YjQ==", + "dev": true + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/deep-equal": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-0.0.0.tgz", + "integrity": "sha512-p1bI/kkDPT6auUI0U+WLuIIrzmDIDo80I406J8tT4y6I4ZGtBuMeTudrKDtBdMJFAcxqrQdx27gosqPVyY3IvQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/difflet": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/difflet/-/difflet-0.2.6.tgz", + "integrity": "sha512-ruldDDRmY1t678UOAJBng6sL77f62SqjHj0498YC0EJhxIe2yKkqJn2qEchwG3eU/dqJ/RxPZkAnYjePS4pDCw==", + "dev": true, + "dependencies": { + "charm": "0.1.x", + "deep-is": "0.1.x", + "traverse": "0.6.x" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/mkdirp": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", + "integrity": "sha512-8OCq0De/h9ZxseqzCH8Kw/Filf5pF/vMI6+BH7Lu0jXz2pqYCjTAQRolSxRIi+Ax+oCCjlxoJMP0YQ4XlrQNHg==", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "dev": true + }, + "node_modules/nopt": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-2.2.1.tgz", + "integrity": "sha512-gIOTA/uJuhPwFqp+spY7VQ1satbnGlD+iQVZxI18K6hs8Evq4sX81Ml7BB5byP/LsbR2yBVtmvdEmhi7evJ6Aw==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/runforcover": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/runforcover/-/runforcover-0.0.2.tgz", + "integrity": "sha512-yarCIK2HcAOadqnKW419+FA38qpWDCKcOr5RZU+jnyLL/hn3No9BHZY+YJDEzvQ0k8Oyl7ffLjZv9ZUxvyKoLQ==", + "dev": true, + "dependencies": { + "bunker": "0.1.X" + }, + "engines": { + "node": "*" + } + }, + "node_modules/slide": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", + "integrity": "sha512-NwrtjCg+lZoqhFU8fOwl4ay2ei8PaqCBOUV3/ektPY9trO1yQ1oXEfmHAhKArUVUr/hOHvy5f6AdP17dCM0zMw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/tap": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/tap/-/tap-0.2.6.tgz", + "integrity": "sha512-uLvaKbh3+A4nh+P3SrfX52kWGkVvP37UYI7LxKjRkd6Bjdqbyc7MARaPFGl7SdwyNwWtZHlUxQX3w9pVNf3FKQ==", + "bundleDependencies": [ + "inherits", + "tap-consumer", + "yamlish" + ], + "dev": true, + "dependencies": { + "buffer-equal": "~0.0.0", + "deep-equal": "~0.0.0", + "difflet": "~0.2.0", + "inherits": "*", + "mkdirp": "~0.3", + "nopt": "~2", + "runforcover": "~0.0.2", + "slide": "*", + "yamlish": "*" + }, + "bin": { + "tap": "bin/tap.js" + } + }, + "node_modules/tap/node_modules/inherits": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "WTFPL2" + }, + "node_modules/tap/node_modules/yamlish": { + "version": "0.0.5", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/traverse": { + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.7.tgz", + "integrity": "sha512-/y956gpUo9ZNCb99YjxG7OaslxZWHfCHAUUfshwqOXmxUIvqLjVO581BT+gM59+QV9tFe6/CGG53tsA1Y7RSdg==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/typescript": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", + "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=12.20" + } + }, + "node_modules/uglify-js": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-1.1.1.tgz", + "integrity": "sha512-YYY9Dle1leC+btgrHnAR05eq0aRdcPJsXlYYD+SYw2lqc5HFuFNHg3wWEW4SNE0iXXEUl0fz43gTQ3r1YK76rg==", + "dev": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": "*" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + } + } +} diff --git a/package.json b/package.json @@ -0,0 +1,20 @@ +{ + "name": "accounting", + "description": "damus accounting", + "version": "0.1.0", + "repository": { + "url": "https://github.com/jb55/accounting" + }, + "main": "index.js", + "scripts": { + "test": "tap test/*.js" + }, + "devDependencies": { + "tap": "~0.2.5", + "ts-node": "^10.9.1", + "typescript": "^5.0.4" + }, + "dependencies": { + "@types/node": "^20.2.5" + } +} diff --git a/run b/run @@ -0,0 +1 @@ +npx ts-node index.ts diff --git a/shell.nix b/shell.nix @@ -0,0 +1,5 @@ +{ pkgs ? import <nixpkgs> {} }: +with pkgs; +mkShell { + buildInputs = [ ledger ]; +} diff --git a/tsconfig.json b/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "module": "commonjs", + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "target": "es6", + "noImplicitAny": true, + "moduleResolution": "node", + "sourceMap": true, + "outDir": "dist", + "baseUrl": ".", + "paths": { + "*": [ + "node_modules/*", + "src/types/*" + ] + } + }, + "include": [ + "src/**/*" + ] +}