@dizzlkheinz/ynab-mcpb 0.18.4 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +87 -8
- package/bin/ynab-mcp-server.cjs +2 -2
- package/bin/ynab-mcp-server.js +3 -3
- package/biome.json +39 -0
- package/dist/bundle/index.cjs +67 -67
- package/dist/index.d.ts +1 -1
- package/dist/index.js +27 -27
- package/dist/server/YNABMCPServer.d.ts +3 -4
- package/dist/server/YNABMCPServer.js +111 -116
- package/dist/server/budgetResolver.d.ts +6 -5
- package/dist/server/budgetResolver.js +46 -36
- package/dist/server/cacheKeys.js +6 -6
- package/dist/server/cacheManager.js +14 -11
- package/dist/server/completions.d.ts +2 -2
- package/dist/server/completions.js +20 -15
- package/dist/server/config.d.ts +10 -5
- package/dist/server/config.js +24 -7
- package/dist/server/deltaCache.d.ts +2 -2
- package/dist/server/deltaCache.js +22 -16
- package/dist/server/deltaCache.merge.d.ts +2 -2
- package/dist/server/diagnostics.d.ts +4 -4
- package/dist/server/diagnostics.js +38 -32
- package/dist/server/errorHandler.d.ts +5 -12
- package/dist/server/errorHandler.js +219 -217
- package/dist/server/prompts.d.ts +2 -2
- package/dist/server/prompts.js +45 -45
- package/dist/server/rateLimiter.js +4 -4
- package/dist/server/requestLogger.d.ts +1 -1
- package/dist/server/requestLogger.js +40 -35
- package/dist/server/resources.d.ts +3 -3
- package/dist/server/resources.js +55 -52
- package/dist/server/responseFormatter.js +6 -6
- package/dist/server/securityMiddleware.d.ts +2 -2
- package/dist/server/securityMiddleware.js +22 -20
- package/dist/server/serverKnowledgeStore.js +1 -1
- package/dist/server/toolRegistry.d.ts +3 -3
- package/dist/server/toolRegistry.js +47 -40
- package/dist/tools/__tests__/deltaTestUtils.d.ts +3 -3
- package/dist/tools/__tests__/deltaTestUtils.js +2 -2
- package/dist/tools/accountTools.d.ts +9 -8
- package/dist/tools/accountTools.js +47 -47
- package/dist/tools/adapters.d.ts +13 -8
- package/dist/tools/adapters.js +21 -11
- package/dist/tools/budgetTools.d.ts +8 -7
- package/dist/tools/budgetTools.js +22 -22
- package/dist/tools/categoryTools.d.ts +9 -8
- package/dist/tools/categoryTools.js +68 -59
- package/dist/tools/compareTransactions/formatter.d.ts +3 -3
- package/dist/tools/compareTransactions/formatter.js +9 -9
- package/dist/tools/compareTransactions/index.d.ts +6 -6
- package/dist/tools/compareTransactions/index.js +58 -43
- package/dist/tools/compareTransactions/matcher.d.ts +1 -1
- package/dist/tools/compareTransactions/matcher.js +28 -15
- package/dist/tools/compareTransactions/parser.d.ts +2 -2
- package/dist/tools/compareTransactions/parser.js +144 -138
- package/dist/tools/compareTransactions/types.d.ts +4 -4
- package/dist/tools/compareTransactions.d.ts +1 -1
- package/dist/tools/compareTransactions.js +1 -1
- package/dist/tools/deltaFetcher.d.ts +2 -2
- package/dist/tools/deltaFetcher.js +16 -15
- package/dist/tools/deltaSupport.d.ts +4 -4
- package/dist/tools/deltaSupport.js +35 -41
- package/dist/tools/exportTransactions.d.ts +5 -4
- package/dist/tools/exportTransactions.js +61 -59
- package/dist/tools/monthTools.d.ts +7 -6
- package/dist/tools/monthTools.js +31 -29
- package/dist/tools/payeeTools.d.ts +7 -6
- package/dist/tools/payeeTools.js +28 -28
- package/dist/tools/reconcileAdapter.d.ts +2 -2
- package/dist/tools/reconcileAdapter.js +19 -12
- package/dist/tools/reconciliation/analyzer.d.ts +4 -4
- package/dist/tools/reconciliation/analyzer.js +73 -59
- package/dist/tools/reconciliation/csvParser.d.ts +3 -3
- package/dist/tools/reconciliation/csvParser.js +128 -104
- package/dist/tools/reconciliation/executor.d.ts +4 -4
- package/dist/tools/reconciliation/executor.js +148 -109
- package/dist/tools/reconciliation/index.d.ts +10 -10
- package/dist/tools/reconciliation/index.js +96 -83
- package/dist/tools/reconciliation/matcher.d.ts +3 -3
- package/dist/tools/reconciliation/matcher.js +17 -16
- package/dist/tools/reconciliation/payeeNormalizer.js +19 -8
- package/dist/tools/reconciliation/recommendationEngine.d.ts +1 -1
- package/dist/tools/reconciliation/recommendationEngine.js +40 -40
- package/dist/tools/reconciliation/reportFormatter.d.ts +2 -2
- package/dist/tools/reconciliation/reportFormatter.js +59 -58
- package/dist/tools/reconciliation/signDetector.d.ts +1 -1
- package/dist/tools/reconciliation/types.d.ts +16 -16
- package/dist/tools/reconciliation/ynabAdapter.d.ts +2 -2
- package/dist/tools/schemas/common.d.ts +1 -1
- package/dist/tools/schemas/common.js +1 -1
- package/dist/tools/schemas/outputs/accountOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/accountOutputs.js +24 -18
- package/dist/tools/schemas/outputs/budgetOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/budgetOutputs.js +14 -11
- package/dist/tools/schemas/outputs/categoryOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/categoryOutputs.js +49 -29
- package/dist/tools/schemas/outputs/comparisonOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/comparisonOutputs.js +12 -12
- package/dist/tools/schemas/outputs/index.d.ts +14 -14
- package/dist/tools/schemas/outputs/index.js +14 -14
- package/dist/tools/schemas/outputs/monthOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/monthOutputs.js +56 -41
- package/dist/tools/schemas/outputs/payeeOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/payeeOutputs.js +10 -10
- package/dist/tools/schemas/outputs/reconciliationOutputs.d.ts +2 -2
- package/dist/tools/schemas/outputs/reconciliationOutputs.js +45 -45
- package/dist/tools/schemas/outputs/transactionMutationOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/transactionMutationOutputs.js +28 -22
- package/dist/tools/schemas/outputs/transactionOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/transactionOutputs.js +43 -35
- package/dist/tools/schemas/outputs/utilityOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/utilityOutputs.js +5 -3
- package/dist/tools/schemas/shared/commonOutputs.d.ts +1 -1
- package/dist/tools/schemas/shared/commonOutputs.js +15 -9
- package/dist/tools/transactionReadTools.d.ts +11 -0
- package/dist/tools/transactionReadTools.js +202 -0
- package/dist/tools/transactionSchemas.d.ts +7 -7
- package/dist/tools/transactionSchemas.js +77 -57
- package/dist/tools/transactionTools.d.ts +6 -24
- package/dist/tools/transactionTools.js +7 -1499
- package/dist/tools/transactionUtils.d.ts +6 -6
- package/dist/tools/transactionUtils.js +78 -63
- package/dist/tools/transactionWriteTools.d.ts +20 -0
- package/dist/tools/transactionWriteTools.js +1342 -0
- package/dist/tools/utilityTools.d.ts +5 -4
- package/dist/tools/utilityTools.js +11 -11
- package/dist/types/index.d.ts +7 -7
- package/dist/types/index.js +6 -6
- package/dist/types/reconciliation.d.ts +1 -1
- package/dist/types/toolRegistration.d.ts +14 -12
- package/dist/utils/amountUtils.js +1 -1
- package/dist/utils/dateUtils.js +4 -4
- package/dist/utils/errors.d.ts +3 -3
- package/dist/utils/errors.js +4 -4
- package/dist/utils/money.d.ts +2 -2
- package/dist/utils/money.js +8 -8
- package/dist/utils/validationError.d.ts +1 -1
- package/dist/utils/validationError.js +1 -1
- package/docs/assets/examples/reconciliation-with-recommendations.json +66 -66
- package/docs/assets/schemas/reconciliation-v2.json +360 -336
- package/esbuild.config.mjs +53 -50
- package/meta.json +12548 -12548
- package/package.json +98 -111
- package/scripts/analyze-bundle.mjs +33 -30
- package/scripts/create-pr-description.js +169 -120
- package/scripts/run-all-tests.js +178 -169
- package/scripts/run-domain-integration-tests.js +28 -18
- package/scripts/run-generate-mcpb.js +19 -17
- package/scripts/run-throttled-integration-tests.js +92 -83
- package/scripts/test-delta-params.mjs +149 -120
- package/scripts/test-recommendations.ts +36 -32
- package/scripts/tmpTransaction.ts +80 -43
- package/scripts/validate-env.js +98 -91
- package/scripts/verify-build.js +78 -76
- package/src/__tests__/comprehensive.integration.test.ts +1281 -1154
- package/src/__tests__/performance.test.ts +723 -671
- package/src/__tests__/setup.ts +442 -395
- package/src/__tests__/smoke.e2e.test.ts +41 -39
- package/src/__tests__/testRunner.ts +314 -295
- package/src/__tests__/testUtils.ts +456 -364
- package/src/__tests__/tools/reconciliation/csvParser.integration.test.ts +109 -107
- package/src/__tests__/tools/reconciliation/real-world.integration.test.ts +41 -41
- package/src/index.ts +68 -59
- package/src/server/CLAUDE.md +480 -0
- package/src/server/YNABMCPServer.ts +821 -794
- package/src/server/__tests__/YNABMCPServer.integration.test.ts +929 -893
- package/src/server/__tests__/YNABMCPServer.test.ts +903 -899
- package/src/server/__tests__/budgetResolver.test.ts +466 -423
- package/src/server/__tests__/cacheManager.test.ts +891 -874
- package/src/server/__tests__/completions.integration.test.ts +115 -106
- package/src/server/__tests__/completions.test.ts +334 -313
- package/src/server/__tests__/config.test.ts +98 -86
- package/src/server/__tests__/deltaCache.merge.test.ts +774 -703
- package/src/server/__tests__/deltaCache.swr.test.ts +198 -153
- package/src/server/__tests__/deltaCache.test.ts +946 -759
- package/src/server/__tests__/diagnostics.test.ts +825 -792
- package/src/server/__tests__/errorHandler.integration.test.ts +512 -462
- package/src/server/__tests__/errorHandler.test.ts +402 -397
- package/src/server/__tests__/prompts.test.ts +424 -347
- package/src/server/__tests__/rateLimiter.test.ts +313 -309
- package/src/server/__tests__/requestLogger.test.ts +443 -403
- package/src/server/__tests__/resources.template.test.ts +196 -185
- package/src/server/__tests__/resources.test.ts +294 -288
- package/src/server/__tests__/security.integration.test.ts +487 -421
- package/src/server/__tests__/securityMiddleware.test.ts +519 -444
- package/src/server/__tests__/server-startup.integration.test.ts +509 -490
- package/src/server/__tests__/serverKnowledgeStore.test.ts +174 -173
- package/src/server/__tests__/toolRegistration.test.ts +239 -210
- package/src/server/__tests__/toolRegistry.test.ts +907 -845
- package/src/server/budgetResolver.ts +221 -181
- package/src/server/cacheKeys.ts +6 -6
- package/src/server/cacheManager.ts +498 -484
- package/src/server/completions.ts +267 -243
- package/src/server/config.ts +35 -14
- package/src/server/deltaCache.merge.ts +146 -128
- package/src/server/deltaCache.ts +352 -309
- package/src/server/diagnostics.ts +257 -242
- package/src/server/errorHandler.ts +747 -744
- package/src/server/prompts.ts +181 -176
- package/src/server/rateLimiter.ts +131 -129
- package/src/server/requestLogger.ts +350 -322
- package/src/server/resources.ts +442 -374
- package/src/server/responseFormatter.ts +41 -37
- package/src/server/securityMiddleware.ts +223 -205
- package/src/server/serverKnowledgeStore.ts +67 -67
- package/src/server/toolRegistry.ts +508 -474
- package/src/tools/CLAUDE.md +604 -0
- package/src/tools/__tests__/accountTools.delta.integration.test.ts +128 -111
- package/src/tools/__tests__/accountTools.integration.test.ts +129 -111
- package/src/tools/__tests__/accountTools.test.ts +685 -638
- package/src/tools/__tests__/adapters.test.ts +142 -108
- package/src/tools/__tests__/budgetTools.delta.integration.test.ts +73 -73
- package/src/tools/__tests__/budgetTools.integration.test.ts +132 -124
- package/src/tools/__tests__/budgetTools.test.ts +442 -413
- package/src/tools/__tests__/categoryTools.delta.integration.test.ts +76 -68
- package/src/tools/__tests__/categoryTools.integration.test.ts +314 -288
- package/src/tools/__tests__/categoryTools.test.ts +656 -625
- package/src/tools/__tests__/compareTransactions/formatter.test.ts +535 -462
- package/src/tools/__tests__/compareTransactions/index.test.ts +378 -358
- package/src/tools/__tests__/compareTransactions/matcher.test.ts +497 -398
- package/src/tools/__tests__/compareTransactions/parser.test.ts +765 -747
- package/src/tools/__tests__/compareTransactions.test.ts +352 -332
- package/src/tools/__tests__/compareTransactions.window.test.ts +150 -146
- package/src/tools/__tests__/deltaFetcher.scheduled.integration.test.ts +69 -65
- package/src/tools/__tests__/deltaFetcher.test.ts +325 -265
- package/src/tools/__tests__/deltaSupport.test.ts +211 -184
- package/src/tools/__tests__/deltaTestUtils.ts +37 -33
- package/src/tools/__tests__/exportTransactions.test.ts +205 -200
- package/src/tools/__tests__/monthTools.delta.integration.test.ts +68 -68
- package/src/tools/__tests__/monthTools.integration.test.ts +178 -166
- package/src/tools/__tests__/monthTools.test.ts +561 -512
- package/src/tools/__tests__/payeeTools.delta.integration.test.ts +68 -68
- package/src/tools/__tests__/payeeTools.integration.test.ts +158 -142
- package/src/tools/__tests__/payeeTools.test.ts +486 -434
- package/src/tools/__tests__/transactionSchemas.test.ts +1202 -1186
- package/src/tools/__tests__/transactionTools.integration.test.ts +875 -825
- package/src/tools/__tests__/transactionTools.test.ts +4923 -4366
- package/src/tools/__tests__/transactionUtils.test.ts +1004 -977
- package/src/tools/__tests__/utilityTools.integration.test.ts +32 -32
- package/src/tools/__tests__/utilityTools.test.ts +68 -58
- package/src/tools/accountTools.ts +293 -271
- package/src/tools/adapters.ts +120 -63
- package/src/tools/budgetTools.ts +121 -116
- package/src/tools/categoryTools.ts +379 -339
- package/src/tools/compareTransactions/formatter.ts +131 -119
- package/src/tools/compareTransactions/index.ts +249 -214
- package/src/tools/compareTransactions/matcher.ts +259 -209
- package/src/tools/compareTransactions/parser.ts +517 -487
- package/src/tools/compareTransactions/types.ts +38 -38
- package/src/tools/compareTransactions.ts +1 -1
- package/src/tools/deltaFetcher.ts +281 -260
- package/src/tools/deltaSupport.ts +264 -259
- package/src/tools/exportTransactions.ts +230 -218
- package/src/tools/monthTools.ts +180 -165
- package/src/tools/payeeTools.ts +152 -140
- package/src/tools/reconcileAdapter.ts +297 -252
- package/src/tools/reconciliation/CLAUDE.md +506 -0
- package/src/tools/reconciliation/__tests__/adapter.causes.test.ts +133 -124
- package/src/tools/reconciliation/__tests__/adapter.test.ts +249 -230
- package/src/tools/reconciliation/__tests__/analyzer.test.ts +408 -400
- package/src/tools/reconciliation/__tests__/csvParser.test.ts +71 -69
- package/src/tools/reconciliation/__tests__/executor.integration.test.ts +348 -323
- package/src/tools/reconciliation/__tests__/executor.progress.test.ts +503 -457
- package/src/tools/reconciliation/__tests__/executor.test.ts +898 -831
- package/src/tools/reconciliation/__tests__/matcher.test.ts +667 -663
- package/src/tools/reconciliation/__tests__/payeeNormalizer.test.ts +296 -276
- package/src/tools/reconciliation/__tests__/recommendationEngine.integration.test.ts +692 -624
- package/src/tools/reconciliation/__tests__/recommendationEngine.test.ts +1008 -989
- package/src/tools/reconciliation/__tests__/reconciliation.delta.integration.test.ts +187 -146
- package/src/tools/reconciliation/__tests__/reportFormatter.test.ts +583 -533
- package/src/tools/reconciliation/__tests__/scenarios/adapterCurrency.scenario.test.ts +75 -74
- package/src/tools/reconciliation/__tests__/scenarios/extremes.scenario.test.ts +70 -62
- package/src/tools/reconciliation/__tests__/scenarios/repeatAmount.scenario.test.ts +102 -88
- package/src/tools/reconciliation/__tests__/schemaUrl.test.ts +56 -55
- package/src/tools/reconciliation/__tests__/signDetector.test.ts +209 -206
- package/src/tools/reconciliation/__tests__/ynabAdapter.test.ts +66 -60
- package/src/tools/reconciliation/analyzer.ts +564 -504
- package/src/tools/reconciliation/csvParser.ts +656 -609
- package/src/tools/reconciliation/executor.ts +1290 -1128
- package/src/tools/reconciliation/index.ts +580 -528
- package/src/tools/reconciliation/matcher.ts +256 -240
- package/src/tools/reconciliation/payeeNormalizer.ts +92 -78
- package/src/tools/reconciliation/recommendationEngine.ts +357 -345
- package/src/tools/reconciliation/reportFormatter.ts +343 -307
- package/src/tools/reconciliation/signDetector.ts +89 -83
- package/src/tools/reconciliation/types.ts +164 -159
- package/src/tools/reconciliation/ynabAdapter.ts +17 -15
- package/src/tools/schemas/CLAUDE.md +546 -0
- package/src/tools/schemas/common.ts +1 -1
- package/src/tools/schemas/outputs/__tests__/accountOutputs.test.ts +410 -409
- package/src/tools/schemas/outputs/__tests__/budgetOutputs.test.ts +305 -299
- package/src/tools/schemas/outputs/__tests__/categoryOutputs.test.ts +431 -430
- package/src/tools/schemas/outputs/__tests__/comparisonOutputs.test.ts +510 -495
- package/src/tools/schemas/outputs/__tests__/dateValidation.test.ts +179 -153
- package/src/tools/schemas/outputs/__tests__/discrepancyDirection.test.ts +293 -254
- package/src/tools/schemas/outputs/__tests__/monthOutputs.test.ts +457 -457
- package/src/tools/schemas/outputs/__tests__/payeeOutputs.test.ts +362 -356
- package/src/tools/schemas/outputs/__tests__/reconciliationOutputs.test.ts +402 -399
- package/src/tools/schemas/outputs/__tests__/transactionMutationSchemas.test.ts +225 -211
- package/src/tools/schemas/outputs/__tests__/transactionOutputs.test.ts +457 -454
- package/src/tools/schemas/outputs/__tests__/utilityOutputs.test.ts +316 -315
- package/src/tools/schemas/outputs/accountOutputs.ts +40 -34
- package/src/tools/schemas/outputs/budgetOutputs.ts +24 -19
- package/src/tools/schemas/outputs/categoryOutputs.ts +76 -56
- package/src/tools/schemas/outputs/comparisonOutputs.ts +192 -169
- package/src/tools/schemas/outputs/index.ts +163 -163
- package/src/tools/schemas/outputs/monthOutputs.ts +95 -80
- package/src/tools/schemas/outputs/payeeOutputs.ts +18 -18
- package/src/tools/schemas/outputs/reconciliationOutputs.ts +386 -373
- package/src/tools/schemas/outputs/transactionMutationOutputs.ts +259 -231
- package/src/tools/schemas/outputs/transactionOutputs.ts +81 -71
- package/src/tools/schemas/outputs/utilityOutputs.ts +90 -84
- package/src/tools/schemas/shared/commonOutputs.ts +27 -19
- package/src/tools/toolCategories.ts +114 -114
- package/src/tools/transactionReadTools.ts +327 -0
- package/src/tools/transactionSchemas.ts +322 -291
- package/src/tools/transactionTools.ts +84 -2246
- package/src/tools/transactionUtils.ts +507 -422
- package/src/tools/transactionWriteTools.ts +2110 -0
- package/src/tools/utilityTools.ts +46 -41
- package/src/types/CLAUDE.md +477 -0
- package/src/types/__tests__/index.test.ts +51 -51
- package/src/types/index.ts +43 -39
- package/src/types/integration-tests.d.ts +26 -26
- package/src/types/reconciliation.ts +29 -29
- package/src/types/toolAnnotations.ts +30 -30
- package/src/types/toolRegistration.ts +43 -32
- package/src/utils/CLAUDE.md +508 -0
- package/src/utils/__tests__/dateUtils.test.ts +174 -168
- package/src/utils/__tests__/money.test.ts +193 -187
- package/src/utils/amountUtils.ts +5 -5
- package/src/utils/baseError.ts +5 -5
- package/src/utils/dateUtils.ts +29 -26
- package/src/utils/errors.ts +14 -14
- package/src/utils/money.ts +66 -52
- package/src/utils/validationError.ts +1 -1
- package/tsconfig.json +29 -29
- package/tsconfig.prod.json +16 -16
- package/vitest-reporters/split-json-reporter.ts +247 -204
- package/vitest.config.ts +99 -95
- package/.prettierignore +0 -10
- package/.prettierrc.json +0 -10
- package/eslint.config.js +0 -49
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
import
|
|
2
|
-
import * as chrono from
|
|
3
|
-
import
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import * as chrono from "chrono-node";
|
|
3
|
+
import Papa from "papaparse";
|
|
4
4
|
export const BANK_PRESETS = {
|
|
5
5
|
td: {
|
|
6
|
-
name:
|
|
6
|
+
name: "TD Canada Trust",
|
|
7
7
|
header: false,
|
|
8
|
-
dateColumn: [
|
|
9
|
-
amountColumn: [
|
|
10
|
-
debitColumn:
|
|
11
|
-
creditColumn:
|
|
12
|
-
descriptionColumn: [
|
|
13
|
-
dateFormat:
|
|
8
|
+
dateColumn: ["0", "Date"],
|
|
9
|
+
amountColumn: ["Amount"],
|
|
10
|
+
debitColumn: "2",
|
|
11
|
+
creditColumn: "3",
|
|
12
|
+
descriptionColumn: ["1", "Description"],
|
|
13
|
+
dateFormat: "MDY",
|
|
14
14
|
},
|
|
15
15
|
rbc: {
|
|
16
|
-
name:
|
|
17
|
-
dateColumn: [
|
|
18
|
-
debitColumn:
|
|
19
|
-
creditColumn:
|
|
20
|
-
descriptionColumn: [
|
|
21
|
-
dateFormat:
|
|
16
|
+
name: "RBC Royal Bank",
|
|
17
|
+
dateColumn: ["Transaction Date", "Date"],
|
|
18
|
+
debitColumn: "Debit",
|
|
19
|
+
creditColumn: "Credit",
|
|
20
|
+
descriptionColumn: ["Description 1", "Description", "Transaction"],
|
|
21
|
+
dateFormat: "YMD",
|
|
22
22
|
},
|
|
23
23
|
scotiabank: {
|
|
24
|
-
name:
|
|
25
|
-
dateColumn: [
|
|
26
|
-
amountColumn: [
|
|
27
|
-
descriptionColumn: [
|
|
28
|
-
dateFormat:
|
|
24
|
+
name: "Scotiabank",
|
|
25
|
+
dateColumn: ["Date", "Transaction Date"],
|
|
26
|
+
amountColumn: ["Amount"],
|
|
27
|
+
descriptionColumn: ["Description", "Transaction Details"],
|
|
28
|
+
dateFormat: "DMY",
|
|
29
29
|
},
|
|
30
30
|
wealthsimple: {
|
|
31
|
-
name:
|
|
32
|
-
dateColumn: [
|
|
33
|
-
amountColumn: [
|
|
34
|
-
descriptionColumn: [
|
|
31
|
+
name: "Wealthsimple",
|
|
32
|
+
dateColumn: ["Date"],
|
|
33
|
+
amountColumn: ["Amount"],
|
|
34
|
+
descriptionColumn: ["Description", "Payee"],
|
|
35
35
|
amountMultiplier: 1,
|
|
36
|
-
dateFormat:
|
|
36
|
+
dateFormat: "YMD",
|
|
37
37
|
},
|
|
38
38
|
tangerine: {
|
|
39
|
-
name:
|
|
40
|
-
dateColumn: [
|
|
41
|
-
amountColumn: [
|
|
42
|
-
descriptionColumn: [
|
|
43
|
-
dateFormat:
|
|
39
|
+
name: "Tangerine",
|
|
40
|
+
dateColumn: ["Date", "Transaction date"],
|
|
41
|
+
amountColumn: ["Amount"],
|
|
42
|
+
descriptionColumn: ["Name", "Transaction name", "Memo"],
|
|
43
|
+
dateFormat: "MDY",
|
|
44
44
|
},
|
|
45
45
|
};
|
|
46
|
-
export const SAFE_DELIMITERS = [
|
|
46
|
+
export const SAFE_DELIMITERS = [",", ";", "\t", "|", " "];
|
|
47
47
|
function validateDelimiter(delimiter) {
|
|
48
48
|
if (!SAFE_DELIMITERS.includes(delimiter)) {
|
|
49
|
-
throw new Error(`Unsafe delimiter "${delimiter}". Allowed delimiters: ${SAFE_DELIMITERS.join(
|
|
49
|
+
throw new Error(`Unsafe delimiter "${delimiter}". Allowed delimiters: ${SAFE_DELIMITERS.join(", ")}`);
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
function autoDetectFormat(content) {
|
|
@@ -68,7 +68,7 @@ function autoDetectFormat(content) {
|
|
|
68
68
|
return { preset: key, header: true };
|
|
69
69
|
}
|
|
70
70
|
if (checkTDPattern(rows)) {
|
|
71
|
-
return { preset:
|
|
71
|
+
return { preset: "td", header: false };
|
|
72
72
|
}
|
|
73
73
|
return undefined;
|
|
74
74
|
}
|
|
@@ -78,7 +78,7 @@ function checkTDPattern(rows) {
|
|
|
78
78
|
return false;
|
|
79
79
|
let matchCount = 0;
|
|
80
80
|
for (const row of validRows) {
|
|
81
|
-
if (!/^\d{1,2}\/\d{1,2}\/\d{4}$/.test(row[0] ||
|
|
81
|
+
if (!/^\d{1,2}\/\d{1,2}\/\d{4}$/.test(row[0] || ""))
|
|
82
82
|
continue;
|
|
83
83
|
const isDebitNumeric = !row[2] || /^-?[\d,.]+$/.test(row[2]);
|
|
84
84
|
const isCreditNumeric = !row[3] || /^-?[\d,.]+$/.test(row[3]);
|
|
@@ -134,9 +134,9 @@ export function parseCSV(content, options = {}) {
|
|
|
134
134
|
for (const err of parsed.errors) {
|
|
135
135
|
errors.push({
|
|
136
136
|
row: err.row ?? 0,
|
|
137
|
-
field:
|
|
137
|
+
field: "csv",
|
|
138
138
|
message: err.message,
|
|
139
|
-
rawValue:
|
|
139
|
+
rawValue: "",
|
|
140
140
|
});
|
|
141
141
|
}
|
|
142
142
|
}
|
|
@@ -156,10 +156,15 @@ export function parseCSV(content, options = {}) {
|
|
|
156
156
|
: undefined;
|
|
157
157
|
const dateCandidates = options.columns?.date
|
|
158
158
|
? [options.columns.date]
|
|
159
|
-
: (preset?.dateColumn ?? [
|
|
159
|
+
: (preset?.dateColumn ?? ["Date", "Transaction Date", "Posted Date"]);
|
|
160
160
|
const descCandidates = options.columns?.description
|
|
161
161
|
? [options.columns.description]
|
|
162
|
-
: (preset?.descriptionColumn ?? [
|
|
162
|
+
: (preset?.descriptionColumn ?? [
|
|
163
|
+
"Description",
|
|
164
|
+
"Payee",
|
|
165
|
+
"Merchant",
|
|
166
|
+
"Name",
|
|
167
|
+
]);
|
|
163
168
|
const dateCol = findColumn(columns, dateCandidates, !hasHeader);
|
|
164
169
|
const descCol = findColumn(columns, descCandidates, !hasHeader);
|
|
165
170
|
let amountCol = null;
|
|
@@ -179,32 +184,32 @@ export function parseCSV(content, options = {}) {
|
|
|
179
184
|
else {
|
|
180
185
|
const amountCandidates = options.columns?.amount
|
|
181
186
|
? [options.columns.amount]
|
|
182
|
-
: (preset?.amountColumn ?? [
|
|
187
|
+
: (preset?.amountColumn ?? ["Amount", "CAD$", "Value"]);
|
|
183
188
|
amountCol = findColumn(columns, amountCandidates, !hasHeader);
|
|
184
189
|
}
|
|
185
190
|
if (!dateCol) {
|
|
186
191
|
errors.push({
|
|
187
192
|
row: 0,
|
|
188
|
-
field:
|
|
189
|
-
message: `Could not identify date column from: ${columns.join(
|
|
190
|
-
rawValue: columns.join(
|
|
193
|
+
field: "date",
|
|
194
|
+
message: `Could not identify date column from: ${columns.join(", ")}. Try using preset option (td, rbc, scotiabank, etc.) or specify columns manually with columns.date`,
|
|
195
|
+
rawValue: columns.join(", "),
|
|
191
196
|
});
|
|
192
197
|
}
|
|
193
198
|
if (!amountCol && (!debitCol || !creditCol)) {
|
|
194
199
|
if (!debitCol && !creditCol) {
|
|
195
200
|
errors.push({
|
|
196
201
|
row: 0,
|
|
197
|
-
field:
|
|
198
|
-
message: `Could not identify amount column from: ${columns.join(
|
|
199
|
-
rawValue: columns.join(
|
|
202
|
+
field: "amount",
|
|
203
|
+
message: `Could not identify amount column from: ${columns.join(", ")}. Try using preset option or specify columns manually with columns.amount (or columns.debit/credit for split columns)`,
|
|
204
|
+
rawValue: columns.join(", "),
|
|
200
205
|
});
|
|
201
206
|
}
|
|
202
207
|
else if (!debitCol || !creditCol) {
|
|
203
208
|
errors.push({
|
|
204
209
|
row: 0,
|
|
205
|
-
field:
|
|
206
|
-
message: `Could not identify debit/credit columns pair from: ${columns.join(
|
|
207
|
-
rawValue: columns.join(
|
|
210
|
+
field: "amount",
|
|
211
|
+
message: `Could not identify debit/credit columns pair from: ${columns.join(", ")}. Found ${debitCol ? "debit" : "credit"} but missing ${debitCol ? "credit" : "debit"}. Specify both with columns.debit and columns.credit`,
|
|
212
|
+
rawValue: columns.join(", "),
|
|
208
213
|
});
|
|
209
214
|
}
|
|
210
215
|
}
|
|
@@ -216,21 +221,21 @@ export function parseCSV(content, options = {}) {
|
|
|
216
221
|
continue;
|
|
217
222
|
const getValue = (colName) => {
|
|
218
223
|
if (!colName)
|
|
219
|
-
return
|
|
224
|
+
return "";
|
|
220
225
|
if (Array.isArray(row)) {
|
|
221
|
-
const idx = parseInt(colName, 10);
|
|
222
|
-
return String(row[idx] ??
|
|
226
|
+
const idx = Number.parseInt(colName, 10);
|
|
227
|
+
return String(row[idx] ?? "");
|
|
223
228
|
}
|
|
224
|
-
return String(row[colName] ??
|
|
229
|
+
return String(row[colName] ?? "");
|
|
225
230
|
};
|
|
226
231
|
const rowNum = i + (hasHeader ? 2 : 1);
|
|
227
232
|
const rowWarnings = [];
|
|
228
|
-
const rawDate = getValue(dateCol)?.trim() ??
|
|
233
|
+
const rawDate = getValue(dateCol)?.trim() ?? "";
|
|
229
234
|
const parsedDate = parseDate(rawDate, dateFormat);
|
|
230
235
|
if (!parsedDate) {
|
|
231
236
|
errors.push({
|
|
232
237
|
row: rowNum,
|
|
233
|
-
field:
|
|
238
|
+
field: "date",
|
|
234
239
|
message: `Could not parse date: "${rawDate}"`,
|
|
235
240
|
rawValue: rawDate,
|
|
236
241
|
});
|
|
@@ -240,12 +245,12 @@ export function parseCSV(content, options = {}) {
|
|
|
240
245
|
let amountMilliunits;
|
|
241
246
|
let rawAmount;
|
|
242
247
|
if (amountCol) {
|
|
243
|
-
rawAmount = getValue(amountCol)?.trim() ??
|
|
248
|
+
rawAmount = getValue(amountCol)?.trim() ?? "";
|
|
244
249
|
const parsedAmount = parseAmount(rawAmount);
|
|
245
250
|
if (!parsedAmount.valid) {
|
|
246
251
|
errors.push({
|
|
247
252
|
row: rowNum,
|
|
248
|
-
field:
|
|
253
|
+
field: "amount",
|
|
249
254
|
message: parsedAmount.reason ?? `Invalid amount: "${rawAmount}"`,
|
|
250
255
|
rawValue: rawAmount,
|
|
251
256
|
});
|
|
@@ -254,15 +259,15 @@ export function parseCSV(content, options = {}) {
|
|
|
254
259
|
amountMilliunits = parsedAmount.valueMilliunits;
|
|
255
260
|
}
|
|
256
261
|
else if (debitCol && creditCol) {
|
|
257
|
-
const debit = getValue(debitCol)?.trim() ??
|
|
258
|
-
const credit = getValue(creditCol)?.trim() ??
|
|
262
|
+
const debit = getValue(debitCol)?.trim() ?? "";
|
|
263
|
+
const credit = getValue(creditCol)?.trim() ?? "";
|
|
259
264
|
rawAmount = debit || credit;
|
|
260
265
|
const parsedDebit = parseAmount(debit);
|
|
261
266
|
const parsedCredit = parseAmount(credit);
|
|
262
267
|
if (!parsedDebit.valid && debit) {
|
|
263
268
|
errors.push({
|
|
264
269
|
row: rowNum,
|
|
265
|
-
field:
|
|
270
|
+
field: "amount",
|
|
266
271
|
message: parsedDebit.reason ?? `Invalid debit amount: "${debit}"`,
|
|
267
272
|
rawValue: debit,
|
|
268
273
|
});
|
|
@@ -271,14 +276,18 @@ export function parseCSV(content, options = {}) {
|
|
|
271
276
|
if (!parsedCredit.valid && credit) {
|
|
272
277
|
errors.push({
|
|
273
278
|
row: rowNum,
|
|
274
|
-
field:
|
|
279
|
+
field: "amount",
|
|
275
280
|
message: parsedCredit.reason ?? `Invalid credit amount: "${credit}"`,
|
|
276
281
|
rawValue: credit,
|
|
277
282
|
});
|
|
278
283
|
continue;
|
|
279
284
|
}
|
|
280
|
-
const debitMilliunits = parsedDebit.valid
|
|
281
|
-
|
|
285
|
+
const debitMilliunits = parsedDebit.valid
|
|
286
|
+
? parsedDebit.valueMilliunits
|
|
287
|
+
: 0;
|
|
288
|
+
const creditMilliunits = parsedCredit.valid
|
|
289
|
+
? parsedCredit.valueMilliunits
|
|
290
|
+
: 0;
|
|
282
291
|
if (Math.abs(debitMilliunits) > 0 && Math.abs(creditMilliunits) > 0) {
|
|
283
292
|
const warning = `Both Debit (${debit}) and Credit (${credit}) have values - using Debit`;
|
|
284
293
|
rowWarnings.push(warning);
|
|
@@ -293,8 +302,8 @@ export function parseCSV(content, options = {}) {
|
|
|
293
302
|
else {
|
|
294
303
|
errors.push({
|
|
295
304
|
row: rowNum,
|
|
296
|
-
field:
|
|
297
|
-
message:
|
|
305
|
+
field: "amount",
|
|
306
|
+
message: "Missing debit/credit amount",
|
|
298
307
|
rawValue: `${debit}|${credit}`,
|
|
299
308
|
});
|
|
300
309
|
continue;
|
|
@@ -308,20 +317,22 @@ export function parseCSV(content, options = {}) {
|
|
|
308
317
|
else {
|
|
309
318
|
continue;
|
|
310
319
|
}
|
|
311
|
-
const multiplier = options.invertAmounts
|
|
320
|
+
const multiplier = options.invertAmounts
|
|
321
|
+
? -1
|
|
322
|
+
: (preset?.amountMultiplier ?? 1);
|
|
312
323
|
amountMilliunits *= multiplier;
|
|
313
|
-
let rawDesc = getValue(descCol)?.trim() ??
|
|
324
|
+
let rawDesc = getValue(descCol)?.trim() ?? "";
|
|
314
325
|
rawDesc = rawDesc
|
|
315
|
-
.replace(/[\u0000-\u001F\u007F-\u009F]/g,
|
|
316
|
-
.replace(/[\u202A-\u202E\u2066-\u2069]/g,
|
|
317
|
-
.replace(
|
|
318
|
-
.replace(/[\u2028-\u2029]/g,
|
|
326
|
+
.replace(/[\u0000-\u001F\u007F-\u009F]/g, "")
|
|
327
|
+
.replace(/[\u202A-\u202E\u2066-\u2069]/g, "")
|
|
328
|
+
.replace(/\u200B|\u200C|\u200D|\uFEFF/g, "")
|
|
329
|
+
.replace(/[\u2028-\u2029]/g, "")
|
|
319
330
|
.substring(0, 500);
|
|
320
331
|
transactions.push({
|
|
321
332
|
id: randomUUID(),
|
|
322
333
|
date: dateStr,
|
|
323
334
|
amount: amountMilliunits,
|
|
324
|
-
payee: rawDesc ||
|
|
335
|
+
payee: rawDesc || "Unknown",
|
|
325
336
|
sourceRow: rowNum,
|
|
326
337
|
raw: {
|
|
327
338
|
date: rawDate,
|
|
@@ -336,7 +347,7 @@ export function parseCSV(content, options = {}) {
|
|
|
336
347
|
errors,
|
|
337
348
|
warnings,
|
|
338
349
|
meta: {
|
|
339
|
-
detectedDelimiter: parsed.meta.delimiter ||
|
|
350
|
+
detectedDelimiter: parsed.meta.delimiter || ",",
|
|
340
351
|
detectedColumns: columns,
|
|
341
352
|
totalRows: rows.length,
|
|
342
353
|
validRows: transactions.length,
|
|
@@ -350,27 +361,33 @@ function parseDate(raw, formatHint) {
|
|
|
350
361
|
const isoMatch = raw.match(/^(\d{4})-(\d{2})-(\d{2})/);
|
|
351
362
|
if (isoMatch) {
|
|
352
363
|
const [, year, month, day] = isoMatch;
|
|
353
|
-
|
|
364
|
+
if (!year || !month || !day)
|
|
365
|
+
return null;
|
|
366
|
+
return new Date(Date.UTC(Number.parseInt(year, 10), Number.parseInt(month, 10) - 1, Number.parseInt(day, 10)));
|
|
354
367
|
}
|
|
355
368
|
const numericMatch = raw.match(/^(\d{1,4})[/-](\d{1,2})[/-](\d{1,4})$/);
|
|
356
369
|
if (numericMatch && formatHint) {
|
|
357
370
|
const [, a, b, c] = numericMatch;
|
|
358
|
-
|
|
371
|
+
if (!a || !b || !c)
|
|
372
|
+
return null;
|
|
373
|
+
let year;
|
|
374
|
+
let month;
|
|
375
|
+
let day;
|
|
359
376
|
switch (formatHint) {
|
|
360
|
-
case
|
|
361
|
-
year = parseInt(a);
|
|
362
|
-
month = parseInt(b);
|
|
363
|
-
day = parseInt(c);
|
|
377
|
+
case "YMD":
|
|
378
|
+
year = Number.parseInt(a, 10);
|
|
379
|
+
month = Number.parseInt(b, 10);
|
|
380
|
+
day = Number.parseInt(c, 10);
|
|
364
381
|
break;
|
|
365
|
-
case
|
|
366
|
-
month = parseInt(a);
|
|
367
|
-
day = parseInt(b);
|
|
368
|
-
year = parseInt(c);
|
|
382
|
+
case "MDY":
|
|
383
|
+
month = Number.parseInt(a, 10);
|
|
384
|
+
day = Number.parseInt(b, 10);
|
|
385
|
+
year = Number.parseInt(c, 10);
|
|
369
386
|
break;
|
|
370
|
-
case
|
|
371
|
-
day = parseInt(a);
|
|
372
|
-
month = parseInt(b);
|
|
373
|
-
year = parseInt(c);
|
|
387
|
+
case "DMY":
|
|
388
|
+
day = Number.parseInt(a, 10);
|
|
389
|
+
month = Number.parseInt(b, 10);
|
|
390
|
+
year = Number.parseInt(c, 10);
|
|
374
391
|
break;
|
|
375
392
|
}
|
|
376
393
|
if (year < 100)
|
|
@@ -387,8 +404,8 @@ function parseDate(raw, formatHint) {
|
|
|
387
404
|
}
|
|
388
405
|
function formatLocalDate(date) {
|
|
389
406
|
const year = date.getUTCFullYear();
|
|
390
|
-
const month = String(date.getUTCMonth() + 1).padStart(2,
|
|
391
|
-
const day = String(date.getUTCDate()).padStart(2,
|
|
407
|
+
const month = String(date.getUTCMonth() + 1).padStart(2, "0");
|
|
408
|
+
const day = String(date.getUTCDate()).padStart(2, "0");
|
|
392
409
|
return `${year}-${month}-${day}`;
|
|
393
410
|
}
|
|
394
411
|
function findColumn(available, candidates, exactIndex = false) {
|
|
@@ -417,14 +434,14 @@ function findColumn(available, candidates, exactIndex = false) {
|
|
|
417
434
|
}
|
|
418
435
|
function detectPreset(columns) {
|
|
419
436
|
const colSet = new Set(columns.map((c) => c.toLowerCase()));
|
|
420
|
-
if (colSet.has(
|
|
421
|
-
return BANK_PRESETS[
|
|
437
|
+
if (colSet.has("description 1") || colSet.has("account type")) {
|
|
438
|
+
return BANK_PRESETS["rbc"];
|
|
422
439
|
}
|
|
423
|
-
if (columns.some((c) => c.toLowerCase().includes(
|
|
424
|
-
return BANK_PRESETS[
|
|
440
|
+
if (columns.some((c) => c.toLowerCase().includes("cad$"))) {
|
|
441
|
+
return BANK_PRESETS["td"];
|
|
425
442
|
}
|
|
426
|
-
if (colSet.has(
|
|
427
|
-
return BANK_PRESETS[
|
|
443
|
+
if (colSet.has("date") && colSet.has("description") && colSet.has("amount")) {
|
|
444
|
+
return BANK_PRESETS["td"];
|
|
428
445
|
}
|
|
429
446
|
return undefined;
|
|
430
447
|
}
|
|
@@ -432,21 +449,28 @@ const CURRENCY_SYMBOLS = /[$€£¥]/g;
|
|
|
432
449
|
const CURRENCY_CODES = /\b(CAD|USD|EUR|GBP)\b/gi;
|
|
433
450
|
function parseAmount(str) {
|
|
434
451
|
if (!str || !str.trim()) {
|
|
435
|
-
return { valid: false, valueMilliunits: 0, reason:
|
|
452
|
+
return { valid: false, valueMilliunits: 0, reason: "Missing amount value" };
|
|
436
453
|
}
|
|
437
|
-
let cleaned = str
|
|
438
|
-
|
|
439
|
-
|
|
454
|
+
let cleaned = str
|
|
455
|
+
.replace(CURRENCY_SYMBOLS, "")
|
|
456
|
+
.replace(CURRENCY_CODES, "")
|
|
457
|
+
.trim();
|
|
458
|
+
if (cleaned.startsWith("(") && cleaned.endsWith(")")) {
|
|
459
|
+
cleaned = `-${cleaned.slice(1, -1)}`;
|
|
440
460
|
}
|
|
441
461
|
if (/^-?\d{1,3}(\.\d{3})+,\d{2}$/.test(cleaned)) {
|
|
442
|
-
cleaned = cleaned.replace(/\./g,
|
|
462
|
+
cleaned = cleaned.replace(/\./g, "").replace(",", ".");
|
|
443
463
|
}
|
|
444
|
-
if (cleaned.includes(
|
|
445
|
-
cleaned = cleaned.replace(/,/g,
|
|
464
|
+
if (cleaned.includes(".")) {
|
|
465
|
+
cleaned = cleaned.replace(/,/g, "");
|
|
446
466
|
}
|
|
447
|
-
const dollars = parseFloat(cleaned);
|
|
467
|
+
const dollars = Number.parseFloat(cleaned);
|
|
448
468
|
if (!Number.isFinite(dollars)) {
|
|
449
|
-
return {
|
|
469
|
+
return {
|
|
470
|
+
valid: false,
|
|
471
|
+
valueMilliunits: 0,
|
|
472
|
+
reason: `Invalid amount: "${str}"`,
|
|
473
|
+
};
|
|
450
474
|
}
|
|
451
475
|
return { valid: true, valueMilliunits: Math.round(dollars * 1000) };
|
|
452
476
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type * as ynab from
|
|
2
|
-
import type { ProgressCallback } from
|
|
3
|
-
import type {
|
|
4
|
-
import type {
|
|
1
|
+
import type * as ynab from "ynab";
|
|
2
|
+
import type { ProgressCallback } from "../../server/toolRegistry.js";
|
|
3
|
+
import type { ReconcileAccountRequest } from "./index.js";
|
|
4
|
+
import type { ReconciliationAnalysis } from "./types.js";
|
|
5
5
|
export interface AccountSnapshot {
|
|
6
6
|
balance: number;
|
|
7
7
|
cleared_balance: number;
|