fin-infra 0.7.0__tar.gz → 0.9.0__tar.gz

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 (182) hide show
  1. {fin_infra-0.7.0 → fin_infra-0.9.0}/PKG-INFO +1 -1
  2. {fin_infra-0.7.0 → fin_infra-0.9.0}/pyproject.toml +1 -1
  3. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/banking/__init__.py +4 -0
  4. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/providers/banking/plaid_client.py +11 -9
  5. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/providers/banking/teller_client.py +43 -8
  6. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/recurring/insights.py +1 -1
  7. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/recurring/normalizers.py +1 -1
  8. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/settings.py +8 -0
  9. {fin_infra-0.7.0 → fin_infra-0.9.0}/LICENSE +0 -0
  10. {fin_infra-0.7.0 → fin_infra-0.9.0}/README.md +0 -0
  11. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/__init__.py +0 -0
  12. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/__main__.py +0 -0
  13. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/analytics/__init__.py +0 -0
  14. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/analytics/add.py +0 -0
  15. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/analytics/benchmark.py +0 -0
  16. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/analytics/cash_flow.py +0 -0
  17. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/analytics/ease.py +0 -0
  18. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/analytics/models.py +0 -0
  19. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/analytics/portfolio.py +0 -0
  20. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/analytics/projections.py +0 -0
  21. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/analytics/rebalancing.py +0 -0
  22. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/analytics/rebalancing_llm.py +0 -0
  23. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/analytics/savings.py +0 -0
  24. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/analytics/scenarios.py +0 -0
  25. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/analytics/spending.py +0 -0
  26. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/banking/history.py +0 -0
  27. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/banking/utils.py +0 -0
  28. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/brokerage/__init__.py +0 -0
  29. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/budgets/__init__.py +0 -0
  30. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/budgets/add.py +0 -0
  31. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/budgets/alerts.py +0 -0
  32. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/budgets/ease.py +0 -0
  33. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/budgets/models.py +0 -0
  34. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/budgets/scaffold_templates/README.md +0 -0
  35. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/budgets/scaffold_templates/__init__.py +0 -0
  36. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/budgets/scaffold_templates/models.py.tmpl +0 -0
  37. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/budgets/scaffold_templates/repository.py.tmpl +0 -0
  38. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/budgets/scaffold_templates/schemas.py.tmpl +0 -0
  39. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/budgets/templates.py +0 -0
  40. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/budgets/tracker.py +0 -0
  41. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/cashflows/__init__.py +0 -0
  42. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/cashflows/core.py +0 -0
  43. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/categorization/__init__.py +0 -0
  44. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/categorization/add.py +0 -0
  45. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/categorization/ease.py +0 -0
  46. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/categorization/engine.py +0 -0
  47. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/categorization/llm_layer.py +0 -0
  48. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/categorization/models.py +0 -0
  49. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/categorization/rules.py +0 -0
  50. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/categorization/taxonomy.py +0 -0
  51. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/chat/__init__.py +0 -0
  52. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/chat/ease.py +0 -0
  53. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/chat/planning.py +0 -0
  54. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/cli/__init__.py +0 -0
  55. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/cli/cmds/__init__.py +0 -0
  56. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/cli/cmds/scaffold_cmds.py +0 -0
  57. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/clients/__init__.py +0 -0
  58. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/clients/base.py +0 -0
  59. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/clients/plaid.py +0 -0
  60. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/compliance/__init__.py +0 -0
  61. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/credit/__init__.py +0 -0
  62. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/credit/add.py +0 -0
  63. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/credit/experian/__init__.py +0 -0
  64. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/credit/experian/auth.py +0 -0
  65. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/credit/experian/client.py +0 -0
  66. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/credit/experian/parser.py +0 -0
  67. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/credit/experian/provider.py +0 -0
  68. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/credit/mock.py +0 -0
  69. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/crypto/__init__.py +0 -0
  70. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/crypto/insights.py +0 -0
  71. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/documents/__init__.py +0 -0
  72. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/documents/add.py +0 -0
  73. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/documents/analysis.py +0 -0
  74. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/documents/ease.py +0 -0
  75. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/documents/models.py +0 -0
  76. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/documents/ocr.py +0 -0
  77. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/documents/storage.py +0 -0
  78. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/exceptions.py +0 -0
  79. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/goals/__init__.py +0 -0
  80. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/goals/add.py +0 -0
  81. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/goals/funding.py +0 -0
  82. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/goals/management.py +0 -0
  83. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/goals/milestones.py +0 -0
  84. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/goals/models.py +0 -0
  85. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/goals/scaffold_templates/README.md +0 -0
  86. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/goals/scaffold_templates/__init__.py +0 -0
  87. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/goals/scaffold_templates/models.py.tmpl +0 -0
  88. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/goals/scaffold_templates/repository.py.tmpl +0 -0
  89. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/goals/scaffold_templates/schemas.py.tmpl +0 -0
  90. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/insights/__init__.py +0 -0
  91. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/insights/aggregator.py +0 -0
  92. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/insights/models.py +0 -0
  93. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/investments/__init__.py +0 -0
  94. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/investments/add.py +0 -0
  95. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/investments/ease.py +0 -0
  96. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/investments/models.py +0 -0
  97. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/investments/providers/__init__.py +0 -0
  98. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/investments/providers/base.py +0 -0
  99. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/investments/providers/plaid.py +0 -0
  100. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/investments/providers/snaptrade.py +0 -0
  101. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/investments/scaffold_templates/README.md +0 -0
  102. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/investments/scaffold_templates/__init__.py +0 -0
  103. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/investments/scaffold_templates/models.py.tmpl +0 -0
  104. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/investments/scaffold_templates/repository.py.tmpl +0 -0
  105. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/investments/scaffold_templates/schemas.py.tmpl +0 -0
  106. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/markets/__init__.py +0 -0
  107. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/models/__init__.py +0 -0
  108. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/models/accounts.py +0 -0
  109. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/models/brokerage.py +0 -0
  110. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/models/candle.py +0 -0
  111. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/models/credit.py +0 -0
  112. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/models/money.py +0 -0
  113. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/models/quotes.py +0 -0
  114. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/models/tax.py +0 -0
  115. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/models/transactions.py +0 -0
  116. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/net_worth/__init__.py +0 -0
  117. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/net_worth/add.py +0 -0
  118. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/net_worth/aggregator.py +0 -0
  119. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/net_worth/calculator.py +0 -0
  120. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/net_worth/ease.py +0 -0
  121. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/net_worth/goals.py +0 -0
  122. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/net_worth/insights.py +0 -0
  123. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/net_worth/models.py +0 -0
  124. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/net_worth/scaffold_templates/README.md +0 -0
  125. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/net_worth/scaffold_templates/__init__.py +0 -0
  126. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/net_worth/scaffold_templates/models.py.tmpl +0 -0
  127. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/net_worth/scaffold_templates/repository.py.tmpl +0 -0
  128. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/net_worth/scaffold_templates/schemas.py.tmpl +0 -0
  129. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/normalization/__init__.py +0 -0
  130. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/normalization/currency_converter.py +0 -0
  131. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/normalization/models.py +0 -0
  132. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/normalization/providers/__init__.py +0 -0
  133. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/normalization/providers/exchangerate.py +0 -0
  134. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/normalization/providers/static_mappings.py +0 -0
  135. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/normalization/symbol_resolver.py +0 -0
  136. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/obs/__init__.py +0 -0
  137. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/obs/classifier.py +0 -0
  138. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/providers/__init__.py +0 -0
  139. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/providers/banking/base.py +0 -0
  140. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/providers/base.py +0 -0
  141. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/providers/brokerage/alpaca.py +0 -0
  142. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/providers/brokerage/base.py +0 -0
  143. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/providers/credit/experian.py +0 -0
  144. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/providers/identity/stripe_identity.py +0 -0
  145. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/providers/market/alphavantage.py +0 -0
  146. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/providers/market/base.py +0 -0
  147. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/providers/market/ccxt_crypto.py +0 -0
  148. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/providers/market/coingecko.py +0 -0
  149. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/providers/market/yahoo.py +0 -0
  150. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/providers/registry.py +0 -0
  151. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/providers/tax/__init__.py +0 -0
  152. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/providers/tax/irs.py +0 -0
  153. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/providers/tax/mock.py +0 -0
  154. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/providers/tax/taxbit.py +0 -0
  155. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/py.typed +0 -0
  156. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/recurring/__init__.py +0 -0
  157. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/recurring/add.py +0 -0
  158. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/recurring/detector.py +0 -0
  159. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/recurring/detectors_llm.py +0 -0
  160. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/recurring/ease.py +0 -0
  161. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/recurring/models.py +0 -0
  162. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/recurring/normalizer.py +0 -0
  163. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/recurring/summary.py +0 -0
  164. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/scaffold/__init__.py +0 -0
  165. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/scaffold/budgets.py +0 -0
  166. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/scaffold/goals.py +0 -0
  167. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/security/__init__.py +0 -0
  168. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/security/add.py +0 -0
  169. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/security/audit.py +0 -0
  170. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/security/encryption.py +0 -0
  171. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/security/models.py +0 -0
  172. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/security/pii_filter.py +0 -0
  173. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/security/pii_patterns.py +0 -0
  174. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/security/token_store.py +0 -0
  175. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/tax/__init__.py +0 -0
  176. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/tax/add.py +0 -0
  177. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/tax/tlh.py +0 -0
  178. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/utils/__init__.py +0 -0
  179. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/utils/deprecation.py +0 -0
  180. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/utils/http.py +0 -0
  181. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/utils/retry.py +0 -0
  182. {fin_infra-0.7.0 → fin_infra-0.9.0}/src/fin_infra/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: fin-infra
3
- Version: 0.7.0
3
+ Version: 0.9.0
4
4
  Summary: Financial infrastructure toolkit: banking connections, market data, credit, cashflows, and brokerage integrations
5
5
  License: MIT
6
6
  Keywords: finance,banking,plaid,brokerage,markets,credit,tax,cashflow,fintech,infra
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "fin-infra"
3
- version = "0.7.0"
3
+ version = "0.9.0"
4
4
  description = "Financial infrastructure toolkit: banking connections, market data, credit, cashflows, and brokerage integrations"
5
5
  authors = ["Ali Khatami <aliikhatami94@gmail.com>"]
6
6
  license = "MIT"
@@ -28,6 +28,8 @@ Environment Variables:
28
28
  Teller:
29
29
  TELLER_CERTIFICATE_PATH: Path to certificate.pem file
30
30
  TELLER_PRIVATE_KEY_PATH: Path to private_key.pem file
31
+ TELLER_CERTIFICATE: Inline certificate PEM content (alternative to path)
32
+ TELLER_PRIVATE_KEY: Inline private key PEM content (alternative to path)
31
33
  TELLER_ENVIRONMENT: "sandbox" or "production" (default: sandbox)
32
34
 
33
35
  Plaid:
@@ -191,6 +193,8 @@ def easy_banking(provider: str = "teller", **config) -> BankingProvider:
191
193
  config = {
192
194
  "cert_path": os.getenv("TELLER_CERTIFICATE_PATH"),
193
195
  "key_path": os.getenv("TELLER_PRIVATE_KEY_PATH"),
196
+ "cert_content": os.getenv("TELLER_CERTIFICATE"),
197
+ "key_content": os.getenv("TELLER_PRIVATE_KEY"),
194
198
  "environment": os.getenv("TELLER_ENVIRONMENT", "sandbox"),
195
199
  }
196
200
  elif provider == "plaid":
@@ -52,6 +52,12 @@ class PlaidClient(BankingProvider):
52
52
  client_id = client_id or settings.plaid_client_id
53
53
  secret = secret or settings.plaid_secret
54
54
  environment = environment or settings.plaid_env
55
+ self._products = settings.plaid_products
56
+ else:
57
+ # Use default products when no settings object provided
58
+ from ...settings import DEFAULT_PLAID_PRODUCTS
59
+
60
+ self._products = DEFAULT_PLAID_PRODUCTS
55
61
 
56
62
  # Map environment string to Plaid Environment enum
57
63
  # Note: Plaid only has Sandbox and Production (no Development in SDK)
@@ -105,15 +111,11 @@ class PlaidClient(BankingProvider):
105
111
  # Don't include products - Plaid uses existing item's products
106
112
  request_params["access_token"] = access_token
107
113
  else:
108
- # New connection: specify products to enable
109
- request_params["products"] = [
110
- Products("auth"), # Account/routing numbers for ACH
111
- Products("transactions"), # Transaction history
112
- Products("liabilities"), # Credit cards, loans, student loans
113
- Products("investments"), # Brokerage, retirement accounts
114
- Products("assets"), # Asset reports for lending/verification
115
- Products("identity"), # Account holder info (name, email, phone)
116
- ]
114
+ # New connection: specify products from settings
115
+ # Configurable via PLAID_PRODUCTS env var (comma-separated)
116
+ # Default: auth,transactions,investments (excludes costly unused products)
117
+ product_list = [Products(p.strip()) for p in self._products.split(",") if p.strip()]
118
+ request_params["products"] = product_list
117
119
 
118
120
  request = LinkTokenCreateRequest(**request_params)
119
121
  response = self.client.link_token_create(request)
@@ -52,25 +52,42 @@ class TellerClient(BankingProvider):
52
52
  self,
53
53
  cert_path: str | None = None,
54
54
  key_path: str | None = None,
55
+ cert_content: str | None = None,
56
+ key_content: str | None = None,
55
57
  environment: str = "sandbox",
56
58
  timeout: float = 30.0,
57
59
  ) -> None:
58
60
  """Initialize TellerClient banking provider.
59
61
 
60
62
  Args:
61
- cert_path: Path to certificate.pem file (required for real usage)
62
- key_path: Path to private_key.pem file (required for real usage)
63
+ cert_path: Path to certificate.pem file
64
+ key_path: Path to private_key.pem file
65
+ cert_content: Inline certificate PEM content (alternative to cert_path)
66
+ key_content: Inline private key PEM content (alternative to key_path)
63
67
  environment: "sandbox" or "production" (default: sandbox)
64
68
  timeout: HTTP request timeout in seconds (default: 30.0)
65
69
 
70
+ Note:
71
+ Either (cert_path, key_path) or (cert_content, key_content) must be provided
72
+ for production. The inline content options are useful for Railway/Vercel
73
+ where env vars are preferred over mounted files.
74
+
66
75
  Raises:
67
- ValueError: If cert/key paths are missing in production environment
76
+ ValueError: If cert/key are missing in production environment
68
77
  """
69
- if environment == "production" and (not cert_path or not key_path):
70
- raise ValueError("cert_path and key_path are required for production environment")
78
+ has_file_creds = cert_path and key_path
79
+ has_inline_creds = cert_content and key_content
80
+
81
+ if environment == "production" and not (has_file_creds or has_inline_creds):
82
+ raise ValueError(
83
+ "Either (cert_path, key_path) or (cert_content, key_content) "
84
+ "are required for production environment"
85
+ )
71
86
 
72
87
  self.cert_path = cert_path
73
88
  self.key_path = key_path
89
+ self.cert_content = cert_content
90
+ self.key_content = key_content
74
91
  self.environment = environment
75
92
  self.timeout = timeout
76
93
 
@@ -81,18 +98,36 @@ class TellerClient(BankingProvider):
81
98
  self.base_url = "https://api.teller.io"
82
99
 
83
100
  # Create HTTP client with mTLS certificate authentication
84
- client_kwargs = {
101
+ client_kwargs: dict = {
85
102
  "base_url": self.base_url,
86
103
  "timeout": timeout,
87
104
  "headers": {"User-Agent": "fin-infra/1.0"},
88
105
  }
89
106
 
90
107
  # Add certificate using SSL context (recommended approach, not deprecated)
91
- if cert_path and key_path:
92
- # Create SSL context with client certificate
108
+ if has_file_creds:
109
+ # Use file paths directly (assertions for type narrowing)
110
+ assert cert_path is not None
111
+ assert key_path is not None
93
112
  ssl_context = ssl.create_default_context()
94
113
  ssl_context.load_cert_chain(certfile=cert_path, keyfile=key_path)
95
114
  client_kwargs["verify"] = ssl_context
115
+ elif has_inline_creds:
116
+ # Write inline content to temp files for SSL context (assertions for type narrowing)
117
+ assert cert_content is not None
118
+ assert key_content is not None
119
+ import tempfile
120
+
121
+ self._cert_file = tempfile.NamedTemporaryFile(mode="w", suffix=".pem", delete=False)
122
+ self._key_file = tempfile.NamedTemporaryFile(mode="w", suffix=".pem", delete=False)
123
+ self._cert_file.write(cert_content)
124
+ self._key_file.write(key_content)
125
+ self._cert_file.close()
126
+ self._key_file.close()
127
+
128
+ ssl_context = ssl.create_default_context()
129
+ ssl_context.load_cert_chain(certfile=self._cert_file.name, keyfile=self._key_file.name)
130
+ client_kwargs["verify"] = ssl_context
96
131
 
97
132
  # Create client with explicit parameters to satisfy type checker
98
133
  self.client = httpx.Client(
@@ -331,7 +331,7 @@ class SubscriptionInsightsGenerator:
331
331
  cache_key = self._make_cache_key(subscriptions, user_id)
332
332
 
333
333
  try:
334
- await self.cache.set(cache_key, result.model_dump(), ttl=self.cache_ttl)
334
+ await self.cache.set(cache_key, result.model_dump(), expire=self.cache_ttl)
335
335
  except Exception as e:
336
336
  logger.warning(f"Cache set failed for insights: {e}")
337
337
 
@@ -318,7 +318,7 @@ class MerchantNormalizer:
318
318
  cache_key = self._make_cache_key(merchant_name)
319
319
 
320
320
  try:
321
- await self.cache.set(cache_key, result.model_dump(), ttl=self.cache_ttl)
321
+ await self.cache.set(cache_key, result.model_dump(), expire=self.cache_ttl)
322
322
  except Exception as e:
323
323
  logger.warning(f"Cache set failed for '{merchant_name}': {e}")
324
324
 
@@ -5,6 +5,13 @@ from functools import lru_cache
5
5
  from pydantic import Field
6
6
  from pydantic_settings import BaseSettings, SettingsConfigDict
7
7
 
8
+ # Default products: only the ones we actually use
9
+ # auth: Account/routing numbers for ACH
10
+ # transactions: Transaction history
11
+ # investments: Brokerage, retirement accounts
12
+ # Excluded: identity, liabilities, assets (not used, cost extra per API call)
13
+ DEFAULT_PLAID_PRODUCTS = "auth,transactions,investments"
14
+
8
15
 
9
16
  class Settings(BaseSettings):
10
17
  # Cache / infra
@@ -14,6 +21,7 @@ class Settings(BaseSettings):
14
21
  plaid_client_id: str | None = Field(default=None, alias="PLAID_CLIENT_ID")
15
22
  plaid_secret: str | None = Field(default=None, alias="PLAID_SECRET")
16
23
  plaid_env: str = Field(default="sandbox", alias="PLAID_ENVIRONMENT")
24
+ plaid_products: str = Field(default=DEFAULT_PLAID_PRODUCTS, alias="PLAID_PRODUCTS")
17
25
 
18
26
  # Alpaca
19
27
  alpaca_api_key: str | None = Field(default=None, alias="ALPACA_API_KEY")
File without changes
File without changes