@dizzlkheinz/ynab-mcpb 0.12.1
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/.chunkhound.json +11 -0
- package/.code/agents/0427d95e-edca-431f-a214-5e53264e29c4/error.txt +8 -0
- package/.code/agents/0d675174-d1e1-41c3-9975-4c2e275819a9/error.txt +3 -0
- package/.code/agents/0d8c5afd-4787-422b-abf8-2e5943fc7e67/error.txt +3 -0
- package/.code/agents/0ec34a70-ed5d-4b9e-bee4-bb0e4cccbc4b/error.txt +1 -0
- package/.code/agents/0ef51a21-1ab1-49d7-9561-0eaa43875ebc/error.txt +12 -0
- package/.code/agents/15db95d7-abad-4b4d-9c3b-8446089cb61d/error.txt +1 -0
- package/.code/agents/19ab9acb-f675-4ff0-902a-09a5476f8149/error.txt +1 -0
- package/.code/agents/1ef7e12d-f6ff-4897-8a9b-152d523d898e/error.txt +5 -0
- package/.code/agents/2465/exec-call_lroN9KKzJVWC7t5423DK1nT9.txt +1453 -0
- package/.code/agents/28edb6fe-95a9-41a0-ae69-aa0100d26c0c/error.txt +8 -0
- package/.code/agents/2ae40cf5-b4bf-42e2-92bf-7ea350a7755e/error.txt +9 -0
- package/.code/agents/2bfc4e1f-ac4b-45a5-b6df-bf89d4dbb54c/error.txt +1 -0
- package/.code/agents/2e2e1134-eff0-49be-ba25-8e2c3468a564/error.txt +5 -0
- package/.code/agents/3/exec-call_203OC4TNVkLxW7z2HCVEQ1cM.txt +81 -0
- package/.code/agents/3/exec-call_SS5T0XSiXB4LSNzUKTl75wkh.txt +610 -0
- package/.code/agents/3322c003-ce5e-48e3-a342-f5049c5bf9a2/error.txt +1 -0
- package/.code/agents/391e9b08-1ebc-468c-9bcd-6d0cc3193b37/error.txt +1 -0
- package/.code/agents/3ab0aa84-b7bb-4054-afa3-40b8fd7d3be0/error.txt +1 -0
- package/.code/agents/3bed368d-50fe-477e-aee3-a6707eaa1ab9/error.txt +3 -0
- package/.code/agents/3e40b925-db12-442f-8d7a-a25fc69a6672/error.txt +8 -0
- package/.code/agents/414d5776-cf58-41f3-9328-a6daed503a50/error.txt +5 -0
- package/.code/agents/42687751-4565-4610-b240-67835b17d861/error.txt +1 -0
- package/.code/agents/46b98876-1a39-43c9-9e2f-507ca6d47335/error.txt +9 -0
- package/.code/agents/4a7d9491-b26f-43dd-850d-2ecdc49b5d1b/error.txt +1 -0
- package/.code/agents/4e60f00a-1b3e-447f-87f3-7faf9deddec3/error.txt +13 -0
- package/.code/agents/5138fc1c-4d49-4b74-a7da-ccdb3a8e44e7/error.txt +14 -0
- package/.code/agents/521cff39-a7a3-42e5-a557-134f0f7daaa0/error.txt +5 -0
- package/.code/agents/53302dc5-3857-4413-9a47-9e0f64a51dc4/error.txt +5 -0
- package/.code/agents/567c7c2e-6a6f-4761-a08d-d36deeb2e0ac/error.txt +5 -0
- package/.code/agents/57b00845-80dc-47c9-953c-3028d16275d6/error.txt +3 -0
- package/.code/agents/593d9005-c2a5-48fd-8813-ece0d3f2de96/error.txt +1 -0
- package/.code/agents/5a112e66-0e1a-42f9-877c-53af56ea3551/error.txt +1 -0
- package/.code/agents/5b05e8ed-7788-4738-b7ee-9faa8180f992/error.txt +5 -0
- package/.code/agents/5f888d6f-d7ca-4ac8-be23-9ea1bf753951/error.txt +5 -0
- package/.code/agents/607db3ab-e4b0-435b-b497-93e9aa525549/error.txt +8 -0
- package/.code/agents/67dcb2a2-900f-4c78-b3fc-80b5213e0ddf/error.txt +8 -0
- package/.code/agents/69ad848c-4e98-49b3-b16c-0094ac2d1759/error.txt +5 -0
- package/.code/agents/6c9cfc5f-0d0b-445c-b121-9f60082c4f70/error.txt +1 -0
- package/.code/agents/6f6f8f77-4ab0-4f6e-9f30-40e8be0bd8f5/error.txt +1 -0
- package/.code/agents/72a7cde4-fa8a-4024-9038-27faa550539b/error.txt +1 -0
- package/.code/agents/7b48335c-8247-43aa-9949-5f820ba8e199/error.txt +1 -0
- package/.code/agents/80944249-bea9-4ac5-87de-a666c4df306e/error.txt +1 -0
- package/.code/agents/826099df-1b66-4186-a915-7eb59f9db19d/error.txt +5 -0
- package/.code/agents/8291d158-18a8-4a92-b799-4e9a4d9cce88/error.txt +1 -0
- package/.code/agents/82fb71a3-20fb-4341-804a-a2fc900f95bc/error.txt +1 -0
- package/.code/agents/855790ea-54ee-43e4-8209-a66994e37590/error.txt +1 -0
- package/.code/agents/88ce3a2e-04f2-42be-9062-bf97aa798da0/error.txt +3 -0
- package/.code/agents/9a17e398-b6ed-4218-bb55-bc64a8d38ce8/error.txt +8 -0
- package/.code/agents/9a4f4bfc-a2a6-4f40-a896-9335b41a7ed1/error.txt +1 -0
- package/.code/agents/9b633e55-ef84-47d6-94bb-fd3dd172ad97/error.txt +1 -0
- package/.code/agents/9b81f3ab-c72b-4a81-9a8f-28a49ddba84a/error.txt +8 -0
- package/.code/agents/a35daf29-b2d1-4aef-9b42-dad63a76bd47/error.txt +3 -0
- package/.code/agents/a81990cc-69ee-44d2-b907-17403c9bc5d7/error.txt +5 -0
- package/.code/agents/ab56260a-4a83-4ad4-9410-f88a23d6520a/error.txt +1 -0
- package/.code/agents/ad722c31-2d1d-45f7-bae2-3f02ca455b60/error.txt +1 -0
- package/.code/agents/b62e8690-3324-4b97-9309-731bee79416b/error.txt +5 -0
- package/.code/agents/baf60a3a-752b-4ad8-99d6-df32423ed2eb/error.txt +1 -0
- package/.code/agents/be049042-7dcb-4ac8-9beb-c8f1aea67742/error.txt +14 -0
- package/.code/agents/bed1dcb4-bfce-4a9f-8594-0f994962aafd/error.txt +1 -0
- package/.code/agents/c324a6cf-e935-4ede-9529-b3ebc18e8d6b/error.txt +5 -0
- package/.code/agents/c37c06ff-dfe3-43f2-9bbc-3ec73ec8f41d/error.txt +5 -0
- package/.code/agents/c8cd6671-433a-456b-9f88-e51cb2df6bfc/error.txt +11 -0
- package/.code/agents/ca2ccb67-2f24-428e-b27d-9365beadd140/error.txt +1 -0
- package/.code/agents/cf08c0c8-e7f0-423e-93ba-547e8e818340/error.txt +8 -0
- package/.code/agents/d579c74f-874b-40a4-9d56-ced1eb6a701d/error.txt +1 -0
- package/.code/agents/df412c98-7378-4deb-8e1e-76c416931181/error.txt +3 -0
- package/.code/agents/e5134eb3-2af4-45b0-8998-051cb4afdb45/error.txt +3 -0
- package/.code/agents/e6308471-aa45-4e9e-9496-2e9404164d97/error.txt +8 -0
- package/.code/agents/e7bd8bc7-23fb-4f46-98dc-b0dcf11b75a1/error.txt +1 -0
- package/.code/agents/e92bec35-378d-4fe1-8ac0-6e1bb3c86911/error.txt +5 -0
- package/.code/agents/ed918fbf-2dc4-4aa2-bfc5-04b65d9471ea/error.txt +1 -0
- package/.code/agents/ef1d756f-b272-48fc-8729-f05c494674f7/error.txt +1 -0
- package/.code/agents/ef359853-0249-4e41-a804-c0fc459fe456/error.txt +1 -0
- package/.code/agents/effc7b4a-4b90-40a0-8c86-a7a99d2d5fd2/error.txt +1 -0
- package/.code/agents/fa15f8d5-8359-4a8b-83a3-2f2056b3ff40/error.txt +3 -0
- package/.code/agents/fbef4193-eadf-4c8a-83ff-4878a6310f25/error.txt +8 -0
- package/.code/agents/fd0a4b4a-fda4-4964-a6d6-2b8a2da387c6/error.txt +1 -0
- package/.dxtignore +57 -0
- package/.env.example +44 -0
- package/.gemini/settings.json +8 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +41 -0
- package/.github/ISSUE_TEMPLATE/config.yml +5 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +24 -0
- package/.github/ISSUE_TEMPLATE/release_checklist.md +31 -0
- package/.github/pull_request_template.md +41 -0
- package/.github/workflows/ci-tests.yml +41 -0
- package/.github/workflows/claude-code-review.yml +57 -0
- package/.github/workflows/claude.yml +50 -0
- package/.github/workflows/full-integration.yml +22 -0
- package/.github/workflows/pr-description-check.yml +88 -0
- package/.github/workflows/publish.yml +33 -0
- package/.github/workflows/release.yml +89 -0
- package/.mcpbignore +58 -0
- package/.prettierignore +10 -0
- package/.prettierrc.json +10 -0
- package/ADOS-2-Module-1-Complete-Manual.md +757 -0
- package/AGENTS.md +36 -0
- package/CHANGELOG.md +187 -0
- package/CLAUDE.md +414 -0
- package/CODEREVIEW_RESPONSE.md +128 -0
- package/LICENSE +17 -0
- package/NUL +1 -0
- package/README.md +222 -0
- package/SCHEMA_IMPROVEMENT_SUMMARY.md +120 -0
- package/TESTING_NOTES.md +217 -0
- package/WARP.md +245 -0
- package/accountactivity-merged.csv +149 -0
- package/bin/ynab-mcp-server.cjs +4 -0
- package/bin/ynab-mcp-server.js +8 -0
- package/bundle-analysis.html +13110 -0
- package/dist/bundle/index.cjs +124 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +85 -0
- package/dist/server/YNABMCPServer.d.ts +264 -0
- package/dist/server/YNABMCPServer.js +845 -0
- package/dist/server/budgetResolver.d.ts +15 -0
- package/dist/server/budgetResolver.js +99 -0
- package/dist/server/cacheManager.d.ts +74 -0
- package/dist/server/cacheManager.js +306 -0
- package/dist/server/config.d.ts +3 -0
- package/dist/server/config.js +19 -0
- package/dist/server/deltaCache.d.ts +61 -0
- package/dist/server/deltaCache.js +206 -0
- package/dist/server/deltaCache.merge.d.ts +9 -0
- package/dist/server/deltaCache.merge.js +111 -0
- package/dist/server/diagnostics.d.ts +90 -0
- package/dist/server/diagnostics.js +163 -0
- package/dist/server/errorHandler.d.ts +69 -0
- package/dist/server/errorHandler.js +524 -0
- package/dist/server/prompts.d.ts +31 -0
- package/dist/server/prompts.js +205 -0
- package/dist/server/rateLimiter.d.ts +27 -0
- package/dist/server/rateLimiter.js +82 -0
- package/dist/server/requestLogger.d.ts +62 -0
- package/dist/server/requestLogger.js +190 -0
- package/dist/server/resources.d.ts +39 -0
- package/dist/server/resources.js +85 -0
- package/dist/server/responseFormatter.d.ts +14 -0
- package/dist/server/responseFormatter.js +42 -0
- package/dist/server/securityMiddleware.d.ts +87 -0
- package/dist/server/securityMiddleware.js +117 -0
- package/dist/server/serverKnowledgeStore.d.ts +11 -0
- package/dist/server/serverKnowledgeStore.js +42 -0
- package/dist/server/toolRegistry.d.ts +85 -0
- package/dist/server/toolRegistry.js +272 -0
- package/dist/tools/__tests__/deltaTestUtils.d.ts +18 -0
- package/dist/tools/__tests__/deltaTestUtils.js +26 -0
- package/dist/tools/accountTools.d.ts +37 -0
- package/dist/tools/accountTools.js +175 -0
- package/dist/tools/budgetTools.d.ts +10 -0
- package/dist/tools/budgetTools.js +68 -0
- package/dist/tools/categoryTools.d.ts +27 -0
- package/dist/tools/categoryTools.js +232 -0
- package/dist/tools/compareTransactions/formatter.d.ts +71 -0
- package/dist/tools/compareTransactions/formatter.js +97 -0
- package/dist/tools/compareTransactions/index.d.ts +30 -0
- package/dist/tools/compareTransactions/index.js +160 -0
- package/dist/tools/compareTransactions/matcher.d.ts +12 -0
- package/dist/tools/compareTransactions/matcher.js +140 -0
- package/dist/tools/compareTransactions/parser.d.ts +14 -0
- package/dist/tools/compareTransactions/parser.js +430 -0
- package/dist/tools/compareTransactions/types.d.ts +27 -0
- package/dist/tools/compareTransactions/types.js +1 -0
- package/dist/tools/compareTransactions.d.ts +1 -0
- package/dist/tools/compareTransactions.js +1 -0
- package/dist/tools/deltaFetcher.d.ts +22 -0
- package/dist/tools/deltaFetcher.js +137 -0
- package/dist/tools/deltaSupport.d.ts +20 -0
- package/dist/tools/deltaSupport.js +176 -0
- package/dist/tools/exportTransactions.d.ts +17 -0
- package/dist/tools/exportTransactions.js +191 -0
- package/dist/tools/monthTools.d.ts +16 -0
- package/dist/tools/monthTools.js +107 -0
- package/dist/tools/payeeTools.d.ts +17 -0
- package/dist/tools/payeeTools.js +82 -0
- package/dist/tools/reconcileAdapter.d.ts +25 -0
- package/dist/tools/reconcileAdapter.js +167 -0
- package/dist/tools/reconciliation/analyzer.d.ts +3 -0
- package/dist/tools/reconciliation/analyzer.js +567 -0
- package/dist/tools/reconciliation/executor.d.ts +94 -0
- package/dist/tools/reconciliation/executor.js +611 -0
- package/dist/tools/reconciliation/index.d.ts +54 -0
- package/dist/tools/reconciliation/index.js +249 -0
- package/dist/tools/reconciliation/matcher.d.ts +3 -0
- package/dist/tools/reconciliation/matcher.js +160 -0
- package/dist/tools/reconciliation/payeeNormalizer.d.ts +6 -0
- package/dist/tools/reconciliation/payeeNormalizer.js +77 -0
- package/dist/tools/reconciliation/recommendationEngine.d.ts +2 -0
- package/dist/tools/reconciliation/recommendationEngine.js +273 -0
- package/dist/tools/reconciliation/reportFormatter.d.ts +13 -0
- package/dist/tools/reconciliation/reportFormatter.js +214 -0
- package/dist/tools/reconciliation/types.d.ts +172 -0
- package/dist/tools/reconciliation/types.js +7 -0
- package/dist/tools/schemas/outputs/accountOutputs.d.ts +58 -0
- package/dist/tools/schemas/outputs/accountOutputs.js +24 -0
- package/dist/tools/schemas/outputs/budgetOutputs.d.ts +48 -0
- package/dist/tools/schemas/outputs/budgetOutputs.js +15 -0
- package/dist/tools/schemas/outputs/categoryOutputs.d.ts +93 -0
- package/dist/tools/schemas/outputs/categoryOutputs.js +37 -0
- package/dist/tools/schemas/outputs/comparisonOutputs.d.ts +269 -0
- package/dist/tools/schemas/outputs/comparisonOutputs.js +181 -0
- package/dist/tools/schemas/outputs/index.d.ts +14 -0
- package/dist/tools/schemas/outputs/index.js +14 -0
- package/dist/tools/schemas/outputs/monthOutputs.d.ts +122 -0
- package/dist/tools/schemas/outputs/monthOutputs.js +51 -0
- package/dist/tools/schemas/outputs/payeeOutputs.d.ts +34 -0
- package/dist/tools/schemas/outputs/payeeOutputs.js +16 -0
- package/dist/tools/schemas/outputs/reconciliationOutputs.d.ts +1275 -0
- package/dist/tools/schemas/outputs/reconciliationOutputs.js +377 -0
- package/dist/tools/schemas/outputs/transactionMutationOutputs.d.ts +717 -0
- package/dist/tools/schemas/outputs/transactionMutationOutputs.js +260 -0
- package/dist/tools/schemas/outputs/transactionOutputs.d.ts +98 -0
- package/dist/tools/schemas/outputs/transactionOutputs.js +49 -0
- package/dist/tools/schemas/outputs/utilityOutputs.d.ts +219 -0
- package/dist/tools/schemas/outputs/utilityOutputs.js +120 -0
- package/dist/tools/schemas/shared/commonOutputs.d.ts +24 -0
- package/dist/tools/schemas/shared/commonOutputs.js +27 -0
- package/dist/tools/toolCategories.d.ts +32 -0
- package/dist/tools/toolCategories.js +32 -0
- package/dist/tools/transactionTools.d.ts +315 -0
- package/dist/tools/transactionTools.js +1722 -0
- package/dist/tools/utilityTools.d.ts +10 -0
- package/dist/tools/utilityTools.js +56 -0
- package/dist/types/index.d.ts +20 -0
- package/dist/types/index.js +16 -0
- package/dist/types/toolAnnotations.d.ts +7 -0
- package/dist/types/toolAnnotations.js +1 -0
- package/dist/utils/amountUtils.d.ts +3 -0
- package/dist/utils/amountUtils.js +10 -0
- package/dist/utils/dateUtils.d.ts +9 -0
- package/dist/utils/dateUtils.js +43 -0
- package/dist/utils/money.d.ts +21 -0
- package/dist/utils/money.js +51 -0
- package/docs/README.md +72 -0
- package/docs/assets/examples/reconciliation-with-recommendations.json +68 -0
- package/docs/assets/schemas/reconciliation-v2.json +338 -0
- package/docs/getting-started/CONFIGURATION.md +175 -0
- package/docs/getting-started/INSTALLATION.md +333 -0
- package/docs/getting-started/QUICKSTART.md +282 -0
- package/docs/guides/ARCHITECTURE.md +650 -0
- package/docs/guides/DEPLOYMENT.md +189 -0
- package/docs/guides/INTEGRATION_TESTING.md +730 -0
- package/docs/guides/TESTING.md +591 -0
- package/docs/reconciliation-flow.md +83 -0
- package/docs/reference/API.md +1450 -0
- package/docs/reference/EXAMPLES.md +946 -0
- package/docs/reference/TOOLS.md +348 -0
- package/docs/reference/TROUBLESHOOTING.md +481 -0
- package/esbuild.config.mjs +68 -0
- package/eslint.config.js +49 -0
- package/fix-types.sh +17 -0
- package/meta.json +12550 -0
- package/package.json +105 -0
- package/package.json.tmp +105 -0
- package/scripts/analyze-bundle.mjs +41 -0
- package/scripts/create-pr-description.js +203 -0
- package/scripts/generate-mcpb.ps1 +96 -0
- package/scripts/run-domain-integration-tests.js +33 -0
- package/scripts/run-generate-mcpb.js +29 -0
- package/scripts/run-throttled-integration-tests.js +116 -0
- package/scripts/test-delta-params.mjs +140 -0
- package/scripts/test-recommendations.ts +53 -0
- package/scripts/tmpTransaction.ts +48 -0
- package/scripts/validate-env.js +122 -0
- package/scripts/verify-build.js +105 -0
- package/scripts/watch-and-restart.ps1 +50 -0
- package/src/__tests__/comprehensive.integration.test.ts +1196 -0
- package/src/__tests__/delta.performance.test.ts +80 -0
- package/src/__tests__/performance.test.ts +725 -0
- package/src/__tests__/setup.ts +449 -0
- package/src/__tests__/testRunner.ts +444 -0
- package/src/__tests__/testUtils.ts +563 -0
- package/src/__tests__/workflows.e2e.test.ts +1675 -0
- package/src/index.ts +124 -0
- package/src/server/.gitkeep +1 -0
- package/src/server/YNABMCPServer.ts +1188 -0
- package/src/server/__tests__/YNABMCPServer.integration.test.ts +903 -0
- package/src/server/__tests__/YNABMCPServer.test.ts +894 -0
- package/src/server/__tests__/budgetResolver.test.ts +425 -0
- package/src/server/__tests__/cacheManager.test.ts +880 -0
- package/src/server/__tests__/config.test.ts +166 -0
- package/src/server/__tests__/deltaCache.merge.test.ts +724 -0
- package/src/server/__tests__/deltaCache.swr.test.ts +168 -0
- package/src/server/__tests__/deltaCache.test.ts +774 -0
- package/src/server/__tests__/diagnostics.test.ts +823 -0
- package/src/server/__tests__/errorHandler.integration.test.ts +466 -0
- package/src/server/__tests__/errorHandler.test.ts +416 -0
- package/src/server/__tests__/prompts.test.ts +354 -0
- package/src/server/__tests__/rateLimiter.test.ts +314 -0
- package/src/server/__tests__/requestLogger.test.ts +408 -0
- package/src/server/__tests__/resources.test.ts +299 -0
- package/src/server/__tests__/security.integration.test.ts +426 -0
- package/src/server/__tests__/securityMiddleware.test.ts +449 -0
- package/src/server/__tests__/server-startup.integration.test.ts +477 -0
- package/src/server/__tests__/serverKnowledgeStore.test.ts +174 -0
- package/src/server/__tests__/toolRegistry.test.ts +855 -0
- package/src/server/budgetResolver.ts +235 -0
- package/src/server/cacheManager.ts +503 -0
- package/src/server/config.ts +41 -0
- package/src/server/deltaCache.merge.ts +149 -0
- package/src/server/deltaCache.ts +341 -0
- package/src/server/diagnostics.ts +338 -0
- package/src/server/errorHandler.ts +756 -0
- package/src/server/prompts.ts +291 -0
- package/src/server/rateLimiter.ts +156 -0
- package/src/server/requestLogger.ts +344 -0
- package/src/server/resources.ts +168 -0
- package/src/server/responseFormatter.ts +51 -0
- package/src/server/securityMiddleware.ts +236 -0
- package/src/server/serverKnowledgeStore.ts +91 -0
- package/src/server/toolRegistry.ts +489 -0
- package/src/tools/.gitkeep +1 -0
- package/src/tools/__tests__/accountTools.delta.integration.test.ts +128 -0
- package/src/tools/__tests__/accountTools.integration.test.ts +117 -0
- package/src/tools/__tests__/accountTools.test.ts +653 -0
- package/src/tools/__tests__/budgetTools.delta.integration.test.ts +90 -0
- package/src/tools/__tests__/budgetTools.integration.test.ts +134 -0
- package/src/tools/__tests__/budgetTools.test.ts +423 -0
- package/src/tools/__tests__/categoryTools.delta.integration.test.ts +80 -0
- package/src/tools/__tests__/categoryTools.integration.test.ts +295 -0
- package/src/tools/__tests__/categoryTools.test.ts +622 -0
- package/src/tools/__tests__/compareTransactions/formatter.test.ts +486 -0
- package/src/tools/__tests__/compareTransactions/index.test.ts +383 -0
- package/src/tools/__tests__/compareTransactions/matcher.test.ts +410 -0
- package/src/tools/__tests__/compareTransactions/parser.test.ts +764 -0
- package/src/tools/__tests__/compareTransactions.test.ts +342 -0
- package/src/tools/__tests__/compareTransactions.window.test.ts +147 -0
- package/src/tools/__tests__/deltaFetcher.scheduled.integration.test.ts +76 -0
- package/src/tools/__tests__/deltaFetcher.test.ts +270 -0
- package/src/tools/__tests__/deltaSupport.test.ts +188 -0
- package/src/tools/__tests__/deltaTestUtils.ts +46 -0
- package/src/tools/__tests__/exportTransactions.test.ts +213 -0
- package/src/tools/__tests__/monthTools.delta.integration.test.ts +80 -0
- package/src/tools/__tests__/monthTools.integration.test.ts +174 -0
- package/src/tools/__tests__/monthTools.test.ts +523 -0
- package/src/tools/__tests__/payeeTools.delta.integration.test.ts +80 -0
- package/src/tools/__tests__/payeeTools.integration.test.ts +150 -0
- package/src/tools/__tests__/payeeTools.test.ts +445 -0
- package/src/tools/__tests__/transactionTools.integration.test.ts +762 -0
- package/src/tools/__tests__/transactionTools.test.ts +3521 -0
- package/src/tools/__tests__/utilityTools.integration.test.ts +128 -0
- package/src/tools/__tests__/utilityTools.test.ts +205 -0
- package/src/tools/accountTools.ts +283 -0
- package/src/tools/budgetTools.ts +112 -0
- package/src/tools/categoryTools.ts +366 -0
- package/src/tools/compareTransactions/formatter.ts +163 -0
- package/src/tools/compareTransactions/index.ts +228 -0
- package/src/tools/compareTransactions/matcher.ts +240 -0
- package/src/tools/compareTransactions/parser.ts +557 -0
- package/src/tools/compareTransactions/types.ts +60 -0
- package/src/tools/compareTransactions.ts +3 -0
- package/src/tools/deltaFetcher.ts +278 -0
- package/src/tools/deltaSupport.ts +293 -0
- package/src/tools/exportTransactions.ts +273 -0
- package/src/tools/monthTools.ts +164 -0
- package/src/tools/payeeTools.ts +140 -0
- package/src/tools/reconcileAdapter.ts +312 -0
- package/src/tools/reconciliation/__tests__/adapter.causes.test.ts +122 -0
- package/src/tools/reconciliation/__tests__/adapter.test.ts +234 -0
- package/src/tools/reconciliation/__tests__/analyzer.test.ts +406 -0
- package/src/tools/reconciliation/__tests__/executor.integration.test.ts +366 -0
- package/src/tools/reconciliation/__tests__/executor.test.ts +779 -0
- package/src/tools/reconciliation/__tests__/matcher.test.ts +650 -0
- package/src/tools/reconciliation/__tests__/payeeNormalizer.test.ts +278 -0
- package/src/tools/reconciliation/__tests__/recommendationEngine.integration.test.ts +658 -0
- package/src/tools/reconciliation/__tests__/recommendationEngine.test.ts +1000 -0
- package/src/tools/reconciliation/__tests__/reconciliation.delta.integration.test.ts +151 -0
- package/src/tools/reconciliation/__tests__/reportFormatter.test.ts +573 -0
- package/src/tools/reconciliation/__tests__/scenarios/adapterCurrency.scenario.test.ts +78 -0
- package/src/tools/reconciliation/__tests__/scenarios/extremes.scenario.test.ts +47 -0
- package/src/tools/reconciliation/__tests__/scenarios/repeatAmount.scenario.test.ts +61 -0
- package/src/tools/reconciliation/__tests__/schemaUrl.test.ts +49 -0
- package/src/tools/reconciliation/analyzer.ts +824 -0
- package/src/tools/reconciliation/executor.ts +880 -0
- package/src/tools/reconciliation/index.ts +400 -0
- package/src/tools/reconciliation/matcher.ts +269 -0
- package/src/tools/reconciliation/payeeNormalizer.ts +167 -0
- package/src/tools/reconciliation/recommendationEngine.ts +506 -0
- package/src/tools/reconciliation/reportFormatter.ts +363 -0
- package/src/tools/reconciliation/types.ts +314 -0
- package/src/tools/schemas/outputs/__tests__/accountOutputs.test.ts +424 -0
- package/src/tools/schemas/outputs/__tests__/budgetOutputs.test.ts +310 -0
- package/src/tools/schemas/outputs/__tests__/categoryOutputs.test.ts +448 -0
- package/src/tools/schemas/outputs/__tests__/comparisonOutputs.test.ts +519 -0
- package/src/tools/schemas/outputs/__tests__/dateValidation.test.ts +155 -0
- package/src/tools/schemas/outputs/__tests__/discrepancyDirection.test.ts +288 -0
- package/src/tools/schemas/outputs/__tests__/monthOutputs.test.ts +478 -0
- package/src/tools/schemas/outputs/__tests__/payeeOutputs.test.ts +370 -0
- package/src/tools/schemas/outputs/__tests__/reconciliationOutputs.test.ts +401 -0
- package/src/tools/schemas/outputs/__tests__/transactionMutationSchemas.test.ts +213 -0
- package/src/tools/schemas/outputs/__tests__/transactionOutputs.test.ts +474 -0
- package/src/tools/schemas/outputs/__tests__/utilityOutputs.test.ts +333 -0
- package/src/tools/schemas/outputs/accountOutputs.ts +137 -0
- package/src/tools/schemas/outputs/budgetOutputs.ts +86 -0
- package/src/tools/schemas/outputs/categoryOutputs.ts +194 -0
- package/src/tools/schemas/outputs/comparisonOutputs.ts +600 -0
- package/src/tools/schemas/outputs/index.ts +270 -0
- package/src/tools/schemas/outputs/monthOutputs.ts +243 -0
- package/src/tools/schemas/outputs/payeeOutputs.ts +105 -0
- package/src/tools/schemas/outputs/reconciliationOutputs.ts +796 -0
- package/src/tools/schemas/outputs/transactionMutationOutputs.ts +758 -0
- package/src/tools/schemas/outputs/transactionOutputs.ts +243 -0
- package/src/tools/schemas/outputs/utilityOutputs.ts +411 -0
- package/src/tools/schemas/shared/commonOutputs.ts +140 -0
- package/src/tools/toolCategories.ts +140 -0
- package/src/tools/transactionTools.ts +2509 -0
- package/src/tools/utilityTools.ts +90 -0
- package/src/types/.gitkeep +1 -0
- package/src/types/__tests__/index.test.ts +52 -0
- package/src/types/index.ts +67 -0
- package/src/types/integration-tests.d.ts +35 -0
- package/src/types/toolAnnotations.ts +44 -0
- package/src/utils/__tests__/dateUtils.test.ts +170 -0
- package/src/utils/__tests__/money.test.ts +189 -0
- package/src/utils/amountUtils.ts +32 -0
- package/src/utils/dateUtils.ts +108 -0
- package/src/utils/money.ts +123 -0
- package/test-csv-sample.csv +28 -0
- package/test-exports/sample_bank_statement.csv +7 -0
- package/test-exports/ynab_account_e9ddc2a6_minimal_1items_2025-11-19_09-04-53.json +23 -0
- package/test-exports/ynab_account_e9ddc2a6_minimal_1items_2025-11-19_10-37-42.json +23 -0
- package/test-exports/ynab_account_e9ddc2a6_minimal_4items_2025-11-19_09-02-09.json +44 -0
- package/test-exports/ynab_account_e9ddc2a6_minimal_6items_2025-11-19_10-37-52.json +58 -0
- package/test-exports/ynab_since_2025-11-01_account_4c18e9f0_minimal_14items_2025-11-16_10-07-10.json +115 -0
- package/test-reconcile-autodetect.js +40 -0
- package/test-reconcile-tool.js +152 -0
- package/test-reconcile-with-csv.cjs +89 -0
- package/test-statement.csv +8 -0
- package/test_debug.js +47 -0
- package/test_simple.mjs +16 -0
- package/tsconfig.json +31 -0
- package/tsconfig.prod.json +18 -0
- package/vitest-reporters/split-json-reporter.ts +211 -0
- package/vitest.config.ts +96 -0
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import * as ynab from 'ynab';
|
|
3
|
+
import {
|
|
4
|
+
handleCompareTransactions,
|
|
5
|
+
CompareTransactionsSchema,
|
|
6
|
+
} from '../compareTransactions/index.js';
|
|
7
|
+
import { readFileSync } from 'fs';
|
|
8
|
+
|
|
9
|
+
// Mock filesystem
|
|
10
|
+
vi.mock('fs', () => ({
|
|
11
|
+
readFileSync: vi.fn(),
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
// Mock the YNAB API
|
|
15
|
+
const mockYnabAPI = {
|
|
16
|
+
transactions: {
|
|
17
|
+
getTransactionsByAccount: vi.fn(),
|
|
18
|
+
},
|
|
19
|
+
} as unknown as ynab.API;
|
|
20
|
+
|
|
21
|
+
describe('compareTransactions', () => {
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
vi.clearAllMocks();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
describe('CompareTransactionsSchema', () => {
|
|
27
|
+
it('should validate valid parameters', () => {
|
|
28
|
+
const validParams = {
|
|
29
|
+
budget_id: 'budget-123',
|
|
30
|
+
account_id: 'account-456',
|
|
31
|
+
csv_data: 'Date,Amount,Description\n2024-01-01,100.00,Test Transaction',
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const result = CompareTransactionsSchema.safeParse(validParams);
|
|
35
|
+
expect(result.success).toBe(true);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should require budget_id and account_id', () => {
|
|
39
|
+
const invalidParams = {
|
|
40
|
+
csv_data: 'Date,Amount,Description\n2024-01-01,100.00,Test Transaction',
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const result = CompareTransactionsSchema.safeParse(invalidParams);
|
|
44
|
+
expect(result.success).toBe(false);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('should require either csv_file_path or csv_data', () => {
|
|
48
|
+
const invalidParams = {
|
|
49
|
+
budget_id: 'budget-123',
|
|
50
|
+
account_id: 'account-456',
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const result = CompareTransactionsSchema.safeParse(invalidParams);
|
|
54
|
+
expect(result.success).toBe(false);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('should apply default values', () => {
|
|
58
|
+
const params = {
|
|
59
|
+
budget_id: 'budget-123',
|
|
60
|
+
account_id: 'account-456',
|
|
61
|
+
csv_data: 'Date,Amount,Description\n2024-01-01,100.00,Test Transaction',
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const parsed = CompareTransactionsSchema.parse(params);
|
|
65
|
+
expect(parsed.amount_tolerance).toBe(0.01);
|
|
66
|
+
expect(parsed.date_tolerance_days).toBe(5);
|
|
67
|
+
expect(parsed.csv_format.date_column).toBe('Date');
|
|
68
|
+
expect(parsed.csv_format.amount_column).toBe('Amount');
|
|
69
|
+
expect(parsed.csv_format.description_column).toBe('Description');
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
describe('handleCompareTransactions', () => {
|
|
74
|
+
const mockTransactions = [
|
|
75
|
+
{
|
|
76
|
+
id: 'ynab-1',
|
|
77
|
+
date: '2024-01-01',
|
|
78
|
+
amount: 100000, // $100.00 in milliunits
|
|
79
|
+
payee_name: 'Test Payee',
|
|
80
|
+
memo: 'Test memo',
|
|
81
|
+
cleared: 'cleared',
|
|
82
|
+
approved: true,
|
|
83
|
+
deleted: false,
|
|
84
|
+
account_id: 'account-456',
|
|
85
|
+
account_name: 'Test Account',
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
id: 'ynab-2',
|
|
89
|
+
date: '2024-01-02',
|
|
90
|
+
amount: -50000, // -$50.00 in milliunits
|
|
91
|
+
payee_name: 'Another Payee',
|
|
92
|
+
memo: null,
|
|
93
|
+
cleared: 'uncleared',
|
|
94
|
+
approved: false,
|
|
95
|
+
deleted: false,
|
|
96
|
+
account_id: 'account-456',
|
|
97
|
+
account_name: 'Test Account',
|
|
98
|
+
},
|
|
99
|
+
];
|
|
100
|
+
|
|
101
|
+
it('should compare CSV data with YNAB transactions', async () => {
|
|
102
|
+
const csvData =
|
|
103
|
+
'Date,Amount,Description\n2024-01-01,100.00,Test Payee\n2024-01-03,25.00,Missing Transaction';
|
|
104
|
+
|
|
105
|
+
(mockYnabAPI.transactions.getTransactionsByAccount as any).mockResolvedValue({
|
|
106
|
+
data: { transactions: mockTransactions },
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// Mock payees endpoint
|
|
110
|
+
(mockYnabAPI as any).payees = {
|
|
111
|
+
getPayees: vi.fn().mockResolvedValue({
|
|
112
|
+
data: { payees: [{ id: 'payee-1', name: 'Test Payee' }] },
|
|
113
|
+
}),
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const params = {
|
|
117
|
+
budget_id: 'budget-123',
|
|
118
|
+
account_id: 'account-456',
|
|
119
|
+
csv_data: csvData,
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const result = await handleCompareTransactions(mockYnabAPI, params);
|
|
123
|
+
|
|
124
|
+
expect(result.content).toHaveLength(1);
|
|
125
|
+
expect(result.content[0].type).toBe('text');
|
|
126
|
+
|
|
127
|
+
const response = JSON.parse(result.content[0].text);
|
|
128
|
+
expect(response.summary).toBeDefined();
|
|
129
|
+
expect(response.summary.bank_transactions_count).toBe(2);
|
|
130
|
+
expect(response.summary.ynab_transactions_count).toBe(2);
|
|
131
|
+
expect(response.matches).toBeDefined();
|
|
132
|
+
expect(response.missing_in_ynab).toBeDefined();
|
|
133
|
+
expect(response.missing_in_bank).toBeDefined();
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('should handle CSV file path', async () => {
|
|
137
|
+
const csvData = 'Date,Amount,Description\n2024-01-01,100.00,Test Payee';
|
|
138
|
+
(readFileSync as any).mockReturnValue(csvData);
|
|
139
|
+
|
|
140
|
+
(mockYnabAPI.transactions.getTransactionsByAccount as any).mockResolvedValue({
|
|
141
|
+
data: { transactions: mockTransactions },
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// Mock payees endpoint
|
|
145
|
+
(mockYnabAPI as any).payees = {
|
|
146
|
+
getPayees: vi.fn().mockResolvedValue({
|
|
147
|
+
data: { payees: [{ id: 'payee-1', name: 'Test Payee' }] },
|
|
148
|
+
}),
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const params = {
|
|
152
|
+
budget_id: 'budget-123',
|
|
153
|
+
account_id: 'account-456',
|
|
154
|
+
csv_file_path: '/path/to/transactions.csv',
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const result = await handleCompareTransactions(mockYnabAPI, params);
|
|
158
|
+
|
|
159
|
+
expect(readFileSync).toHaveBeenCalledWith('/path/to/transactions.csv', 'utf-8');
|
|
160
|
+
expect(result.content).toHaveLength(1);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it('should handle custom CSV format', async () => {
|
|
164
|
+
const csvData = 'Transaction Date|Dollar Amount|Memo\n01/01/2024|$100.00|Test Payee';
|
|
165
|
+
|
|
166
|
+
(mockYnabAPI.transactions.getTransactionsByAccount as any).mockResolvedValue({
|
|
167
|
+
data: { transactions: mockTransactions },
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Mock payees endpoint
|
|
171
|
+
(mockYnabAPI as any).payees = {
|
|
172
|
+
getPayees: vi.fn().mockResolvedValue({
|
|
173
|
+
data: { payees: [{ id: 'payee-1', name: 'Test Payee' }] },
|
|
174
|
+
}),
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
const params = {
|
|
178
|
+
budget_id: 'budget-123',
|
|
179
|
+
account_id: 'account-456',
|
|
180
|
+
csv_data: csvData,
|
|
181
|
+
csv_format: {
|
|
182
|
+
date_column: 'Transaction Date',
|
|
183
|
+
amount_column: 'Dollar Amount',
|
|
184
|
+
description_column: 'Memo',
|
|
185
|
+
delimiter: '|',
|
|
186
|
+
has_header: true,
|
|
187
|
+
date_format: 'MM/DD/YYYY',
|
|
188
|
+
},
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const result = await handleCompareTransactions(mockYnabAPI, params);
|
|
192
|
+
|
|
193
|
+
expect(result.content).toHaveLength(1);
|
|
194
|
+
const response = JSON.parse(result.content[0].text);
|
|
195
|
+
expect(response.summary.bank_transactions_count).toBe(1);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it('should handle CSV without headers using column indices', async () => {
|
|
199
|
+
const csvData = '2024-01-01,100.00,Test Transaction\n2024-01-02,-25.50,Another Transaction';
|
|
200
|
+
|
|
201
|
+
(mockYnabAPI.transactions.getTransactionsByAccount as any).mockResolvedValue({
|
|
202
|
+
data: { transactions: mockTransactions },
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
// Mock payees endpoint
|
|
206
|
+
(mockYnabAPI as any).payees = {
|
|
207
|
+
getPayees: vi.fn().mockResolvedValue({
|
|
208
|
+
data: { payees: [{ id: 'payee-1', name: 'Test Payee' }] },
|
|
209
|
+
}),
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
const params = {
|
|
213
|
+
budget_id: 'budget-123',
|
|
214
|
+
account_id: 'account-456',
|
|
215
|
+
csv_data: csvData,
|
|
216
|
+
csv_format: {
|
|
217
|
+
date_column: '0',
|
|
218
|
+
amount_column: '1',
|
|
219
|
+
description_column: '2',
|
|
220
|
+
delimiter: ',',
|
|
221
|
+
has_header: false,
|
|
222
|
+
date_format: 'YYYY-MM-DD',
|
|
223
|
+
},
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
const result = await handleCompareTransactions(mockYnabAPI, params);
|
|
227
|
+
|
|
228
|
+
expect(result.content).toHaveLength(1);
|
|
229
|
+
const response = JSON.parse(result.content[0].text);
|
|
230
|
+
expect(response.summary.bank_transactions_count).toBe(2);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it('should handle MMM dd, yyyy date format (bank statement format)', async () => {
|
|
234
|
+
const csvData =
|
|
235
|
+
'Date,Amount,Description\nSep 18, 2025,-62.82,Amazon.ca\nSep 17, 2025,-24.63,AMZN Mktp CA';
|
|
236
|
+
|
|
237
|
+
(mockYnabAPI.transactions.getTransactionsByAccount as any).mockResolvedValue({
|
|
238
|
+
data: { transactions: mockTransactions },
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
// Mock payees endpoint
|
|
242
|
+
(mockYnabAPI as any).payees = {
|
|
243
|
+
getPayees: vi.fn().mockResolvedValue({
|
|
244
|
+
data: { payees: [{ id: 'payee-1', name: 'Amazon' }] },
|
|
245
|
+
}),
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
const params = {
|
|
249
|
+
budget_id: 'budget-123',
|
|
250
|
+
account_id: 'account-456',
|
|
251
|
+
csv_data: csvData,
|
|
252
|
+
csv_format: {
|
|
253
|
+
date_column: 'Date',
|
|
254
|
+
amount_column: 'Amount',
|
|
255
|
+
description_column: 'Description',
|
|
256
|
+
delimiter: ',',
|
|
257
|
+
has_header: true,
|
|
258
|
+
date_format: 'MMM dd, yyyy',
|
|
259
|
+
},
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
const result = await handleCompareTransactions(mockYnabAPI, params);
|
|
263
|
+
|
|
264
|
+
expect(result.content).toHaveLength(1);
|
|
265
|
+
const response = JSON.parse(result.content[0].text);
|
|
266
|
+
expect(response.summary.bank_transactions_count).toBe(2);
|
|
267
|
+
// Should successfully parse the date format and process the transactions
|
|
268
|
+
expect(response.missing_in_ynab).toHaveLength(2); // No matches with mock transactions
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it('should maintain backward compatibility with modular structure', async () => {
|
|
272
|
+
// This test verifies that the modular refactor maintains exact backward compatibility
|
|
273
|
+
const csvData = 'Date,Amount,Description\n2024-01-01,100.00,Test Transaction';
|
|
274
|
+
|
|
275
|
+
(mockYnabAPI.transactions.getTransactionsByAccount as any).mockResolvedValue({
|
|
276
|
+
data: { transactions: mockTransactions },
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
(mockYnabAPI as any).payees = {
|
|
280
|
+
getPayees: vi.fn().mockResolvedValue({
|
|
281
|
+
data: { payees: [{ id: 'payee-1', name: 'Test' }] },
|
|
282
|
+
}),
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
const params = {
|
|
286
|
+
budget_id: 'budget-123',
|
|
287
|
+
account_id: 'account-456',
|
|
288
|
+
csv_data: csvData,
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
const result = await handleCompareTransactions(mockYnabAPI, params);
|
|
292
|
+
|
|
293
|
+
// Verify response structure matches original exactly
|
|
294
|
+
expect(result.content).toHaveLength(1);
|
|
295
|
+
expect(result.content[0].type).toBe('text');
|
|
296
|
+
|
|
297
|
+
const response = JSON.parse(result.content[0].text);
|
|
298
|
+
expect(response).toHaveProperty('summary');
|
|
299
|
+
expect(response).toHaveProperty('matches');
|
|
300
|
+
expect(response).toHaveProperty('missing_in_ynab');
|
|
301
|
+
expect(response).toHaveProperty('missing_in_bank');
|
|
302
|
+
|
|
303
|
+
// Verify summary structure
|
|
304
|
+
expect(response.summary).toHaveProperty('bank_transactions_count');
|
|
305
|
+
expect(response.summary).toHaveProperty('ynab_transactions_count');
|
|
306
|
+
expect(response.summary).toHaveProperty('matches_found');
|
|
307
|
+
expect(response.summary).toHaveProperty('missing_in_ynab');
|
|
308
|
+
expect(response.summary).toHaveProperty('missing_in_bank');
|
|
309
|
+
expect(response.summary).toHaveProperty('date_range');
|
|
310
|
+
expect(response.summary).toHaveProperty('parameters');
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
it('should handle auto-detection correctly through modular structure', async () => {
|
|
314
|
+
const csvData =
|
|
315
|
+
'Date,Description,Debit,Credit\n2024-01-01,Test Transaction,100.00,\n2024-01-02,Credit Transaction,,50.00';
|
|
316
|
+
|
|
317
|
+
(mockYnabAPI.transactions.getTransactionsByAccount as any).mockResolvedValue({
|
|
318
|
+
data: { transactions: mockTransactions },
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
(mockYnabAPI as any).payees = {
|
|
322
|
+
getPayees: vi.fn().mockResolvedValue({
|
|
323
|
+
data: { payees: [] },
|
|
324
|
+
}),
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
const params = {
|
|
328
|
+
budget_id: 'budget-123',
|
|
329
|
+
account_id: 'account-456',
|
|
330
|
+
csv_data: csvData,
|
|
331
|
+
auto_detect_format: true,
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
const result = await handleCompareTransactions(mockYnabAPI, params);
|
|
335
|
+
|
|
336
|
+
expect(result.content).toHaveLength(1);
|
|
337
|
+
const response = JSON.parse(result.content[0].text);
|
|
338
|
+
expect(response.summary.bank_transactions_count).toBe(2);
|
|
339
|
+
// Should correctly detect debit/credit format and parse both transactions
|
|
340
|
+
});
|
|
341
|
+
});
|
|
342
|
+
});
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { inWindow } from '../../utils/money.js';
|
|
3
|
+
|
|
4
|
+
describe('compareTransactions statement window filtering', () => {
|
|
5
|
+
describe('inWindow function', () => {
|
|
6
|
+
it('excludes transactions outside statement window', () => {
|
|
7
|
+
const statementStart = '2024-01-01';
|
|
8
|
+
const statementEnd = '2024-01-31';
|
|
9
|
+
|
|
10
|
+
// Transaction within window
|
|
11
|
+
expect(inWindow('2024-01-15', statementStart, statementEnd)).toBe(true);
|
|
12
|
+
|
|
13
|
+
// Transaction before window
|
|
14
|
+
expect(inWindow('2023-12-31', statementStart, statementEnd)).toBe(false);
|
|
15
|
+
|
|
16
|
+
// Transaction after window
|
|
17
|
+
expect(inWindow('2024-02-01', statementStart, statementEnd)).toBe(false);
|
|
18
|
+
|
|
19
|
+
// Boundary dates
|
|
20
|
+
expect(inWindow('2024-01-01', statementStart, statementEnd)).toBe(true);
|
|
21
|
+
expect(inWindow('2024-01-31', statementStart, statementEnd)).toBe(true);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('handles partial window bounds', () => {
|
|
25
|
+
// Only end date specified
|
|
26
|
+
expect(inWindow('2024-01-15', undefined, '2024-01-31')).toBe(true);
|
|
27
|
+
expect(inWindow('2024-02-01', undefined, '2024-01-31')).toBe(false);
|
|
28
|
+
|
|
29
|
+
// Only start date specified
|
|
30
|
+
expect(inWindow('2024-01-15', '2024-01-01', undefined)).toBe(true);
|
|
31
|
+
expect(inWindow('2023-12-31', '2024-01-01', undefined)).toBe(false);
|
|
32
|
+
|
|
33
|
+
// No bounds specified (all transactions pass)
|
|
34
|
+
expect(inWindow('2024-01-15', undefined, undefined)).toBe(true);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('filters candidates before matching logic', () => {
|
|
38
|
+
const allTransactions = [
|
|
39
|
+
{ date: '2023-12-31', amount: 100 }, // Before window
|
|
40
|
+
{ date: '2024-01-15', amount: 200 }, // In window
|
|
41
|
+
{ date: '2024-01-20', amount: 300 }, // In window
|
|
42
|
+
{ date: '2024-02-01', amount: 400 }, // After window
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
const filteredTxns = allTransactions.filter((t) =>
|
|
46
|
+
inWindow(t.date, '2024-01-01', '2024-01-31'),
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
expect(filteredTxns).toHaveLength(2);
|
|
50
|
+
expect(filteredTxns[0]?.amount).toBe(200);
|
|
51
|
+
expect(filteredTxns[1]?.amount).toBe(300);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe('statement window clamping', () => {
|
|
56
|
+
it('clamps bank and YNAB candidates to statement window', () => {
|
|
57
|
+
const bankTxns = [
|
|
58
|
+
{ date: '2023-12-25', description: 'Before window' },
|
|
59
|
+
{ date: '2024-01-10', description: 'In window' },
|
|
60
|
+
{ date: '2024-02-05', description: 'After window' },
|
|
61
|
+
];
|
|
62
|
+
|
|
63
|
+
const ynabTxns = [
|
|
64
|
+
{ date: '2023-12-30', payee: 'Before window' },
|
|
65
|
+
{ date: '2024-01-12', payee: 'In window' },
|
|
66
|
+
{ date: '2024-02-10', payee: 'After window' },
|
|
67
|
+
];
|
|
68
|
+
|
|
69
|
+
const statementStart = '2024-01-01';
|
|
70
|
+
const statementEnd = '2024-01-31';
|
|
71
|
+
|
|
72
|
+
const filteredBank = bankTxns.filter((t) => inWindow(t.date, statementStart, statementEnd));
|
|
73
|
+
const filteredYnab = ynabTxns.filter((t) => inWindow(t.date, statementStart, statementEnd));
|
|
74
|
+
|
|
75
|
+
// Only transactions in January 2024 should remain
|
|
76
|
+
expect(filteredBank).toHaveLength(1);
|
|
77
|
+
expect(filteredBank[0]?.description).toBe('In window');
|
|
78
|
+
|
|
79
|
+
expect(filteredYnab).toHaveLength(1);
|
|
80
|
+
expect(filteredYnab[0]?.payee).toBe('In window');
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('matches use filtered transactions not original counts', () => {
|
|
84
|
+
// This test validates that when statement window filtering is applied,
|
|
85
|
+
// the matching algorithm operates on filtered transactions,
|
|
86
|
+
// and the summary counts reflect filtered transactions, not original totals
|
|
87
|
+
const originalBankCount = 5;
|
|
88
|
+
const originalYnabCount = 4;
|
|
89
|
+
const filteredBankCount = 2; // After window filtering
|
|
90
|
+
const filteredYnabCount = 3; // After window filtering
|
|
91
|
+
|
|
92
|
+
// The summary should show filtered counts, not original
|
|
93
|
+
expect(filteredBankCount).toBeLessThan(originalBankCount);
|
|
94
|
+
expect(filteredYnabCount).toBeLessThan(originalYnabCount);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
describe('integration with modular compareTransactions', () => {
|
|
99
|
+
it('should apply window filtering in the main handler', () => {
|
|
100
|
+
// This test verifies that the main handler correctly applies window filtering
|
|
101
|
+
// to both bank and YNAB transactions before passing them to the matcher
|
|
102
|
+
const testDate1 = '2024-01-15'; // In window
|
|
103
|
+
const testDate2 = '2024-02-15'; // Out of window
|
|
104
|
+
const statementStart = '2024-01-01';
|
|
105
|
+
const statementEnd = '2024-01-31';
|
|
106
|
+
|
|
107
|
+
// Test that filtering logic works as expected
|
|
108
|
+
expect(inWindow(testDate1, statementStart, statementEnd)).toBe(true);
|
|
109
|
+
expect(inWindow(testDate2, statementStart, statementEnd)).toBe(false);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('should filter transactions before matching in modular structure', () => {
|
|
113
|
+
// This test documents that window filtering happens in the main handler
|
|
114
|
+
// before passing transactions to the matcher module
|
|
115
|
+
const bankTransactions = [
|
|
116
|
+
{ date: '2023-12-31', amount: 100, description: 'Before' },
|
|
117
|
+
{ date: '2024-01-15', amount: 200, description: 'During' },
|
|
118
|
+
{ date: '2024-02-01', amount: 300, description: 'After' },
|
|
119
|
+
];
|
|
120
|
+
|
|
121
|
+
const ynabTransactions = [
|
|
122
|
+
{ date: '2023-12-30', amount: 150, payee: 'Before' },
|
|
123
|
+
{ date: '2024-01-16', amount: 250, payee: 'During' },
|
|
124
|
+
{ date: '2024-02-02', amount: 350, payee: 'After' },
|
|
125
|
+
];
|
|
126
|
+
|
|
127
|
+
const statementStart = '2024-01-01';
|
|
128
|
+
const statementEnd = '2024-01-31';
|
|
129
|
+
|
|
130
|
+
// Simulate the filtering that happens in the main handler
|
|
131
|
+
const filteredBank = bankTransactions.filter((t) =>
|
|
132
|
+
inWindow(t.date, statementStart, statementEnd),
|
|
133
|
+
);
|
|
134
|
+
const filteredYnab = ynabTransactions.filter((t) =>
|
|
135
|
+
inWindow(t.date, statementStart, statementEnd),
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
expect(filteredBank).toHaveLength(1);
|
|
139
|
+
expect(filteredBank[0]?.description).toBe('During');
|
|
140
|
+
expect(filteredYnab).toHaveLength(1);
|
|
141
|
+
expect(filteredYnab[0]?.payee).toBe('During');
|
|
142
|
+
|
|
143
|
+
// The matcher would receive these filtered arrays, not the original ones
|
|
144
|
+
// This ensures that out-of-window transactions don't affect matching
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
});
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { describe, it, expect, beforeAll, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import * as ynab from 'ynab';
|
|
3
|
+
import { CacheManager } from '../../server/cacheManager.js';
|
|
4
|
+
import { ServerKnowledgeStore } from '../../server/serverKnowledgeStore.js';
|
|
5
|
+
import { DeltaCache } from '../../server/deltaCache.js';
|
|
6
|
+
import { DeltaFetcher } from '../deltaFetcher.js';
|
|
7
|
+
|
|
8
|
+
const shouldSkip = ['true', '1', 'yes', 'y', 'on'].includes(
|
|
9
|
+
(process.env['SKIP_E2E_TESTS'] || '').toLowerCase().trim(),
|
|
10
|
+
);
|
|
11
|
+
const hasToken = !!process.env['YNAB_ACCESS_TOKEN'];
|
|
12
|
+
const skipTests = shouldSkip || !hasToken;
|
|
13
|
+
const describeIntegration = skipTests ? describe.skip : describe;
|
|
14
|
+
|
|
15
|
+
describeIntegration('Delta fetcher scheduled transactions integration', () => {
|
|
16
|
+
let ynabAPI: ynab.API;
|
|
17
|
+
let testBudgetId: string;
|
|
18
|
+
let deltaFetcher: DeltaFetcher;
|
|
19
|
+
let previousNodeEnv: string | undefined;
|
|
20
|
+
|
|
21
|
+
beforeAll(async () => {
|
|
22
|
+
const accessToken = process.env['YNAB_ACCESS_TOKEN']!;
|
|
23
|
+
ynabAPI = new ynab.API(accessToken);
|
|
24
|
+
const budgetsResponse = await ynabAPI.budgets.getBudgets();
|
|
25
|
+
const budget = budgetsResponse.data.budgets[0];
|
|
26
|
+
if (!budget) {
|
|
27
|
+
throw new Error('No budgets available for delta integration tests.');
|
|
28
|
+
}
|
|
29
|
+
testBudgetId = budget.id;
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
beforeEach(() => {
|
|
33
|
+
previousNodeEnv = process.env['NODE_ENV'];
|
|
34
|
+
process.env['NODE_ENV'] = 'integration';
|
|
35
|
+
const cacheManager = new CacheManager();
|
|
36
|
+
const knowledgeStore = new ServerKnowledgeStore();
|
|
37
|
+
const deltaCache = new DeltaCache(cacheManager, knowledgeStore);
|
|
38
|
+
deltaFetcher = new DeltaFetcher(ynabAPI, deltaCache);
|
|
39
|
+
process.env['YNAB_MCP_ENABLE_DELTA'] = 'true';
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
afterEach(() => {
|
|
43
|
+
delete process.env['YNAB_MCP_ENABLE_DELTA'];
|
|
44
|
+
if (previousNodeEnv === undefined) {
|
|
45
|
+
delete process.env['NODE_ENV'];
|
|
46
|
+
} else {
|
|
47
|
+
process.env['NODE_ENV'] = previousNodeEnv;
|
|
48
|
+
}
|
|
49
|
+
previousNodeEnv = undefined;
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it(
|
|
53
|
+
'caches scheduled transactions on repeated fetches',
|
|
54
|
+
{ meta: { tier: 'domain', domain: 'delta' } },
|
|
55
|
+
async () => {
|
|
56
|
+
const firstResult = await deltaFetcher.fetchScheduledTransactions(testBudgetId);
|
|
57
|
+
expect(firstResult.wasCached).toBe(false);
|
|
58
|
+
expect(firstResult.serverKnowledge).toBeGreaterThanOrEqual(0);
|
|
59
|
+
// Validate data structure
|
|
60
|
+
expect(Array.isArray(firstResult.data)).toBe(true);
|
|
61
|
+
if (firstResult.data.length > 0) {
|
|
62
|
+
const sample = firstResult.data[0];
|
|
63
|
+
expect(sample).toHaveProperty('id');
|
|
64
|
+
expect(sample).toHaveProperty('date_first');
|
|
65
|
+
expect(sample).toHaveProperty('frequency');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const secondResult = await deltaFetcher.fetchScheduledTransactions(testBudgetId);
|
|
69
|
+
expect(secondResult.wasCached).toBe(true);
|
|
70
|
+
expect(secondResult.serverKnowledge).toBeGreaterThanOrEqual(firstResult.serverKnowledge);
|
|
71
|
+
// Validate cached data structure matches
|
|
72
|
+
expect(Array.isArray(secondResult.data)).toBe(true);
|
|
73
|
+
expect(secondResult.data.length).toBe(firstResult.data.length);
|
|
74
|
+
},
|
|
75
|
+
);
|
|
76
|
+
});
|