@bubblelab/bubble-core 0.1.10 → 0.1.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bubble-bundle.d.ts +803 -351
- package/dist/bubble-factory.d.ts.map +1 -1
- package/dist/bubble-factory.js +130 -35
- package/dist/bubble-factory.js.map +1 -1
- package/dist/bubble-flow/bubble-flow-class.d.ts +5 -0
- package/dist/bubble-flow/bubble-flow-class.d.ts.map +1 -1
- package/dist/bubble-flow/bubble-flow-class.js +20 -0
- package/dist/bubble-flow/bubble-flow-class.js.map +1 -1
- package/dist/bubble-flow/sample/simplified-data-analysis.flow.d.ts.map +1 -1
- package/dist/bubble-flow/sample/simplified-data-analysis.flow.js +6 -3
- package/dist/bubble-flow/sample/simplified-data-analysis.flow.js.map +1 -1
- package/dist/bubbles/service-bubble/agi-inc.d.ts +1121 -0
- package/dist/bubbles/service-bubble/agi-inc.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/agi-inc.js +730 -0
- package/dist/bubbles/service-bubble/agi-inc.js.map +1 -0
- package/dist/bubbles/service-bubble/ai-agent.d.ts +273 -61
- package/dist/bubbles/service-bubble/ai-agent.d.ts.map +1 -1
- package/dist/bubbles/service-bubble/ai-agent.js +536 -405
- package/dist/bubbles/service-bubble/ai-agent.js.map +1 -1
- package/dist/bubbles/service-bubble/airtable.d.ts +1753 -0
- package/dist/bubbles/service-bubble/airtable.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/airtable.js +1173 -0
- package/dist/bubbles/service-bubble/airtable.js.map +1 -0
- package/dist/bubbles/service-bubble/apify/actors/google-maps-scraper.d.ts +240 -0
- package/dist/bubbles/service-bubble/apify/actors/google-maps-scraper.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/apify/actors/google-maps-scraper.js +119 -0
- package/dist/bubbles/service-bubble/apify/actors/google-maps-scraper.js.map +1 -0
- package/dist/bubbles/service-bubble/apify/actors/instagram-hashtag-scraper.d.ts +4 -4
- package/dist/bubbles/service-bubble/apify/actors/instagram-scraper.d.ts +14 -14
- package/dist/bubbles/service-bubble/apify/actors/linkedin-jobs-scraper.d.ts +137 -0
- package/dist/bubbles/service-bubble/apify/actors/linkedin-jobs-scraper.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/apify/actors/linkedin-jobs-scraper.js +81 -0
- package/dist/bubbles/service-bubble/apify/actors/linkedin-jobs-scraper.js.map +1 -0
- package/dist/bubbles/service-bubble/apify/actors/linkedin-posts-search.d.ts +6 -6
- package/dist/bubbles/service-bubble/apify/actors/linkedin-profile-posts.d.ts +32 -32
- package/dist/bubbles/service-bubble/apify/actors/tiktok-scraper.d.ts +488 -0
- package/dist/bubbles/service-bubble/apify/actors/tiktok-scraper.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/apify/actors/tiktok-scraper.js +463 -0
- package/dist/bubbles/service-bubble/apify/actors/tiktok-scraper.js.map +1 -0
- package/dist/bubbles/service-bubble/apify/actors/twitter-scraper.d.ts +262 -0
- package/dist/bubbles/service-bubble/apify/actors/twitter-scraper.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/apify/actors/twitter-scraper.js +291 -0
- package/dist/bubbles/service-bubble/apify/actors/twitter-scraper.js.map +1 -0
- package/dist/bubbles/service-bubble/apify/actors/youtube-scraper.d.ts +12 -12
- package/dist/bubbles/service-bubble/apify/apify-scraper.schema.d.ts +1301 -170
- package/dist/bubbles/service-bubble/apify/apify-scraper.schema.d.ts.map +1 -1
- package/dist/bubbles/service-bubble/apify/apify-scraper.schema.js +32 -0
- package/dist/bubbles/service-bubble/apify/apify-scraper.schema.js.map +1 -1
- package/dist/bubbles/service-bubble/apify/apify.d.ts +158 -13
- package/dist/bubbles/service-bubble/apify/apify.d.ts.map +1 -1
- package/dist/bubbles/service-bubble/apify/apify.js +222 -37
- package/dist/bubbles/service-bubble/apify/apify.js.map +1 -1
- package/dist/bubbles/service-bubble/browserbase/browserbase.d.ts +542 -0
- package/dist/bubbles/service-bubble/browserbase/browserbase.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/browserbase/browserbase.integration.flow.d.ts +37 -0
- package/dist/bubbles/service-bubble/browserbase/browserbase.integration.flow.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/browserbase/browserbase.integration.flow.js +203 -0
- package/dist/bubbles/service-bubble/browserbase/browserbase.integration.flow.js.map +1 -0
- package/dist/bubbles/service-bubble/browserbase/browserbase.js +593 -0
- package/dist/bubbles/service-bubble/browserbase/browserbase.js.map +1 -0
- package/dist/bubbles/service-bubble/browserbase/browserbase.schema.d.ts +518 -0
- package/dist/bubbles/service-bubble/browserbase/browserbase.schema.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/browserbase/browserbase.schema.js +311 -0
- package/dist/bubbles/service-bubble/browserbase/browserbase.schema.js.map +1 -0
- package/dist/bubbles/service-bubble/browserbase/index.d.ts +3 -0
- package/dist/bubbles/service-bubble/browserbase/index.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/browserbase/index.js +3 -0
- package/dist/bubbles/service-bubble/browserbase/index.js.map +1 -0
- package/dist/bubbles/service-bubble/crustdata/crustdata.d.ts +1358 -0
- package/dist/bubbles/service-bubble/crustdata/crustdata.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/crustdata/crustdata.js +219 -0
- package/dist/bubbles/service-bubble/crustdata/crustdata.js.map +1 -0
- package/dist/bubbles/service-bubble/crustdata/crustdata.schema.d.ts +1604 -0
- package/dist/bubbles/service-bubble/crustdata/crustdata.schema.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/crustdata/crustdata.schema.js +194 -0
- package/dist/bubbles/service-bubble/crustdata/crustdata.schema.js.map +1 -0
- package/dist/bubbles/service-bubble/crustdata/index.d.ts +3 -0
- package/dist/bubbles/service-bubble/crustdata/index.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/crustdata/index.js +3 -0
- package/dist/bubbles/service-bubble/crustdata/index.js.map +1 -0
- package/dist/bubbles/service-bubble/eleven-labs.d.ts +421 -0
- package/dist/bubbles/service-bubble/eleven-labs.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/eleven-labs.js +479 -0
- package/dist/bubbles/service-bubble/eleven-labs.js.map +1 -0
- package/dist/bubbles/service-bubble/firecrawl.d.ts +37748 -0
- package/dist/bubbles/service-bubble/firecrawl.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/firecrawl.js +1489 -0
- package/dist/bubbles/service-bubble/firecrawl.js.map +1 -0
- package/dist/bubbles/service-bubble/followupboss.d.ts +6822 -0
- package/dist/bubbles/service-bubble/followupboss.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/followupboss.js +1394 -0
- package/dist/bubbles/service-bubble/followupboss.js.map +1 -0
- package/dist/bubbles/service-bubble/github.d.ts +2393 -0
- package/dist/bubbles/service-bubble/github.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/github.js +1046 -0
- package/dist/bubbles/service-bubble/github.js.map +1 -0
- package/dist/bubbles/service-bubble/gmail.d.ts +180 -180
- package/dist/bubbles/service-bubble/google-calendar.d.ts +60 -60
- package/dist/bubbles/service-bubble/google-drive.d.ts +69 -68
- package/dist/bubbles/service-bubble/google-drive.d.ts.map +1 -1
- package/dist/bubbles/service-bubble/google-drive.js +35 -3
- package/dist/bubbles/service-bubble/google-drive.js.map +1 -1
- package/dist/bubbles/service-bubble/google-sheets/google-sheets.d.ts +943 -0
- package/dist/bubbles/service-bubble/google-sheets/google-sheets.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/google-sheets/google-sheets.integration.flow.d.ts +31 -0
- package/dist/bubbles/service-bubble/google-sheets/google-sheets.integration.flow.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/google-sheets/google-sheets.integration.flow.js +184 -0
- package/dist/bubbles/service-bubble/google-sheets/google-sheets.integration.flow.js.map +1 -0
- package/dist/bubbles/service-bubble/google-sheets/google-sheets.js +401 -0
- package/dist/bubbles/service-bubble/google-sheets/google-sheets.js.map +1 -0
- package/dist/bubbles/service-bubble/google-sheets/google-sheets.schema.d.ts +1024 -0
- package/dist/bubbles/service-bubble/google-sheets/google-sheets.schema.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/{google-sheets.js → google-sheets/google-sheets.schema.js} +45 -409
- package/dist/bubbles/service-bubble/google-sheets/google-sheets.schema.js.map +1 -0
- package/dist/bubbles/service-bubble/google-sheets/google-sheets.utils.d.ts +38 -0
- package/dist/bubbles/service-bubble/google-sheets/google-sheets.utils.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/google-sheets/google-sheets.utils.js +183 -0
- package/dist/bubbles/service-bubble/google-sheets/google-sheets.utils.js.map +1 -0
- package/dist/bubbles/service-bubble/google-sheets/index.d.ts +4 -0
- package/dist/bubbles/service-bubble/google-sheets/index.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/google-sheets/index.js +4 -0
- package/dist/bubbles/service-bubble/google-sheets/index.js.map +1 -0
- package/dist/bubbles/service-bubble/hello-world.d.ts +4 -4
- package/dist/bubbles/service-bubble/http.d.ts +17 -5
- package/dist/bubbles/service-bubble/http.d.ts.map +1 -1
- package/dist/bubbles/service-bubble/http.integration.flow.d.ts +49 -0
- package/dist/bubbles/service-bubble/http.integration.flow.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/http.integration.flow.js +425 -0
- package/dist/bubbles/service-bubble/http.integration.flow.js.map +1 -0
- package/dist/bubbles/service-bubble/http.js +47 -5
- package/dist/bubbles/service-bubble/http.js.map +1 -1
- package/dist/bubbles/service-bubble/insforge-db.d.ts +140 -0
- package/dist/bubbles/service-bubble/insforge-db.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/insforge-db.js +260 -0
- package/dist/bubbles/service-bubble/insforge-db.js.map +1 -0
- package/dist/bubbles/service-bubble/notion/index.d.ts +3 -0
- package/dist/bubbles/service-bubble/notion/index.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/notion/index.js +3 -0
- package/dist/bubbles/service-bubble/notion/index.js.map +1 -0
- package/dist/bubbles/service-bubble/notion/notion.d.ts +35405 -0
- package/dist/bubbles/service-bubble/notion/notion.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/notion/notion.js +1492 -0
- package/dist/bubbles/service-bubble/notion/notion.js.map +1 -0
- package/dist/bubbles/service-bubble/notion/property-schemas.d.ts +1148 -0
- package/dist/bubbles/service-bubble/notion/property-schemas.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/notion/property-schemas.js +341 -0
- package/dist/bubbles/service-bubble/notion/property-schemas.js.map +1 -0
- package/dist/bubbles/service-bubble/postgresql.d.ts +12 -12
- package/dist/bubbles/service-bubble/resend.d.ts +30 -9
- package/dist/bubbles/service-bubble/resend.d.ts.map +1 -1
- package/dist/bubbles/service-bubble/resend.js +133 -2
- package/dist/bubbles/service-bubble/resend.js.map +1 -1
- package/dist/bubbles/service-bubble/slack.d.ts +1741 -798
- package/dist/bubbles/service-bubble/slack.d.ts.map +1 -1
- package/dist/bubbles/service-bubble/slack.js +322 -28
- package/dist/bubbles/service-bubble/slack.js.map +1 -1
- package/dist/bubbles/service-bubble/storage.d.ts +26 -22
- package/dist/bubbles/service-bubble/storage.d.ts.map +1 -1
- package/dist/bubbles/service-bubble/storage.js +45 -4
- package/dist/bubbles/service-bubble/storage.js.map +1 -1
- package/dist/bubbles/service-bubble/telegram.d.ts +7742 -0
- package/dist/bubbles/service-bubble/telegram.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/telegram.js +1132 -0
- package/dist/bubbles/service-bubble/telegram.js.map +1 -0
- package/dist/bubbles/tool-bubble/amazon-shopping-tool/amazon-shopping-tool.d.ts +494 -0
- package/dist/bubbles/tool-bubble/amazon-shopping-tool/amazon-shopping-tool.d.ts.map +1 -0
- package/dist/bubbles/tool-bubble/amazon-shopping-tool/amazon-shopping-tool.integration.flow.d.ts +31 -0
- package/dist/bubbles/tool-bubble/amazon-shopping-tool/amazon-shopping-tool.integration.flow.d.ts.map +1 -0
- package/dist/bubbles/tool-bubble/amazon-shopping-tool/amazon-shopping-tool.integration.flow.js +100 -0
- package/dist/bubbles/tool-bubble/amazon-shopping-tool/amazon-shopping-tool.integration.flow.js.map +1 -0
- package/dist/bubbles/tool-bubble/amazon-shopping-tool/amazon-shopping-tool.js +1301 -0
- package/dist/bubbles/tool-bubble/amazon-shopping-tool/amazon-shopping-tool.js.map +1 -0
- package/dist/bubbles/tool-bubble/amazon-shopping-tool/amazon-shopping-tool.schema.d.ts +473 -0
- package/dist/bubbles/tool-bubble/amazon-shopping-tool/amazon-shopping-tool.schema.d.ts.map +1 -0
- package/dist/bubbles/tool-bubble/amazon-shopping-tool/amazon-shopping-tool.schema.js +230 -0
- package/dist/bubbles/tool-bubble/amazon-shopping-tool/amazon-shopping-tool.schema.js.map +1 -0
- package/dist/bubbles/tool-bubble/amazon-shopping-tool/index.d.ts +3 -0
- package/dist/bubbles/tool-bubble/amazon-shopping-tool/index.d.ts.map +1 -0
- package/dist/bubbles/tool-bubble/amazon-shopping-tool/index.js +3 -0
- package/dist/bubbles/tool-bubble/amazon-shopping-tool/index.js.map +1 -0
- package/dist/bubbles/tool-bubble/bubbleflow-validation-tool.d.ts +76 -20
- package/dist/bubbles/tool-bubble/bubbleflow-validation-tool.d.ts.map +1 -1
- package/dist/bubbles/tool-bubble/bubbleflow-validation-tool.js +12 -0
- package/dist/bubbles/tool-bubble/bubbleflow-validation-tool.js.map +1 -1
- package/dist/bubbles/tool-bubble/chart-js-tool.d.ts +14 -14
- package/dist/bubbles/tool-bubble/code-edit-tool.d.ts +188 -0
- package/dist/bubbles/tool-bubble/code-edit-tool.d.ts.map +1 -0
- package/dist/bubbles/tool-bubble/code-edit-tool.js +321 -0
- package/dist/bubbles/tool-bubble/code-edit-tool.js.map +1 -0
- package/dist/bubbles/tool-bubble/company-enrichment-tool.d.ts +740 -0
- package/dist/bubbles/tool-bubble/company-enrichment-tool.d.ts.map +1 -0
- package/dist/bubbles/tool-bubble/company-enrichment-tool.js +350 -0
- package/dist/bubbles/tool-bubble/company-enrichment-tool.js.map +1 -0
- package/dist/bubbles/tool-bubble/get-bubble-details-tool.d.ts +8 -4
- package/dist/bubbles/tool-bubble/get-bubble-details-tool.d.ts.map +1 -1
- package/dist/bubbles/tool-bubble/get-bubble-details-tool.js +115 -10
- package/dist/bubbles/tool-bubble/get-bubble-details-tool.js.map +1 -1
- package/dist/bubbles/tool-bubble/google-maps-tool.d.ts +455 -0
- package/dist/bubbles/tool-bubble/google-maps-tool.d.ts.map +1 -0
- package/dist/bubbles/tool-bubble/google-maps-tool.js +206 -0
- package/dist/bubbles/tool-bubble/google-maps-tool.js.map +1 -0
- package/dist/bubbles/tool-bubble/instagram-tool.d.ts +36 -36
- package/dist/bubbles/tool-bubble/instagram-tool.d.ts.map +1 -1
- package/dist/bubbles/tool-bubble/instagram-tool.js +4 -2
- package/dist/bubbles/tool-bubble/instagram-tool.js.map +1 -1
- package/dist/bubbles/tool-bubble/linkedin-tool.d.ts +830 -453
- package/dist/bubbles/tool-bubble/linkedin-tool.d.ts.map +1 -1
- package/dist/bubbles/tool-bubble/linkedin-tool.js +236 -14
- package/dist/bubbles/tool-bubble/linkedin-tool.js.map +1 -1
- package/dist/bubbles/tool-bubble/list-bubbles-tool.d.ts +4 -4
- package/dist/bubbles/tool-bubble/reddit-scrape-tool.d.ts +66 -66
- package/dist/bubbles/tool-bubble/research-agent-tool.d.ts +17 -16
- package/dist/bubbles/tool-bubble/research-agent-tool.d.ts.map +1 -1
- package/dist/bubbles/tool-bubble/research-agent-tool.js +32 -17
- package/dist/bubbles/tool-bubble/research-agent-tool.js.map +1 -1
- package/dist/bubbles/tool-bubble/sql-query-tool.d.ts +8 -8
- package/dist/bubbles/tool-bubble/tiktok-tool.d.ts +485 -0
- package/dist/bubbles/tool-bubble/tiktok-tool.d.ts.map +1 -0
- package/dist/bubbles/tool-bubble/tiktok-tool.js +226 -0
- package/dist/bubbles/tool-bubble/tiktok-tool.js.map +1 -0
- package/dist/bubbles/tool-bubble/tool-template.d.ts +8 -8
- package/dist/bubbles/tool-bubble/twitter-tool.d.ts +947 -0
- package/dist/bubbles/tool-bubble/twitter-tool.d.ts.map +1 -0
- package/dist/bubbles/tool-bubble/twitter-tool.js +497 -0
- package/dist/bubbles/tool-bubble/twitter-tool.js.map +1 -0
- package/dist/bubbles/tool-bubble/web-crawl-tool.d.ts +22 -16
- package/dist/bubbles/tool-bubble/web-crawl-tool.d.ts.map +1 -1
- package/dist/bubbles/tool-bubble/web-crawl-tool.js +58 -59
- package/dist/bubbles/tool-bubble/web-crawl-tool.js.map +1 -1
- package/dist/bubbles/tool-bubble/web-extract-tool.d.ts +8 -8
- package/dist/bubbles/tool-bubble/web-extract-tool.d.ts.map +1 -1
- package/dist/bubbles/tool-bubble/web-extract-tool.js +17 -17
- package/dist/bubbles/tool-bubble/web-extract-tool.js.map +1 -1
- package/dist/bubbles/tool-bubble/web-scrape-tool.d.ts +21 -113
- package/dist/bubbles/tool-bubble/web-scrape-tool.d.ts.map +1 -1
- package/dist/bubbles/tool-bubble/web-scrape-tool.js +55 -73
- package/dist/bubbles/tool-bubble/web-scrape-tool.js.map +1 -1
- package/dist/bubbles/tool-bubble/web-search-tool.d.ts +20 -9
- package/dist/bubbles/tool-bubble/web-search-tool.d.ts.map +1 -1
- package/dist/bubbles/tool-bubble/web-search-tool.js +45 -35
- package/dist/bubbles/tool-bubble/web-search-tool.js.map +1 -1
- package/dist/bubbles/tool-bubble/youtube-tool.d.ts +25 -25
- package/dist/bubbles/tool-bubble/youtube-tool.d.ts.map +1 -1
- package/dist/bubbles/tool-bubble/youtube-tool.js +8 -5
- package/dist/bubbles/tool-bubble/youtube-tool.js.map +1 -1
- package/dist/bubbles/workflow-bubble/database-analyzer.workflow.d.ts +4 -4
- package/dist/bubbles/workflow-bubble/generate-document.workflow.d.ts +30 -30
- package/dist/bubbles/workflow-bubble/generate-document.workflow.js +1 -1
- package/dist/bubbles/workflow-bubble/parse-document.workflow.d.ts +22 -22
- package/dist/bubbles/workflow-bubble/parse-document.workflow.js +1 -1
- package/dist/bubbles/workflow-bubble/pdf-form-operations.workflow.d.ts +70 -70
- package/dist/bubbles/workflow-bubble/pdf-form-operations.workflow.d.ts.map +1 -1
- package/dist/bubbles/workflow-bubble/pdf-form-operations.workflow.js +4 -4
- package/dist/bubbles/workflow-bubble/pdf-form-operations.workflow.js.map +1 -1
- package/dist/bubbles/workflow-bubble/pdf-ocr.workflow.d.ts +36 -36
- package/dist/bubbles/workflow-bubble/pdf-ocr.workflow.js +1 -1
- package/dist/bubbles/workflow-bubble/slack-data-assistant.workflow.d.ts +14 -14
- package/dist/bubbles/workflow-bubble/slack-data-assistant.workflow.d.ts.map +1 -1
- package/dist/bubbles/workflow-bubble/slack-data-assistant.workflow.js +6 -6
- package/dist/bubbles/workflow-bubble/slack-data-assistant.workflow.js.map +1 -1
- package/dist/bubbles/workflow-bubble/slack-formatter-agent.d.ts +18 -18
- package/dist/bubbles/workflow-bubble/slack-formatter-agent.d.ts.map +1 -1
- package/dist/bubbles/workflow-bubble/slack-formatter-agent.js +24 -4
- package/dist/bubbles/workflow-bubble/slack-formatter-agent.js.map +1 -1
- package/dist/bubbles/workflow-bubble/slack-notifier.workflow.d.ts +19 -19
- package/dist/bubbles/workflow-bubble/slack-notifier.workflow.d.ts.map +1 -1
- package/dist/bubbles/workflow-bubble/slack-notifier.workflow.js +8 -8
- package/dist/bubbles/workflow-bubble/slack-notifier.workflow.js.map +1 -1
- package/dist/bubbles.json +260 -77
- package/dist/index.d.ts +25 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -3
- package/dist/index.js.map +1 -1
- package/dist/logging/BubbleLogger.d.ts +55 -16
- package/dist/logging/BubbleLogger.d.ts.map +1 -1
- package/dist/logging/BubbleLogger.js +192 -77
- package/dist/logging/BubbleLogger.js.map +1 -1
- package/dist/logging/StreamingBubbleLogger.d.ts +21 -1
- package/dist/logging/StreamingBubbleLogger.d.ts.map +1 -1
- package/dist/logging/StreamingBubbleLogger.js +80 -8
- package/dist/logging/StreamingBubbleLogger.js.map +1 -1
- package/dist/logging/WebhookStreamLogger.d.ts +66 -0
- package/dist/logging/WebhookStreamLogger.d.ts.map +1 -0
- package/dist/logging/WebhookStreamLogger.js +291 -0
- package/dist/logging/WebhookStreamLogger.js.map +1 -0
- package/dist/types/available-tools.d.ts +1 -1
- package/dist/types/available-tools.d.ts.map +1 -1
- package/dist/types/available-tools.js +7 -0
- package/dist/types/available-tools.js.map +1 -1
- package/dist/types/base-bubble-class.d.ts +6 -4
- package/dist/types/base-bubble-class.d.ts.map +1 -1
- package/dist/types/base-bubble-class.js +30 -23
- package/dist/types/base-bubble-class.js.map +1 -1
- package/dist/types/bubble.d.ts +2 -0
- package/dist/types/bubble.d.ts.map +1 -1
- package/dist/types/service-bubble-class.d.ts +1 -1
- package/dist/types/service-bubble-class.d.ts.map +1 -1
- package/dist/types/service-bubble-class.js +2 -2
- package/dist/types/service-bubble-class.js.map +1 -1
- package/dist/types/tool-bubble-class.d.ts +1 -1
- package/dist/types/tool-bubble-class.d.ts.map +1 -1
- package/dist/types/tool-bubble-class.js +60 -10
- package/dist/types/tool-bubble-class.js.map +1 -1
- package/dist/types/workflow-bubble-class.d.ts +1 -1
- package/dist/types/workflow-bubble-class.d.ts.map +1 -1
- package/dist/types/workflow-bubble-class.js +2 -2
- package/dist/types/workflow-bubble-class.js.map +1 -1
- package/dist/utils/agent-formatter.d.ts +14 -2
- package/dist/utils/agent-formatter.d.ts.map +1 -1
- package/dist/utils/agent-formatter.js +174 -26
- package/dist/utils/agent-formatter.js.map +1 -1
- package/dist/utils/bubbleflow-validation.d.ts +7 -0
- package/dist/utils/bubbleflow-validation.d.ts.map +1 -1
- package/dist/utils/bubbleflow-validation.js +171 -6
- package/dist/utils/bubbleflow-validation.js.map +1 -1
- package/dist/utils/json-parsing.d.ts.map +1 -1
- package/dist/utils/json-parsing.js +146 -0
- package/dist/utils/json-parsing.js.map +1 -1
- package/dist/utils/safe-gemini-chat.d.ts +31 -0
- package/dist/utils/safe-gemini-chat.d.ts.map +1 -0
- package/dist/utils/safe-gemini-chat.js +93 -0
- package/dist/utils/safe-gemini-chat.js.map +1 -0
- package/dist/utils/schema-comparison.d.ts +92 -0
- package/dist/utils/schema-comparison.d.ts.map +1 -0
- package/dist/utils/schema-comparison.js +716 -0
- package/dist/utils/schema-comparison.js.map +1 -0
- package/dist/utils/zod-schema.d.ts +24 -0
- package/dist/utils/zod-schema.d.ts.map +1 -0
- package/dist/utils/zod-schema.js +56 -0
- package/dist/utils/zod-schema.js.map +1 -0
- package/package.json +6 -4
- package/dist/bubbles/service-bubble/google-sheets.d.ts +0 -1811
- package/dist/bubbles/service-bubble/google-sheets.d.ts.map +0 -1
- package/dist/bubbles/service-bubble/google-sheets.js.map +0 -1
- package/dist/bubbles/service-bubble/x-twitter.d.ts +0 -814
- package/dist/bubbles/service-bubble/x-twitter.d.ts.map +0 -1
- package/dist/bubbles/service-bubble/x-twitter.js +0 -445
- package/dist/bubbles/service-bubble/x-twitter.js.map +0 -1
- package/dist/bubbles/workflow-bubble/bubbleflow-generator.workflow.d.ts +0 -125
- package/dist/bubbles/workflow-bubble/bubbleflow-generator.workflow.d.ts.map +0 -1
- package/dist/bubbles/workflow-bubble/bubbleflow-generator.workflow.js +0 -808
- package/dist/bubbles/workflow-bubble/bubbleflow-generator.workflow.js.map +0 -1
- package/dist/test-gm.d.ts +0 -10
- package/dist/test-gm.d.ts.map +0 -1
- package/dist/test-gm.js +0 -95
- package/dist/test-gm.js.map +0 -1
- package/dist/utils/param-helper.d.ts +0 -2
- package/dist/utils/param-helper.d.ts.map +0 -1
- package/dist/utils/param-helper.js +0 -5
- package/dist/utils/param-helper.js.map +0 -1
|
@@ -0,0 +1,1173 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { ServiceBubble } from '../../types/service-bubble-class.js';
|
|
3
|
+
import { CredentialType } from '@bubblelab/shared-schemas';
|
|
4
|
+
// Airtable API base URL
|
|
5
|
+
const AIRTABLE_API_BASE = 'https://api.airtable.com/v0';
|
|
6
|
+
// Define Airtable field value schema (supports multiple types)
|
|
7
|
+
const AirtableFieldValueSchema = z
|
|
8
|
+
.union([
|
|
9
|
+
z.string(),
|
|
10
|
+
z.number(),
|
|
11
|
+
z.boolean(),
|
|
12
|
+
z.array(z.unknown()),
|
|
13
|
+
z.record(z.unknown()),
|
|
14
|
+
z.null(),
|
|
15
|
+
])
|
|
16
|
+
.describe('Value for an Airtable field (string, number, boolean, array, object, or null)');
|
|
17
|
+
// Define Airtable record schema
|
|
18
|
+
const AirtableRecordSchema = z
|
|
19
|
+
.object({
|
|
20
|
+
id: z.string().describe('Unique record identifier (starts with rec)'),
|
|
21
|
+
createdTime: z
|
|
22
|
+
.string()
|
|
23
|
+
.datetime()
|
|
24
|
+
.describe('ISO 8601 datetime when record was created'),
|
|
25
|
+
fields: z
|
|
26
|
+
.record(z.string(), AirtableFieldValueSchema)
|
|
27
|
+
.describe('Record field values as key-value pairs'),
|
|
28
|
+
})
|
|
29
|
+
.describe('Airtable record with ID, creation time, and field data');
|
|
30
|
+
// Define sort direction
|
|
31
|
+
const SortDirectionSchema = z
|
|
32
|
+
.enum(['asc', 'desc'])
|
|
33
|
+
.describe('Sort direction: ascending or descending');
|
|
34
|
+
// Define sort specification
|
|
35
|
+
const SortSpecSchema = z
|
|
36
|
+
.object({
|
|
37
|
+
field: z.string().describe('Field name to sort by'),
|
|
38
|
+
direction: SortDirectionSchema.optional()
|
|
39
|
+
.default('asc')
|
|
40
|
+
.describe('Sort direction (asc or desc)'),
|
|
41
|
+
})
|
|
42
|
+
.describe('Sort specification for ordering records');
|
|
43
|
+
const AirtableFieldTypeEnum = z.enum([
|
|
44
|
+
'singleLineText',
|
|
45
|
+
'multilineText',
|
|
46
|
+
'richText',
|
|
47
|
+
'email',
|
|
48
|
+
'url',
|
|
49
|
+
'phoneNumber',
|
|
50
|
+
'number',
|
|
51
|
+
'percent',
|
|
52
|
+
'currency',
|
|
53
|
+
'rating',
|
|
54
|
+
'duration',
|
|
55
|
+
'singleSelect',
|
|
56
|
+
'multipleSelects',
|
|
57
|
+
'singleCollaborator',
|
|
58
|
+
'multipleCollaborators',
|
|
59
|
+
'date',
|
|
60
|
+
'dateTime',
|
|
61
|
+
'checkbox',
|
|
62
|
+
'multipleRecordLinks',
|
|
63
|
+
'multipleAttachments',
|
|
64
|
+
'barcode',
|
|
65
|
+
'button',
|
|
66
|
+
'formula',
|
|
67
|
+
'createdTime',
|
|
68
|
+
'lastModifiedTime',
|
|
69
|
+
'createdBy',
|
|
70
|
+
'lastModifiedBy',
|
|
71
|
+
'autoNumber',
|
|
72
|
+
'externalSyncSource',
|
|
73
|
+
'count',
|
|
74
|
+
'lookup',
|
|
75
|
+
'rollup',
|
|
76
|
+
]);
|
|
77
|
+
// Define the parameters schema for different Airtable operations
|
|
78
|
+
const AirtableParamsSchema = z.discriminatedUnion('operation', [
|
|
79
|
+
// List records operation
|
|
80
|
+
z.object({
|
|
81
|
+
operation: z
|
|
82
|
+
.literal('list_records')
|
|
83
|
+
.describe('List records from an Airtable table with filtering and sorting'),
|
|
84
|
+
baseId: z
|
|
85
|
+
.string()
|
|
86
|
+
.min(1, 'Base ID is required')
|
|
87
|
+
.describe('Airtable base ID (e.g., appXXXXXXXXXXXXXX)'),
|
|
88
|
+
tableIdOrName: z
|
|
89
|
+
.string()
|
|
90
|
+
.min(1, 'Table ID or name is required')
|
|
91
|
+
.describe('Table ID (e.g., tblXXXXXXXXXXXXXX) or table name'),
|
|
92
|
+
fields: z
|
|
93
|
+
.array(z.string())
|
|
94
|
+
.optional()
|
|
95
|
+
.describe('Array of field names to include in results (returns all fields if not specified)'),
|
|
96
|
+
filterByFormula: z
|
|
97
|
+
.string()
|
|
98
|
+
.optional()
|
|
99
|
+
.describe('Airtable formula to filter records (e.g., "{Status} = \'Done\'")'),
|
|
100
|
+
maxRecords: z
|
|
101
|
+
.number()
|
|
102
|
+
.min(1)
|
|
103
|
+
.max(100)
|
|
104
|
+
.optional()
|
|
105
|
+
.describe('Maximum number of records to return (1-100, returns all if not specified)'),
|
|
106
|
+
pageSize: z
|
|
107
|
+
.number()
|
|
108
|
+
.min(1)
|
|
109
|
+
.max(100)
|
|
110
|
+
.optional()
|
|
111
|
+
.default(100)
|
|
112
|
+
.describe('Number of records per page for pagination (1-100)'),
|
|
113
|
+
sort: z
|
|
114
|
+
.array(SortSpecSchema)
|
|
115
|
+
.optional()
|
|
116
|
+
.describe('Array of sort specifications to order records'),
|
|
117
|
+
view: z
|
|
118
|
+
.string()
|
|
119
|
+
.optional()
|
|
120
|
+
.describe("View name or ID to use (includes view's filters and sorts)"),
|
|
121
|
+
cellFormat: z
|
|
122
|
+
.enum(['json', 'string'])
|
|
123
|
+
.optional()
|
|
124
|
+
.default('json')
|
|
125
|
+
.describe('Format for cell values: json (structured) or string (formatted)'),
|
|
126
|
+
timeZone: z
|
|
127
|
+
.string()
|
|
128
|
+
.optional()
|
|
129
|
+
.describe('Time zone for date/time fields (e.g., "America/Los_Angeles")'),
|
|
130
|
+
userLocale: z
|
|
131
|
+
.string()
|
|
132
|
+
.optional()
|
|
133
|
+
.describe('Locale for formatting (e.g., "en-US")'),
|
|
134
|
+
offset: z
|
|
135
|
+
.string()
|
|
136
|
+
.optional()
|
|
137
|
+
.describe('Pagination offset from previous response'),
|
|
138
|
+
credentials: z
|
|
139
|
+
.record(z.nativeEnum(CredentialType), z.string())
|
|
140
|
+
.optional()
|
|
141
|
+
.describe('Object mapping credential types to values (injected at runtime)'),
|
|
142
|
+
}),
|
|
143
|
+
// Get record operation
|
|
144
|
+
z.object({
|
|
145
|
+
operation: z
|
|
146
|
+
.literal('get_record')
|
|
147
|
+
.describe('Retrieve a single record by its ID'),
|
|
148
|
+
baseId: z
|
|
149
|
+
.string()
|
|
150
|
+
.min(1, 'Base ID is required')
|
|
151
|
+
.describe('Airtable base ID (e.g., appXXXXXXXXXXXXXX)'),
|
|
152
|
+
tableIdOrName: z
|
|
153
|
+
.string()
|
|
154
|
+
.min(1, 'Table ID or name is required')
|
|
155
|
+
.describe('Table ID (e.g., tblXXXXXXXXXXXXXX) or table name'),
|
|
156
|
+
recordId: z
|
|
157
|
+
.string()
|
|
158
|
+
.min(1, 'Record ID is required')
|
|
159
|
+
.describe('Record ID to retrieve (starts with rec)'),
|
|
160
|
+
credentials: z
|
|
161
|
+
.record(z.nativeEnum(CredentialType), z.string())
|
|
162
|
+
.optional()
|
|
163
|
+
.describe('Object mapping credential types to values (injected at runtime)'),
|
|
164
|
+
}),
|
|
165
|
+
// Create records operation
|
|
166
|
+
z.object({
|
|
167
|
+
operation: z
|
|
168
|
+
.literal('create_records')
|
|
169
|
+
.describe('Create one or more new records in an Airtable table'),
|
|
170
|
+
baseId: z
|
|
171
|
+
.string()
|
|
172
|
+
.min(1, 'Base ID is required')
|
|
173
|
+
.describe('Airtable base ID (e.g., appXXXXXXXXXXXXXX)'),
|
|
174
|
+
tableIdOrName: z
|
|
175
|
+
.string()
|
|
176
|
+
.min(1, 'Table ID or name is required')
|
|
177
|
+
.describe('Table ID (e.g., tblXXXXXXXXXXXXXX) or table name'),
|
|
178
|
+
records: z
|
|
179
|
+
.array(z
|
|
180
|
+
.object({
|
|
181
|
+
fields: z
|
|
182
|
+
.record(z.string(), AirtableFieldValueSchema)
|
|
183
|
+
.describe('Field values for the new record'),
|
|
184
|
+
})
|
|
185
|
+
.describe('Record data to create'))
|
|
186
|
+
.min(1, 'At least one record is required')
|
|
187
|
+
.max(10, 'Maximum 10 records can be created at once')
|
|
188
|
+
.describe('Array of records to create (max 10 per request)'),
|
|
189
|
+
typecast: z
|
|
190
|
+
.boolean()
|
|
191
|
+
.optional()
|
|
192
|
+
.default(false)
|
|
193
|
+
.describe('Automatically convert field values to the appropriate type'),
|
|
194
|
+
credentials: z
|
|
195
|
+
.record(z.nativeEnum(CredentialType), z.string())
|
|
196
|
+
.optional()
|
|
197
|
+
.describe('Object mapping credential types to values (injected at runtime)'),
|
|
198
|
+
}),
|
|
199
|
+
// Update records operation
|
|
200
|
+
z.object({
|
|
201
|
+
operation: z
|
|
202
|
+
.literal('update_records')
|
|
203
|
+
.describe('Update existing records in an Airtable table'),
|
|
204
|
+
baseId: z
|
|
205
|
+
.string()
|
|
206
|
+
.min(1, 'Base ID is required')
|
|
207
|
+
.describe('Airtable base ID (e.g., appXXXXXXXXXXXXXX)'),
|
|
208
|
+
tableIdOrName: z
|
|
209
|
+
.string()
|
|
210
|
+
.min(1, 'Table ID or name is required')
|
|
211
|
+
.describe('Table ID (e.g., tblXXXXXXXXXXXXXX) or table name'),
|
|
212
|
+
records: z
|
|
213
|
+
.array(z
|
|
214
|
+
.object({
|
|
215
|
+
id: z
|
|
216
|
+
.string()
|
|
217
|
+
.min(1, 'Record ID is required')
|
|
218
|
+
.describe('Record ID to update (starts with rec)'),
|
|
219
|
+
fields: z
|
|
220
|
+
.record(z.string(), AirtableFieldValueSchema)
|
|
221
|
+
.describe('Field values to update (only specified fields will be updated)'),
|
|
222
|
+
})
|
|
223
|
+
.describe('Record data to update'))
|
|
224
|
+
.min(1, 'At least one record is required')
|
|
225
|
+
.max(10, 'Maximum 10 records can be updated at once')
|
|
226
|
+
.describe('Array of records to update (max 10 per request)'),
|
|
227
|
+
typecast: z
|
|
228
|
+
.boolean()
|
|
229
|
+
.optional()
|
|
230
|
+
.default(false)
|
|
231
|
+
.describe('Automatically convert field values to the appropriate type'),
|
|
232
|
+
credentials: z
|
|
233
|
+
.record(z.nativeEnum(CredentialType), z.string())
|
|
234
|
+
.optional()
|
|
235
|
+
.describe('Object mapping credential types to values (injected at runtime)'),
|
|
236
|
+
}),
|
|
237
|
+
// Delete records operation
|
|
238
|
+
z.object({
|
|
239
|
+
operation: z
|
|
240
|
+
.literal('delete_records')
|
|
241
|
+
.describe('Delete one or more records from an Airtable table'),
|
|
242
|
+
baseId: z
|
|
243
|
+
.string()
|
|
244
|
+
.min(1, 'Base ID is required')
|
|
245
|
+
.describe('Airtable base ID (e.g., appXXXXXXXXXXXXXX)'),
|
|
246
|
+
tableIdOrName: z
|
|
247
|
+
.string()
|
|
248
|
+
.min(1, 'Table ID or name is required')
|
|
249
|
+
.describe('Table ID (e.g., tblXXXXXXXXXXXXXX) or table name'),
|
|
250
|
+
recordIds: z
|
|
251
|
+
.array(z.string())
|
|
252
|
+
.min(1, 'At least one record ID is required')
|
|
253
|
+
.max(10, 'Maximum 10 records can be deleted at once')
|
|
254
|
+
.describe('Array of record IDs to delete (max 10 per request)'),
|
|
255
|
+
credentials: z
|
|
256
|
+
.record(z.nativeEnum(CredentialType), z.string())
|
|
257
|
+
.optional()
|
|
258
|
+
.describe('Object mapping credential types to values (injected at runtime)'),
|
|
259
|
+
}),
|
|
260
|
+
// List bases operation
|
|
261
|
+
z.object({
|
|
262
|
+
operation: z
|
|
263
|
+
.literal('list_bases')
|
|
264
|
+
.describe('List all bases accessible with the current API key'),
|
|
265
|
+
credentials: z
|
|
266
|
+
.record(z.nativeEnum(CredentialType), z.string())
|
|
267
|
+
.optional()
|
|
268
|
+
.describe('Object mapping credential types to values (injected at runtime)'),
|
|
269
|
+
}),
|
|
270
|
+
// Get base schema operation
|
|
271
|
+
z.object({
|
|
272
|
+
operation: z
|
|
273
|
+
.literal('get_base_schema')
|
|
274
|
+
.describe('Get the schema for a specific base including all tables and fields'),
|
|
275
|
+
baseId: z
|
|
276
|
+
.string()
|
|
277
|
+
.min(1, 'Base ID is required')
|
|
278
|
+
.describe('Airtable base ID (e.g., appXXXXXXXXXXXXXX)'),
|
|
279
|
+
credentials: z
|
|
280
|
+
.record(z.nativeEnum(CredentialType), z.string())
|
|
281
|
+
.optional()
|
|
282
|
+
.describe('Object mapping credential types to values (injected at runtime)'),
|
|
283
|
+
}),
|
|
284
|
+
// Create table operation
|
|
285
|
+
z.object({
|
|
286
|
+
operation: z
|
|
287
|
+
.literal('create_table')
|
|
288
|
+
.describe('Create a new table in an Airtable base'),
|
|
289
|
+
baseId: z
|
|
290
|
+
.string()
|
|
291
|
+
.min(1, 'Base ID is required')
|
|
292
|
+
.describe('Airtable base ID (e.g., appXXXXXXXXXXXXXX)'),
|
|
293
|
+
name: z
|
|
294
|
+
.string()
|
|
295
|
+
.min(1, 'Table name is required')
|
|
296
|
+
.describe('Name for the new table'),
|
|
297
|
+
description: z
|
|
298
|
+
.string()
|
|
299
|
+
.optional()
|
|
300
|
+
.describe('Optional description for the table'),
|
|
301
|
+
fields: z
|
|
302
|
+
.array(z.object({
|
|
303
|
+
name: z.string().describe('Field name'),
|
|
304
|
+
type: AirtableFieldTypeEnum.describe('Field type'),
|
|
305
|
+
description: z.string().optional().describe('Field description'),
|
|
306
|
+
options: z.record(z.unknown()).optional().describe('Field options'),
|
|
307
|
+
}))
|
|
308
|
+
.describe('Array of field definitions for the table'),
|
|
309
|
+
credentials: z
|
|
310
|
+
.record(z.nativeEnum(CredentialType), z.string())
|
|
311
|
+
.optional()
|
|
312
|
+
.describe('Object mapping credential types to values (injected at runtime)'),
|
|
313
|
+
}),
|
|
314
|
+
// Update table operation
|
|
315
|
+
z.object({
|
|
316
|
+
operation: z
|
|
317
|
+
.literal('update_table')
|
|
318
|
+
.describe('Update table properties like name and description'),
|
|
319
|
+
baseId: z
|
|
320
|
+
.string()
|
|
321
|
+
.min(1, 'Base ID is required')
|
|
322
|
+
.describe('Airtable base ID (e.g., appXXXXXXXXXXXXXX)'),
|
|
323
|
+
tableIdOrName: z
|
|
324
|
+
.string()
|
|
325
|
+
.min(1, 'Table ID or name is required')
|
|
326
|
+
.describe('Table ID (e.g., tblXXXXXXXXXXXXXX) or table name'),
|
|
327
|
+
name: z.string().optional().describe('New name for the table'),
|
|
328
|
+
description: z
|
|
329
|
+
.string()
|
|
330
|
+
.optional()
|
|
331
|
+
.describe('New description for the table'),
|
|
332
|
+
credentials: z
|
|
333
|
+
.record(z.nativeEnum(CredentialType), z.string())
|
|
334
|
+
.optional()
|
|
335
|
+
.describe('Object mapping credential types to values (injected at runtime)'),
|
|
336
|
+
}),
|
|
337
|
+
// Create field operation
|
|
338
|
+
z.object({
|
|
339
|
+
operation: z
|
|
340
|
+
.literal('create_field')
|
|
341
|
+
.describe('Create a new field in an Airtable table'),
|
|
342
|
+
baseId: z
|
|
343
|
+
.string()
|
|
344
|
+
.min(1, 'Base ID is required')
|
|
345
|
+
.describe('Airtable base ID (e.g., appXXXXXXXXXXXXXX)'),
|
|
346
|
+
tableIdOrName: z
|
|
347
|
+
.string()
|
|
348
|
+
.min(1, 'Table ID or name is required')
|
|
349
|
+
.describe('Table ID (e.g., tblXXXXXXXXXXXXXX) or table name'),
|
|
350
|
+
name: z
|
|
351
|
+
.string()
|
|
352
|
+
.min(1, 'Field name is required')
|
|
353
|
+
.describe('Name for the new field'),
|
|
354
|
+
type: AirtableFieldTypeEnum.describe('Field type'),
|
|
355
|
+
description: z.string().optional().describe('Field description'),
|
|
356
|
+
options: z
|
|
357
|
+
.record(z.unknown())
|
|
358
|
+
.optional()
|
|
359
|
+
.describe('Field-specific options'),
|
|
360
|
+
credentials: z
|
|
361
|
+
.record(z.nativeEnum(CredentialType), z.string())
|
|
362
|
+
.optional()
|
|
363
|
+
.describe('Object mapping credential types to values (injected at runtime)'),
|
|
364
|
+
}),
|
|
365
|
+
// Update field operation
|
|
366
|
+
z.object({
|
|
367
|
+
operation: z
|
|
368
|
+
.literal('update_field')
|
|
369
|
+
.describe('Update field properties like name, type, or description'),
|
|
370
|
+
baseId: z
|
|
371
|
+
.string()
|
|
372
|
+
.min(1, 'Base ID is required')
|
|
373
|
+
.describe('Airtable base ID (e.g., appXXXXXXXXXXXXXX)'),
|
|
374
|
+
tableIdOrName: z
|
|
375
|
+
.string()
|
|
376
|
+
.min(1, 'Table ID or name is required')
|
|
377
|
+
.describe('Table ID (e.g., tblXXXXXXXXXXXXXX) or table name'),
|
|
378
|
+
fieldIdOrName: z
|
|
379
|
+
.string()
|
|
380
|
+
.min(1, 'Field ID or name is required')
|
|
381
|
+
.describe('Field ID (e.g., fldXXXXXXXXXXXXXX) or field name'),
|
|
382
|
+
name: z.string().optional().describe('New name for the field'),
|
|
383
|
+
description: z
|
|
384
|
+
.string()
|
|
385
|
+
.optional()
|
|
386
|
+
.describe('New description for the field'),
|
|
387
|
+
credentials: z
|
|
388
|
+
.record(z.nativeEnum(CredentialType), z.string())
|
|
389
|
+
.optional()
|
|
390
|
+
.describe('Object mapping credential types to values (injected at runtime)'),
|
|
391
|
+
}),
|
|
392
|
+
]);
|
|
393
|
+
// Define result schemas for different operations
|
|
394
|
+
const AirtableResultSchema = z.discriminatedUnion('operation', [
|
|
395
|
+
z.object({
|
|
396
|
+
operation: z
|
|
397
|
+
.literal('list_records')
|
|
398
|
+
.describe('List records from an Airtable table with filtering and sorting'),
|
|
399
|
+
ok: z.boolean().describe('Whether the Airtable API call was successful'),
|
|
400
|
+
records: z
|
|
401
|
+
.array(AirtableRecordSchema)
|
|
402
|
+
.optional()
|
|
403
|
+
.describe('Array of record objects'),
|
|
404
|
+
offset: z
|
|
405
|
+
.string()
|
|
406
|
+
.optional()
|
|
407
|
+
.describe('Pagination offset for retrieving next page of results'),
|
|
408
|
+
error: z.string().default('').describe('Error message if operation failed'),
|
|
409
|
+
success: z.boolean().describe('Whether the operation was successful'),
|
|
410
|
+
}),
|
|
411
|
+
z.object({
|
|
412
|
+
operation: z
|
|
413
|
+
.literal('get_record')
|
|
414
|
+
.describe('Retrieve a single record by its ID'),
|
|
415
|
+
ok: z.boolean().describe('Whether the Airtable API call was successful'),
|
|
416
|
+
record: AirtableRecordSchema.optional().describe('Record object'),
|
|
417
|
+
error: z.string().default('').describe('Error message if operation failed'),
|
|
418
|
+
success: z.boolean().describe('Whether the operation was successful'),
|
|
419
|
+
}),
|
|
420
|
+
z.object({
|
|
421
|
+
operation: z
|
|
422
|
+
.literal('create_records')
|
|
423
|
+
.describe('Create one or more new records in an Airtable table'),
|
|
424
|
+
ok: z.boolean().describe('Whether the Airtable API call was successful'),
|
|
425
|
+
records: z
|
|
426
|
+
.array(AirtableRecordSchema)
|
|
427
|
+
.optional()
|
|
428
|
+
.describe('Array of created record objects'),
|
|
429
|
+
error: z.string().default('').describe('Error message if operation failed'),
|
|
430
|
+
success: z.boolean().describe('Whether the operation was successful'),
|
|
431
|
+
}),
|
|
432
|
+
z.object({
|
|
433
|
+
operation: z
|
|
434
|
+
.literal('update_records')
|
|
435
|
+
.describe('Update existing records in an Airtable table'),
|
|
436
|
+
ok: z.boolean().describe('Whether the Airtable API call was successful'),
|
|
437
|
+
records: z
|
|
438
|
+
.array(AirtableRecordSchema)
|
|
439
|
+
.optional()
|
|
440
|
+
.describe('Array of updated record objects'),
|
|
441
|
+
error: z.string().default('').describe('Error message if operation failed'),
|
|
442
|
+
success: z.boolean().describe('Whether the operation was successful'),
|
|
443
|
+
}),
|
|
444
|
+
z.object({
|
|
445
|
+
operation: z
|
|
446
|
+
.literal('delete_records')
|
|
447
|
+
.describe('Delete one or more records from an Airtable table'),
|
|
448
|
+
ok: z.boolean().describe('Whether the Airtable API call was successful'),
|
|
449
|
+
records: z
|
|
450
|
+
.array(z
|
|
451
|
+
.object({
|
|
452
|
+
id: z.string().describe('ID of deleted record'),
|
|
453
|
+
deleted: z.boolean().describe('Whether the record was deleted'),
|
|
454
|
+
})
|
|
455
|
+
.describe('Deletion confirmation object'))
|
|
456
|
+
.optional()
|
|
457
|
+
.describe('Array of deletion confirmation objects'),
|
|
458
|
+
error: z.string().default('').describe('Error message if operation failed'),
|
|
459
|
+
success: z.boolean().describe('Whether the operation was successful'),
|
|
460
|
+
}),
|
|
461
|
+
// List bases result
|
|
462
|
+
z.object({
|
|
463
|
+
operation: z
|
|
464
|
+
.literal('list_bases')
|
|
465
|
+
.describe('List all bases accessible with the current API key'),
|
|
466
|
+
ok: z.boolean().describe('Whether the Airtable API call was successful'),
|
|
467
|
+
bases: z
|
|
468
|
+
.array(z.object({
|
|
469
|
+
id: z.string().describe('Base ID'),
|
|
470
|
+
name: z.string().describe('Base name'),
|
|
471
|
+
permissionLevel: z
|
|
472
|
+
.string()
|
|
473
|
+
.describe('Permission level for this base'),
|
|
474
|
+
}))
|
|
475
|
+
.optional()
|
|
476
|
+
.describe('Array of base objects'),
|
|
477
|
+
error: z.string().default('').describe('Error message if operation failed'),
|
|
478
|
+
success: z.boolean().describe('Whether the operation was successful'),
|
|
479
|
+
}),
|
|
480
|
+
// Get base schema result
|
|
481
|
+
z.object({
|
|
482
|
+
operation: z
|
|
483
|
+
.literal('get_base_schema')
|
|
484
|
+
.describe('Get the schema for a specific base including all tables and fields'),
|
|
485
|
+
ok: z.boolean().describe('Whether the Airtable API call was successful'),
|
|
486
|
+
tables: z
|
|
487
|
+
.array(z.object({
|
|
488
|
+
id: z.string().describe('Table ID'),
|
|
489
|
+
name: z.string().describe('Table name'),
|
|
490
|
+
description: z.string().optional().describe('Table description'),
|
|
491
|
+
primaryFieldId: z.string().describe('ID of the primary field'),
|
|
492
|
+
fields: z
|
|
493
|
+
.array(z.object({
|
|
494
|
+
id: z.string().describe('Field ID'),
|
|
495
|
+
name: z.string().describe('Field name'),
|
|
496
|
+
type: z.string().describe('Field type'),
|
|
497
|
+
description: z
|
|
498
|
+
.string()
|
|
499
|
+
.optional()
|
|
500
|
+
.describe('Field description'),
|
|
501
|
+
options: z
|
|
502
|
+
.record(z.unknown())
|
|
503
|
+
.optional()
|
|
504
|
+
.describe('Field options'),
|
|
505
|
+
}))
|
|
506
|
+
.describe('Array of field definitions'),
|
|
507
|
+
views: z
|
|
508
|
+
.array(z.object({
|
|
509
|
+
id: z.string().describe('View ID'),
|
|
510
|
+
name: z.string().describe('View name'),
|
|
511
|
+
type: z.string().describe('View type'),
|
|
512
|
+
}))
|
|
513
|
+
.optional()
|
|
514
|
+
.describe('Array of view definitions'),
|
|
515
|
+
}))
|
|
516
|
+
.optional()
|
|
517
|
+
.describe('Array of table schemas'),
|
|
518
|
+
error: z.string().default('').describe('Error message if operation failed'),
|
|
519
|
+
success: z.boolean().describe('Whether the operation was successful'),
|
|
520
|
+
}),
|
|
521
|
+
// Create table result
|
|
522
|
+
z.object({
|
|
523
|
+
operation: z
|
|
524
|
+
.literal('create_table')
|
|
525
|
+
.describe('Create a new table in an Airtable base'),
|
|
526
|
+
ok: z.boolean().describe('Whether the Airtable API call was successful'),
|
|
527
|
+
table: z
|
|
528
|
+
.object({
|
|
529
|
+
id: z.string().describe('Table ID'),
|
|
530
|
+
name: z.string().describe('Table name'),
|
|
531
|
+
description: z.string().optional().describe('Table description'),
|
|
532
|
+
primaryFieldId: z.string().describe('ID of the primary field'),
|
|
533
|
+
fields: z
|
|
534
|
+
.array(z.object({
|
|
535
|
+
id: z.string().describe('Field ID'),
|
|
536
|
+
name: z.string().describe('Field name'),
|
|
537
|
+
type: AirtableFieldTypeEnum.describe('Field type'),
|
|
538
|
+
}))
|
|
539
|
+
.describe('Array of field definitions'),
|
|
540
|
+
})
|
|
541
|
+
.optional()
|
|
542
|
+
.describe('Created table object'),
|
|
543
|
+
error: z.string().default('').describe('Error message if operation failed'),
|
|
544
|
+
success: z.boolean().describe('Whether the operation was successful'),
|
|
545
|
+
}),
|
|
546
|
+
// Update table result
|
|
547
|
+
z.object({
|
|
548
|
+
operation: z
|
|
549
|
+
.literal('update_table')
|
|
550
|
+
.describe('Update table properties like name and description'),
|
|
551
|
+
ok: z.boolean().describe('Whether the Airtable API call was successful'),
|
|
552
|
+
table: z
|
|
553
|
+
.object({
|
|
554
|
+
id: z.string().describe('Table ID'),
|
|
555
|
+
name: z.string().describe('Table name'),
|
|
556
|
+
description: z.string().optional().describe('Table description'),
|
|
557
|
+
})
|
|
558
|
+
.optional()
|
|
559
|
+
.describe('Updated table object'),
|
|
560
|
+
error: z.string().default('').describe('Error message if operation failed'),
|
|
561
|
+
success: z.boolean().describe('Whether the operation was successful'),
|
|
562
|
+
}),
|
|
563
|
+
// Create field result
|
|
564
|
+
z.object({
|
|
565
|
+
operation: z
|
|
566
|
+
.literal('create_field')
|
|
567
|
+
.describe('Create a new field in an Airtable table'),
|
|
568
|
+
ok: z.boolean().describe('Whether the Airtable API call was successful'),
|
|
569
|
+
field: z
|
|
570
|
+
.object({
|
|
571
|
+
id: z.string().describe('Field ID'),
|
|
572
|
+
name: z.string().describe('Field name'),
|
|
573
|
+
type: z.string().describe('Field type'),
|
|
574
|
+
description: z.string().optional().describe('Field description'),
|
|
575
|
+
})
|
|
576
|
+
.optional()
|
|
577
|
+
.describe('Created field object'),
|
|
578
|
+
error: z.string().default('').describe('Error message if operation failed'),
|
|
579
|
+
success: z.boolean().describe('Whether the operation was successful'),
|
|
580
|
+
}),
|
|
581
|
+
// Update field result
|
|
582
|
+
z.object({
|
|
583
|
+
operation: z
|
|
584
|
+
.literal('update_field')
|
|
585
|
+
.describe('Update field properties like name, type, or description'),
|
|
586
|
+
ok: z.boolean().describe('Whether the Airtable API call was successful'),
|
|
587
|
+
field: z
|
|
588
|
+
.object({
|
|
589
|
+
id: z.string().describe('Field ID'),
|
|
590
|
+
name: z.string().describe('Field name'),
|
|
591
|
+
type: z.string().describe('Field type'),
|
|
592
|
+
description: z.string().optional().describe('Field description'),
|
|
593
|
+
})
|
|
594
|
+
.optional()
|
|
595
|
+
.describe('Updated field object'),
|
|
596
|
+
error: z.string().default('').describe('Error message if operation failed'),
|
|
597
|
+
success: z.boolean().describe('Whether the operation was successful'),
|
|
598
|
+
}),
|
|
599
|
+
]);
|
|
600
|
+
export class AirtableBubble extends ServiceBubble {
|
|
601
|
+
async testCredential() {
|
|
602
|
+
// Test credential by checking the Authorization header format
|
|
603
|
+
// Note: We cannot test actual API access without knowing which base/table the user wants to access
|
|
604
|
+
// and what scopes their PAT has. Airtable PATs can have varying scopes and base restrictions.
|
|
605
|
+
//
|
|
606
|
+
// The best we can do is verify the token format is valid.
|
|
607
|
+
// Actual access will be validated when the user makes their first API call.
|
|
608
|
+
try {
|
|
609
|
+
const credential = this.chooseCredential();
|
|
610
|
+
if (!credential) {
|
|
611
|
+
return false;
|
|
612
|
+
}
|
|
613
|
+
// Verify the token format looks like an Airtable PAT
|
|
614
|
+
// Format: patXXXXXXXXXX.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
|
615
|
+
if (!credential.startsWith('pat') || credential.length < 50) {
|
|
616
|
+
return false;
|
|
617
|
+
}
|
|
618
|
+
return true;
|
|
619
|
+
}
|
|
620
|
+
catch {
|
|
621
|
+
return false;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
static type = 'service';
|
|
625
|
+
static service = 'airtable';
|
|
626
|
+
static authType = 'apikey';
|
|
627
|
+
static bubbleName = 'airtable';
|
|
628
|
+
static schema = AirtableParamsSchema;
|
|
629
|
+
static resultSchema = AirtableResultSchema;
|
|
630
|
+
static shortDescription = 'Airtable integration for managing records in bases and tables';
|
|
631
|
+
static longDescription = `
|
|
632
|
+
Comprehensive Airtable integration bubble for managing bases, tables, fields, and records.
|
|
633
|
+
Use cases:
|
|
634
|
+
- List records with filtering, sorting, and pagination
|
|
635
|
+
- Retrieve individual records by ID
|
|
636
|
+
- Create, update, and delete records
|
|
637
|
+
- List all accessible bases
|
|
638
|
+
- Get base schema with all tables and fields
|
|
639
|
+
- Create and update tables
|
|
640
|
+
- Create and update fields
|
|
641
|
+
- Support for all Airtable field types (text, number, attachments, links, etc.)
|
|
642
|
+
|
|
643
|
+
Security Features:
|
|
644
|
+
- Personal Access Token authentication
|
|
645
|
+
- Parameter validation and sanitization
|
|
646
|
+
- Rate limiting awareness (5 requests per second per base)
|
|
647
|
+
- Comprehensive error handling
|
|
648
|
+
`;
|
|
649
|
+
static alias = 'airtable';
|
|
650
|
+
constructor(params = {
|
|
651
|
+
operation: 'list_records',
|
|
652
|
+
baseId: '',
|
|
653
|
+
tableIdOrName: '',
|
|
654
|
+
}, context, instanceId) {
|
|
655
|
+
super(params, context, instanceId);
|
|
656
|
+
}
|
|
657
|
+
async performAction(context) {
|
|
658
|
+
void context;
|
|
659
|
+
const { operation } = this.params;
|
|
660
|
+
try {
|
|
661
|
+
const result = await (async () => {
|
|
662
|
+
switch (operation) {
|
|
663
|
+
case 'list_records':
|
|
664
|
+
return await this.listRecords(this.params);
|
|
665
|
+
case 'get_record':
|
|
666
|
+
return await this.getRecord(this.params);
|
|
667
|
+
case 'create_records':
|
|
668
|
+
return await this.createRecords(this.params);
|
|
669
|
+
case 'update_records':
|
|
670
|
+
return await this.updateRecords(this.params);
|
|
671
|
+
case 'delete_records':
|
|
672
|
+
return await this.deleteRecords(this.params);
|
|
673
|
+
case 'list_bases':
|
|
674
|
+
return await this.listBases(this.params);
|
|
675
|
+
case 'get_base_schema':
|
|
676
|
+
return await this.getBaseSchema(this.params);
|
|
677
|
+
case 'create_table':
|
|
678
|
+
return await this.createTable(this.params);
|
|
679
|
+
case 'update_table':
|
|
680
|
+
return await this.updateTable(this.params);
|
|
681
|
+
case 'create_field':
|
|
682
|
+
return await this.createField(this.params);
|
|
683
|
+
case 'update_field':
|
|
684
|
+
return await this.updateField(this.params);
|
|
685
|
+
default:
|
|
686
|
+
throw new Error(`Unsupported operation: ${operation}`);
|
|
687
|
+
}
|
|
688
|
+
})();
|
|
689
|
+
return result;
|
|
690
|
+
}
|
|
691
|
+
catch (error) {
|
|
692
|
+
const failedOperation = this.params.operation;
|
|
693
|
+
return {
|
|
694
|
+
success: false,
|
|
695
|
+
ok: false,
|
|
696
|
+
operation: failedOperation,
|
|
697
|
+
error: error instanceof Error
|
|
698
|
+
? error.message
|
|
699
|
+
: 'Unknown error occurred in AirtableBubble',
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
async listRecords(params) {
|
|
704
|
+
// Parse params to apply defaults
|
|
705
|
+
const parsed = AirtableParamsSchema.parse(params);
|
|
706
|
+
const { baseId, tableIdOrName, fields, filterByFormula, maxRecords, pageSize, sort, view, cellFormat, timeZone, userLocale, offset, } = parsed;
|
|
707
|
+
const queryParams = new URLSearchParams();
|
|
708
|
+
if (fields && fields.length > 0) {
|
|
709
|
+
fields.forEach((field) => queryParams.append('fields[]', field));
|
|
710
|
+
}
|
|
711
|
+
if (filterByFormula)
|
|
712
|
+
queryParams.append('filterByFormula', filterByFormula);
|
|
713
|
+
if (maxRecords)
|
|
714
|
+
queryParams.append('maxRecords', maxRecords.toString());
|
|
715
|
+
if (pageSize)
|
|
716
|
+
queryParams.append('pageSize', pageSize.toString());
|
|
717
|
+
if (sort && sort.length > 0) {
|
|
718
|
+
sort.forEach((s, index) => {
|
|
719
|
+
queryParams.append(`sort[${index}][field]`, s.field);
|
|
720
|
+
queryParams.append(`sort[${index}][direction]`, s.direction);
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
if (view)
|
|
724
|
+
queryParams.append('view', view);
|
|
725
|
+
if (cellFormat)
|
|
726
|
+
queryParams.append('cellFormat', cellFormat);
|
|
727
|
+
if (timeZone)
|
|
728
|
+
queryParams.append('timeZone', timeZone);
|
|
729
|
+
if (userLocale)
|
|
730
|
+
queryParams.append('userLocale', userLocale);
|
|
731
|
+
if (offset)
|
|
732
|
+
queryParams.append('offset', offset);
|
|
733
|
+
const response = await this.makeAirtableApiCall(`${baseId}/${encodeURIComponent(tableIdOrName)}?${queryParams.toString()}`, 'GET');
|
|
734
|
+
if ('error' in response) {
|
|
735
|
+
return {
|
|
736
|
+
operation: 'list_records',
|
|
737
|
+
ok: false,
|
|
738
|
+
error: this.formatAirtableError(response),
|
|
739
|
+
success: false,
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
return {
|
|
743
|
+
operation: 'list_records',
|
|
744
|
+
ok: true,
|
|
745
|
+
records: response.records
|
|
746
|
+
? z.array(AirtableRecordSchema).parse(response.records)
|
|
747
|
+
: undefined,
|
|
748
|
+
offset: response.offset,
|
|
749
|
+
error: '',
|
|
750
|
+
success: true,
|
|
751
|
+
};
|
|
752
|
+
}
|
|
753
|
+
async getRecord(params) {
|
|
754
|
+
const { baseId, tableIdOrName, recordId } = params;
|
|
755
|
+
const response = await this.makeAirtableApiCall(`${baseId}/${encodeURIComponent(tableIdOrName)}/${recordId}`, 'GET');
|
|
756
|
+
if ('error' in response) {
|
|
757
|
+
return {
|
|
758
|
+
operation: 'get_record',
|
|
759
|
+
ok: false,
|
|
760
|
+
error: this.formatAirtableError(response),
|
|
761
|
+
success: false,
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
return {
|
|
765
|
+
operation: 'get_record',
|
|
766
|
+
ok: true,
|
|
767
|
+
record: AirtableRecordSchema.parse(response),
|
|
768
|
+
error: '',
|
|
769
|
+
success: true,
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
async createRecords(params) {
|
|
773
|
+
// Parse params to apply defaults
|
|
774
|
+
const parsed = AirtableParamsSchema.parse(params);
|
|
775
|
+
const { baseId, tableIdOrName, records, typecast } = parsed;
|
|
776
|
+
const body = {
|
|
777
|
+
records,
|
|
778
|
+
typecast,
|
|
779
|
+
};
|
|
780
|
+
const response = await this.makeAirtableApiCall(`${baseId}/${encodeURIComponent(tableIdOrName)}`, 'POST', body);
|
|
781
|
+
if ('error' in response) {
|
|
782
|
+
return {
|
|
783
|
+
operation: 'create_records',
|
|
784
|
+
ok: false,
|
|
785
|
+
error: this.formatAirtableError(response),
|
|
786
|
+
success: false,
|
|
787
|
+
};
|
|
788
|
+
}
|
|
789
|
+
return {
|
|
790
|
+
operation: 'create_records',
|
|
791
|
+
ok: true,
|
|
792
|
+
records: response.records
|
|
793
|
+
? z.array(AirtableRecordSchema).parse(response.records)
|
|
794
|
+
: undefined,
|
|
795
|
+
error: '',
|
|
796
|
+
success: true,
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
async updateRecords(params) {
|
|
800
|
+
// Parse params to apply defaults
|
|
801
|
+
const parsed = AirtableParamsSchema.parse(params);
|
|
802
|
+
const { baseId, tableIdOrName, records, typecast } = parsed;
|
|
803
|
+
const body = {
|
|
804
|
+
records,
|
|
805
|
+
typecast,
|
|
806
|
+
};
|
|
807
|
+
const response = await this.makeAirtableApiCall(`${baseId}/${encodeURIComponent(tableIdOrName)}`, 'PATCH', body);
|
|
808
|
+
if ('error' in response) {
|
|
809
|
+
return {
|
|
810
|
+
operation: 'update_records',
|
|
811
|
+
ok: false,
|
|
812
|
+
error: this.formatAirtableError(response),
|
|
813
|
+
success: false,
|
|
814
|
+
};
|
|
815
|
+
}
|
|
816
|
+
return {
|
|
817
|
+
operation: 'update_records',
|
|
818
|
+
ok: true,
|
|
819
|
+
records: response.records
|
|
820
|
+
? z.array(AirtableRecordSchema).parse(response.records)
|
|
821
|
+
: undefined,
|
|
822
|
+
error: '',
|
|
823
|
+
success: true,
|
|
824
|
+
};
|
|
825
|
+
}
|
|
826
|
+
async deleteRecords(params) {
|
|
827
|
+
const { baseId, tableIdOrName, recordIds } = params;
|
|
828
|
+
// Airtable expects record IDs as query parameters for DELETE
|
|
829
|
+
const queryParams = new URLSearchParams();
|
|
830
|
+
recordIds.forEach((id) => queryParams.append('records[]', id));
|
|
831
|
+
const response = await this.makeAirtableApiCall(`${baseId}/${encodeURIComponent(tableIdOrName)}?${queryParams.toString()}`, 'DELETE');
|
|
832
|
+
if ('error' in response) {
|
|
833
|
+
return {
|
|
834
|
+
operation: 'delete_records',
|
|
835
|
+
ok: false,
|
|
836
|
+
error: this.formatAirtableError(response),
|
|
837
|
+
success: false,
|
|
838
|
+
};
|
|
839
|
+
}
|
|
840
|
+
// For delete, response.records has a different structure
|
|
841
|
+
const deleteRecords = response.records;
|
|
842
|
+
return {
|
|
843
|
+
operation: 'delete_records',
|
|
844
|
+
ok: true,
|
|
845
|
+
records: deleteRecords,
|
|
846
|
+
error: '',
|
|
847
|
+
success: true,
|
|
848
|
+
};
|
|
849
|
+
}
|
|
850
|
+
async listBases(params) {
|
|
851
|
+
void params;
|
|
852
|
+
const response = await this.makeAirtableApiCall('meta/bases', 'GET');
|
|
853
|
+
if ('error' in response) {
|
|
854
|
+
return {
|
|
855
|
+
operation: 'list_bases',
|
|
856
|
+
ok: false,
|
|
857
|
+
error: this.formatAirtableError(response),
|
|
858
|
+
success: false,
|
|
859
|
+
};
|
|
860
|
+
}
|
|
861
|
+
return {
|
|
862
|
+
operation: 'list_bases',
|
|
863
|
+
ok: true,
|
|
864
|
+
bases: response.bases,
|
|
865
|
+
error: '',
|
|
866
|
+
success: true,
|
|
867
|
+
};
|
|
868
|
+
}
|
|
869
|
+
async getBaseSchema(params) {
|
|
870
|
+
const { baseId } = params;
|
|
871
|
+
const response = await this.makeAirtableApiCall(`meta/bases/${baseId}/tables`, 'GET');
|
|
872
|
+
if ('error' in response) {
|
|
873
|
+
return {
|
|
874
|
+
operation: 'get_base_schema',
|
|
875
|
+
ok: false,
|
|
876
|
+
error: this.formatAirtableError(response),
|
|
877
|
+
success: false,
|
|
878
|
+
};
|
|
879
|
+
}
|
|
880
|
+
return {
|
|
881
|
+
operation: 'get_base_schema',
|
|
882
|
+
ok: true,
|
|
883
|
+
tables: response.tables,
|
|
884
|
+
error: '',
|
|
885
|
+
success: true,
|
|
886
|
+
};
|
|
887
|
+
}
|
|
888
|
+
/**
|
|
889
|
+
* Normalizes field definitions by adding required default options for field types that need them.
|
|
890
|
+
* This provides a better UX by auto-fixing common configuration issues.
|
|
891
|
+
*/
|
|
892
|
+
normalizeFieldOptions(fields) {
|
|
893
|
+
const typeRequiresOptions = new Set([
|
|
894
|
+
'multipleRecordLinks',
|
|
895
|
+
'lookup',
|
|
896
|
+
'rollup',
|
|
897
|
+
'count',
|
|
898
|
+
'button',
|
|
899
|
+
'externalSyncSource',
|
|
900
|
+
'formula',
|
|
901
|
+
]);
|
|
902
|
+
return fields.map((field) => {
|
|
903
|
+
const normalizedField = { ...field };
|
|
904
|
+
// Add default options for field types that require them
|
|
905
|
+
switch (field.type) {
|
|
906
|
+
case 'date':
|
|
907
|
+
// Date fields require a dateFormat option
|
|
908
|
+
if (!field.options || Object.keys(field.options).length === 0) {
|
|
909
|
+
normalizedField.options = {
|
|
910
|
+
dateFormat: {
|
|
911
|
+
name: 'local',
|
|
912
|
+
format: 'l',
|
|
913
|
+
},
|
|
914
|
+
};
|
|
915
|
+
}
|
|
916
|
+
break;
|
|
917
|
+
case 'dateTime':
|
|
918
|
+
// DateTime fields require dateFormat, timeFormat, and timeZone
|
|
919
|
+
if (!field.options || Object.keys(field.options).length === 0) {
|
|
920
|
+
normalizedField.options = {
|
|
921
|
+
dateFormat: {
|
|
922
|
+
name: 'local',
|
|
923
|
+
format: 'l',
|
|
924
|
+
},
|
|
925
|
+
timeFormat: {
|
|
926
|
+
name: '12hour',
|
|
927
|
+
format: 'h:mma',
|
|
928
|
+
},
|
|
929
|
+
timeZone: 'utc',
|
|
930
|
+
};
|
|
931
|
+
}
|
|
932
|
+
break;
|
|
933
|
+
case 'number':
|
|
934
|
+
// Number fields should have precision
|
|
935
|
+
if (!field.options || !('precision' in field.options)) {
|
|
936
|
+
normalizedField.options = {
|
|
937
|
+
...field.options,
|
|
938
|
+
precision: 0,
|
|
939
|
+
};
|
|
940
|
+
}
|
|
941
|
+
break;
|
|
942
|
+
case 'currency':
|
|
943
|
+
// Currency fields need precision and symbol
|
|
944
|
+
if (!field.options || !('precision' in field.options)) {
|
|
945
|
+
normalizedField.options = {
|
|
946
|
+
...field.options,
|
|
947
|
+
precision: 2,
|
|
948
|
+
symbol: '$',
|
|
949
|
+
};
|
|
950
|
+
}
|
|
951
|
+
break;
|
|
952
|
+
case 'percent':
|
|
953
|
+
// Percent fields need precision
|
|
954
|
+
if (!field.options || !('precision' in field.options)) {
|
|
955
|
+
normalizedField.options = {
|
|
956
|
+
...field.options,
|
|
957
|
+
precision: 0,
|
|
958
|
+
};
|
|
959
|
+
}
|
|
960
|
+
break;
|
|
961
|
+
case 'rating':
|
|
962
|
+
// Rating fields need max, icon, and color
|
|
963
|
+
if (!field.options || !('max' in field.options)) {
|
|
964
|
+
normalizedField.options = {
|
|
965
|
+
...field.options,
|
|
966
|
+
max: 5,
|
|
967
|
+
icon: 'star',
|
|
968
|
+
color: 'yellowBright',
|
|
969
|
+
};
|
|
970
|
+
}
|
|
971
|
+
break;
|
|
972
|
+
case 'duration':
|
|
973
|
+
// Duration fields need durationFormat
|
|
974
|
+
if (!field.options || !('durationFormat' in field.options)) {
|
|
975
|
+
normalizedField.options = {
|
|
976
|
+
...field.options,
|
|
977
|
+
durationFormat: 'h:mm',
|
|
978
|
+
};
|
|
979
|
+
}
|
|
980
|
+
break;
|
|
981
|
+
case 'checkbox':
|
|
982
|
+
// Checkbox fields support icon/color options; provide sensible defaults
|
|
983
|
+
if (!field.options || Object.keys(field.options).length === 0) {
|
|
984
|
+
normalizedField.options = {
|
|
985
|
+
icon: 'check',
|
|
986
|
+
color: 'greenBright',
|
|
987
|
+
};
|
|
988
|
+
}
|
|
989
|
+
break;
|
|
990
|
+
case 'singleSelect':
|
|
991
|
+
case 'multipleSelects':
|
|
992
|
+
// Select fields require an options object with choices.
|
|
993
|
+
// Provide an empty choices array if none are supplied so Airtable's schema validation passes.
|
|
994
|
+
if (!field.options ||
|
|
995
|
+
typeof field.options !== 'object' ||
|
|
996
|
+
!('choices' in field.options)) {
|
|
997
|
+
normalizedField.options = {
|
|
998
|
+
...field.options,
|
|
999
|
+
choices: [],
|
|
1000
|
+
};
|
|
1001
|
+
}
|
|
1002
|
+
break;
|
|
1003
|
+
// singleSelect and multipleSelects MUST have choices - don't auto-fix these
|
|
1004
|
+
// as we can't guess what the choices should be. Let it fail with Airtable's error.
|
|
1005
|
+
}
|
|
1006
|
+
if (typeRequiresOptions.has(field.type) &&
|
|
1007
|
+
(!normalizedField.options ||
|
|
1008
|
+
(typeof normalizedField.options === 'object' &&
|
|
1009
|
+
Object.keys(normalizedField.options).length === 0))) {
|
|
1010
|
+
throw new Error(`Airtable field "${field.name}" of type "${field.type}" requires an options object`);
|
|
1011
|
+
}
|
|
1012
|
+
return normalizedField;
|
|
1013
|
+
});
|
|
1014
|
+
}
|
|
1015
|
+
async createTable(params) {
|
|
1016
|
+
const { baseId, name, description, fields } = params;
|
|
1017
|
+
// Normalize field options to add sensible defaults where needed
|
|
1018
|
+
const normalizedFields = this.normalizeFieldOptions(fields);
|
|
1019
|
+
const body = {
|
|
1020
|
+
name,
|
|
1021
|
+
fields: normalizedFields,
|
|
1022
|
+
};
|
|
1023
|
+
if (description) {
|
|
1024
|
+
body.description = description;
|
|
1025
|
+
}
|
|
1026
|
+
const response = await this.makeAirtableApiCall(`meta/bases/${baseId}/tables`, 'POST', body);
|
|
1027
|
+
console.log('response', response);
|
|
1028
|
+
if ('error' in response) {
|
|
1029
|
+
return {
|
|
1030
|
+
operation: 'create_table',
|
|
1031
|
+
ok: false,
|
|
1032
|
+
error: this.formatAirtableError(response),
|
|
1033
|
+
success: false,
|
|
1034
|
+
};
|
|
1035
|
+
}
|
|
1036
|
+
return {
|
|
1037
|
+
operation: 'create_table',
|
|
1038
|
+
ok: true,
|
|
1039
|
+
table: response,
|
|
1040
|
+
error: '',
|
|
1041
|
+
success: true,
|
|
1042
|
+
};
|
|
1043
|
+
}
|
|
1044
|
+
async updateTable(params) {
|
|
1045
|
+
const { baseId, tableIdOrName, name, description } = params;
|
|
1046
|
+
const body = {};
|
|
1047
|
+
if (name) {
|
|
1048
|
+
body.name = name;
|
|
1049
|
+
}
|
|
1050
|
+
if (description !== undefined) {
|
|
1051
|
+
body.description = description;
|
|
1052
|
+
}
|
|
1053
|
+
const response = await this.makeAirtableApiCall(`meta/bases/${baseId}/tables/${encodeURIComponent(tableIdOrName)}`, 'PATCH', body);
|
|
1054
|
+
if ('error' in response) {
|
|
1055
|
+
return {
|
|
1056
|
+
operation: 'update_table',
|
|
1057
|
+
ok: false,
|
|
1058
|
+
error: this.formatAirtableError(response),
|
|
1059
|
+
success: false,
|
|
1060
|
+
};
|
|
1061
|
+
}
|
|
1062
|
+
return {
|
|
1063
|
+
operation: 'update_table',
|
|
1064
|
+
ok: true,
|
|
1065
|
+
table: response,
|
|
1066
|
+
error: '',
|
|
1067
|
+
success: true,
|
|
1068
|
+
};
|
|
1069
|
+
}
|
|
1070
|
+
async createField(params) {
|
|
1071
|
+
const { baseId, tableIdOrName, name, type, description, options } = params;
|
|
1072
|
+
// Normalize the field to add default options if needed
|
|
1073
|
+
const normalizedField = this.normalizeFieldOptions([
|
|
1074
|
+
{ name, type, description, options },
|
|
1075
|
+
])[0];
|
|
1076
|
+
const body = {
|
|
1077
|
+
name: normalizedField.name,
|
|
1078
|
+
type: normalizedField.type,
|
|
1079
|
+
};
|
|
1080
|
+
if (normalizedField.description) {
|
|
1081
|
+
body.description = normalizedField.description;
|
|
1082
|
+
}
|
|
1083
|
+
if (normalizedField.options) {
|
|
1084
|
+
body.options = normalizedField.options;
|
|
1085
|
+
}
|
|
1086
|
+
const response = await this.makeAirtableApiCall(`meta/bases/${baseId}/tables/${encodeURIComponent(tableIdOrName)}/fields`, 'POST', body);
|
|
1087
|
+
if ('error' in response) {
|
|
1088
|
+
return {
|
|
1089
|
+
operation: 'create_field',
|
|
1090
|
+
ok: false,
|
|
1091
|
+
error: this.formatAirtableError(response),
|
|
1092
|
+
success: false,
|
|
1093
|
+
};
|
|
1094
|
+
}
|
|
1095
|
+
return {
|
|
1096
|
+
operation: 'create_field',
|
|
1097
|
+
ok: true,
|
|
1098
|
+
field: response,
|
|
1099
|
+
error: '',
|
|
1100
|
+
success: true,
|
|
1101
|
+
};
|
|
1102
|
+
}
|
|
1103
|
+
async updateField(params) {
|
|
1104
|
+
const { baseId, tableIdOrName, fieldIdOrName, name, description } = params;
|
|
1105
|
+
const body = {};
|
|
1106
|
+
if (name) {
|
|
1107
|
+
body.name = name;
|
|
1108
|
+
}
|
|
1109
|
+
if (description !== undefined) {
|
|
1110
|
+
body.description = description;
|
|
1111
|
+
}
|
|
1112
|
+
const response = await this.makeAirtableApiCall(`meta/bases/${baseId}/tables/${encodeURIComponent(tableIdOrName)}/fields/${encodeURIComponent(fieldIdOrName)}`, 'PATCH', body);
|
|
1113
|
+
if ('error' in response) {
|
|
1114
|
+
return {
|
|
1115
|
+
operation: 'update_field',
|
|
1116
|
+
ok: false,
|
|
1117
|
+
error: this.formatAirtableError(response),
|
|
1118
|
+
success: false,
|
|
1119
|
+
};
|
|
1120
|
+
}
|
|
1121
|
+
return {
|
|
1122
|
+
operation: 'update_field',
|
|
1123
|
+
ok: true,
|
|
1124
|
+
field: response,
|
|
1125
|
+
error: '',
|
|
1126
|
+
success: true,
|
|
1127
|
+
};
|
|
1128
|
+
}
|
|
1129
|
+
formatAirtableError(errorResponse) {
|
|
1130
|
+
const topLevelMessage = 'message' in errorResponse ? errorResponse.message : undefined;
|
|
1131
|
+
const { error } = errorResponse;
|
|
1132
|
+
if (typeof error === 'string') {
|
|
1133
|
+
return topLevelMessage ?? error;
|
|
1134
|
+
}
|
|
1135
|
+
if (error && typeof error === 'object' && !Array.isArray(error)) {
|
|
1136
|
+
const { message, type } = error;
|
|
1137
|
+
return topLevelMessage ?? message ?? type ?? JSON.stringify(error);
|
|
1138
|
+
}
|
|
1139
|
+
return topLevelMessage ?? 'Unknown Airtable API error';
|
|
1140
|
+
}
|
|
1141
|
+
chooseCredential() {
|
|
1142
|
+
const { credentials } = this.params;
|
|
1143
|
+
if (!credentials || typeof credentials !== 'object') {
|
|
1144
|
+
throw new Error('No Airtable credentials provided');
|
|
1145
|
+
}
|
|
1146
|
+
return credentials[CredentialType.AIRTABLE_CRED];
|
|
1147
|
+
}
|
|
1148
|
+
async makeAirtableApiCall(endpoint, method = 'GET', body) {
|
|
1149
|
+
const url = `${AIRTABLE_API_BASE}/${endpoint}`;
|
|
1150
|
+
const authToken = this.chooseCredential();
|
|
1151
|
+
if (!authToken) {
|
|
1152
|
+
throw new Error('Airtable authentication token is required but was not provided');
|
|
1153
|
+
}
|
|
1154
|
+
const headers = {
|
|
1155
|
+
Authorization: `Bearer ${authToken}`,
|
|
1156
|
+
'Content-Type': 'application/json',
|
|
1157
|
+
};
|
|
1158
|
+
const fetchConfig = {
|
|
1159
|
+
method,
|
|
1160
|
+
headers,
|
|
1161
|
+
};
|
|
1162
|
+
if (body && (method === 'POST' || method === 'PATCH')) {
|
|
1163
|
+
fetchConfig.body = JSON.stringify(body);
|
|
1164
|
+
}
|
|
1165
|
+
const response = await fetch(url, fetchConfig);
|
|
1166
|
+
const data = (await response.json());
|
|
1167
|
+
if (!response.ok) {
|
|
1168
|
+
return data;
|
|
1169
|
+
}
|
|
1170
|
+
return data;
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
//# sourceMappingURL=airtable.js.map
|