@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,270 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
2
|
+
import * as ynab from 'ynab';
|
|
3
|
+
import { DeltaFetcher } from '../deltaFetcher.js';
|
|
4
|
+
import type { DeltaCache } from '../../server/deltaCache.js';
|
|
5
|
+
import { CACHE_TTLS } from '../../server/cacheManager.js';
|
|
6
|
+
import {
|
|
7
|
+
mergeFlatEntities,
|
|
8
|
+
mergeCategories,
|
|
9
|
+
mergeTransactions,
|
|
10
|
+
mergeMonths,
|
|
11
|
+
} from '../../server/deltaCache.merge.js';
|
|
12
|
+
|
|
13
|
+
const createMockDeltaCache = () => ({ fetchWithDelta: vi.fn() });
|
|
14
|
+
|
|
15
|
+
describe('DeltaFetcher', () => {
|
|
16
|
+
let mockYnabAPI: ynab.API;
|
|
17
|
+
let mockDeltaCache: ReturnType<typeof createMockDeltaCache>;
|
|
18
|
+
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
mockDeltaCache = createMockDeltaCache();
|
|
21
|
+
mockYnabAPI = {
|
|
22
|
+
accounts: { getAccounts: vi.fn() },
|
|
23
|
+
categories: { getCategories: vi.fn() },
|
|
24
|
+
transactions: {
|
|
25
|
+
getTransactions: vi.fn(),
|
|
26
|
+
getTransactionsByAccount: vi.fn(),
|
|
27
|
+
},
|
|
28
|
+
scheduledTransactions: { getScheduledTransactions: vi.fn() },
|
|
29
|
+
payees: { getPayees: vi.fn() },
|
|
30
|
+
months: { getBudgetMonths: vi.fn() },
|
|
31
|
+
budgets: { getBudgets: vi.fn() },
|
|
32
|
+
} as unknown as ynab.API;
|
|
33
|
+
|
|
34
|
+
(mockYnabAPI.accounts.getAccounts as unknown as vi.Mock).mockResolvedValue({
|
|
35
|
+
data: { accounts: [], server_knowledge: 0 },
|
|
36
|
+
});
|
|
37
|
+
(mockYnabAPI.categories.getCategories as unknown as vi.Mock).mockResolvedValue({
|
|
38
|
+
data: { category_groups: [], server_knowledge: 0 },
|
|
39
|
+
});
|
|
40
|
+
(mockYnabAPI.transactions.getTransactions as unknown as vi.Mock).mockResolvedValue({
|
|
41
|
+
data: { transactions: [], server_knowledge: 0 },
|
|
42
|
+
});
|
|
43
|
+
(mockYnabAPI.transactions.getTransactionsByAccount as unknown as vi.Mock).mockResolvedValue({
|
|
44
|
+
data: { transactions: [], server_knowledge: 0 },
|
|
45
|
+
});
|
|
46
|
+
(
|
|
47
|
+
mockYnabAPI.scheduledTransactions.getScheduledTransactions as unknown as vi.Mock
|
|
48
|
+
).mockResolvedValue({
|
|
49
|
+
data: { scheduled_transactions: [], server_knowledge: 0 },
|
|
50
|
+
});
|
|
51
|
+
(mockYnabAPI.payees.getPayees as unknown as vi.Mock).mockResolvedValue({
|
|
52
|
+
data: { payees: [], server_knowledge: 0 },
|
|
53
|
+
});
|
|
54
|
+
(mockYnabAPI.months.getBudgetMonths as unknown as vi.Mock).mockResolvedValue({
|
|
55
|
+
data: { months: [], server_knowledge: 0 },
|
|
56
|
+
});
|
|
57
|
+
(mockYnabAPI.budgets.getBudgets as unknown as vi.Mock).mockResolvedValue({
|
|
58
|
+
data: { budgets: [], server_knowledge: 0 },
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('fetchAccounts wires delta cache with proper key and merge strategy', async () => {
|
|
63
|
+
const fetcher = new DeltaFetcher(mockYnabAPI, mockDeltaCache as unknown as DeltaCache);
|
|
64
|
+
const mockResult = { data: [], wasCached: false, usedDelta: false, serverKnowledge: 1 };
|
|
65
|
+
(mockDeltaCache.fetchWithDelta as unknown as vi.Mock).mockResolvedValue(mockResult);
|
|
66
|
+
|
|
67
|
+
const result = await fetcher.fetchAccounts('budget-1');
|
|
68
|
+
|
|
69
|
+
expect(result).toBe(mockResult);
|
|
70
|
+
expect(mockDeltaCache.fetchWithDelta).toHaveBeenCalledWith(
|
|
71
|
+
'accounts:list:budget-1',
|
|
72
|
+
'budget-1',
|
|
73
|
+
expect.any(Function),
|
|
74
|
+
mergeFlatEntities,
|
|
75
|
+
expect.objectContaining({ ttl: CACHE_TTLS.ACCOUNTS }),
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const fetcherFn = (mockDeltaCache.fetchWithDelta as unknown as vi.Mock).mock.calls[0][2];
|
|
79
|
+
await fetcherFn(42);
|
|
80
|
+
expect(mockYnabAPI.accounts.getAccounts).toHaveBeenCalledWith('budget-1', 42);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('fetchCategories uses mergeCategories and TTL', async () => {
|
|
84
|
+
const fetcher = new DeltaFetcher(mockYnabAPI, mockDeltaCache as unknown as DeltaCache);
|
|
85
|
+
(mockDeltaCache.fetchWithDelta as unknown as vi.Mock).mockResolvedValue({});
|
|
86
|
+
|
|
87
|
+
await fetcher.fetchCategories('budget-2');
|
|
88
|
+
|
|
89
|
+
expect(mockDeltaCache.fetchWithDelta).toHaveBeenCalledWith(
|
|
90
|
+
'categories:list:budget-2',
|
|
91
|
+
'budget-2',
|
|
92
|
+
expect.any(Function),
|
|
93
|
+
mergeCategories,
|
|
94
|
+
expect.objectContaining({ ttl: CACHE_TTLS.CATEGORIES }),
|
|
95
|
+
);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('fetchTransactions includes filters in key and uses mergeTransactions', async () => {
|
|
99
|
+
const fetcher = new DeltaFetcher(mockYnabAPI, mockDeltaCache as unknown as DeltaCache);
|
|
100
|
+
(mockDeltaCache.fetchWithDelta as unknown as vi.Mock).mockResolvedValue({});
|
|
101
|
+
|
|
102
|
+
await fetcher.fetchTransactions(
|
|
103
|
+
'budget-3',
|
|
104
|
+
'2024-01-01',
|
|
105
|
+
ynab.GetTransactionsTypeEnum.Uncategorized,
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
expect(mockDeltaCache.fetchWithDelta).toHaveBeenCalledWith(
|
|
109
|
+
'transactions:list:budget-3:2024-01-01:uncategorized',
|
|
110
|
+
'budget-3',
|
|
111
|
+
expect.any(Function),
|
|
112
|
+
mergeTransactions,
|
|
113
|
+
expect.objectContaining({ ttl: CACHE_TTLS.TRANSACTIONS }),
|
|
114
|
+
);
|
|
115
|
+
const fetcherFn = (mockDeltaCache.fetchWithDelta as unknown as vi.Mock).mock.calls[0][2];
|
|
116
|
+
await fetcherFn(undefined);
|
|
117
|
+
expect(mockYnabAPI.transactions.getTransactions).toHaveBeenCalledWith(
|
|
118
|
+
'budget-3',
|
|
119
|
+
'2024-01-01',
|
|
120
|
+
'uncategorized',
|
|
121
|
+
undefined,
|
|
122
|
+
);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('fetchTransactionsByAccount encodes account in key', async () => {
|
|
126
|
+
const fetcher = new DeltaFetcher(mockYnabAPI, mockDeltaCache as unknown as DeltaCache);
|
|
127
|
+
(mockDeltaCache.fetchWithDelta as unknown as vi.Mock).mockResolvedValue({});
|
|
128
|
+
|
|
129
|
+
await fetcher.fetchTransactionsByAccount('budget-4', 'acct-1', '2024-02-02');
|
|
130
|
+
|
|
131
|
+
expect(mockDeltaCache.fetchWithDelta).toHaveBeenCalledWith(
|
|
132
|
+
'transactions:account:budget-4:acct-1:2024-02-02',
|
|
133
|
+
'budget-4',
|
|
134
|
+
expect.any(Function),
|
|
135
|
+
mergeTransactions,
|
|
136
|
+
expect.objectContaining({ ttl: CACHE_TTLS.TRANSACTIONS }),
|
|
137
|
+
);
|
|
138
|
+
const fetcherFn = (mockDeltaCache.fetchWithDelta as unknown as vi.Mock).mock.calls[0][2];
|
|
139
|
+
await fetcherFn(5);
|
|
140
|
+
expect(mockYnabAPI.transactions.getTransactionsByAccount).toHaveBeenCalledWith(
|
|
141
|
+
'budget-4',
|
|
142
|
+
'acct-1',
|
|
143
|
+
'2024-02-02',
|
|
144
|
+
undefined,
|
|
145
|
+
5,
|
|
146
|
+
);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('fetchScheduledTransactions wires cache key and merge strategy', async () => {
|
|
150
|
+
const fetcher = new DeltaFetcher(mockYnabAPI, mockDeltaCache as unknown as DeltaCache);
|
|
151
|
+
(mockDeltaCache.fetchWithDelta as unknown as vi.Mock).mockResolvedValue({});
|
|
152
|
+
|
|
153
|
+
await fetcher.fetchScheduledTransactions('budget-sched');
|
|
154
|
+
|
|
155
|
+
expect(mockDeltaCache.fetchWithDelta).toHaveBeenCalledWith(
|
|
156
|
+
'scheduled_transactions:list:budget-sched',
|
|
157
|
+
'budget-sched',
|
|
158
|
+
expect.any(Function),
|
|
159
|
+
mergeFlatEntities,
|
|
160
|
+
expect.objectContaining({ ttl: CACHE_TTLS.SCHEDULED_TRANSACTIONS }),
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
const fetcherFn = (mockDeltaCache.fetchWithDelta as unknown as vi.Mock).mock.calls[0][2];
|
|
164
|
+
await fetcherFn(321);
|
|
165
|
+
expect(mockYnabAPI.scheduledTransactions.getScheduledTransactions).toHaveBeenCalledWith(
|
|
166
|
+
'budget-sched',
|
|
167
|
+
321,
|
|
168
|
+
);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it('fetchPayees delegates to mergeFlatEntities', async () => {
|
|
172
|
+
const fetcher = new DeltaFetcher(mockYnabAPI, mockDeltaCache as unknown as DeltaCache);
|
|
173
|
+
(mockDeltaCache.fetchWithDelta as unknown as vi.Mock).mockResolvedValue({});
|
|
174
|
+
|
|
175
|
+
await fetcher.fetchPayees('budget-5');
|
|
176
|
+
|
|
177
|
+
expect(mockDeltaCache.fetchWithDelta).toHaveBeenCalledWith(
|
|
178
|
+
'payees:list:budget-5',
|
|
179
|
+
'budget-5',
|
|
180
|
+
expect.any(Function),
|
|
181
|
+
mergeFlatEntities,
|
|
182
|
+
expect.objectContaining({ ttl: CACHE_TTLS.PAYEES }),
|
|
183
|
+
);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it('fetchMonths uses mergeMonths and month TTL', async () => {
|
|
187
|
+
const fetcher = new DeltaFetcher(mockYnabAPI, mockDeltaCache as unknown as DeltaCache);
|
|
188
|
+
(mockDeltaCache.fetchWithDelta as unknown as vi.Mock).mockResolvedValue({});
|
|
189
|
+
|
|
190
|
+
await fetcher.fetchMonths('budget-6');
|
|
191
|
+
|
|
192
|
+
expect(mockDeltaCache.fetchWithDelta).toHaveBeenCalledWith(
|
|
193
|
+
'months:list:budget-6',
|
|
194
|
+
'budget-6',
|
|
195
|
+
expect.any(Function),
|
|
196
|
+
mergeMonths,
|
|
197
|
+
expect.objectContaining({ ttl: CACHE_TTLS.MONTHS }),
|
|
198
|
+
);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it('fetchBudgets always forces full refresh', async () => {
|
|
202
|
+
const fetcher = new DeltaFetcher(mockYnabAPI, mockDeltaCache as unknown as DeltaCache);
|
|
203
|
+
(mockDeltaCache.fetchWithDelta as unknown as vi.Mock).mockResolvedValue({});
|
|
204
|
+
|
|
205
|
+
await fetcher.fetchBudgets();
|
|
206
|
+
|
|
207
|
+
expect(mockDeltaCache.fetchWithDelta).toHaveBeenCalledWith(
|
|
208
|
+
'budgets:list',
|
|
209
|
+
'global',
|
|
210
|
+
expect.any(Function),
|
|
211
|
+
mergeFlatEntities,
|
|
212
|
+
expect.objectContaining({ ttl: CACHE_TTLS.BUDGETS, forceFullRefresh: true }),
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
// Verify the loader function calls the YNAB API correctly
|
|
216
|
+
const fetcherFn = (mockDeltaCache.fetchWithDelta as unknown as vi.Mock).mock.calls[0][2];
|
|
217
|
+
await fetcherFn();
|
|
218
|
+
expect(mockYnabAPI.budgets.getBudgets).toHaveBeenCalledWith();
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it('fetchAccountsFull bypasses cache and filters deleted accounts', async () => {
|
|
222
|
+
const fetcher = new DeltaFetcher(mockYnabAPI, mockDeltaCache as unknown as DeltaCache);
|
|
223
|
+
(mockYnabAPI.accounts.getAccounts as unknown as vi.Mock).mockResolvedValue({
|
|
224
|
+
data: {
|
|
225
|
+
accounts: [
|
|
226
|
+
{ id: 'acct-1', deleted: false },
|
|
227
|
+
{ id: 'acct-2', deleted: true },
|
|
228
|
+
],
|
|
229
|
+
server_knowledge: 12,
|
|
230
|
+
},
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
const result = await fetcher.fetchAccountsFull('budget-x');
|
|
234
|
+
|
|
235
|
+
expect(mockYnabAPI.accounts.getAccounts).toHaveBeenCalledWith('budget-x');
|
|
236
|
+
expect(result).toEqual({
|
|
237
|
+
data: [{ id: 'acct-1', deleted: false }],
|
|
238
|
+
wasCached: false,
|
|
239
|
+
usedDelta: false,
|
|
240
|
+
serverKnowledge: 12,
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
it('fetchTransactionsByAccountFull bypasses delta cache', async () => {
|
|
245
|
+
const fetcher = new DeltaFetcher(mockYnabAPI, mockDeltaCache as unknown as DeltaCache);
|
|
246
|
+
(mockYnabAPI.transactions.getTransactionsByAccount as unknown as vi.Mock).mockResolvedValue({
|
|
247
|
+
data: {
|
|
248
|
+
transactions: [
|
|
249
|
+
{ id: 'tx-1', deleted: false },
|
|
250
|
+
{ id: 'tx-2', deleted: true },
|
|
251
|
+
],
|
|
252
|
+
server_knowledge: 55,
|
|
253
|
+
},
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
const result = await fetcher.fetchTransactionsByAccountFull('budget-x', 'acct-1', '2024-03-01');
|
|
257
|
+
|
|
258
|
+
expect(mockYnabAPI.transactions.getTransactionsByAccount).toHaveBeenCalledWith(
|
|
259
|
+
'budget-x',
|
|
260
|
+
'acct-1',
|
|
261
|
+
'2024-03-01',
|
|
262
|
+
);
|
|
263
|
+
expect(result).toEqual({
|
|
264
|
+
data: [{ id: 'tx-1', deleted: false }],
|
|
265
|
+
wasCached: false,
|
|
266
|
+
usedDelta: false,
|
|
267
|
+
serverKnowledge: 55,
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
});
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for deltaSupport.ts - argument resolution with runtime validation
|
|
3
|
+
*/
|
|
4
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
5
|
+
import * as ynab from 'ynab';
|
|
6
|
+
import { resolveDeltaFetcherArgs, resolveDeltaWriteArgs } from '../deltaSupport.js';
|
|
7
|
+
import { DeltaFetcher } from '../deltaFetcher.js';
|
|
8
|
+
import { DeltaCache } from '../../server/deltaCache.js';
|
|
9
|
+
import { ServerKnowledgeStore } from '../../server/serverKnowledgeStore.js';
|
|
10
|
+
import { cacheManager } from '../../server/cacheManager.js';
|
|
11
|
+
|
|
12
|
+
describe('deltaSupport runtime validation', () => {
|
|
13
|
+
let ynabAPI: ynab.API;
|
|
14
|
+
let deltaFetcher: DeltaFetcher;
|
|
15
|
+
let deltaCache: DeltaCache;
|
|
16
|
+
let knowledgeStore: ServerKnowledgeStore;
|
|
17
|
+
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
ynabAPI = new ynab.API('test-token');
|
|
20
|
+
knowledgeStore = new ServerKnowledgeStore();
|
|
21
|
+
deltaCache = new DeltaCache(cacheManager, knowledgeStore);
|
|
22
|
+
deltaFetcher = new DeltaFetcher(ynabAPI, deltaCache);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe('resolveDeltaFetcherArgs', () => {
|
|
26
|
+
it('should accept valid 2-argument form (ynabAPI, params)', () => {
|
|
27
|
+
const params = { budgetId: 'test-budget' };
|
|
28
|
+
const result = resolveDeltaFetcherArgs(ynabAPI, params);
|
|
29
|
+
|
|
30
|
+
expect(result.deltaFetcher).toBeDefined();
|
|
31
|
+
expect(result.params).toBe(params);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should accept valid 3-argument form (ynabAPI, deltaFetcher, params)', () => {
|
|
35
|
+
const params = { budgetId: 'test-budget' };
|
|
36
|
+
const result = resolveDeltaFetcherArgs(ynabAPI, deltaFetcher, params);
|
|
37
|
+
|
|
38
|
+
expect(result.deltaFetcher).toBe(deltaFetcher);
|
|
39
|
+
expect(result.params).toBe(params);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should reject 2-argument form with DeltaFetcher instead of params', () => {
|
|
43
|
+
expect(() => {
|
|
44
|
+
resolveDeltaFetcherArgs(ynabAPI, deltaFetcher as unknown as Record<string, unknown>);
|
|
45
|
+
}).toThrow(
|
|
46
|
+
'resolveDeltaFetcherArgs: When providing 2 arguments, the second argument must be a params object, not a DeltaFetcher',
|
|
47
|
+
);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should reject 3-argument form with wrong types', () => {
|
|
51
|
+
const params = { budgetId: 'test-budget' };
|
|
52
|
+
|
|
53
|
+
// Second arg should be DeltaFetcher, not params
|
|
54
|
+
expect(() => {
|
|
55
|
+
resolveDeltaFetcherArgs(ynabAPI, params as unknown as DeltaFetcher, params);
|
|
56
|
+
}).toThrow(
|
|
57
|
+
'resolveDeltaFetcherArgs: When providing 3 arguments, the second argument must be a DeltaFetcher instance',
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
// Third arg should be params object, not DeltaFetcher
|
|
61
|
+
expect(() => {
|
|
62
|
+
resolveDeltaFetcherArgs(
|
|
63
|
+
ynabAPI,
|
|
64
|
+
deltaFetcher,
|
|
65
|
+
deltaFetcher as unknown as Record<string, unknown>,
|
|
66
|
+
);
|
|
67
|
+
}).toThrow(
|
|
68
|
+
'resolveDeltaFetcherArgs: When providing 3 arguments, the third argument must be a params object',
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('should reject non-object params', () => {
|
|
73
|
+
expect(() => {
|
|
74
|
+
resolveDeltaFetcherArgs(ynabAPI, 'invalid' as unknown as Record<string, unknown>);
|
|
75
|
+
}).toThrow(
|
|
76
|
+
'resolveDeltaFetcherArgs: When providing 2 arguments, the second argument must be a params object',
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
expect(() => {
|
|
80
|
+
resolveDeltaFetcherArgs(ynabAPI, 123 as unknown as Record<string, unknown>);
|
|
81
|
+
}).toThrow(
|
|
82
|
+
'resolveDeltaFetcherArgs: When providing 2 arguments, the second argument must be a params object',
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
expect(() => {
|
|
86
|
+
resolveDeltaFetcherArgs(ynabAPI, null as unknown as Record<string, unknown>);
|
|
87
|
+
}).toThrow(
|
|
88
|
+
'resolveDeltaFetcherArgs: When providing 2 arguments, the second argument must be a params object',
|
|
89
|
+
);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
describe('resolveDeltaWriteArgs', () => {
|
|
94
|
+
it('should accept valid 1-argument form (params)', () => {
|
|
95
|
+
const params = { budgetId: 'test-budget' };
|
|
96
|
+
const result = resolveDeltaWriteArgs(params);
|
|
97
|
+
|
|
98
|
+
expect(result.deltaCache).toBeDefined();
|
|
99
|
+
expect(result.knowledgeStore).toBeDefined();
|
|
100
|
+
expect(result.params).toBe(params);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('should accept valid 3-argument form (deltaCache, knowledgeStore, params)', () => {
|
|
104
|
+
const params = { budgetId: 'test-budget' };
|
|
105
|
+
const result = resolveDeltaWriteArgs(deltaCache, knowledgeStore, params);
|
|
106
|
+
|
|
107
|
+
expect(result.deltaCache).toBe(deltaCache);
|
|
108
|
+
expect(result.knowledgeStore).toBe(knowledgeStore);
|
|
109
|
+
expect(result.params).toBe(params);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('should reject 1-argument form with DeltaCache instead of params', () => {
|
|
113
|
+
expect(() => {
|
|
114
|
+
resolveDeltaWriteArgs(deltaCache as unknown as Record<string, unknown>);
|
|
115
|
+
}).toThrow(
|
|
116
|
+
'resolveDeltaWriteArgs: When providing only 1 argument, it must be a params object, not a DeltaCache',
|
|
117
|
+
);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('should reject 2-argument form (ambiguous)', () => {
|
|
121
|
+
const params = { budgetId: 'test-budget' };
|
|
122
|
+
|
|
123
|
+
// (deltaCache, knowledgeStore) - missing params
|
|
124
|
+
expect(() => {
|
|
125
|
+
resolveDeltaWriteArgs(
|
|
126
|
+
deltaCache as unknown as Record<string, unknown>,
|
|
127
|
+
knowledgeStore as unknown as Record<string, unknown>,
|
|
128
|
+
);
|
|
129
|
+
}).toThrow(
|
|
130
|
+
'resolveDeltaWriteArgs: When providing DeltaCache and ServerKnowledgeStore, you must also provide params',
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
// (params, params) - ambiguous
|
|
134
|
+
expect(() => {
|
|
135
|
+
resolveDeltaWriteArgs(params, params);
|
|
136
|
+
}).toThrow('resolveDeltaWriteArgs: Invalid argument combination');
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('should reject 3-argument form with wrong types', () => {
|
|
140
|
+
const params = { budgetId: 'test-budget' };
|
|
141
|
+
|
|
142
|
+
// First arg should be DeltaCache
|
|
143
|
+
expect(() => {
|
|
144
|
+
resolveDeltaWriteArgs(params as unknown as DeltaCache, knowledgeStore, params);
|
|
145
|
+
}).toThrow(
|
|
146
|
+
'resolveDeltaWriteArgs: When providing 3 arguments, the first argument must be a DeltaCache instance',
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
// Second arg should be ServerKnowledgeStore
|
|
150
|
+
expect(() => {
|
|
151
|
+
resolveDeltaWriteArgs(deltaCache, params as unknown as ServerKnowledgeStore, params);
|
|
152
|
+
}).toThrow(
|
|
153
|
+
'resolveDeltaWriteArgs: When providing 3 arguments, the second argument must be a ServerKnowledgeStore instance',
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
// Third arg should be params
|
|
157
|
+
expect(() => {
|
|
158
|
+
resolveDeltaWriteArgs(
|
|
159
|
+
deltaCache,
|
|
160
|
+
knowledgeStore,
|
|
161
|
+
deltaCache as unknown as Record<string, unknown>,
|
|
162
|
+
);
|
|
163
|
+
}).toThrow(
|
|
164
|
+
'resolveDeltaWriteArgs: When providing 3 arguments, the third argument must be a params object',
|
|
165
|
+
);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it('should reject non-object params', () => {
|
|
169
|
+
expect(() => {
|
|
170
|
+
resolveDeltaWriteArgs('invalid' as unknown as Record<string, unknown>);
|
|
171
|
+
}).toThrow(
|
|
172
|
+
'resolveDeltaWriteArgs: When providing only 1 argument, it must be a params object',
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
expect(() => {
|
|
176
|
+
resolveDeltaWriteArgs(123 as unknown as Record<string, unknown>);
|
|
177
|
+
}).toThrow(
|
|
178
|
+
'resolveDeltaWriteArgs: When providing only 1 argument, it must be a params object',
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
expect(() => {
|
|
182
|
+
resolveDeltaWriteArgs(null as unknown as Record<string, unknown>);
|
|
183
|
+
}).toThrow(
|
|
184
|
+
'resolveDeltaWriteArgs: When providing only 1 argument, it must be a params object',
|
|
185
|
+
);
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { vi } from 'vitest';
|
|
2
|
+
import { DeltaFetcher } from '../deltaFetcher.js';
|
|
3
|
+
|
|
4
|
+
export interface MockDeltaResult<T> {
|
|
5
|
+
data: T[];
|
|
6
|
+
wasCached?: boolean;
|
|
7
|
+
usedDelta?: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
type DeltaFetcherMethod = 'fetchAccounts' | 'fetchBudgets' | 'fetchCategories' | 'fetchMonths';
|
|
11
|
+
|
|
12
|
+
export function createDeltaFetcherMock<T>(
|
|
13
|
+
method: DeltaFetcherMethod,
|
|
14
|
+
result: MockDeltaResult<T>,
|
|
15
|
+
): {
|
|
16
|
+
fetcher: DeltaFetcher;
|
|
17
|
+
spy: ReturnType<typeof vi.fn>;
|
|
18
|
+
resolved: Required<MockDeltaResult<T>>;
|
|
19
|
+
} {
|
|
20
|
+
const resolved = {
|
|
21
|
+
wasCached: false,
|
|
22
|
+
usedDelta: false,
|
|
23
|
+
...result,
|
|
24
|
+
};
|
|
25
|
+
const spy = vi.fn().mockResolvedValue(resolved);
|
|
26
|
+
return {
|
|
27
|
+
fetcher: Object.assign(Object.create(DeltaFetcher.prototype), {
|
|
28
|
+
[method]: spy,
|
|
29
|
+
}) as DeltaFetcher,
|
|
30
|
+
spy,
|
|
31
|
+
resolved,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function createRejectingDeltaFetcherMock(
|
|
36
|
+
method: DeltaFetcherMethod,
|
|
37
|
+
error: Error,
|
|
38
|
+
): { fetcher: DeltaFetcher; spy: ReturnType<typeof vi.fn> } {
|
|
39
|
+
const spy = vi.fn().mockRejectedValue(error);
|
|
40
|
+
return {
|
|
41
|
+
fetcher: Object.assign(Object.create(DeltaFetcher.prototype), {
|
|
42
|
+
[method]: spy,
|
|
43
|
+
}) as DeltaFetcher,
|
|
44
|
+
spy,
|
|
45
|
+
};
|
|
46
|
+
}
|