Cache YNAB data responses
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
node_modules/
|
||||
.cache/
|
||||
2
config.js
Normal file
2
config.js
Normal file
@@ -0,0 +1,2 @@
|
||||
exports.pat = "992a2de8f26768d1a7cbb120ad545698c8712332f1dffdc1be74a528606b8b45";
|
||||
exports.cacheDir = "./.cache"
|
||||
71
index.js
Normal file
71
index.js
Normal file
@@ -0,0 +1,71 @@
|
||||
const ynab = require("ynab");
|
||||
const { argv } = require('yargs');
|
||||
const fs = require('fs');
|
||||
const { pat, cacheDir } = require('./config');
|
||||
const ynabAPI = new ynab.API(pat);
|
||||
|
||||
const ensureDataDir = async function(path) {
|
||||
if (!fs.existsSync(path)) {
|
||||
await fs.promises.mkdir(path);
|
||||
}
|
||||
}
|
||||
|
||||
const getCachedJsonOrHydrate = async function(fileName, hydrator) {
|
||||
const filePath = `${cacheDir}/${fileName}`
|
||||
|
||||
if (fs.existsSync(filePath)) {
|
||||
return JSON.parse(await fs.promises.readFile(filePath));
|
||||
}
|
||||
|
||||
const data = await hydrator();
|
||||
await ensureDataDir(cacheDir);
|
||||
await fs.promises.writeFile(filePath, JSON.stringify(data));
|
||||
return data;
|
||||
}
|
||||
|
||||
const getBudgetId = async function(budgetName) {
|
||||
const budgets = await getCachedJsonOrHydrate("budgets.json", async () => {
|
||||
console.log("Grabbing budgets from YNAB");
|
||||
const budgetsResponse = await ynabAPI.budgets.getBudgets();
|
||||
return budgetsResponse.data.budgets;
|
||||
});
|
||||
|
||||
const budgetId = budgets.filter(b => { return b.name === budgetName; })[0].id;
|
||||
return budgetId;
|
||||
}
|
||||
|
||||
const getAccountId = async function(budgetId, accountName) {
|
||||
let accounts = await getCachedJsonOrHydrate("accounts.json", async () => {
|
||||
console.log("Grabbing accounts from YNAB");
|
||||
const accountsResponse = await ynabAPI.accounts.getAccounts(budgetId);
|
||||
return accountsResponse.data.accounts;
|
||||
});
|
||||
|
||||
const accountId = accounts.filter(a => { return a.name === accountName; })[0].id;
|
||||
return accountId;
|
||||
}
|
||||
|
||||
const getTransactions = async function(budgetId, accountId) {
|
||||
const date = new Date();
|
||||
const jsonFile = `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}-transactions.json`;
|
||||
let transactions = await getCachedJsonOrHydrate(jsonFile, async () => {
|
||||
console.log("Grabbing transactions from YNAB");
|
||||
const transactionsResponse = await ynabAPI.transactions.getTransactionsByAccount(budgetId, accountId);
|
||||
return transactionsResponse.data.transactions;
|
||||
});
|
||||
|
||||
return transactions;
|
||||
}
|
||||
|
||||
const main = async function(budgetName, accountName) {
|
||||
console.log(`Looking for account '${accountName}' in budget named '${budgetName}'.`);
|
||||
|
||||
const budgetId = await getBudgetId(budgetName);
|
||||
const accountId = await getAccountId(budgetId, accountName);
|
||||
const transactions = await getTransactions(budgetId, accountId);
|
||||
|
||||
console.log(transactions.length);
|
||||
console.log(transactions[transactions.length - 1]);
|
||||
};
|
||||
|
||||
main(argv.budgetName, argv.accountName);
|
||||
178
package-lock.json
generated
Normal file
178
package-lock.json
generated
Normal file
@@ -0,0 +1,178 @@
|
||||
{
|
||||
"name": "ynabreconciler",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"ansi-regex": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
|
||||
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"requires": {
|
||||
"color-convert": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"cliui": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.1.tgz",
|
||||
"integrity": "sha512-rcvHOWyGyid6I1WjT/3NatKj2kDt9OdSHSXpyLXaMWFbKpGACNW8pRhhdPUq9MWUOdwn8Rz9AVETjF4105rZZQ==",
|
||||
"requires": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.0",
|
||||
"wrap-ansi": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"requires": {
|
||||
"color-name": "~1.1.4"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
||||
},
|
||||
"encoding": {
|
||||
"version": "0.1.13",
|
||||
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
|
||||
"integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
|
||||
"requires": {
|
||||
"iconv-lite": "^0.6.2"
|
||||
}
|
||||
},
|
||||
"escalade": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.0.tgz",
|
||||
"integrity": "sha512-mAk+hPSO8fLDkhV7V0dXazH5pDc6MrjBTPyD3VeKzxnVFjH1MIxbCdqGZB9O8+EwWakZs3ZCbDS4IpRt79V1ig=="
|
||||
},
|
||||
"get-caller-file": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
|
||||
},
|
||||
"iconv-lite": {
|
||||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz",
|
||||
"integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==",
|
||||
"requires": {
|
||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||
}
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
|
||||
},
|
||||
"is-stream": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
|
||||
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "1.7.3",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
|
||||
"integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==",
|
||||
"requires": {
|
||||
"encoding": "^0.1.11",
|
||||
"is-stream": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"portable-fetch": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/portable-fetch/-/portable-fetch-3.0.0.tgz",
|
||||
"integrity": "sha1-PL9KptvFpXNLQcBBnJJzMTv9mtg=",
|
||||
"requires": {
|
||||
"node-fetch": "^1.0.1",
|
||||
"whatwg-fetch": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||
},
|
||||
"string-width": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
|
||||
"integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
|
||||
"requires": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
|
||||
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
|
||||
"requires": {
|
||||
"ansi-regex": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"whatwg-fetch": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.4.1.tgz",
|
||||
"integrity": "sha512-sofZVzE1wKwO+EYPbWfiwzaKovWiZXf4coEzjGP9b2GBVgQRLQUZ2QcuPpQExGDAW5GItpEm6Tl4OU5mywnAoQ=="
|
||||
},
|
||||
"wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"requires": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"y18n": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.2.tgz",
|
||||
"integrity": "sha512-CkwaeZw6dQgqgPGeTWKMXCRmMcBgETFlTml1+ZOO+q7kGst8NREJ+eWwFNPVUQ4QGdAaklbqCZHH6Zuep1RjiA=="
|
||||
},
|
||||
"yargs": {
|
||||
"version": "16.0.3",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.0.3.tgz",
|
||||
"integrity": "sha512-6+nLw8xa9uK1BOEOykaiYAJVh6/CjxWXK/q9b5FpRgNslt8s22F2xMBqVIKgCRjNgGvGPBy8Vog7WN7yh4amtA==",
|
||||
"requires": {
|
||||
"cliui": "^7.0.0",
|
||||
"escalade": "^3.0.2",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"require-directory": "^2.1.1",
|
||||
"string-width": "^4.2.0",
|
||||
"y18n": "^5.0.1",
|
||||
"yargs-parser": "^20.0.0"
|
||||
}
|
||||
},
|
||||
"yargs-parser": {
|
||||
"version": "20.2.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.1.tgz",
|
||||
"integrity": "sha512-yYsjuSkjbLMBp16eaOt7/siKTjNVjMm3SoJnIg3sEh/JsvqVVDyjRKmaJV4cl+lNIgq6QEco2i3gDebJl7/vLA=="
|
||||
},
|
||||
"ynab": {
|
||||
"version": "1.20.0",
|
||||
"resolved": "https://registry.npmjs.org/ynab/-/ynab-1.20.0.tgz",
|
||||
"integrity": "sha512-agn2NhLGx/hXKLh5/Y8Ri45DZvyabXJCtJ9jTHOnaocr7XAL0R5jW7ZnKupUI9dIJy3vAXln5i+KDgjQ98ieqA==",
|
||||
"requires": {
|
||||
"portable-fetch": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
15
package.json
Normal file
15
package.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "ynabreconciler",
|
||||
"version": "1.0.0",
|
||||
"description": "Command line tool to reconcile YNAB account",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"yargs": "^16.0.3",
|
||||
"ynab": "^1.20.0"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user