ingestr 0.14.4__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.
- {ingestr-0.14.4 → ingestr-0.14.5}/PKG-INFO +1 -1
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/.vitepress/config.mjs +1 -0
- ingestr-0.14.5/docs/supported-sources/plusvibeai.md +93 -0
- ingestr-0.14.5/ingestr/src/buildinfo.py +1 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/factory.py +2 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/jira_source/__init__.py +27 -1
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/jira_source/helpers.py +8 -21
- ingestr-0.14.5/ingestr/src/plusvibeai/__init__.py +335 -0
- ingestr-0.14.5/ingestr/src/plusvibeai/helpers.py +544 -0
- ingestr-0.14.5/ingestr/src/plusvibeai/settings.py +252 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/sources.py +47 -0
- ingestr-0.14.4/ingestr/src/buildinfo.py +0 -1
- {ingestr-0.14.4 → ingestr-0.14.5}/.dlt/config.toml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/.dockerignore +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/.githooks/pre-commit-hook.sh +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/.github/workflows/deploy-docs.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/.github/workflows/release.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/.github/workflows/secrets-scan.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/.github/workflows/tests.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/.gitignore +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/.gitleaksignore +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/.python-version +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/.vale.ini +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/Dockerfile +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/LICENSE.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/Makefile +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/README.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/.vitepress/theme/custom.css +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/.vitepress/theme/index.js +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/commands/example-uris.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/commands/ingest.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/getting-started/core-concepts.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/getting-started/data-masking.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/getting-started/incremental-loading.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/getting-started/quickstart.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/getting-started/telemetry.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/index.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/media/applovin_max.png +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/media/athena.png +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/media/clickhouse_img.png +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/media/clickup_ingestion.png +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/media/cratedb-destination.png +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/media/cratedb-source.png +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/media/freshdesk_ingestion.png +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/media/gcp_spanner_ingestion.png +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/media/github.png +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/media/google_analytics_realtime_report.png +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/media/googleanalytics.png +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/media/ingestion_elasticsearch_img.png +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/media/kinesis.bigquery.png +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/media/linear.png +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/media/linkedin_ads.png +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/media/mixpanel_ingestion.png +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/media/personio.png +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/media/personio_duckdb.png +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/media/phantombuster.png +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/media/pipedrive.png +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/media/quickbook_ingestion.png +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/media/sftp.png +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/media/stripe_postgres.png +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/media/tiktok.png +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/media/wise_ingestion.png +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/media/zoom_ingestion.png +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/public/demo.gif +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/adjust.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/airtable.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/anthropic.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/applovin.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/applovin_max.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/appsflyer.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/appstore.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/asana.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/athena.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/attio.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/bigquery.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/chess.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/clickhouse.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/clickup.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/cratedb.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/csv.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/custom_queries.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/databricks.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/db2.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/docebo.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/duckdb.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/dynamodb.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/elasticsearch.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/facebook-ads.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/fluxx.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/frankfurter.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/freshdesk.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/fundraiseup.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/gcs.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/github.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/google-ads.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/google_analytics.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/gorgias.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/gsheets.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/hubspot.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/influxdb.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/intercom.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/isoc-pulse.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/jira.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/kafka.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/kinesis.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/klaviyo.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/linear.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/linkedin_ads.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/mixpanel.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/mongodb.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/motherduck.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/mssql.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/mysql.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/notion.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/oracle.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/personio.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/phantombuster.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/pinterest.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/pipedrive.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/postgres.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/quickbooks.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/redshift.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/revenuecat.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/s3.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/salesforce.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/sap-hana.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/sftp.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/shopify.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/slack.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/smartsheets.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/snowflake.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/solidgate.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/spanner.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/sqlite.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/stripe.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/tiktok-ads.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/trino.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/trustpilot.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/wise.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/zendesk.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/supported-sources/zoom.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/tutorials/load-kinesis-bigquery.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/tutorials/load-personio-duckdb.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/docs/tutorials/load-stripe-postgres.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/conftest.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/main.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/.gitignore +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/adjust/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/adjust/adjust_helpers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/airtable/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/anthropic/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/anthropic/helpers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/applovin/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/applovin_max/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/appsflyer/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/appsflyer/client.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/appstore/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/appstore/client.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/appstore/errors.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/appstore/models.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/appstore/resources.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/arrow/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/asana_source/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/asana_source/helpers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/asana_source/settings.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/attio/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/attio/helpers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/blob.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/chess/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/chess/helpers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/chess/settings.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/clickup/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/clickup/helpers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/collector/spinner.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/destinations.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/docebo/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/docebo/client.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/docebo/helpers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/dynamodb/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/elasticsearch/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/elasticsearch/helpers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/errors.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/facebook_ads/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/facebook_ads/exceptions.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/facebook_ads/helpers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/facebook_ads/settings.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/facebook_ads/utils.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/filesystem/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/filesystem/helpers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/filesystem/readers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/filters.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/fluxx/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/fluxx/helpers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/frankfurter/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/frankfurter/helpers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/freshdesk/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/freshdesk/freshdesk_client.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/freshdesk/settings.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/fundraiseup/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/fundraiseup/client.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/github/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/github/helpers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/github/queries.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/github/settings.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/google_ads/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/google_ads/field.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/google_ads/metrics.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/google_ads/predicates.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/google_ads/reports.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/google_analytics/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/google_analytics/helpers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/google_sheets/README.md +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/google_sheets/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/google_sheets/helpers/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/google_sheets/helpers/api_calls.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/google_sheets/helpers/data_processing.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/gorgias/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/gorgias/helpers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/http_client.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/hubspot/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/hubspot/helpers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/hubspot/settings.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/influxdb/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/influxdb/client.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/intercom/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/intercom/helpers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/intercom/settings.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/isoc_pulse/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/jira_source/settings.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/kafka/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/kafka/helpers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/kinesis/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/kinesis/helpers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/klaviyo/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/klaviyo/client.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/klaviyo/helpers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/linear/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/linear/helpers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/linkedin_ads/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/linkedin_ads/dimension_time_enum.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/linkedin_ads/helpers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/loader.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/masking.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/mixpanel/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/mixpanel/client.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/mongodb/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/mongodb/helpers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/notion/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/notion/helpers/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/notion/helpers/client.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/notion/helpers/database.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/notion/settings.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/partition.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/personio/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/personio/helpers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/phantombuster/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/phantombuster/client.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/pinterest/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/pipedrive/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/pipedrive/helpers/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/pipedrive/helpers/custom_fields_munger.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/pipedrive/helpers/pages.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/pipedrive/settings.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/pipedrive/typing.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/quickbooks/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/resource.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/revenuecat/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/revenuecat/helpers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/salesforce/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/salesforce/helpers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/shopify/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/shopify/exceptions.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/shopify/helpers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/shopify/settings.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/slack/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/slack/helpers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/slack/settings.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/smartsheets/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/solidgate/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/solidgate/helpers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/sql_database/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/sql_database/callbacks.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/stripe_analytics/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/stripe_analytics/helpers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/stripe_analytics/settings.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/table_definition.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/telemetry/event.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/testdata/fakebqcredentials.json +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/tiktok_ads/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/tiktok_ads/tiktok_helpers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/time.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/trustpilot/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/trustpilot/client.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/version.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/wise/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/wise/client.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/zendesk/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/zendesk/helpers/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/zendesk/helpers/api_helpers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/zendesk/helpers/credentials.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/zendesk/helpers/talk_api.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/zendesk/settings.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/zoom/__init__.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/src/zoom/helpers.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/testdata/.gitignore +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/testdata/create_replace.csv +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/testdata/delete_insert_expected.csv +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/testdata/delete_insert_part1.csv +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/testdata/delete_insert_part2.csv +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/testdata/merge_expected.csv +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/testdata/merge_part1.csv +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/testdata/merge_part2.csv +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/ingestr/tests/unit/test_smartsheets.py +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/package-lock.json +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/package.json +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/pyproject.toml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/requirements-dev.txt +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/requirements.in +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/requirements.txt +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/requirements_arm64.txt +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/resources/demo.gif +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/resources/demo.tape +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/resources/ingestr.svg +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/Google/AMPM.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/Google/Acronyms.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/Google/Colons.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/Google/Contractions.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/Google/DateFormat.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/Google/Ellipses.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/Google/EmDash.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/Google/Exclamation.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/Google/FirstPerson.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/Google/Gender.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/Google/GenderBias.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/Google/HeadingPunctuation.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/Google/Headings.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/Google/Latin.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/Google/LyHyphens.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/Google/OptionalPlurals.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/Google/Ordinal.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/Google/OxfordComma.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/Google/Parens.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/Google/Passive.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/Google/Periods.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/Google/Quotes.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/Google/Ranges.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/Google/Semicolons.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/Google/Slang.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/Google/Spacing.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/Google/Spelling.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/Google/Units.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/Google/We.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/Google/Will.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/Google/WordList.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/Google/meta.json +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/Google/vocab.txt +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/bruin/Ingestr.yml +0 -0
- {ingestr-0.14.4 → ingestr-0.14.5}/styles/config/vocabularies/bruin/accept.txt +0 -0
- {ingestr-0.14.4 → 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
|
+
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" },
|
|
@@ -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,
|
|
@@ -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(
|
|
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
|