ingestr 0.14.3__tar.gz → 0.14.5__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.

Potentially problematic release.


This version of ingestr might be problematic. Click here for more details.

Files changed (359) hide show
  1. {ingestr-0.14.3 → ingestr-0.14.5}/PKG-INFO +1 -1
  2. {ingestr-0.14.3 → ingestr-0.14.5}/docs/.vitepress/config.mjs +1 -0
  3. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/freshdesk.md +1 -0
  4. ingestr-0.14.5/docs/supported-sources/plusvibeai.md +93 -0
  5. ingestr-0.14.5/ingestr/src/buildinfo.py +1 -0
  6. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/factory.py +2 -0
  7. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/freshdesk/__init__.py +2 -0
  8. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/freshdesk/freshdesk_client.py +15 -1
  9. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/jira_source/__init__.py +27 -1
  10. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/jira_source/helpers.py +8 -21
  11. ingestr-0.14.5/ingestr/src/plusvibeai/__init__.py +335 -0
  12. ingestr-0.14.5/ingestr/src/plusvibeai/helpers.py +544 -0
  13. ingestr-0.14.5/ingestr/src/plusvibeai/settings.py +252 -0
  14. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/sources.py +55 -0
  15. ingestr-0.14.3/ingestr/src/buildinfo.py +0 -1
  16. {ingestr-0.14.3 → ingestr-0.14.5}/.dlt/config.toml +0 -0
  17. {ingestr-0.14.3 → ingestr-0.14.5}/.dockerignore +0 -0
  18. {ingestr-0.14.3 → ingestr-0.14.5}/.githooks/pre-commit-hook.sh +0 -0
  19. {ingestr-0.14.3 → ingestr-0.14.5}/.github/workflows/deploy-docs.yml +0 -0
  20. {ingestr-0.14.3 → ingestr-0.14.5}/.github/workflows/release.yml +0 -0
  21. {ingestr-0.14.3 → ingestr-0.14.5}/.github/workflows/secrets-scan.yml +0 -0
  22. {ingestr-0.14.3 → ingestr-0.14.5}/.github/workflows/tests.yml +0 -0
  23. {ingestr-0.14.3 → ingestr-0.14.5}/.gitignore +0 -0
  24. {ingestr-0.14.3 → ingestr-0.14.5}/.gitleaksignore +0 -0
  25. {ingestr-0.14.3 → ingestr-0.14.5}/.python-version +0 -0
  26. {ingestr-0.14.3 → ingestr-0.14.5}/.vale.ini +0 -0
  27. {ingestr-0.14.3 → ingestr-0.14.5}/Dockerfile +0 -0
  28. {ingestr-0.14.3 → ingestr-0.14.5}/LICENSE.md +0 -0
  29. {ingestr-0.14.3 → ingestr-0.14.5}/Makefile +0 -0
  30. {ingestr-0.14.3 → ingestr-0.14.5}/README.md +0 -0
  31. {ingestr-0.14.3 → ingestr-0.14.5}/docs/.vitepress/theme/custom.css +0 -0
  32. {ingestr-0.14.3 → ingestr-0.14.5}/docs/.vitepress/theme/index.js +0 -0
  33. {ingestr-0.14.3 → ingestr-0.14.5}/docs/commands/example-uris.md +0 -0
  34. {ingestr-0.14.3 → ingestr-0.14.5}/docs/commands/ingest.md +0 -0
  35. {ingestr-0.14.3 → ingestr-0.14.5}/docs/getting-started/core-concepts.md +0 -0
  36. {ingestr-0.14.3 → ingestr-0.14.5}/docs/getting-started/data-masking.md +0 -0
  37. {ingestr-0.14.3 → ingestr-0.14.5}/docs/getting-started/incremental-loading.md +0 -0
  38. {ingestr-0.14.3 → ingestr-0.14.5}/docs/getting-started/quickstart.md +0 -0
  39. {ingestr-0.14.3 → ingestr-0.14.5}/docs/getting-started/telemetry.md +0 -0
  40. {ingestr-0.14.3 → ingestr-0.14.5}/docs/index.md +0 -0
  41. {ingestr-0.14.3 → ingestr-0.14.5}/docs/media/applovin_max.png +0 -0
  42. {ingestr-0.14.3 → ingestr-0.14.5}/docs/media/athena.png +0 -0
  43. {ingestr-0.14.3 → ingestr-0.14.5}/docs/media/clickhouse_img.png +0 -0
  44. {ingestr-0.14.3 → ingestr-0.14.5}/docs/media/clickup_ingestion.png +0 -0
  45. {ingestr-0.14.3 → ingestr-0.14.5}/docs/media/cratedb-destination.png +0 -0
  46. {ingestr-0.14.3 → ingestr-0.14.5}/docs/media/cratedb-source.png +0 -0
  47. {ingestr-0.14.3 → ingestr-0.14.5}/docs/media/freshdesk_ingestion.png +0 -0
  48. {ingestr-0.14.3 → ingestr-0.14.5}/docs/media/gcp_spanner_ingestion.png +0 -0
  49. {ingestr-0.14.3 → ingestr-0.14.5}/docs/media/github.png +0 -0
  50. {ingestr-0.14.3 → ingestr-0.14.5}/docs/media/google_analytics_realtime_report.png +0 -0
  51. {ingestr-0.14.3 → ingestr-0.14.5}/docs/media/googleanalytics.png +0 -0
  52. {ingestr-0.14.3 → ingestr-0.14.5}/docs/media/ingestion_elasticsearch_img.png +0 -0
  53. {ingestr-0.14.3 → ingestr-0.14.5}/docs/media/kinesis.bigquery.png +0 -0
  54. {ingestr-0.14.3 → ingestr-0.14.5}/docs/media/linear.png +0 -0
  55. {ingestr-0.14.3 → ingestr-0.14.5}/docs/media/linkedin_ads.png +0 -0
  56. {ingestr-0.14.3 → ingestr-0.14.5}/docs/media/mixpanel_ingestion.png +0 -0
  57. {ingestr-0.14.3 → ingestr-0.14.5}/docs/media/personio.png +0 -0
  58. {ingestr-0.14.3 → ingestr-0.14.5}/docs/media/personio_duckdb.png +0 -0
  59. {ingestr-0.14.3 → ingestr-0.14.5}/docs/media/phantombuster.png +0 -0
  60. {ingestr-0.14.3 → ingestr-0.14.5}/docs/media/pipedrive.png +0 -0
  61. {ingestr-0.14.3 → ingestr-0.14.5}/docs/media/quickbook_ingestion.png +0 -0
  62. {ingestr-0.14.3 → ingestr-0.14.5}/docs/media/sftp.png +0 -0
  63. {ingestr-0.14.3 → ingestr-0.14.5}/docs/media/stripe_postgres.png +0 -0
  64. {ingestr-0.14.3 → ingestr-0.14.5}/docs/media/tiktok.png +0 -0
  65. {ingestr-0.14.3 → ingestr-0.14.5}/docs/media/wise_ingestion.png +0 -0
  66. {ingestr-0.14.3 → ingestr-0.14.5}/docs/media/zoom_ingestion.png +0 -0
  67. {ingestr-0.14.3 → ingestr-0.14.5}/docs/public/demo.gif +0 -0
  68. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/adjust.md +0 -0
  69. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/airtable.md +0 -0
  70. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/anthropic.md +0 -0
  71. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/applovin.md +0 -0
  72. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/applovin_max.md +0 -0
  73. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/appsflyer.md +0 -0
  74. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/appstore.md +0 -0
  75. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/asana.md +0 -0
  76. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/athena.md +0 -0
  77. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/attio.md +0 -0
  78. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/bigquery.md +0 -0
  79. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/chess.md +0 -0
  80. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/clickhouse.md +0 -0
  81. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/clickup.md +0 -0
  82. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/cratedb.md +0 -0
  83. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/csv.md +0 -0
  84. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/custom_queries.md +0 -0
  85. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/databricks.md +0 -0
  86. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/db2.md +0 -0
  87. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/docebo.md +0 -0
  88. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/duckdb.md +0 -0
  89. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/dynamodb.md +0 -0
  90. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/elasticsearch.md +0 -0
  91. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/facebook-ads.md +0 -0
  92. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/fluxx.md +0 -0
  93. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/frankfurter.md +0 -0
  94. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/fundraiseup.md +0 -0
  95. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/gcs.md +0 -0
  96. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/github.md +0 -0
  97. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/google-ads.md +0 -0
  98. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/google_analytics.md +0 -0
  99. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/gorgias.md +0 -0
  100. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/gsheets.md +0 -0
  101. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/hubspot.md +0 -0
  102. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/influxdb.md +0 -0
  103. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/intercom.md +0 -0
  104. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/isoc-pulse.md +0 -0
  105. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/jira.md +0 -0
  106. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/kafka.md +0 -0
  107. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/kinesis.md +0 -0
  108. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/klaviyo.md +0 -0
  109. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/linear.md +0 -0
  110. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/linkedin_ads.md +0 -0
  111. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/mixpanel.md +0 -0
  112. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/mongodb.md +0 -0
  113. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/motherduck.md +0 -0
  114. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/mssql.md +0 -0
  115. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/mysql.md +0 -0
  116. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/notion.md +0 -0
  117. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/oracle.md +0 -0
  118. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/personio.md +0 -0
  119. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/phantombuster.md +0 -0
  120. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/pinterest.md +0 -0
  121. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/pipedrive.md +0 -0
  122. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/postgres.md +0 -0
  123. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/quickbooks.md +0 -0
  124. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/redshift.md +0 -0
  125. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/revenuecat.md +0 -0
  126. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/s3.md +0 -0
  127. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/salesforce.md +0 -0
  128. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/sap-hana.md +0 -0
  129. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/sftp.md +0 -0
  130. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/shopify.md +0 -0
  131. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/slack.md +0 -0
  132. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/smartsheets.md +0 -0
  133. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/snowflake.md +0 -0
  134. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/solidgate.md +0 -0
  135. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/spanner.md +0 -0
  136. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/sqlite.md +0 -0
  137. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/stripe.md +0 -0
  138. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/tiktok-ads.md +0 -0
  139. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/trino.md +0 -0
  140. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/trustpilot.md +0 -0
  141. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/wise.md +0 -0
  142. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/zendesk.md +0 -0
  143. {ingestr-0.14.3 → ingestr-0.14.5}/docs/supported-sources/zoom.md +0 -0
  144. {ingestr-0.14.3 → ingestr-0.14.5}/docs/tutorials/load-kinesis-bigquery.md +0 -0
  145. {ingestr-0.14.3 → ingestr-0.14.5}/docs/tutorials/load-personio-duckdb.md +0 -0
  146. {ingestr-0.14.3 → ingestr-0.14.5}/docs/tutorials/load-stripe-postgres.md +0 -0
  147. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/conftest.py +0 -0
  148. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/main.py +0 -0
  149. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/.gitignore +0 -0
  150. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/adjust/__init__.py +0 -0
  151. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/adjust/adjust_helpers.py +0 -0
  152. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/airtable/__init__.py +0 -0
  153. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/anthropic/__init__.py +0 -0
  154. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/anthropic/helpers.py +0 -0
  155. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/applovin/__init__.py +0 -0
  156. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/applovin_max/__init__.py +0 -0
  157. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/appsflyer/__init__.py +0 -0
  158. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/appsflyer/client.py +0 -0
  159. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/appstore/__init__.py +0 -0
  160. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/appstore/client.py +0 -0
  161. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/appstore/errors.py +0 -0
  162. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/appstore/models.py +0 -0
  163. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/appstore/resources.py +0 -0
  164. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/arrow/__init__.py +0 -0
  165. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/asana_source/__init__.py +0 -0
  166. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/asana_source/helpers.py +0 -0
  167. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/asana_source/settings.py +0 -0
  168. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/attio/__init__.py +0 -0
  169. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/attio/helpers.py +0 -0
  170. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/blob.py +0 -0
  171. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/chess/__init__.py +0 -0
  172. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/chess/helpers.py +0 -0
  173. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/chess/settings.py +0 -0
  174. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/clickup/__init__.py +0 -0
  175. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/clickup/helpers.py +0 -0
  176. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/collector/spinner.py +0 -0
  177. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/destinations.py +0 -0
  178. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/docebo/__init__.py +0 -0
  179. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/docebo/client.py +0 -0
  180. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/docebo/helpers.py +0 -0
  181. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/dynamodb/__init__.py +0 -0
  182. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/elasticsearch/__init__.py +0 -0
  183. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/elasticsearch/helpers.py +0 -0
  184. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/errors.py +0 -0
  185. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/facebook_ads/__init__.py +0 -0
  186. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/facebook_ads/exceptions.py +0 -0
  187. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/facebook_ads/helpers.py +0 -0
  188. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/facebook_ads/settings.py +0 -0
  189. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/facebook_ads/utils.py +0 -0
  190. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/filesystem/__init__.py +0 -0
  191. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/filesystem/helpers.py +0 -0
  192. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/filesystem/readers.py +0 -0
  193. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/filters.py +0 -0
  194. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/fluxx/__init__.py +0 -0
  195. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/fluxx/helpers.py +0 -0
  196. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/frankfurter/__init__.py +0 -0
  197. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/frankfurter/helpers.py +0 -0
  198. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/freshdesk/settings.py +0 -0
  199. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/fundraiseup/__init__.py +0 -0
  200. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/fundraiseup/client.py +0 -0
  201. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/github/__init__.py +0 -0
  202. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/github/helpers.py +0 -0
  203. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/github/queries.py +0 -0
  204. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/github/settings.py +0 -0
  205. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/google_ads/__init__.py +0 -0
  206. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/google_ads/field.py +0 -0
  207. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/google_ads/metrics.py +0 -0
  208. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/google_ads/predicates.py +0 -0
  209. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/google_ads/reports.py +0 -0
  210. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/google_analytics/__init__.py +0 -0
  211. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/google_analytics/helpers.py +0 -0
  212. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/google_sheets/README.md +0 -0
  213. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/google_sheets/__init__.py +0 -0
  214. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/google_sheets/helpers/__init__.py +0 -0
  215. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/google_sheets/helpers/api_calls.py +0 -0
  216. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/google_sheets/helpers/data_processing.py +0 -0
  217. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/gorgias/__init__.py +0 -0
  218. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/gorgias/helpers.py +0 -0
  219. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/http_client.py +0 -0
  220. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/hubspot/__init__.py +0 -0
  221. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/hubspot/helpers.py +0 -0
  222. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/hubspot/settings.py +0 -0
  223. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/influxdb/__init__.py +0 -0
  224. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/influxdb/client.py +0 -0
  225. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/intercom/__init__.py +0 -0
  226. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/intercom/helpers.py +0 -0
  227. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/intercom/settings.py +0 -0
  228. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/isoc_pulse/__init__.py +0 -0
  229. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/jira_source/settings.py +0 -0
  230. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/kafka/__init__.py +0 -0
  231. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/kafka/helpers.py +0 -0
  232. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/kinesis/__init__.py +0 -0
  233. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/kinesis/helpers.py +0 -0
  234. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/klaviyo/__init__.py +0 -0
  235. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/klaviyo/client.py +0 -0
  236. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/klaviyo/helpers.py +0 -0
  237. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/linear/__init__.py +0 -0
  238. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/linear/helpers.py +0 -0
  239. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/linkedin_ads/__init__.py +0 -0
  240. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/linkedin_ads/dimension_time_enum.py +0 -0
  241. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/linkedin_ads/helpers.py +0 -0
  242. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/loader.py +0 -0
  243. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/masking.py +0 -0
  244. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/mixpanel/__init__.py +0 -0
  245. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/mixpanel/client.py +0 -0
  246. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/mongodb/__init__.py +0 -0
  247. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/mongodb/helpers.py +0 -0
  248. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/notion/__init__.py +0 -0
  249. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/notion/helpers/__init__.py +0 -0
  250. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/notion/helpers/client.py +0 -0
  251. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/notion/helpers/database.py +0 -0
  252. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/notion/settings.py +0 -0
  253. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/partition.py +0 -0
  254. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/personio/__init__.py +0 -0
  255. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/personio/helpers.py +0 -0
  256. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/phantombuster/__init__.py +0 -0
  257. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/phantombuster/client.py +0 -0
  258. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/pinterest/__init__.py +0 -0
  259. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/pipedrive/__init__.py +0 -0
  260. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/pipedrive/helpers/__init__.py +0 -0
  261. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/pipedrive/helpers/custom_fields_munger.py +0 -0
  262. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/pipedrive/helpers/pages.py +0 -0
  263. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/pipedrive/settings.py +0 -0
  264. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/pipedrive/typing.py +0 -0
  265. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/quickbooks/__init__.py +0 -0
  266. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/resource.py +0 -0
  267. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/revenuecat/__init__.py +0 -0
  268. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/revenuecat/helpers.py +0 -0
  269. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/salesforce/__init__.py +0 -0
  270. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/salesforce/helpers.py +0 -0
  271. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/shopify/__init__.py +0 -0
  272. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/shopify/exceptions.py +0 -0
  273. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/shopify/helpers.py +0 -0
  274. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/shopify/settings.py +0 -0
  275. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/slack/__init__.py +0 -0
  276. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/slack/helpers.py +0 -0
  277. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/slack/settings.py +0 -0
  278. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/smartsheets/__init__.py +0 -0
  279. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/solidgate/__init__.py +0 -0
  280. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/solidgate/helpers.py +0 -0
  281. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/sql_database/__init__.py +0 -0
  282. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/sql_database/callbacks.py +0 -0
  283. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/stripe_analytics/__init__.py +0 -0
  284. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/stripe_analytics/helpers.py +0 -0
  285. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/stripe_analytics/settings.py +0 -0
  286. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/table_definition.py +0 -0
  287. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/telemetry/event.py +0 -0
  288. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/testdata/fakebqcredentials.json +0 -0
  289. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/tiktok_ads/__init__.py +0 -0
  290. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/tiktok_ads/tiktok_helpers.py +0 -0
  291. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/time.py +0 -0
  292. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/trustpilot/__init__.py +0 -0
  293. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/trustpilot/client.py +0 -0
  294. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/version.py +0 -0
  295. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/wise/__init__.py +0 -0
  296. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/wise/client.py +0 -0
  297. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/zendesk/__init__.py +0 -0
  298. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/zendesk/helpers/__init__.py +0 -0
  299. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/zendesk/helpers/api_helpers.py +0 -0
  300. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/zendesk/helpers/credentials.py +0 -0
  301. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/zendesk/helpers/talk_api.py +0 -0
  302. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/zendesk/settings.py +0 -0
  303. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/zoom/__init__.py +0 -0
  304. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/src/zoom/helpers.py +0 -0
  305. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/testdata/.gitignore +0 -0
  306. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/testdata/create_replace.csv +0 -0
  307. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/testdata/delete_insert_expected.csv +0 -0
  308. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/testdata/delete_insert_part1.csv +0 -0
  309. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/testdata/delete_insert_part2.csv +0 -0
  310. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/testdata/merge_expected.csv +0 -0
  311. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/testdata/merge_part1.csv +0 -0
  312. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/testdata/merge_part2.csv +0 -0
  313. {ingestr-0.14.3 → ingestr-0.14.5}/ingestr/tests/unit/test_smartsheets.py +0 -0
  314. {ingestr-0.14.3 → ingestr-0.14.5}/package-lock.json +0 -0
  315. {ingestr-0.14.3 → ingestr-0.14.5}/package.json +0 -0
  316. {ingestr-0.14.3 → ingestr-0.14.5}/pyproject.toml +0 -0
  317. {ingestr-0.14.3 → ingestr-0.14.5}/requirements-dev.txt +0 -0
  318. {ingestr-0.14.3 → ingestr-0.14.5}/requirements.in +0 -0
  319. {ingestr-0.14.3 → ingestr-0.14.5}/requirements.txt +0 -0
  320. {ingestr-0.14.3 → ingestr-0.14.5}/requirements_arm64.txt +0 -0
  321. {ingestr-0.14.3 → ingestr-0.14.5}/resources/demo.gif +0 -0
  322. {ingestr-0.14.3 → ingestr-0.14.5}/resources/demo.tape +0 -0
  323. {ingestr-0.14.3 → ingestr-0.14.5}/resources/ingestr.svg +0 -0
  324. {ingestr-0.14.3 → ingestr-0.14.5}/styles/Google/AMPM.yml +0 -0
  325. {ingestr-0.14.3 → ingestr-0.14.5}/styles/Google/Acronyms.yml +0 -0
  326. {ingestr-0.14.3 → ingestr-0.14.5}/styles/Google/Colons.yml +0 -0
  327. {ingestr-0.14.3 → ingestr-0.14.5}/styles/Google/Contractions.yml +0 -0
  328. {ingestr-0.14.3 → ingestr-0.14.5}/styles/Google/DateFormat.yml +0 -0
  329. {ingestr-0.14.3 → ingestr-0.14.5}/styles/Google/Ellipses.yml +0 -0
  330. {ingestr-0.14.3 → ingestr-0.14.5}/styles/Google/EmDash.yml +0 -0
  331. {ingestr-0.14.3 → ingestr-0.14.5}/styles/Google/Exclamation.yml +0 -0
  332. {ingestr-0.14.3 → ingestr-0.14.5}/styles/Google/FirstPerson.yml +0 -0
  333. {ingestr-0.14.3 → ingestr-0.14.5}/styles/Google/Gender.yml +0 -0
  334. {ingestr-0.14.3 → ingestr-0.14.5}/styles/Google/GenderBias.yml +0 -0
  335. {ingestr-0.14.3 → ingestr-0.14.5}/styles/Google/HeadingPunctuation.yml +0 -0
  336. {ingestr-0.14.3 → ingestr-0.14.5}/styles/Google/Headings.yml +0 -0
  337. {ingestr-0.14.3 → ingestr-0.14.5}/styles/Google/Latin.yml +0 -0
  338. {ingestr-0.14.3 → ingestr-0.14.5}/styles/Google/LyHyphens.yml +0 -0
  339. {ingestr-0.14.3 → ingestr-0.14.5}/styles/Google/OptionalPlurals.yml +0 -0
  340. {ingestr-0.14.3 → ingestr-0.14.5}/styles/Google/Ordinal.yml +0 -0
  341. {ingestr-0.14.3 → ingestr-0.14.5}/styles/Google/OxfordComma.yml +0 -0
  342. {ingestr-0.14.3 → ingestr-0.14.5}/styles/Google/Parens.yml +0 -0
  343. {ingestr-0.14.3 → ingestr-0.14.5}/styles/Google/Passive.yml +0 -0
  344. {ingestr-0.14.3 → ingestr-0.14.5}/styles/Google/Periods.yml +0 -0
  345. {ingestr-0.14.3 → ingestr-0.14.5}/styles/Google/Quotes.yml +0 -0
  346. {ingestr-0.14.3 → ingestr-0.14.5}/styles/Google/Ranges.yml +0 -0
  347. {ingestr-0.14.3 → ingestr-0.14.5}/styles/Google/Semicolons.yml +0 -0
  348. {ingestr-0.14.3 → ingestr-0.14.5}/styles/Google/Slang.yml +0 -0
  349. {ingestr-0.14.3 → ingestr-0.14.5}/styles/Google/Spacing.yml +0 -0
  350. {ingestr-0.14.3 → ingestr-0.14.5}/styles/Google/Spelling.yml +0 -0
  351. {ingestr-0.14.3 → ingestr-0.14.5}/styles/Google/Units.yml +0 -0
  352. {ingestr-0.14.3 → ingestr-0.14.5}/styles/Google/We.yml +0 -0
  353. {ingestr-0.14.3 → ingestr-0.14.5}/styles/Google/Will.yml +0 -0
  354. {ingestr-0.14.3 → ingestr-0.14.5}/styles/Google/WordList.yml +0 -0
  355. {ingestr-0.14.3 → ingestr-0.14.5}/styles/Google/meta.json +0 -0
  356. {ingestr-0.14.3 → ingestr-0.14.5}/styles/Google/vocab.txt +0 -0
  357. {ingestr-0.14.3 → ingestr-0.14.5}/styles/bruin/Ingestr.yml +0 -0
  358. {ingestr-0.14.3 → ingestr-0.14.5}/styles/config/vocabularies/bruin/accept.txt +0 -0
  359. {ingestr-0.14.3 → ingestr-0.14.5}/test.env.template +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ingestr
3
- Version: 0.14.3
3
+ Version: 0.14.5
4
4
  Summary: ingestr is a command-line application that ingests data from various sources and stores them in any database.
5
5
  Project-URL: Homepage, https://github.com/bruin-data/ingestr
6
6
  Project-URL: Issues, https://github.com/bruin-data/ingestr/issues
@@ -162,6 +162,7 @@ export default defineConfig({
162
162
  { text: "PhantomBuster", link: "/supported-sources/phantombuster.md" },
163
163
  { text: "Pinterest", link: "/supported-sources/pinterest.md" },
164
164
  { text: "Pipedrive", link: "/supported-sources/pipedrive.md" },
165
+ { text: "Plus Vibe AI", link: "/supported-sources/plusvibeai.md" },
165
166
  { text: "QuickBooks", link: "/supported-sources/quickbooks.md" },
166
167
  { text: "RevenueCat", link: "/supported-sources/revenuecat.md" },
167
168
  { text: "S3", link: "/supported-sources/s3.md" },
@@ -44,5 +44,6 @@ The Freshdesk source allows you to ingest the following tables:
44
44
  | [groups](https://developers.freshdesk.com/api/#groups) | id | updated_at | merge | Retrieves agents organized based on specific criteria. |
45
45
  | [roles](https://developers.freshdesk.com/api/#roles) | id | updated_at | merge | Retrieves predefined sets of permissions that determine what actions an agent can perform.|
46
46
  | [tickets](https://developers.freshdesk.com/api/#tickets) | id | updated_at | merge | Retrieves customer inquiries or issues submitted via various channels like email, chat, phone, etc.
47
+ | [tickets:<query>](https://developers.freshdesk.com/api/#filter_tickets) | id | updated_at | merge | Executes the [Freshdesk ticket filter query](https://developers.freshdesk.com/api/#filter_tickets) while preserving incremental sync. |
47
48
 
48
49
  Use these as the `--source-table` parameter in the `ingestr ingest` command.
@@ -0,0 +1,93 @@
1
+ # Plus Vibe AI
2
+
3
+ [Plus Vibe AI](https://plusvibe.ai/) is an email marketing and outreach platform that helps businesses automate their email campaigns, manage leads, and track engagement metrics.
4
+
5
+ ingestr supports Plus Vibe AI as a source.
6
+
7
+ ## URI format
8
+
9
+ The URI format for Plus Vibe AI is as follows:
10
+
11
+ ```plaintext
12
+ plusvibeai://?api_key=<api-key-here>&workspace_id=<workspace-id-here>
13
+ ```
14
+
15
+ URI parameters:
16
+
17
+ - `api_key`: API key for authentication (get from https://app.plusvibe.ai/v2/settings/api-access/)
18
+ - `workspace_id`: Workspace ID to access your data
19
+
20
+ The URI is used to connect to the Plus Vibe AI API for extracting data.
21
+
22
+ ## Setting up a Plus Vibe AI Integration
23
+
24
+ To set up a Plus Vibe AI integration, you need to:
25
+
26
+ 1. Log in to your Plus Vibe AI account
27
+ 2. Navigate to Settings > API Access (https://app.plusvibe.ai/v2/settings/api-access/)
28
+ 3. Generate an API key
29
+ 4. Find your workspace ID in your account settings
30
+
31
+ Once you have your API key and workspace ID, here's a sample command that will copy the data from Plus Vibe AI into a DuckDB database:
32
+
33
+ ```sh
34
+ ingestr ingest --source-uri 'plusvibeai://?api_key=your_api_key&workspace_id=your_workspace_id' --source-table 'campaigns' --dest-uri duckdb:///plusvibeai.duckdb --dest-table 'campaigns.data'
35
+ ```
36
+
37
+ The result of this command will be a table in the `plusvibeai.duckdb` database with JSON columns for nested objects.
38
+
39
+ ## Tables
40
+
41
+ Plus Vibe AI source allows ingesting the following sources into separate tables:
42
+
43
+ | Table | PK | Inc Key | Inc Strategy | Details |
44
+ | ----- | -- | ------- | ------------ | ------- |
45
+ | `campaigns` | id | modified_at | merge | Contains campaign information including configuration, schedules, sequences, and performance metrics. Nested objects (schedule, sequences) are stored as JSON columns. |
46
+ | `leads` | _id | modified_at | merge | Contains lead information including contact details, campaign association, engagement metrics, and professional information. |
47
+ | `email_accounts` | _id | timestamp_updated | merge | Contains email account configurations including SMTP/IMAP settings, warmup configurations, and analytics data stored in payload JSON. |
48
+ | `emails` | id | timestamp_created | merge | Contains email data including message content, headers, thread information, and recipient details. Uses cursor-based pagination. |
49
+ | `blocklist` | _id | created_at | merge | Contains blocklist entries for email addresses or domains that should be excluded from campaigns. |
50
+ | `webhooks` | _id | modified_at | merge | Contains webhook configurations for receiving real-time notifications about campaign events and lead interactions. |
51
+ | `tags` | _id | modified_at | merge | Contains tag information used for organizing and categorizing campaigns, leads, and other resources. |
52
+
53
+ Use these as `--source-table` parameter in the `ingestr ingest` command.
54
+
55
+ ## Features
56
+
57
+ ### Incremental Loading
58
+
59
+ Plus Vibe AI source supports incremental loading based on modification timestamps. Each table uses its respective timestamp field to fetch only updated records since the last sync:
60
+
61
+ - **Campaigns**: Uses `modified_at` field
62
+ - **Leads**: Uses `modified_at` field
63
+ - **Email Accounts**: Uses `timestamp_updated` field
64
+ - **Emails**: Uses `timestamp_created` field
65
+ - **Blocklist**: Uses `created_at` field
66
+ - **Webhooks**: Uses `modified_at` field
67
+ - **Tags**: Uses `modified_at` field
68
+
69
+ ### Nested Data Handling
70
+
71
+ The source preserves nested objects as JSON columns with `max_table_nesting=0` to maintain data structure integrity:
72
+
73
+ - **Campaigns**: Schedule, sequences, and events are stored as JSON
74
+ - **Email Accounts**: All configuration data is stored in the `payload` JSON field
75
+ - **Emails**: Headers and address information are stored as JSON
76
+
77
+ ### Rate Limiting
78
+
79
+ Plus Vibe AI API has a rate limit of 5 requests per second. The source automatically handles rate limiting with exponential backoff and retry logic.
80
+
81
+ ### Error Handling
82
+
83
+ The source includes comprehensive error handling for:
84
+ - Authentication failures (401/403)
85
+ - Rate limiting (429)
86
+ - Server errors (5xx) with automatic retries
87
+ - Network timeouts and connection issues
88
+
89
+ > [!TIP]
90
+ > For optimal performance, use incremental loading for regular syncs and full loading only for initial data extraction or when you need to capture all historical updates.
91
+
92
+ > [!NOTE]
93
+ > The emails endpoint uses cursor-based pagination with `page_trail` parameter, while other endpoints use standard offset-based pagination.
@@ -0,0 +1 @@
1
+ version = "v0.14.5"
@@ -70,6 +70,7 @@ from ingestr.src.sources import (
70
70
  PhantombusterSource,
71
71
  PinterestSource,
72
72
  PipedriveSource,
73
+ PlusVibeAISource,
73
74
  QuickBooksSource,
74
75
  RevenueCatSource,
75
76
  S3Source,
@@ -212,6 +213,7 @@ class SourceDestinationFactory:
212
213
  "clickup": ClickupSource,
213
214
  "influxdb": InfluxDBSource,
214
215
  "wise": WiseSource,
216
+ "plusvibeai": PlusVibeAISource,
215
217
  }
216
218
  destinations: Dict[str, Type[DestinationProtocol]] = {
217
219
  "bigquery": BigQueryDestination,
@@ -20,6 +20,7 @@ def freshdesk_source(
20
20
  end_date: Optional[pendulum.DateTime] = None,
21
21
  per_page: int = 100,
22
22
  endpoints: Optional[List[str]] = None,
23
+ query: Optional[str] = None,
23
24
  ) -> Iterable[DltResource]:
24
25
  """
25
26
  Retrieves data from specified Freshdesk API endpoints.
@@ -72,6 +73,7 @@ def freshdesk_source(
72
73
  per_page=per_page,
73
74
  start_date=start_date,
74
75
  end_date=end_date,
76
+ query=query,
75
77
  )
76
78
 
77
79
  # Set default endpoints if not provided
@@ -2,7 +2,7 @@
2
2
 
3
3
  import logging
4
4
  import time
5
- from typing import Any, Dict, Iterable
5
+ from typing import Any, Dict, Iterable, Optional
6
6
 
7
7
  import pendulum
8
8
  from dlt.common.typing import TDataItem
@@ -70,6 +70,7 @@ class FreshdeskClient:
70
70
  per_page: int,
71
71
  start_date: pendulum.DateTime,
72
72
  end_date: pendulum.DateTime,
73
+ query: Optional[str] = None,
73
74
  ) -> Iterable[TDataItem]:
74
75
  """
75
76
  Fetches a paginated response from a specified endpoint.
@@ -79,6 +80,9 @@ class FreshdeskClient:
79
80
  updated at the specified timestamp.
80
81
  """
81
82
  page = 1
83
+ if query is not None:
84
+ query = query.replace('"', "").strip()
85
+
82
86
  while True:
83
87
  # Construct the URL for the specific endpoint
84
88
  url = f"{self.base_url}/{endpoint}"
@@ -93,11 +97,21 @@ class FreshdeskClient:
93
97
 
94
98
  params[param_key] = start_date.to_iso8601_string()
95
99
 
100
+ if query and endpoint == "tickets":
101
+ url = f"{self.base_url}/search/tickets"
102
+ params = {
103
+ "query": f'"{query}"',
104
+ "page": page,
105
+ }
106
+
96
107
  # Handle requests with rate-limiting
97
108
  # A maximum of 300 pages (30000 tickets) will be returned.
98
109
  response = self._request_with_rate_limit(url, params=params)
99
110
  data = response.json()
100
111
 
112
+ if query and endpoint == "tickets":
113
+ data = data["results"]
114
+
101
115
  if not data:
102
116
  break # Stop if no data or max page limit reached
103
117
 
@@ -37,6 +37,7 @@ def jira_source() -> Any:
37
37
  resolutions,
38
38
  project_versions,
39
39
  project_components,
40
+ events,
40
41
  ]
41
42
 
42
43
 
@@ -65,7 +66,11 @@ def projects(
65
66
  yield from client.get_projects(expand=expand, recent=recent)
66
67
 
67
68
 
68
- @dlt.resource(write_disposition="merge", primary_key="id")
69
+ @dlt.resource(
70
+ write_disposition="merge",
71
+ primary_key="id",
72
+ max_table_nesting=2,
73
+ )
69
74
  def issues(
70
75
  base_url: str = dlt.secrets.value,
71
76
  email: str = dlt.secrets.value,
@@ -312,3 +317,24 @@ def project_components(
312
317
  return []
313
318
 
314
319
  return list(client.get_project_components(project_key))
320
+
321
+
322
+ @dlt.resource(write_disposition="replace")
323
+ def events(
324
+ base_url: str = dlt.secrets.value,
325
+ email: str = dlt.secrets.value,
326
+ api_token: str = dlt.secrets.value,
327
+ ) -> Iterable[TDataItem]:
328
+ """
329
+ Fetches all event types from Jira (e.g., Issue Created, Issue Updated, etc.).
330
+
331
+ Args:
332
+ base_url (str): Jira instance URL
333
+ email (str): User email for authentication
334
+ api_token (str): API token for authentication
335
+
336
+ Yields:
337
+ dict: The event data.
338
+ """
339
+ client = get_client(base_url, email, api_token)
340
+ yield from client.get_events()
@@ -98,8 +98,6 @@ class JiraClient:
98
98
 
99
99
  for attempt in range(max_retries + 1):
100
100
  try:
101
- logger.debug(f"Making request to {url} (attempt {attempt + 1})")
102
-
103
101
  response = requests.request(
104
102
  method=method,
105
103
  url=url,
@@ -214,10 +212,6 @@ class JiraClient:
214
212
  consecutive_empty_pages = 0
215
213
  max_empty_pages = 3
216
214
 
217
- logger.info(
218
- f"Starting paginated request to {endpoint} with page_size={page_size}"
219
- )
220
-
221
215
  while True:
222
216
  try:
223
217
  response = self._make_request(endpoint, params)
@@ -238,7 +232,6 @@ class JiraClient:
238
232
  is_last = True
239
233
  else:
240
234
  # Single item response
241
- logger.debug(f"Received single item response from {endpoint}")
242
235
  yield response
243
236
  break
244
237
 
@@ -253,27 +246,18 @@ class JiraClient:
253
246
  else:
254
247
  consecutive_empty_pages = 0
255
248
 
256
- logger.debug(
257
- f"Retrieved {len(items)} items from {endpoint} (page {params['startAt'] // page_size + 1})"
258
- )
259
-
260
249
  for item in items:
261
250
  if max_results and total_returned >= max_results:
262
- logger.info(f"Reached max_results limit of {max_results}")
263
251
  return
264
252
  yield item
265
253
  total_returned += 1
266
254
 
267
255
  # Check if we've reached the end
268
256
  if is_last or len(items) < page_size:
269
- logger.debug(f"Reached end of pagination for {endpoint}")
270
257
  break
271
258
 
272
259
  # Check if we've got all available items
273
260
  if total and total_returned >= total:
274
- logger.debug(
275
- f"Retrieved all {total} available items from {endpoint}"
276
- )
277
261
  break
278
262
 
279
263
  # Move to next page
@@ -295,10 +279,6 @@ class JiraClient:
295
279
  )
296
280
  raise JiraAPIError(f"Pagination failed: {str(e)}")
297
281
 
298
- logger.info(
299
- f"Completed pagination for {endpoint}, returned {total_returned} items"
300
- )
301
-
302
282
  def search_issues(
303
283
  self,
304
284
  jql: str,
@@ -327,7 +307,7 @@ class JiraClient:
327
307
  params["expand"] = expand
328
308
 
329
309
  yield from self.get_paginated(
330
- "search", params=params, page_size=page_size, max_results=max_results
310
+ "search/jql", params=params, page_size=page_size, max_results=max_results
331
311
  )
332
312
 
333
313
  def get_projects(
@@ -433,6 +413,13 @@ class JiraClient:
433
413
  """
434
414
  yield from self.get_paginated(f"project/{project_key}/component")
435
415
 
416
+ def get_events(self) -> Iterator[Dict[str, Any]]:
417
+ """Get all events (issue events like created, updated, etc.)."""
418
+ response = self._make_request("events")
419
+ if isinstance(response, list):
420
+ for event in response:
421
+ yield event
422
+
436
423
 
437
424
  def get_client(
438
425
  base_url: str, email: str, api_token: str, timeout: int = REQUEST_TIMEOUT
@@ -0,0 +1,335 @@
1
+ """
2
+ This source provides data extraction from PlusVibeAI via the REST API.
3
+
4
+ It defines functions to fetch data from different parts of PlusVibeAI including
5
+ campaigns and other marketing analytics data.
6
+ """
7
+
8
+ from typing import Any, Iterable, Optional
9
+
10
+ import dlt
11
+ from dlt.common.typing import TDataItem
12
+
13
+ from .helpers import get_client
14
+ from .settings import DEFAULT_PAGE_SIZE, DEFAULT_START_DATE
15
+
16
+
17
+ @dlt.source
18
+ def plusvibeai_source() -> Any:
19
+ """
20
+ The main function that runs all the other functions to fetch data from PlusVibeAI.
21
+
22
+ Returns:
23
+ Sequence[DltResource]: A sequence of DltResource objects containing the fetched data.
24
+ """
25
+ return [
26
+ campaigns,
27
+ leads,
28
+ email_accounts,
29
+ emails,
30
+ blocklist,
31
+ webhooks,
32
+ tags,
33
+ ]
34
+
35
+
36
+ @dlt.resource(
37
+ write_disposition="merge",
38
+ primary_key="id",
39
+ max_table_nesting=0, # Keep nested objects (schedule, sequences) as JSON columns
40
+ )
41
+ def campaigns(
42
+ api_key: str = dlt.secrets.value,
43
+ workspace_id: str = dlt.secrets.value,
44
+ base_url: str = "https://api.plusvibe.ai",
45
+ max_results: Optional[int] = None,
46
+ updated: dlt.sources.incremental[str] = dlt.sources.incremental(
47
+ "modified_at", # PlusVibeAI uses modified_at for updates
48
+ initial_value=DEFAULT_START_DATE,
49
+ range_end="closed",
50
+ range_start="closed",
51
+ ),
52
+ ) -> Iterable[TDataItem]:
53
+ """
54
+ Fetches campaigns from PlusVibeAI.
55
+
56
+ Args:
57
+ api_key (str): API key for authentication (get from https://app.plusvibe.ai/v2/settings/api-access/)
58
+ workspace_id (str): Workspace ID to access
59
+ base_url (str): PlusVibeAI API base URL
60
+ max_results (int): Maximum number of results to return
61
+ updated (str): The date from which to fetch updated campaigns
62
+
63
+ Yields:
64
+ dict: The campaign data with nested objects (schedule, sequences, etc.) as JSON.
65
+ """
66
+ client = get_client(api_key, workspace_id, base_url)
67
+
68
+ for campaign in client.get_campaigns(
69
+ page_size=DEFAULT_PAGE_SIZE, max_results=max_results
70
+ ):
71
+ # Apply incremental filter if needed
72
+ if updated.start_value:
73
+ campaign_updated = campaign.get("modified_at")
74
+ if campaign_updated and campaign_updated < updated.start_value:
75
+ continue
76
+
77
+ yield campaign
78
+
79
+
80
+ @dlt.resource(
81
+ write_disposition="merge",
82
+ primary_key="_id",
83
+ max_table_nesting=0,
84
+ )
85
+ def leads(
86
+ api_key: str = dlt.secrets.value,
87
+ workspace_id: str = dlt.secrets.value,
88
+ base_url: str = "https://api.plusvibe.ai",
89
+ max_results: Optional[int] = None,
90
+ updated: dlt.sources.incremental[str] = dlt.sources.incremental(
91
+ "modified_at",
92
+ initial_value=DEFAULT_START_DATE,
93
+ range_end="closed",
94
+ range_start="closed",
95
+ ),
96
+ ) -> Iterable[TDataItem]:
97
+ """
98
+ Fetches leads from PlusVibeAI.
99
+
100
+ Args:
101
+ api_key (str): API key for authentication
102
+ workspace_id (str): Workspace ID to access
103
+ base_url (str): PlusVibeAI API base URL
104
+ max_results (int): Maximum number of results to return
105
+ updated (str): The date from which to fetch updated leads
106
+
107
+ Yields:
108
+ dict: The lead data.
109
+ """
110
+ client = get_client(api_key, workspace_id, base_url)
111
+
112
+ for lead in client.get_leads(page_size=DEFAULT_PAGE_SIZE, max_results=max_results):
113
+ # Apply incremental filter if needed
114
+ if updated.start_value:
115
+ lead_updated = lead.get("modified_at")
116
+ if lead_updated and lead_updated < updated.start_value:
117
+ continue
118
+
119
+ yield lead
120
+
121
+
122
+ @dlt.resource(
123
+ write_disposition="merge",
124
+ primary_key="_id",
125
+ max_table_nesting=0,
126
+ )
127
+ def email_accounts(
128
+ api_key: str = dlt.secrets.value,
129
+ workspace_id: str = dlt.secrets.value,
130
+ base_url: str = "https://api.plusvibe.ai",
131
+ max_results: Optional[int] = None,
132
+ updated: dlt.sources.incremental[str] = dlt.sources.incremental(
133
+ "timestamp_updated",
134
+ initial_value=DEFAULT_START_DATE,
135
+ range_end="closed",
136
+ range_start="closed",
137
+ ),
138
+ ) -> Iterable[TDataItem]:
139
+ """
140
+ Fetches email accounts from PlusVibeAI.
141
+
142
+ Args:
143
+ api_key (str): API key for authentication
144
+ workspace_id (str): Workspace ID to access
145
+ base_url (str): PlusVibeAI API base URL
146
+ max_results (int): Maximum number of results to return
147
+ updated (str): The date from which to fetch updated email accounts
148
+
149
+ Yields:
150
+ dict: The email account data.
151
+ """
152
+ client = get_client(api_key, workspace_id, base_url)
153
+
154
+ for account in client.get_email_accounts(
155
+ page_size=DEFAULT_PAGE_SIZE, max_results=max_results
156
+ ):
157
+ # Apply incremental filter if needed
158
+ if updated.start_value:
159
+ account_updated = account.get("timestamp_updated")
160
+ if account_updated and account_updated < updated.start_value:
161
+ continue
162
+
163
+ yield account
164
+
165
+
166
+ @dlt.resource(
167
+ write_disposition="merge",
168
+ primary_key="id",
169
+ max_table_nesting=0,
170
+ )
171
+ def emails(
172
+ api_key: str = dlt.secrets.value,
173
+ workspace_id: str = dlt.secrets.value,
174
+ base_url: str = "https://api.plusvibe.ai",
175
+ max_results: Optional[int] = None,
176
+ updated: dlt.sources.incremental[str] = dlt.sources.incremental(
177
+ "timestamp_created",
178
+ initial_value=DEFAULT_START_DATE,
179
+ range_end="closed",
180
+ range_start="closed",
181
+ ),
182
+ ) -> Iterable[TDataItem]:
183
+ """
184
+ Fetches emails from PlusVibeAI.
185
+
186
+ Args:
187
+ api_key (str): API key for authentication
188
+ workspace_id (str): Workspace ID to access
189
+ base_url (str): PlusVibeAI API base URL
190
+ max_results (int): Maximum number of results to return
191
+ updated (str): The date from which to fetch emails
192
+
193
+ Yields:
194
+ dict: The email data.
195
+ """
196
+ client = get_client(api_key, workspace_id, base_url)
197
+
198
+ for email in client.get_emails(max_results=max_results):
199
+ # Apply incremental filter if needed
200
+ if updated.start_value:
201
+ email_created = email.get("timestamp_created")
202
+ if email_created and email_created < updated.start_value:
203
+ continue
204
+
205
+ yield email
206
+
207
+
208
+ @dlt.resource(
209
+ write_disposition="merge",
210
+ primary_key="_id",
211
+ max_table_nesting=0,
212
+ )
213
+ def blocklist(
214
+ api_key: str = dlt.secrets.value,
215
+ workspace_id: str = dlt.secrets.value,
216
+ base_url: str = "https://api.plusvibe.ai",
217
+ max_results: Optional[int] = None,
218
+ updated: dlt.sources.incremental[str] = dlt.sources.incremental(
219
+ "created_at",
220
+ initial_value=DEFAULT_START_DATE,
221
+ range_end="closed",
222
+ range_start="closed",
223
+ ),
224
+ ) -> Iterable[TDataItem]:
225
+ """
226
+ Fetches blocklist entries from PlusVibeAI.
227
+
228
+ Args:
229
+ api_key (str): API key for authentication
230
+ workspace_id (str): Workspace ID to access
231
+ base_url (str): PlusVibeAI API base URL
232
+ max_results (int): Maximum number of results to return
233
+ updated (str): The date from which to fetch blocklist entries
234
+
235
+ Yields:
236
+ dict: The blocklist entry data.
237
+ """
238
+ client = get_client(api_key, workspace_id, base_url)
239
+
240
+ for entry in client.get_blocklist(
241
+ page_size=DEFAULT_PAGE_SIZE, max_results=max_results
242
+ ):
243
+ # Apply incremental filter if needed
244
+ if updated.start_value:
245
+ entry_created = entry.get("created_at")
246
+ if entry_created and entry_created < updated.start_value:
247
+ continue
248
+
249
+ yield entry
250
+
251
+
252
+ @dlt.resource(
253
+ write_disposition="merge",
254
+ primary_key="_id",
255
+ max_table_nesting=0,
256
+ )
257
+ def webhooks(
258
+ api_key: str = dlt.secrets.value,
259
+ workspace_id: str = dlt.secrets.value,
260
+ base_url: str = "https://api.plusvibe.ai",
261
+ max_results: Optional[int] = None,
262
+ updated: dlt.sources.incremental[str] = dlt.sources.incremental(
263
+ "modified_at",
264
+ initial_value=DEFAULT_START_DATE,
265
+ range_end="closed",
266
+ range_start="closed",
267
+ ),
268
+ ) -> Iterable[TDataItem]:
269
+ """
270
+ Fetches webhooks from PlusVibeAI.
271
+
272
+ Args:
273
+ api_key (str): API key for authentication
274
+ workspace_id (str): Workspace ID to access
275
+ base_url (str): PlusVibeAI API base URL
276
+ max_results (int): Maximum number of results to return
277
+ updated (str): The date from which to fetch updated webhooks
278
+
279
+ Yields:
280
+ dict: The webhook data.
281
+ """
282
+ client = get_client(api_key, workspace_id, base_url)
283
+
284
+ for webhook in client.get_webhooks(
285
+ page_size=DEFAULT_PAGE_SIZE, max_results=max_results
286
+ ):
287
+ # Apply incremental filter if needed
288
+ if updated.start_value:
289
+ webhook_updated = webhook.get("modified_at")
290
+ if webhook_updated and webhook_updated < updated.start_value:
291
+ continue
292
+
293
+ yield webhook
294
+
295
+
296
+ @dlt.resource(
297
+ write_disposition="merge",
298
+ primary_key="_id",
299
+ max_table_nesting=0,
300
+ )
301
+ def tags(
302
+ api_key: str = dlt.secrets.value,
303
+ workspace_id: str = dlt.secrets.value,
304
+ base_url: str = "https://api.plusvibe.ai",
305
+ max_results: Optional[int] = None,
306
+ updated: dlt.sources.incremental[str] = dlt.sources.incremental(
307
+ "modified_at",
308
+ initial_value=DEFAULT_START_DATE,
309
+ range_end="closed",
310
+ range_start="closed",
311
+ ),
312
+ ) -> Iterable[TDataItem]:
313
+ """
314
+ Fetches tags from PlusVibeAI.
315
+
316
+ Args:
317
+ api_key (str): API key for authentication
318
+ workspace_id (str): Workspace ID to access
319
+ base_url (str): PlusVibeAI API base URL
320
+ max_results (int): Maximum number of results to return
321
+ updated (str): The date from which to fetch updated tags
322
+
323
+ Yields:
324
+ dict: The tag data.
325
+ """
326
+ client = get_client(api_key, workspace_id, base_url)
327
+
328
+ for tag in client.get_tags(page_size=DEFAULT_PAGE_SIZE, max_results=max_results):
329
+ # Apply incremental filter if needed
330
+ if updated.start_value:
331
+ tag_updated = tag.get("modified_at")
332
+ if tag_updated and tag_updated < updated.start_value:
333
+ continue
334
+
335
+ yield tag