Fixes
- Added Actual account ids and log level to .env.example. - Fixed timestamp error by downloading the budget after init. - Hardcoded date in test. - Separate logging file for configurations. - Organized test - More logging in main - Fixed wrong paths for some files - Load a .env.test.local file when running tests Signed-off-by: Martin Berg Alstad <git@martials.no>
This commit is contained in:
parent
29b394baf4
commit
480c0356f9
@ -2,9 +2,13 @@ ACTUAL_BUDGET_ID=your-budget-id
|
|||||||
ACTUAL_SYNC_ID=your-sync-id
|
ACTUAL_SYNC_ID=your-sync-id
|
||||||
ACTUAL_SERVER_URL=your-server-url
|
ACTUAL_SERVER_URL=your-server-url
|
||||||
ACTUAL_PASSWORD=your-password
|
ACTUAL_PASSWORD=your-password
|
||||||
|
ACTUAL_ACCOUNT_IDS=your-account-id1,your-account-id2
|
||||||
# Bank
|
# Bank
|
||||||
BANK_OAUTH_CLIENT_ID=your-client-id
|
BANK_OAUTH_CLIENT_ID=your-client-id
|
||||||
BANK_OAUTH_CLIENT_SECRET=your-client-secret
|
BANK_OAUTH_CLIENT_SECRET=your-client-secret
|
||||||
BANK_OAUTH_STATE=your-state
|
BANK_OAUTH_STATE=your-state
|
||||||
BANK_OAUTH_REDIRECT_URI=your-redirect-uri
|
BANK_OAUTH_REDIRECT_URI=your-redirect-uri
|
||||||
BANK_ACCOUNT_IDS=your-account-id1,your-account-id2
|
BANK_ACCOUNT_IDS=your-account-id1,your-account-id2
|
||||||
|
# Configuration
|
||||||
|
# trace | error | warn | info | debug | trace
|
||||||
|
LOG_LEVEL=info
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node --import=tsx ./src/main.ts | pino-pretty",
|
"start": "node --import=tsx ./src/main.ts | pino-pretty",
|
||||||
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
|
"test": "dotenvx run --env-file=.env.test.local -- node --experimental-vm-modules node_modules/jest/bin/jest.js | pino-pretty",
|
||||||
"format": "prettier --write \"./**/*.{js,mjs,ts,md,json}\""
|
"format": "prettier --write \"./**/*.{js,mjs,ts,md,json}\""
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
@ -13,6 +13,7 @@
|
|||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actual-app/api": "^24.12.0",
|
"@actual-app/api": "^24.12.0",
|
||||||
|
"@dotenvx/dotenvx": "^1.31.3",
|
||||||
"cron": "^3.3.1",
|
"cron": "^3.3.1",
|
||||||
"dotenv": "^16.4.7",
|
"dotenv": "^16.4.7",
|
||||||
"pino": "^9.5.0",
|
"pino": "^9.5.0",
|
||||||
|
119
pnpm-lock.yaml
generated
119
pnpm-lock.yaml
generated
@ -8,6 +8,9 @@ dependencies:
|
|||||||
'@actual-app/api':
|
'@actual-app/api':
|
||||||
specifier: ^24.12.0
|
specifier: ^24.12.0
|
||||||
version: 24.12.0
|
version: 24.12.0
|
||||||
|
'@dotenvx/dotenvx':
|
||||||
|
specifier: ^1.31.3
|
||||||
|
version: 1.31.3
|
||||||
cron:
|
cron:
|
||||||
specifier: ^3.3.1
|
specifier: ^3.3.1
|
||||||
version: 3.3.1
|
version: 3.3.1
|
||||||
@ -397,6 +400,30 @@ packages:
|
|||||||
'@jridgewell/trace-mapping': 0.3.9
|
'@jridgewell/trace-mapping': 0.3.9
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@dotenvx/dotenvx@1.31.3:
|
||||||
|
resolution: {integrity: sha512-NgRjBV8NrCIoRhdbPozkKp+HvSn0Sc8DrOT22YDvTbs5pgPC2YrXKqwI7YwLFDVHBjSJHJTvkhQ5QHCCO+//yg==}
|
||||||
|
hasBin: true
|
||||||
|
dependencies:
|
||||||
|
commander: 11.1.0
|
||||||
|
dotenv: 16.4.7
|
||||||
|
eciesjs: 0.4.13
|
||||||
|
execa: 5.1.1
|
||||||
|
fdir: 6.4.2(picomatch@4.0.2)
|
||||||
|
ignore: 5.3.2
|
||||||
|
object-treeify: 1.1.33
|
||||||
|
picomatch: 4.0.2
|
||||||
|
which: 4.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@ecies/ciphers@0.2.2(@noble/ciphers@1.1.3):
|
||||||
|
resolution: {integrity: sha512-ylfGR7PyTd+Rm2PqQowG08BCKA22QuX8NzrL+LxAAvazN10DMwdJ2fWwAzRj05FI/M8vNFGm3cv9Wq/GFWCBLg==}
|
||||||
|
engines: {bun: '>=1', deno: '>=2', node: '>=16'}
|
||||||
|
peerDependencies:
|
||||||
|
'@noble/ciphers': ^1.0.0
|
||||||
|
dependencies:
|
||||||
|
'@noble/ciphers': 1.1.3
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@esbuild/aix-ppc64@0.23.1:
|
/@esbuild/aix-ppc64@0.23.1:
|
||||||
resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==}
|
resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@ -880,6 +907,28 @@ packages:
|
|||||||
'@jridgewell/sourcemap-codec': 1.5.0
|
'@jridgewell/sourcemap-codec': 1.5.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@noble/ciphers@1.1.3:
|
||||||
|
resolution: {integrity: sha512-Ygv6WnWJHLLiW4fnNDC1z+i13bud+enXOFRBlpxI+NJliPWx5wdR+oWlTjLuBPTqjUjtHXtjkU6w3kuuH6upZA==}
|
||||||
|
engines: {node: ^14.21.3 || >=16}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@noble/curves@1.7.0:
|
||||||
|
resolution: {integrity: sha512-UTMhXK9SeDhFJVrHeUJ5uZlI6ajXg10O6Ddocf9S6GjbSBVZsJo88HzKwXznNfGpMTRDyJkqMjNDPYgf0qFWnw==}
|
||||||
|
engines: {node: ^14.21.3 || >=16}
|
||||||
|
dependencies:
|
||||||
|
'@noble/hashes': 1.6.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@noble/hashes@1.6.0:
|
||||||
|
resolution: {integrity: sha512-YUULf0Uk4/mAA89w+k3+yUYh6NrEvxZa5T6SY3wlMvE2chHkxFUUIDI8/XW1QSC357iA5pSnqt7XEhvFOqmDyQ==}
|
||||||
|
engines: {node: ^14.21.3 || >=16}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@noble/hashes@1.6.1:
|
||||||
|
resolution: {integrity: sha512-pq5D8h10hHBjyqX+cfBm0i8JUXJ0UhczFc4r74zbuT9XgewFo2E3J1cOaGtdZynILNmQ685YWGzGE1Zv6io50w==}
|
||||||
|
engines: {node: ^14.21.3 || >=16}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@sinclair/typebox@0.27.8:
|
/@sinclair/typebox@0.27.8:
|
||||||
resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==}
|
resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==}
|
||||||
dev: true
|
dev: true
|
||||||
@ -1292,6 +1341,11 @@ packages:
|
|||||||
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/commander@11.1.0:
|
||||||
|
resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==}
|
||||||
|
engines: {node: '>=16'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/compare-versions@6.1.1:
|
/compare-versions@6.1.1:
|
||||||
resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==}
|
resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==}
|
||||||
dev: false
|
dev: false
|
||||||
@ -1341,7 +1395,6 @@ packages:
|
|||||||
path-key: 3.1.1
|
path-key: 3.1.1
|
||||||
shebang-command: 2.0.0
|
shebang-command: 2.0.0
|
||||||
which: 2.0.2
|
which: 2.0.2
|
||||||
dev: true
|
|
||||||
|
|
||||||
/data-uri-to-buffer@4.0.1:
|
/data-uri-to-buffer@4.0.1:
|
||||||
resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==}
|
resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==}
|
||||||
@ -1411,6 +1464,16 @@ packages:
|
|||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/eciesjs@0.4.13:
|
||||||
|
resolution: {integrity: sha512-zBdtR4K+wbj10bWPpIOF9DW+eFYQu8miU5ypunh0t4Bvt83ZPlEWgT5Dq/0G6uwEXumZKjfb5BZxYUZQ2Hzn/Q==}
|
||||||
|
engines: {bun: '>=1', deno: '>=2', node: '>=16'}
|
||||||
|
dependencies:
|
||||||
|
'@ecies/ciphers': 0.2.2(@noble/ciphers@1.1.3)
|
||||||
|
'@noble/ciphers': 1.1.3
|
||||||
|
'@noble/curves': 1.7.0
|
||||||
|
'@noble/hashes': 1.6.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/ejs@3.1.10:
|
/ejs@3.1.10:
|
||||||
resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==}
|
resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@ -1505,7 +1568,6 @@ packages:
|
|||||||
onetime: 5.1.2
|
onetime: 5.1.2
|
||||||
signal-exit: 3.0.7
|
signal-exit: 3.0.7
|
||||||
strip-final-newline: 2.0.0
|
strip-final-newline: 2.0.0
|
||||||
dev: true
|
|
||||||
|
|
||||||
/exit@0.1.2:
|
/exit@0.1.2:
|
||||||
resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==}
|
resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==}
|
||||||
@ -1543,6 +1605,17 @@ packages:
|
|||||||
bser: 2.1.1
|
bser: 2.1.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/fdir@6.4.2(picomatch@4.0.2):
|
||||||
|
resolution: {integrity: sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==}
|
||||||
|
peerDependencies:
|
||||||
|
picomatch: ^3 || ^4
|
||||||
|
peerDependenciesMeta:
|
||||||
|
picomatch:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
picomatch: 4.0.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
/fetch-blob@3.2.0:
|
/fetch-blob@3.2.0:
|
||||||
resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
|
resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
|
||||||
engines: {node: ^12.20 || >= 14.13}
|
engines: {node: ^12.20 || >= 14.13}
|
||||||
@ -1621,7 +1694,6 @@ packages:
|
|||||||
/get-stream@6.0.1:
|
/get-stream@6.0.1:
|
||||||
resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
|
resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/get-tsconfig@4.8.1:
|
/get-tsconfig@4.8.1:
|
||||||
resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==}
|
resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==}
|
||||||
@ -1677,12 +1749,16 @@ packages:
|
|||||||
/human-signals@2.1.0:
|
/human-signals@2.1.0:
|
||||||
resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
|
resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
|
||||||
engines: {node: '>=10.17.0'}
|
engines: {node: '>=10.17.0'}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/ieee754@1.2.1:
|
/ieee754@1.2.1:
|
||||||
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
|
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/ignore@5.3.2:
|
||||||
|
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
|
||||||
|
engines: {node: '>= 4'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/import-local@3.2.0:
|
/import-local@3.2.0:
|
||||||
resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==}
|
resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@ -1741,11 +1817,14 @@ packages:
|
|||||||
/is-stream@2.0.1:
|
/is-stream@2.0.1:
|
||||||
resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
|
resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/isexe@2.0.0:
|
/isexe@2.0.0:
|
||||||
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
|
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
|
||||||
dev: true
|
|
||||||
|
/isexe@3.1.1:
|
||||||
|
resolution: {integrity: sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==}
|
||||||
|
engines: {node: '>=16'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/istanbul-lib-coverage@3.2.2:
|
/istanbul-lib-coverage@3.2.2:
|
||||||
resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}
|
resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}
|
||||||
@ -2311,7 +2390,6 @@ packages:
|
|||||||
|
|
||||||
/merge-stream@2.0.0:
|
/merge-stream@2.0.0:
|
||||||
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
|
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/micromatch@4.0.8:
|
/micromatch@4.0.8:
|
||||||
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
|
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
|
||||||
@ -2324,7 +2402,6 @@ packages:
|
|||||||
/mimic-fn@2.1.0:
|
/mimic-fn@2.1.0:
|
||||||
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
|
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/mimic-response@3.1.0:
|
/mimic-response@3.1.0:
|
||||||
resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
|
resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
|
||||||
@ -2407,7 +2484,11 @@ packages:
|
|||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
dependencies:
|
dependencies:
|
||||||
path-key: 3.1.1
|
path-key: 3.1.1
|
||||||
dev: true
|
|
||||||
|
/object-treeify@1.1.33:
|
||||||
|
resolution: {integrity: sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/on-exit-leak-free@2.1.2:
|
/on-exit-leak-free@2.1.2:
|
||||||
resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==}
|
resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==}
|
||||||
@ -2424,7 +2505,6 @@ packages:
|
|||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
dependencies:
|
dependencies:
|
||||||
mimic-fn: 2.1.0
|
mimic-fn: 2.1.0
|
||||||
dev: true
|
|
||||||
|
|
||||||
/p-limit@2.3.0:
|
/p-limit@2.3.0:
|
||||||
resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
|
resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
|
||||||
@ -2475,7 +2555,6 @@ packages:
|
|||||||
/path-key@3.1.1:
|
/path-key@3.1.1:
|
||||||
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
|
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/path-parse@1.0.7:
|
/path-parse@1.0.7:
|
||||||
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
|
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
|
||||||
@ -2490,6 +2569,11 @@ packages:
|
|||||||
engines: {node: '>=8.6'}
|
engines: {node: '>=8.6'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/picomatch@4.0.2:
|
||||||
|
resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/pino-abstract-transport@2.0.0:
|
/pino-abstract-transport@2.0.0:
|
||||||
resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==}
|
resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -2678,16 +2762,13 @@ packages:
|
|||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
dependencies:
|
dependencies:
|
||||||
shebang-regex: 3.0.0
|
shebang-regex: 3.0.0
|
||||||
dev: true
|
|
||||||
|
|
||||||
/shebang-regex@3.0.0:
|
/shebang-regex@3.0.0:
|
||||||
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
|
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/signal-exit@3.0.7:
|
/signal-exit@3.0.7:
|
||||||
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
|
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/simple-concat@1.0.1:
|
/simple-concat@1.0.1:
|
||||||
resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
|
resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
|
||||||
@ -2782,7 +2863,6 @@ packages:
|
|||||||
/strip-final-newline@2.0.0:
|
/strip-final-newline@2.0.0:
|
||||||
resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
|
resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/strip-json-comments@2.0.1:
|
/strip-json-comments@2.0.1:
|
||||||
resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
|
resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
|
||||||
@ -3015,7 +3095,14 @@ packages:
|
|||||||
hasBin: true
|
hasBin: true
|
||||||
dependencies:
|
dependencies:
|
||||||
isexe: 2.0.0
|
isexe: 2.0.0
|
||||||
dev: true
|
|
||||||
|
/which@4.0.0:
|
||||||
|
resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==}
|
||||||
|
engines: {node: ^16.13.0 || >=18.0.0}
|
||||||
|
hasBin: true
|
||||||
|
dependencies:
|
||||||
|
isexe: 3.1.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/wrap-ansi@7.0.0:
|
/wrap-ansi@7.0.0:
|
||||||
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
|
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
|
||||||
|
@ -3,9 +3,11 @@ import {
|
|||||||
ACTUAL_DATA_DIR,
|
ACTUAL_DATA_DIR,
|
||||||
ACTUAL_PASSWORD,
|
ACTUAL_PASSWORD,
|
||||||
ACTUAL_SERVER_URL,
|
ACTUAL_SERVER_URL,
|
||||||
|
ACTUAL_SYNC_ID,
|
||||||
} from "../config.ts"
|
} from "../config.ts"
|
||||||
import type { TransactionEntity } from "@actual-app/api/@types/loot-core/types/models"
|
import type { TransactionEntity } from "@actual-app/api/@types/loot-core/types/models"
|
||||||
import { type UUID } from "node:crypto"
|
import { type UUID } from "node:crypto"
|
||||||
|
import logger from "@/logger.ts"
|
||||||
|
|
||||||
export interface Actual {
|
export interface Actual {
|
||||||
importTransactions: (
|
importTransactions: (
|
||||||
@ -38,6 +40,9 @@ export class ActualImpl implements Actual {
|
|||||||
// This is the password you use to log into the server
|
// This is the password you use to log into the server
|
||||||
password: ACTUAL_PASSWORD,
|
password: ACTUAL_PASSWORD,
|
||||||
})
|
})
|
||||||
|
logger.info(`Initialized ActualBudget API for ${ACTUAL_SERVER_URL}`)
|
||||||
|
await actual.downloadBudget(ACTUAL_SYNC_ID)
|
||||||
|
logger.info(`Downloaded budget`)
|
||||||
return new ActualImpl()
|
return new ActualImpl()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
8
src/logger.ts
Normal file
8
src/logger.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import pino from "pino"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* / Returns a logging instance with the default log-level "info"
|
||||||
|
*/
|
||||||
|
export default pino({
|
||||||
|
level: process.env.LOG_LEVEL as string || "info",
|
||||||
|
})
|
20
src/main.ts
20
src/main.ts
@ -7,7 +7,7 @@ import {
|
|||||||
} from "@/bank/sparebank1.ts"
|
} from "@/bank/sparebank1.ts"
|
||||||
import { bankTransactionIntoActualTransaction } from "@/mappings.ts"
|
import { bankTransactionIntoActualTransaction } from "@/mappings.ts"
|
||||||
import { ACTUAL_ACCOUNT_IDS, BANK_ACCOUNT_IDS } from "../config.ts"
|
import { ACTUAL_ACCOUNT_IDS, BANK_ACCOUNT_IDS } from "../config.ts"
|
||||||
import logger from "pino"
|
import logger from "./logger.ts"
|
||||||
import type { UUID } from "node:crypto"
|
import type { UUID } from "node:crypto"
|
||||||
|
|
||||||
// TODO Transports api for pino https://github.com/pinojs/pino/blob/HEAD/docs/transports.md
|
// TODO Transports api for pino https://github.com/pinojs/pino/blob/HEAD/docs/transports.md
|
||||||
@ -16,7 +16,7 @@ import type { UUID } from "node:crypto"
|
|||||||
export async function daily(actual: Actual, bank: Bank): Promise<void> {
|
export async function daily(actual: Actual, bank: Bank): Promise<void> {
|
||||||
// Fetch transactions from the bank
|
// Fetch transactions from the bank
|
||||||
const transactions = await fetchTransactionsFromPastDay(bank)
|
const transactions = await fetchTransactionsFromPastDay(bank)
|
||||||
logger().info(`Fetched ${transactions.length} transactions`)
|
logger.info(`Fetched ${transactions.length} transactions`)
|
||||||
|
|
||||||
// TODO multiple accounts
|
// TODO multiple accounts
|
||||||
const accountId = ACTUAL_ACCOUNT_IDS[0] as UUID
|
const accountId = ACTUAL_ACCOUNT_IDS[0] as UUID
|
||||||
@ -24,12 +24,14 @@ export async function daily(actual: Actual, bank: Bank): Promise<void> {
|
|||||||
bankTransactionIntoActualTransaction(transaction, accountId),
|
bankTransactionIntoActualTransaction(transaction, accountId),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
logger.debug(`Mapped ${JSON.stringify(transactions)} to ${JSON.stringify(actualTransactions)} transactions`)
|
||||||
|
|
||||||
// TODO Import transactions into Actual
|
// TODO Import transactions into Actual
|
||||||
// If multiple accounts, loop over them
|
// If multiple accounts, loop over them
|
||||||
// Get account ID from mapper
|
// Get account ID from mapper
|
||||||
|
|
||||||
// TODO TypeError: Cannot read properties of undefined (reading 'timestamp')
|
const response = await actual.importTransactions(accountId, actualTransactions)
|
||||||
await actual.importTransactions(accountId, actualTransactions)
|
logger.info(`ImportTransactionsResponse=${JSON.stringify(response)}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchTransactionsFromPastDay(
|
async function fetchTransactionsFromPastDay(
|
||||||
@ -41,17 +43,17 @@ async function fetchTransactionsFromPastDay(
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function main(): Promise<void> {
|
async function main(): Promise<void> {
|
||||||
logger().info("Starting application")
|
logger.info("Starting application")
|
||||||
const actual = await ActualImpl.init()
|
const actual = await ActualImpl.init()
|
||||||
logger().info("Initialized Actual Budget API")
|
logger.info("Waiting for CRON job to start")
|
||||||
|
|
||||||
cronJobDaily(async () => {
|
cronJobDaily(async () => {
|
||||||
logger().info("Running daily job")
|
logger.info("Running daily job")
|
||||||
await daily(actual, new Sparebank1Impl())
|
await daily(actual, new Sparebank1Impl())
|
||||||
logger().info("Finished daily job")
|
logger.info("Finished daily job")
|
||||||
})
|
})
|
||||||
|
|
||||||
// logger().info("Shutting down")
|
// logger.info("Shutting down")
|
||||||
// await actual.shutdown()
|
// await actual.shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import type { Transaction } from "@/sparebank1.ts"
|
import type { Transaction } from "@/bank/sparebank1.ts"
|
||||||
import type { TransactionEntity } from "@actual-app/api/@types/loot-core/types/models"
|
import type { TransactionEntity } from "@actual-app/api/@types/loot-core/types/models"
|
||||||
import type { UUID } from "node:crypto"
|
import type { UUID } from "node:crypto"
|
||||||
|
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
import { describe, expect, it } from "@jest/globals"
|
import { describe, it } from "@jest/globals"
|
||||||
|
|
||||||
import { daily } from "@/main.ts"
|
import { daily } from "@/main.ts"
|
||||||
import { ActualImpl } from "@/actual.ts"
|
import { ActualImpl } from "@/actual.ts"
|
||||||
import { BankStub } from "./stubs/bankStub.ts"
|
import { BankStub } from "./stubs/bankStub.ts"
|
||||||
|
|
||||||
|
// TODO testcontainers with Actual?
|
||||||
|
// TODO tests don't stop after completing
|
||||||
|
|
||||||
describe("Main logic of the application", () => {
|
describe("Main logic of the application", () => {
|
||||||
it("should import the transactions to Actual Budget", async () => {
|
it("should import the transactions to Actual Budget", async () => {
|
||||||
await daily(await ActualImpl.init(), new BankStub())
|
const actual = await ActualImpl.init()
|
||||||
expect(true)
|
await daily(actual, new BankStub())
|
||||||
|
await actual.shutdown()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import type { Bank, OAuthTokenResponse, Transaction } from "@/sparebank1.ts"
|
import type { Bank, OAuthTokenResponse, Transaction } from "@/bank/sparebank1.ts"
|
||||||
|
|
||||||
const tokenResponse: OAuthTokenResponse = {
|
const tokenResponse: OAuthTokenResponse = {
|
||||||
access_token: "my_access_token",
|
access_token: "my_access_token",
|
||||||
@ -23,7 +23,7 @@ export class BankStub implements Bank {
|
|||||||
_accessToken: string,
|
_accessToken: string,
|
||||||
): Promise<ReadonlyArray<Transaction>> {
|
): Promise<ReadonlyArray<Transaction>> {
|
||||||
const someFields = {
|
const someFields = {
|
||||||
date: new Date().toDateString(),
|
date: "2019-08-20",
|
||||||
description: "Test transaction",
|
description: "Test transaction",
|
||||||
cleanedDescription: "Test transaction",
|
cleanedDescription: "Test transaction",
|
||||||
remoteAccountName: "Test account",
|
remoteAccountName: "Test account",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user