@dizzlkheinz/ynab-mcpb 0.12.2 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (262) hide show
  1. package/.code/agents/01a13ef4-3f23-4f52-b33b-3585b73cfa60/error.txt +3 -0
  2. package/.code/agents/084fd32f-e298-4728-9103-a78d7dc39613/error.txt +3 -0
  3. package/.code/agents/0fed51e1-a943-4b97-a2a8-a6f0f27c844d/status.txt +1 -0
  4. package/.code/agents/1059b6bd-5ccd-4d83-a12c-7c9d89137399/error.txt +5 -0
  5. package/.code/agents/110/exec-call_F9BDNG7JfxKkq7Vc8ESAvdft.txt +1569 -0
  6. package/.code/agents/11ebcef3-b13f-4e44-ad80-d94a866804b7/error.txt +3 -0
  7. package/.code/agents/1398/exec-call_CjItcWMU1G6JoPshX62QvpaR.txt +2832 -0
  8. package/.code/agents/1398/exec-call_SUVq2ivmONQ5LMCmd7ngmOqr.txt +2709 -0
  9. package/.code/agents/1398/exec-call_SdNY4NOffdcC5pRYjVXHjPCK.txt +2832 -0
  10. package/.code/agents/1398/exec-call_qblJo9et1gsFFB63TtLOiji2.txt +2832 -0
  11. package/.code/agents/1398/exec-call_zaRrzlGz7GJcNzVfkAmML7Zg.txt +2709 -0
  12. package/.code/agents/171834fd-5905-42fc-bbcc-2c755145b0fc/status.txt +1 -0
  13. package/.code/agents/1724/exec-call_HvHQe0w5CCG3T7Q3ULT6MO3g.txt +5217 -0
  14. package/.code/agents/1724/exec-call_QwUNESVzfxxk78K1frh1Vahb.txt +2594 -0
  15. package/.code/agents/1724/exec-call_aJ1Xwz71XmIpD4SBxSHERzLe.txt +2594 -0
  16. package/.code/agents/1d7d7ab7-7473-4b69-8b97-6e914f56056a/result.txt +231 -0
  17. package/.code/agents/210/exec-call_0tQCsKNJ1WTuIchb8wlcFJpW.txt +2590 -0
  18. package/.code/agents/210/exec-call_8ZlY9cUc8Ft1twi4ch8UJ6IN.txt +5195 -0
  19. package/.code/agents/2188/exec-call_5HqayBxIteJtoI8oPTiLWgvJ.txt +286 -0
  20. package/.code/agents/2188/exec-call_XRbBKBq3adZe6dcppAvQtM7G.txt +218 -0
  21. package/.code/agents/2188/exec-call_ehA0SjpYtrUi6GJXmibLjp4i.txt +180 -0
  22. package/.code/agents/21902821-ecaf-4759-bb9d-222b90921af5/error.txt +3 -0
  23. package/.code/agents/232073be-aa0e-46da-b478-5b64dbf03cf5/status.txt +1 -0
  24. package/.code/agents/234ff534-2336-4771-a8d9-aa04421a63be/result.txt +747 -0
  25. package/.code/agents/253e2695-dc36-4022-b436-27655e0fc6c7/status.txt +1 -0
  26. package/.code/agents/2583/exec-call_M59I4eDjpjlBIWBiSxyS0YlJ.txt +2594 -0
  27. package/.code/agents/2583/exec-call_usLRGh7OhVHtsRBL4iUwRhjq.txt +2594 -0
  28. package/.code/agents/292aa3ff-dbab-470f-97c9-e7e8fd65e0db/result.txt +144 -0
  29. package/.code/agents/3134/exec-call_IgCAMGx19lWfuo8zfYIt5FFC.txt +416 -0
  30. package/.code/agents/3134/exec-call_IxvLR2Oo7kba2QTsI1gHVko8.txt +2590 -0
  31. package/.code/agents/3134/exec-call_jYvc8hksZChSiysbzKjl2ZbB.txt +2590 -0
  32. package/.code/agents/329/exec-call_4QdP3SfSO7HGPCwVcqZIth6s.txt +2590 -0
  33. package/.code/agents/472/exec-call_4AxzEEcWwkKhpqRB3bE8Ha4L.txt +790 -0
  34. package/.code/agents/472/exec-call_CB3LPYQA8QIZRi8I6kj4J17A.txt +766 -0
  35. package/.code/agents/472/exec-call_YeoUWvaFoktay2nqVUsa9KKX.txt +790 -0
  36. package/.code/agents/472/exec-call_jPWgKVquBBXTg0T3Lks5ZfkK.txt +2594 -0
  37. package/.code/agents/472/exec-call_qBkvunpGBDEHph2jPmTwtcsb.txt +1000 -0
  38. package/.code/agents/472/exec-call_v0ffRV1p0kTckBmJPzzHAEy0.txt +3489 -0
  39. package/.code/agents/472/exec-call_xAX5FXqWIlk02d9WubHbHWh8.txt +766 -0
  40. package/.code/agents/5346/exec-call_9q0muXUuLaucwEqI51Pt7idT.txt +2594 -0
  41. package/.code/agents/5346/exec-call_B2el3B79rVkq9LhWTI2VYlz7.txt +2456 -0
  42. package/.code/agents/5346/exec-call_BfX08f02qkZI9uJD5dvCvuoj.txt +2594 -0
  43. package/.code/agents/543328d0-61d6-4fd1-a723-bb168656e2e2/error.txt +18 -0
  44. package/.code/agents/5580c02c-1383-4d18-9cbd-cc8a06e3408d/result.txt +48 -0
  45. package/.code/agents/60ce1a22-5126-44b2-b977-1d5b56142a7b/status.txt +1 -0
  46. package/.code/agents/6215d9db-7fa9-4429-aeec-3835c3212291/error.txt +1 -0
  47. package/.code/agents/6743db55-30e5-4b4e-9366-a8214fc7f714/error.txt +1 -0
  48. package/.code/agents/6bf9591b-b9c9-422c-b0a5-e968c7d8422a/status.txt +1 -0
  49. package/.code/agents/7/exec-call_eww3GfdEiJZx61sJEQ9wNmt3.txt +1271 -0
  50. package/.code/agents/70/exec-call_owUtDMYiVgqDf8vsz1i32PFf.txt +1570 -0
  51. package/.code/agents/8/exec-call_UtrjAcLbhYLatxR4O97fZgnm.txt +2590 -0
  52. package/.code/agents/82490bc9-f34e-4b1b-8a8e-bccc2e6254f5/error.txt +3 -0
  53. package/.code/agents/841/exec-call_7nTNhSBCNjTDUIJv7py6CepO.txt +3299 -0
  54. package/.code/agents/841/exec-call_TLI0yUdUijuUAvI4o3DXEvHO.txt +3299 -0
  55. package/.code/agents/9/exec-call_XaABQT1hIlRpnKZ2uyBMWsTC.txt +1882 -0
  56. package/.code/agents/941/exec-call_GuGHRx7NNXWIDAnxUG2NEWPa.txt +2594 -0
  57. package/.code/agents/95d9fbab-19a2-48af-83f9-c792566a347f/error.txt +1 -0
  58. package/.code/agents/b0098cb8-cb32-4ada-9bc4-37c587518896/result.txt +170 -0
  59. package/.code/agents/b4fe59a4-81df-42e2-a112-0153e504faca/error.txt +1 -0
  60. package/.code/agents/bf4ce152-f623-49d7-aa52-c18631625c3c/error.txt +3 -0
  61. package/.code/agents/d7d1db75-d7eb-468e-adea-4ef4d916d187/status.txt +1 -0
  62. package/.code/agents/e2baa9c8-bac3-49e3-a39d-024333e6a990/status.txt +1 -0
  63. package/.code/agents/e350b8c3-8483-408c-b2bb-94515f492a11/error.txt +3 -0
  64. package/.code/agents/e63f9919-719f-4ad0-bccf-01b1a596e1e9/status.txt +1 -0
  65. package/.code/agents/e71695a8-3044-478d-8f12-ed13d02884c7/status.txt +1 -0
  66. package/.code/agents/f95b7464-3e25-4897-b153-c8dfd63fd605/error.txt +5 -0
  67. package/.code/agents/fa3c5ddf-cdf7-47a2-930a-b806c6363689/status.txt +1 -0
  68. package/.github/workflows/ci-tests.yml +6 -2
  69. package/.github/workflows/publish.yml +3 -3
  70. package/.github/workflows/release.yml +4 -0
  71. package/CHANGELOG.md +89 -1
  72. package/NUL +1 -1
  73. package/README.md +36 -10
  74. package/dist/bundle/index.cjs +65 -42
  75. package/dist/index.js +9 -20
  76. package/dist/server/YNABMCPServer.d.ts +2 -1
  77. package/dist/server/YNABMCPServer.js +61 -27
  78. package/dist/server/cacheKeys.d.ts +8 -0
  79. package/dist/server/cacheKeys.js +8 -0
  80. package/dist/server/config.d.ts +22 -3
  81. package/dist/server/config.js +16 -17
  82. package/dist/server/errorHandler.d.ts +2 -0
  83. package/dist/server/errorHandler.js +49 -5
  84. package/dist/server/securityMiddleware.js +3 -6
  85. package/dist/server/toolRegistry.js +8 -10
  86. package/dist/tools/accountTools.js +4 -3
  87. package/dist/tools/categoryTools.js +8 -7
  88. package/dist/tools/monthTools.js +2 -1
  89. package/dist/tools/payeeTools.js +2 -1
  90. package/dist/tools/reconcileAdapter.js +10 -5
  91. package/dist/tools/reconciliation/analyzer.d.ts +4 -2
  92. package/dist/tools/reconciliation/analyzer.js +120 -404
  93. package/dist/tools/reconciliation/csvParser.d.ts +51 -0
  94. package/dist/tools/reconciliation/csvParser.js +413 -0
  95. package/dist/tools/reconciliation/executor.d.ts +8 -0
  96. package/dist/tools/reconciliation/executor.js +277 -50
  97. package/dist/tools/reconciliation/index.d.ts +7 -7
  98. package/dist/tools/reconciliation/index.js +115 -39
  99. package/dist/tools/reconciliation/matcher.d.ts +24 -3
  100. package/dist/tools/reconciliation/matcher.js +175 -133
  101. package/dist/tools/reconciliation/recommendationEngine.js +22 -18
  102. package/dist/tools/reconciliation/reportFormatter.js +9 -8
  103. package/dist/tools/reconciliation/signDetector.d.ts +2 -0
  104. package/dist/tools/reconciliation/signDetector.js +54 -0
  105. package/dist/tools/reconciliation/types.d.ts +20 -34
  106. package/dist/tools/reconciliation/types.js +1 -7
  107. package/dist/tools/reconciliation/ynabAdapter.d.ts +4 -0
  108. package/dist/tools/reconciliation/ynabAdapter.js +15 -0
  109. package/dist/tools/transactionTools.d.ts +3 -17
  110. package/dist/tools/transactionTools.js +5 -17
  111. package/dist/types/reconciliation.d.ts +24 -0
  112. package/dist/types/reconciliation.js +1 -0
  113. package/dist/utils/baseError.d.ts +3 -0
  114. package/dist/utils/baseError.js +7 -0
  115. package/dist/utils/errors.d.ts +13 -0
  116. package/dist/utils/errors.js +15 -0
  117. package/dist/utils/validationError.d.ts +3 -0
  118. package/dist/utils/validationError.js +3 -0
  119. package/docs/guides/ARCHITECTURE.md +12 -129
  120. package/docs/plans/2025-11-20-reloadable-config-token-validation.md +93 -0
  121. package/docs/plans/2025-11-21-fix-transaction-cached-property.md +362 -0
  122. package/docs/plans/2025-11-21-reconciliation-error-handling.md +90 -0
  123. package/docs/plans/2025-11-21-v014-hardening.md +153 -0
  124. package/docs/plans/reconciliation-v2-redesign.md +1571 -0
  125. package/package.json +8 -2
  126. package/scripts/run-throttled-integration-tests.js +9 -3
  127. package/scripts/test-recommendations.ts +1 -1
  128. package/src/__tests__/performance.test.ts +12 -5
  129. package/src/__tests__/testUtils.ts +62 -5
  130. package/src/__tests__/tools/reconciliation/csvParser.integration.test.ts +129 -0
  131. package/src/__tests__/tools/reconciliation/real-world.integration.test.ts +53 -0
  132. package/src/__tests__/workflows.e2e.test.ts +33 -0
  133. package/src/index.ts +8 -31
  134. package/src/server/YNABMCPServer.ts +81 -42
  135. package/src/server/__tests__/YNABMCPServer.integration.test.ts +10 -12
  136. package/src/server/__tests__/YNABMCPServer.test.ts +27 -15
  137. package/src/server/__tests__/config.test.ts +76 -152
  138. package/src/server/__tests__/server-startup.integration.test.ts +42 -14
  139. package/src/server/__tests__/toolRegistry.test.ts +1 -1
  140. package/src/server/cacheKeys.ts +8 -0
  141. package/src/server/config.ts +20 -38
  142. package/src/server/errorHandler.ts +52 -5
  143. package/src/server/securityMiddleware.ts +3 -7
  144. package/src/server/toolRegistry.ts +14 -10
  145. package/src/tools/__tests__/categoryTools.test.ts +37 -19
  146. package/src/tools/__tests__/transactionTools.test.ts +58 -2
  147. package/src/tools/accountTools.ts +8 -3
  148. package/src/tools/categoryTools.ts +12 -7
  149. package/src/tools/monthTools.ts +7 -1
  150. package/src/tools/payeeTools.ts +7 -1
  151. package/src/tools/reconcileAdapter.ts +10 -5
  152. package/src/tools/reconciliation/__tests__/adapter.test.ts +28 -22
  153. package/src/tools/reconciliation/__tests__/analyzer.test.ts +114 -180
  154. package/src/tools/reconciliation/__tests__/csvParser.test.ts +87 -0
  155. package/src/tools/reconciliation/__tests__/executor.integration.test.ts +26 -6
  156. package/src/tools/reconciliation/__tests__/executor.test.ts +133 -60
  157. package/src/tools/reconciliation/__tests__/matcher.test.ts +68 -54
  158. package/src/tools/reconciliation/__tests__/recommendationEngine.test.ts +37 -30
  159. package/src/tools/reconciliation/__tests__/reportFormatter.test.ts +6 -5
  160. package/src/tools/reconciliation/__tests__/scenarios/extremes.scenario.test.ts +30 -11
  161. package/src/tools/reconciliation/__tests__/scenarios/repeatAmount.scenario.test.ts +50 -15
  162. package/src/tools/reconciliation/__tests__/signDetector.test.ts +211 -0
  163. package/src/tools/reconciliation/__tests__/ynabAdapter.test.ts +61 -0
  164. package/src/tools/reconciliation/analyzer.ts +174 -545
  165. package/src/tools/reconciliation/csvParser.ts +617 -0
  166. package/src/tools/reconciliation/executor.ts +344 -58
  167. package/src/tools/reconciliation/index.ts +141 -48
  168. package/src/tools/reconciliation/matcher.ts +234 -214
  169. package/src/tools/reconciliation/recommendationEngine.ts +23 -19
  170. package/src/tools/reconciliation/reportFormatter.ts +16 -11
  171. package/src/tools/reconciliation/signDetector.ts +117 -0
  172. package/src/tools/reconciliation/types.ts +39 -61
  173. package/src/tools/reconciliation/ynabAdapter.ts +33 -0
  174. package/src/tools/schemas/outputs/utilityOutputs.ts +1 -1
  175. package/src/tools/transactionTools.ts +7 -18
  176. package/src/types/reconciliation.ts +49 -0
  177. package/src/utils/baseError.ts +7 -0
  178. package/src/utils/errors.ts +21 -0
  179. package/src/utils/validationError.ts +3 -0
  180. package/temp-recon.ts +126 -0
  181. package/test-exports/ynab_since_2025-10-16_account_53298e13_238items_2025-11-28_13-46-20.json +3662 -0
  182. package/test_mcp_tools.mjs +75 -0
  183. package/.code/agents/0427d95e-edca-431f-a214-5e53264e29c4/error.txt +0 -8
  184. package/.code/agents/0d675174-d1e1-41c3-9975-4c2e275819a9/error.txt +0 -3
  185. package/.code/agents/0d8c5afd-4787-422b-abf8-2e5943fc7e67/error.txt +0 -3
  186. package/.code/agents/0ec34a70-ed5d-4b9e-bee4-bb0e4cccbc4b/error.txt +0 -1
  187. package/.code/agents/0ef51a21-1ab1-49d7-9561-0eaa43875ebc/error.txt +0 -12
  188. package/.code/agents/15db95d7-abad-4b4d-9c3b-8446089cb61d/error.txt +0 -1
  189. package/.code/agents/19ab9acb-f675-4ff0-902a-09a5476f8149/error.txt +0 -1
  190. package/.code/agents/1ef7e12d-f6ff-4897-8a9b-152d523d898e/error.txt +0 -5
  191. package/.code/agents/2465/exec-call_lroN9KKzJVWC7t5423DK1nT9.txt +0 -1453
  192. package/.code/agents/28edb6fe-95a9-41a0-ae69-aa0100d26c0c/error.txt +0 -8
  193. package/.code/agents/2ae40cf5-b4bf-42e2-92bf-7ea350a7755e/error.txt +0 -9
  194. package/.code/agents/2bfc4e1f-ac4b-45a5-b6df-bf89d4dbb54c/error.txt +0 -1
  195. package/.code/agents/2e2e1134-eff0-49be-ba25-8e2c3468a564/error.txt +0 -5
  196. package/.code/agents/3/exec-call_203OC4TNVkLxW7z2HCVEQ1cM.txt +0 -81
  197. package/.code/agents/3/exec-call_SS5T0XSiXB4LSNzUKTl75wkh.txt +0 -610
  198. package/.code/agents/3322c003-ce5e-48e3-a342-f5049c5bf9a2/error.txt +0 -1
  199. package/.code/agents/391e9b08-1ebc-468c-9bcd-6d0cc3193b37/error.txt +0 -1
  200. package/.code/agents/3ab0aa84-b7bb-4054-afa3-40b8fd7d3be0/error.txt +0 -1
  201. package/.code/agents/3bed368d-50fe-477e-aee3-a6707eaa1ab9/error.txt +0 -3
  202. package/.code/agents/3e40b925-db12-442f-8d7a-a25fc69a6672/error.txt +0 -8
  203. package/.code/agents/414d5776-cf58-41f3-9328-a6daed503a50/error.txt +0 -5
  204. package/.code/agents/42687751-4565-4610-b240-67835b17d861/error.txt +0 -1
  205. package/.code/agents/46b98876-1a39-43c9-9e2f-507ca6d47335/error.txt +0 -9
  206. package/.code/agents/4a7d9491-b26f-43dd-850d-2ecdc49b5d1b/error.txt +0 -1
  207. package/.code/agents/4e60f00a-1b3e-447f-87f3-7faf9deddec3/error.txt +0 -13
  208. package/.code/agents/5138fc1c-4d49-4b74-a7da-ccdb3a8e44e7/error.txt +0 -14
  209. package/.code/agents/521cff39-a7a3-42e5-a557-134f0f7daaa0/error.txt +0 -5
  210. package/.code/agents/53302dc5-3857-4413-9a47-9e0f64a51dc4/error.txt +0 -5
  211. package/.code/agents/567c7c2e-6a6f-4761-a08d-d36deeb2e0ac/error.txt +0 -5
  212. package/.code/agents/57b00845-80dc-47c9-953c-3028d16275d6/error.txt +0 -3
  213. package/.code/agents/593d9005-c2a5-48fd-8813-ece0d3f2de96/error.txt +0 -1
  214. package/.code/agents/5a112e66-0e1a-42f9-877c-53af56ea3551/error.txt +0 -1
  215. package/.code/agents/5b05e8ed-7788-4738-b7ee-9faa8180f992/error.txt +0 -5
  216. package/.code/agents/5f888d6f-d7ca-4ac8-be23-9ea1bf753951/error.txt +0 -5
  217. package/.code/agents/607db3ab-e4b0-435b-b497-93e9aa525549/error.txt +0 -8
  218. package/.code/agents/67dcb2a2-900f-4c78-b3fc-80b5213e0ddf/error.txt +0 -8
  219. package/.code/agents/69ad848c-4e98-49b3-b16c-0094ac2d1759/error.txt +0 -5
  220. package/.code/agents/6c9cfc5f-0d0b-445c-b121-9f60082c4f70/error.txt +0 -1
  221. package/.code/agents/6f6f8f77-4ab0-4f6e-9f30-40e8be0bd8f5/error.txt +0 -1
  222. package/.code/agents/72a7cde4-fa8a-4024-9038-27faa550539b/error.txt +0 -1
  223. package/.code/agents/7b48335c-8247-43aa-9949-5f820ba8e199/error.txt +0 -1
  224. package/.code/agents/80944249-bea9-4ac5-87de-a666c4df306e/error.txt +0 -1
  225. package/.code/agents/826099df-1b66-4186-a915-7eb59f9db19d/error.txt +0 -5
  226. package/.code/agents/8291d158-18a8-4a92-b799-4e9a4d9cce88/error.txt +0 -1
  227. package/.code/agents/82fb71a3-20fb-4341-804a-a2fc900f95bc/error.txt +0 -1
  228. package/.code/agents/855790ea-54ee-43e4-8209-a66994e37590/error.txt +0 -1
  229. package/.code/agents/88ce3a2e-04f2-42be-9062-bf97aa798da0/error.txt +0 -3
  230. package/.code/agents/9a17e398-b6ed-4218-bb55-bc64a8d38ce8/error.txt +0 -8
  231. package/.code/agents/9a4f4bfc-a2a6-4f40-a896-9335b41a7ed1/error.txt +0 -1
  232. package/.code/agents/9b633e55-ef84-47d6-94bb-fd3dd172ad97/error.txt +0 -1
  233. package/.code/agents/9b81f3ab-c72b-4a81-9a8f-28a49ddba84a/error.txt +0 -8
  234. package/.code/agents/a35daf29-b2d1-4aef-9b42-dad63a76bd47/error.txt +0 -3
  235. package/.code/agents/a81990cc-69ee-44d2-b907-17403c9bc5d7/error.txt +0 -5
  236. package/.code/agents/ab56260a-4a83-4ad4-9410-f88a23d6520a/error.txt +0 -1
  237. package/.code/agents/ad722c31-2d1d-45f7-bae2-3f02ca455b60/error.txt +0 -1
  238. package/.code/agents/b62e8690-3324-4b97-9309-731bee79416b/error.txt +0 -5
  239. package/.code/agents/baf60a3a-752b-4ad8-99d6-df32423ed2eb/error.txt +0 -1
  240. package/.code/agents/be049042-7dcb-4ac8-9beb-c8f1aea67742/error.txt +0 -14
  241. package/.code/agents/bed1dcb4-bfce-4a9f-8594-0f994962aafd/error.txt +0 -1
  242. package/.code/agents/c324a6cf-e935-4ede-9529-b3ebc18e8d6b/error.txt +0 -5
  243. package/.code/agents/c37c06ff-dfe3-43f2-9bbc-3ec73ec8f41d/error.txt +0 -5
  244. package/.code/agents/c8cd6671-433a-456b-9f88-e51cb2df6bfc/error.txt +0 -11
  245. package/.code/agents/ca2ccb67-2f24-428e-b27d-9365beadd140/error.txt +0 -1
  246. package/.code/agents/cf08c0c8-e7f0-423e-93ba-547e8e818340/error.txt +0 -8
  247. package/.code/agents/d579c74f-874b-40a4-9d56-ced1eb6a701d/error.txt +0 -1
  248. package/.code/agents/df412c98-7378-4deb-8e1e-76c416931181/error.txt +0 -3
  249. package/.code/agents/e5134eb3-2af4-45b0-8998-051cb4afdb45/error.txt +0 -3
  250. package/.code/agents/e6308471-aa45-4e9e-9496-2e9404164d97/error.txt +0 -8
  251. package/.code/agents/e7bd8bc7-23fb-4f46-98dc-b0dcf11b75a1/error.txt +0 -1
  252. package/.code/agents/e92bec35-378d-4fe1-8ac0-6e1bb3c86911/error.txt +0 -5
  253. package/.code/agents/ed918fbf-2dc4-4aa2-bfc5-04b65d9471ea/error.txt +0 -1
  254. package/.code/agents/ef1d756f-b272-48fc-8729-f05c494674f7/error.txt +0 -1
  255. package/.code/agents/ef359853-0249-4e41-a804-c0fc459fe456/error.txt +0 -1
  256. package/.code/agents/effc7b4a-4b90-40a0-8c86-a7a99d2d5fd2/error.txt +0 -1
  257. package/.code/agents/fa15f8d5-8359-4a8b-83a3-2f2056b3ff40/error.txt +0 -3
  258. package/.code/agents/fbef4193-eadf-4c8a-83ff-4878a6310f25/error.txt +0 -8
  259. package/.code/agents/fd0a4b4a-fda4-4964-a6d6-2b8a2da387c6/error.txt +0 -1
  260. package/.gemini/settings.json +0 -8
  261. package/ADOS-2-Module-1-Complete-Manual.md +0 -757
  262. package/WARP.md +0 -245
@@ -1,10 +1,14 @@
1
1
  import { createHash } from 'crypto';
2
- import { toMilli, toMoneyValue, toMoneyValueFromDecimal, addMilli } from '../../utils/money.js';
2
+ import { YNABAPIError } from '../../server/errorHandler.js';
3
+ import { toMilli, toMoneyValue, addMilli } from '../../utils/money.js';
3
4
  import { generateCorrelationKey, correlateResults, toCorrelationPayload, } from '../transactionTools.js';
4
5
  const MONEY_EPSILON_MILLI = 100;
5
6
  const DEFAULT_TOLERANCE_CENTS = 1;
6
7
  const CENTS_TO_MILLI = 10;
7
8
  const MAX_BULK_CREATE_CHUNK = 100;
9
+ const MAX_BULK_UPDATE_CHUNK = 100;
10
+ const BATCH_DELAY_MS = 200;
11
+ const MAX_MEMO_LENGTH = 500;
8
12
  function chunkArray(array, size) {
9
13
  if (size <= 0) {
10
14
  throw new Error('chunk size must be positive');
@@ -15,6 +19,16 @@ function chunkArray(array, size) {
15
19
  }
16
20
  return chunks;
17
21
  }
22
+ function sleep(ms) {
23
+ return new Promise((resolve) => setTimeout(resolve, ms));
24
+ }
25
+ function truncateMemo(memo) {
26
+ if (!memo)
27
+ return 'Auto-reconciled from bank statement';
28
+ if (memo.length <= MAX_MEMO_LENGTH)
29
+ return memo;
30
+ return memo.substring(0, MAX_MEMO_LENGTH - 3) + '...';
31
+ }
18
32
  function generateBulkImportId(accountId, date, amountMilli, payee) {
19
33
  const normalizedPayee = (payee ?? '').trim().toLowerCase();
20
34
  const raw = `${accountId}|${date}|${amountMilli}|${normalizedPayee}`;
@@ -74,13 +88,13 @@ export async function executeReconciliation(options) {
74
88
  let bulkOperationDetails;
75
89
  if (params.auto_create_transactions && !balanceAligned) {
76
90
  const buildPreparedEntry = (bankTxn) => {
77
- const amountMilli = toMilli(bankTxn.amount);
91
+ const amountMilli = bankTxn.amount;
78
92
  const saveTransaction = {
79
93
  account_id: accountId,
80
94
  amount: amountMilli,
81
95
  date: bankTxn.date,
82
96
  payee_name: bankTxn.payee ?? undefined,
83
- memo: bankTxn.memo ?? 'Auto-reconciled from bank statement',
97
+ memo: truncateMemo(bankTxn.memo),
84
98
  cleared: 'cleared',
85
99
  approved: true,
86
100
  import_id: generateBulkImportId(accountId, bankTxn.date, amountMilli, bankTxn.payee),
@@ -139,22 +153,27 @@ export async function executeReconciliation(options) {
139
153
  recordAlignmentIfNeeded(trigger);
140
154
  }
141
155
  catch (error) {
156
+ const ynabError = normalizeYnabError(error);
142
157
  if (bulkOperationDetails) {
143
158
  bulkOperationDetails.transaction_failures += 1;
144
159
  }
145
- const failureReason = error instanceof Error ? error.message : 'Unknown error occurred';
160
+ const failureReason = ynabError.message || 'Unknown error occurred';
161
+ const statusSuffix = ynabError.status ? ` (HTTP ${ynabError.status})` : '';
146
162
  const failureAction = {
147
163
  type: 'create_transaction_failed',
148
164
  transaction: entry.saveTransaction,
149
165
  reason: options.fallbackError
150
- ? `Bulk fallback failed for ${entry.bankTransaction.payee ?? 'Unknown'} (${failureReason})`
151
- : `Failed to create transaction ${entry.bankTransaction.payee ?? 'Unknown'} (${failureReason})`,
166
+ ? `Bulk fallback failed for ${entry.bankTransaction.payee ?? 'Unknown'} (${failureReason}${statusSuffix})`
167
+ : `Failed to create transaction ${entry.bankTransaction.payee ?? 'Unknown'} (${failureReason}${statusSuffix})`,
152
168
  correlation_key: entry.correlationKey,
153
169
  };
154
170
  if (options.chunkIndex !== undefined) {
155
171
  failureAction.bulk_chunk_index = options.chunkIndex;
156
172
  }
157
173
  actions_taken.push(failureAction);
174
+ if (shouldPropagateYnabError(ynabError)) {
175
+ throw attachStatusToError(ynabError, error);
176
+ }
158
177
  }
159
178
  }
160
179
  if (bulkOperationDetails && options.fallbackError && sequentialAttempts > 0) {
@@ -280,15 +299,21 @@ export async function executeReconciliation(options) {
280
299
  bulkOperationDetails.bulk_successes += 1;
281
300
  }
282
301
  catch (error) {
283
- bulkOperationDetails.sequential_fallbacks += 1;
302
+ const ynabError = normalizeYnabError(error);
303
+ const failureReason = ynabError.message || 'unknown error';
284
304
  bulkOperationDetails.bulk_chunk_failures += 1;
305
+ if (shouldPropagateYnabError(ynabError)) {
306
+ bulkOperationDetails.transaction_failures += chunk.length;
307
+ throw attachStatusToError(ynabError, error);
308
+ }
309
+ bulkOperationDetails.sequential_fallbacks += 1;
285
310
  actions_taken.push({
286
311
  type: 'bulk_create_fallback',
287
312
  transaction: null,
288
- reason: `Bulk chunk #${chunkIndex} failed (${error instanceof Error ? error.message : 'unknown error'}) - falling back to sequential creation`,
313
+ reason: `Bulk chunk #${chunkIndex} failed (${failureReason}${ynabError.status ? ` (HTTP ${ynabError.status})` : ''}) - falling back to sequential creation`,
289
314
  bulk_chunk_index: chunkIndex,
290
315
  });
291
- await processSequentialEntries(chunk, { chunkIndex, fallbackError: error });
316
+ await processSequentialEntries(chunk, { chunkIndex, fallbackError: ynabError });
292
317
  }
293
318
  }
294
319
  }
@@ -306,13 +331,16 @@ export async function executeReconciliation(options) {
306
331
  const flags = computeUpdateFlags(match, params);
307
332
  if (!flags.needsClearedUpdate && !flags.needsDateUpdate)
308
333
  continue;
309
- if (!match.ynab_transaction)
334
+ if (!match.ynabTransaction)
310
335
  continue;
311
336
  const updatePayload = {
312
- id: match.ynab_transaction.id,
337
+ id: match.ynabTransaction.id,
313
338
  };
339
+ if (match.ynabTransaction.memo) {
340
+ updatePayload.memo = truncateMemo(match.ynabTransaction.memo);
341
+ }
314
342
  if (flags.needsDateUpdate) {
315
- updatePayload.date = match.bank_transaction.date;
343
+ updatePayload.date = match.bankTransaction.date;
316
344
  }
317
345
  if (flags.needsClearedUpdate) {
318
346
  updatePayload.cleared = 'cleared';
@@ -324,15 +352,15 @@ export async function executeReconciliation(options) {
324
352
  actions_taken.push({
325
353
  type: 'update_transaction',
326
354
  transaction: {
327
- transaction_id: match.ynab_transaction.id,
328
- new_date: flags.needsDateUpdate ? match.bank_transaction.date : undefined,
355
+ transaction_id: match.ynabTransaction.id,
356
+ new_date: flags.needsDateUpdate ? match.bankTransaction.date : undefined,
329
357
  cleared: flags.needsClearedUpdate ? 'cleared' : undefined,
330
358
  },
331
359
  reason: `Would update transaction: ${updateReason(match, flags, currencyCode)}`,
332
360
  });
333
361
  if (flags.needsClearedUpdate) {
334
- applyClearedDelta(match.ynab_transaction.amount);
335
- if (recordAlignmentIfNeeded(`clearing ${match.ynab_transaction.id ?? 'transaction'} (dry run)`)) {
362
+ applyClearedDelta(match.ynabTransaction.amount);
363
+ if (recordAlignmentIfNeeded(`clearing ${match.ynabTransaction.id ?? 'transaction'} (dry run)`)) {
336
364
  break;
337
365
  }
338
366
  }
@@ -342,34 +370,75 @@ export async function executeReconciliation(options) {
342
370
  if (flags.needsDateUpdate)
343
371
  summary.dates_adjusted += 1;
344
372
  if (flags.needsClearedUpdate) {
345
- applyClearedDelta(match.ynab_transaction.amount);
346
- if (recordAlignmentIfNeeded(`clearing ${match.ynab_transaction.id}`)) {
373
+ applyClearedDelta(match.ynabTransaction.amount);
374
+ if (recordAlignmentIfNeeded(`clearing ${match.ynabTransaction.id}`)) {
347
375
  break;
348
376
  }
349
377
  }
350
378
  }
351
379
  }
352
380
  if (!params.dry_run && transactionsToUpdate.length > 0) {
353
- const response = await ynabAPI.transactions.updateTransactions(budgetId, {
354
- transactions: transactionsToUpdate,
355
- });
356
- const updatedTransactions = response.data.transactions ?? [];
357
- summary.transactions_updated += updatedTransactions.length;
358
- for (const updatedTransaction of updatedTransactions) {
359
- const match = orderedAutoMatches.find((m) => m.ynab_transaction?.id === updatedTransaction.id);
360
- const flags = match
361
- ? computeUpdateFlags(match, params)
362
- : { needsClearedUpdate: false, needsDateUpdate: false };
363
- actions_taken.push({
364
- type: 'update_transaction',
365
- transaction: updatedTransaction,
366
- reason: `Updated transaction: ${match ? updateReason(match, flags, currencyCode) : 'cleared'}`,
367
- });
381
+ const updateChunks = chunkArray(transactionsToUpdate, MAX_BULK_UPDATE_CHUNK);
382
+ for (let chunkIdx = 0; chunkIdx < updateChunks.length; chunkIdx++) {
383
+ const chunk = updateChunks[chunkIdx];
384
+ try {
385
+ const response = await ynabAPI.transactions.updateTransactions(budgetId, {
386
+ transactions: chunk,
387
+ });
388
+ const updatedTransactions = response.data.transactions ?? [];
389
+ summary.transactions_updated += updatedTransactions.length;
390
+ for (const updatedTransaction of updatedTransactions) {
391
+ const match = orderedAutoMatches.find((m) => m.ynabTransaction?.id === updatedTransaction.id);
392
+ const flags = match
393
+ ? computeUpdateFlags(match, params)
394
+ : { needsClearedUpdate: false, needsDateUpdate: false };
395
+ actions_taken.push({
396
+ type: 'update_transaction',
397
+ transaction: updatedTransaction,
398
+ reason: `Updated transaction: ${match ? updateReason(match, flags, currencyCode) : 'cleared'}`,
399
+ });
400
+ }
401
+ accountSnapshotDirty = true;
402
+ }
403
+ catch (error) {
404
+ const ynabError = normalizeYnabError(error);
405
+ const failureReason = ynabError.message || 'Unknown error occurred';
406
+ const statusSuffix = ynabError.status ? ` (HTTP ${ynabError.status})` : '';
407
+ actions_taken.push({
408
+ type: 'batch_update_failed',
409
+ transaction: null,
410
+ reason: `Failed to update chunk ${chunkIdx + 1}/${updateChunks.length} (${chunk.length} transaction(s)): ${failureReason}${statusSuffix}`,
411
+ });
412
+ if (shouldPropagateYnabError(ynabError)) {
413
+ throw attachStatusToError(ynabError, error);
414
+ }
415
+ }
416
+ if (chunkIdx < updateChunks.length - 1) {
417
+ await sleep(BATCH_DELAY_MS);
418
+ }
368
419
  }
369
- accountSnapshotDirty = true;
370
420
  }
371
421
  }
372
422
  const shouldRunSanityPass = params.auto_unclear_missing && !balanceAligned;
423
+ actions_taken.push({
424
+ type: 'diagnostic_step3_entry',
425
+ transaction: null,
426
+ reason: `STEP 3 diagnostics: auto_unclear_missing=${params.auto_unclear_missing}, balanceAligned=${balanceAligned}, shouldRunSanityPass=${shouldRunSanityPass}, orderedUnmatchedYNAB.length=${orderedUnmatchedYNAB.length}`,
427
+ });
428
+ if (orderedUnmatchedYNAB.length > 0) {
429
+ const unmatchedDetails = orderedUnmatchedYNAB.slice(0, 10).map((t) => ({
430
+ id: t.id,
431
+ date: t.date,
432
+ cleared: t.cleared,
433
+ amount: formatDisplay(t.amount, currencyCode),
434
+ payee: t.payee ?? 'Unknown',
435
+ }));
436
+ actions_taken.push({
437
+ type: 'diagnostic_unmatched_ynab',
438
+ transaction: { unmatched_transactions: unmatchedDetails },
439
+ reason: `First ${Math.min(10, orderedUnmatchedYNAB.length)} unmatched YNAB transactions (cleared status and amounts)`,
440
+ });
441
+ }
373
442
  if (shouldRunSanityPass) {
374
443
  const transactionsToUnclear = [];
375
444
  for (const ynabTxn of orderedUnmatchedYNAB) {
@@ -401,19 +470,97 @@ export async function executeReconciliation(options) {
401
470
  }
402
471
  }
403
472
  if (!params.dry_run && transactionsToUnclear.length > 0) {
404
- const response = await ynabAPI.transactions.updateTransactions(budgetId, {
405
- transactions: transactionsToUnclear,
473
+ const unclearChunks = chunkArray(transactionsToUnclear, MAX_BULK_UPDATE_CHUNK);
474
+ for (let chunkIdx = 0; chunkIdx < unclearChunks.length; chunkIdx++) {
475
+ const chunk = unclearChunks[chunkIdx];
476
+ try {
477
+ const response = await ynabAPI.transactions.updateTransactions(budgetId, {
478
+ transactions: chunk,
479
+ });
480
+ const updatedTransactions = response.data.transactions ?? [];
481
+ summary.transactions_updated += updatedTransactions.length;
482
+ for (const updatedTransaction of updatedTransactions) {
483
+ actions_taken.push({
484
+ type: 'update_transaction',
485
+ transaction: updatedTransaction,
486
+ reason: `Marked transaction ${updatedTransaction.id} as uncleared - not found on statement`,
487
+ });
488
+ }
489
+ accountSnapshotDirty = true;
490
+ }
491
+ catch (error) {
492
+ const ynabError = normalizeYnabError(error);
493
+ const failureReason = ynabError.message || 'Unknown error occurred';
494
+ const statusSuffix = ynabError.status ? ` (HTTP ${ynabError.status})` : '';
495
+ actions_taken.push({
496
+ type: 'batch_unclear_failed',
497
+ transaction: null,
498
+ reason: `Failed to unclear chunk ${chunkIdx + 1}/${unclearChunks.length} (${chunk.length} transaction(s)): ${failureReason}${statusSuffix}`,
499
+ });
500
+ if (shouldPropagateYnabError(ynabError)) {
501
+ throw attachStatusToError(ynabError, error);
502
+ }
503
+ }
504
+ if (chunkIdx < unclearChunks.length - 1) {
505
+ await sleep(BATCH_DELAY_MS);
506
+ }
507
+ }
508
+ }
509
+ }
510
+ if (balanceAligned && !params.dry_run) {
511
+ const transactionsToReconcile = [];
512
+ for (const match of orderedAutoMatches) {
513
+ if (!match.ynabTransaction)
514
+ continue;
515
+ if (match.ynabTransaction.cleared === 'reconciled')
516
+ continue;
517
+ transactionsToReconcile.push({
518
+ id: match.ynabTransaction.id,
519
+ cleared: 'reconciled',
406
520
  });
407
- const updatedTransactions = response.data.transactions ?? [];
408
- summary.transactions_updated += updatedTransactions.length;
409
- for (const updatedTransaction of updatedTransactions) {
410
- actions_taken.push({
411
- type: 'update_transaction',
412
- transaction: updatedTransaction,
413
- reason: `Marked transaction ${updatedTransaction.id} as uncleared - not found on statement`,
414
- });
521
+ }
522
+ if (transactionsToReconcile.length > 0) {
523
+ const reconcileChunks = chunkArray(transactionsToReconcile, MAX_BULK_UPDATE_CHUNK);
524
+ for (let chunkIdx = 0; chunkIdx < reconcileChunks.length; chunkIdx++) {
525
+ const chunk = reconcileChunks[chunkIdx];
526
+ try {
527
+ const response = await ynabAPI.transactions.updateTransactions(budgetId, {
528
+ transactions: chunk,
529
+ });
530
+ const reconciledTransactions = response.data.transactions ?? [];
531
+ summary.transactions_updated += reconciledTransactions.length;
532
+ for (const reconciledTransaction of reconciledTransactions) {
533
+ const match = orderedAutoMatches.find((m) => m.ynabTransaction?.id === reconciledTransaction.id);
534
+ actions_taken.push({
535
+ type: 'update_transaction',
536
+ transaction: reconciledTransaction,
537
+ reason: `Marked as reconciled: ${match?.bankTransaction.payee ?? 'transaction'} (${formatDisplay(reconciledTransaction.amount, currencyCode)})`,
538
+ });
539
+ }
540
+ accountSnapshotDirty = true;
541
+ }
542
+ catch (error) {
543
+ const ynabError = normalizeYnabError(error);
544
+ const failureReason = ynabError.message || 'Unknown error occurred';
545
+ const statusSuffix = ynabError.status ? ` (HTTP ${ynabError.status})` : '';
546
+ actions_taken.push({
547
+ type: 'batch_reconcile_failed',
548
+ transaction: null,
549
+ reason: `Failed to reconcile chunk ${chunkIdx + 1}/${reconcileChunks.length} (${chunk.length} transaction(s)): ${failureReason}${statusSuffix}`,
550
+ });
551
+ if (shouldPropagateYnabError(ynabError)) {
552
+ throw attachStatusToError(ynabError, error);
553
+ }
554
+ }
555
+ if (chunkIdx < reconcileChunks.length - 1) {
556
+ await sleep(BATCH_DELAY_MS);
557
+ }
415
558
  }
416
- accountSnapshotDirty = true;
559
+ actions_taken.push({
560
+ type: 'reconciliation_complete',
561
+ transaction: null,
562
+ reason: `Marked ${transactionsToReconcile.length} matched transaction(s) as reconciled - balance aligned within tolerance`,
563
+ });
417
564
  }
418
565
  }
419
566
  let balance_reconciliation;
@@ -456,12 +603,92 @@ export async function executeReconciliation(options) {
456
603
  }
457
604
  return result;
458
605
  }
606
+ const FATAL_YNAB_STATUS_CODES = new Set([400, 401, 403, 404, 429, 500, 503]);
607
+ export function normalizeYnabError(error) {
608
+ const parseStatus = (value) => {
609
+ if (typeof value === 'number' && Number.isFinite(value))
610
+ return value;
611
+ if (typeof value === 'string') {
612
+ const numeric = Number(value);
613
+ if (Number.isFinite(numeric))
614
+ return numeric;
615
+ }
616
+ return undefined;
617
+ };
618
+ if (error instanceof Error) {
619
+ const status = parseStatus(error.status) ??
620
+ parseStatus(error.response?.status);
621
+ const detailSource = error.detail;
622
+ const detail = typeof detailSource === 'string' && detailSource.trim().length > 0 ? detailSource : undefined;
623
+ const result = {
624
+ name: error.name,
625
+ message: error.message || 'Unknown error occurred',
626
+ };
627
+ if (status !== undefined)
628
+ result.status = status;
629
+ if (detail !== undefined)
630
+ result.detail = detail;
631
+ return result;
632
+ }
633
+ if (error && typeof error === 'object') {
634
+ const errObj = error.error ?? error;
635
+ const status = parseStatus(errObj.id ?? errObj.status);
636
+ const detailCandidate = errObj.detail ??
637
+ errObj.message ??
638
+ errObj.name;
639
+ const detail = typeof detailCandidate === 'string' && detailCandidate.trim().length > 0
640
+ ? detailCandidate
641
+ : undefined;
642
+ const message = detail ??
643
+ (typeof errObj === 'string' && errObj.trim().length > 0 ? errObj : 'Unknown error occurred');
644
+ const name = typeof errObj.name === 'string'
645
+ ? errObj.name
646
+ : undefined;
647
+ const result = { message };
648
+ if (status !== undefined)
649
+ result.status = status;
650
+ if (name !== undefined)
651
+ result.name = name;
652
+ if (detail !== undefined)
653
+ result.detail = detail;
654
+ return result;
655
+ }
656
+ if (typeof error === 'string') {
657
+ return { message: error };
658
+ }
659
+ return { message: 'Unknown error occurred' };
660
+ }
661
+ export function shouldPropagateYnabError(error) {
662
+ return error.status !== undefined && FATAL_YNAB_STATUS_CODES.has(error.status);
663
+ }
664
+ function attachStatusToError(error, originalError) {
665
+ const message = error.message || 'YNAB API error';
666
+ const isKnownCode = error.status === 400 ||
667
+ error.status === 401 ||
668
+ error.status === 403 ||
669
+ error.status === 404 ||
670
+ error.status === 429 ||
671
+ error.status === 500;
672
+ if (isKnownCode) {
673
+ return new YNABAPIError(error.status, message, originalError);
674
+ }
675
+ const statusFragment = error.status ? ` (HTTP ${error.status})` : '';
676
+ const detailFragment = error.detail && !message.includes(error.detail) ? ` (${error.detail})` : '';
677
+ const err = new Error(`${message}${statusFragment}${detailFragment}`);
678
+ if (error.status !== undefined) {
679
+ err.status = error.status;
680
+ }
681
+ if (error.name) {
682
+ err.name = error.name;
683
+ }
684
+ return err;
685
+ }
459
686
  function formatDisplay(amount, currency) {
460
- return toMoneyValueFromDecimal(amount, currency).value_display;
687
+ return toMoneyValue(amount, currency).value_display;
461
688
  }
462
689
  function computeUpdateFlags(match, params) {
463
- const ynabTxn = match.ynab_transaction;
464
- const bankTxn = match.bank_transaction;
690
+ const ynabTxn = match.ynabTransaction;
691
+ const bankTxn = match.bankTransaction;
465
692
  if (!ynabTxn) {
466
693
  return { needsClearedUpdate: false, needsDateUpdate: false };
467
694
  }
@@ -475,7 +702,7 @@ function updateReason(match, flags, _currency) {
475
702
  parts.push('marked as cleared');
476
703
  }
477
704
  if (flags.needsDateUpdate) {
478
- parts.push(`date adjusted to ${match.bank_transaction.date}`);
705
+ parts.push(`date adjusted to ${match.bankTransaction.date}`);
479
706
  }
480
707
  return parts.join(', ');
481
708
  }
@@ -596,7 +823,7 @@ function sortByDateDescending(items) {
596
823
  return [...items].sort((a, b) => compareDates(b.date, a.date));
597
824
  }
598
825
  function sortMatchesByBankDateDescending(matches) {
599
- return [...matches].sort((a, b) => compareDates(b.bank_transaction.date, a.bank_transaction.date));
826
+ return [...matches].sort((a, b) => compareDates(b.bankTransaction.date, a.bankTransaction.date));
600
827
  }
601
828
  function compareDates(dateA, dateB) {
602
829
  return toChronoValue(dateA) - toChronoValue(dateB);
@@ -11,16 +11,16 @@ export declare const ReconcileAccountSchema: z.ZodObject<{
11
11
  account_id: z.ZodString;
12
12
  csv_file_path: z.ZodOptional<z.ZodString>;
13
13
  csv_data: z.ZodOptional<z.ZodString>;
14
- csv_format: z.ZodDefault<z.ZodOptional<z.ZodObject<{
15
- date_column: z.ZodDefault<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
14
+ csv_format: z.ZodOptional<z.ZodObject<{
15
+ date_column: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
16
16
  amount_column: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
17
17
  debit_column: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
18
18
  credit_column: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
19
- description_column: z.ZodDefault<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
20
- date_format: z.ZodDefault<z.ZodOptional<z.ZodString>>;
21
- has_header: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
22
- delimiter: z.ZodDefault<z.ZodOptional<z.ZodString>>;
23
- }, z.core.$strict>>>;
19
+ description_column: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
20
+ date_format: z.ZodOptional<z.ZodString>;
21
+ has_header: z.ZodOptional<z.ZodBoolean>;
22
+ delimiter: z.ZodOptional<z.ZodString>;
23
+ }, z.core.$strict>>;
24
24
  statement_balance: z.ZodNumber;
25
25
  statement_start_date: z.ZodOptional<z.ZodString>;
26
26
  statement_end_date: z.ZodOptional<z.ZodString>;