@oomol-lab/open-connector 1.6.5 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/assets/open-connector/catalog/apps/airtable.json +134 -0
- package/assets/open-connector/catalog/apps/aisa.json +6985 -319
- package/assets/open-connector/catalog/apps/baizhi_mcp.json +135 -0
- package/assets/open-connector/catalog/apps/cal.json +24 -6
- package/assets/open-connector/catalog/apps/discordbot.json +2888 -248
- package/assets/open-connector/catalog/apps/drawio_mcp.json +192 -0
- package/assets/open-connector/catalog/apps/enormail.json +411 -0
- package/assets/open-connector/catalog/apps/feishu_app_bot.json +158 -0
- package/assets/open-connector/catalog/apps/firecrawl.json +176 -32
- package/assets/open-connector/catalog/apps/framejet.json +273 -0
- package/assets/open-connector/catalog/apps/futunn.json +2967 -0
- package/assets/open-connector/catalog/apps/github.json +275 -0
- package/assets/open-connector/catalog/apps/gitlab.json +125 -0
- package/assets/open-connector/catalog/apps/gmail.json +376 -0
- package/assets/open-connector/catalog/apps/google_analytics.json +4 -1
- package/assets/open-connector/catalog/apps/google_bigquery.json +4 -1
- package/assets/open-connector/catalog/apps/google_search_console.json +4 -1
- package/assets/open-connector/catalog/apps/googlecalendar.json +210 -1
- package/assets/open-connector/catalog/apps/googlechat.json +694 -7
- package/assets/open-connector/catalog/apps/googledocs.json +4 -1
- package/assets/open-connector/catalog/apps/googledrive.json +479 -0
- package/assets/open-connector/catalog/apps/googlesheets.json +148 -1
- package/assets/open-connector/catalog/apps/granola.json +23 -0
- package/assets/open-connector/catalog/apps/hithink_finance.json +6 -3
- package/assets/open-connector/catalog/apps/indexed.json +1115 -0
- package/assets/open-connector/catalog/apps/keepa.json +3534 -987
- package/assets/open-connector/catalog/apps/linear.json +133 -0
- package/assets/open-connector/catalog/apps/linear_mcp.json +510 -0
- package/assets/open-connector/catalog/apps/moneyforward_mcp.json +1432 -0
- package/assets/open-connector/catalog/apps/notion.json +588 -1
- package/assets/open-connector/catalog/apps/notion_mcp.json +490 -0
- package/assets/open-connector/catalog/apps/odoo.json +619 -0
- package/assets/open-connector/catalog/apps/one_drive.json +185 -0
- package/assets/open-connector/catalog/apps/outlook.json +212 -8
- package/assets/open-connector/catalog/apps/outlook_calendar.json +23 -2
- package/assets/open-connector/catalog/apps/postiz.json +334 -0
- package/assets/open-connector/catalog/apps/proworkflow.json +529 -0
- package/assets/open-connector/catalog/apps/sellersprite_mcp.json +2 -1
- package/assets/open-connector/catalog/apps/shopify.json +282 -0
- package/assets/open-connector/catalog/apps/slack.json +405 -0
- package/assets/open-connector/catalog/apps/slackbot.json +214 -0
- package/assets/open-connector/catalog/apps/spotify.json +46 -43
- package/assets/open-connector/catalog/apps/stripe.json +96 -0
- package/assets/open-connector/catalog/apps/telegram.json +138 -0
- package/assets/open-connector/catalog/apps/tencent_docs.json +3 -0
- package/assets/open-connector/catalog/apps/weixin_store.json +543 -2
- package/assets/open-connector/catalog/apps/wisburg.json +1528 -0
- package/assets/open-connector/catalog/apps/woocommerce.json +127 -0
- package/assets/open-connector/catalog/apps/youtube.json +4 -1
- package/assets/open-connector/catalog/apps/zendesk.json +152 -0
- package/assets/open-connector/catalog/apps/zerotier.json +3319 -0
- package/assets/open-connector/catalog/apps-index.json +1 -1
- package/assets/open-connector/migrations/0014_saas_project.sql +55 -0
- package/assets/open-connector/migrations/0015_saas_cleanup_runtime.sql +8 -0
- package/assets/open-connector/migrations/0016_trigger_policy.sql +1 -0
- package/assets/open-connector/migrations/0017_trigger_subscriptions.sql +17 -0
- package/assets/open-connector/migrations/postgresql/0014_saas_project.sql +55 -0
- package/assets/open-connector/migrations/postgresql/0015_saas_cleanup_runtime.sql +8 -0
- package/assets/open-connector/migrations/postgresql/0016_trigger_policy.sql +1 -0
- package/assets/open-connector/migrations/postgresql/0017_trigger_subscriptions.sql +17 -0
- package/package.json +2 -2
- package/src/connection-service.d.ts +40 -7
- package/src/connection-service.js +60 -18
- package/src/core/action-policy.d.ts +8 -1
- package/src/core/action-policy.js +51 -0
- package/src/core/cast.d.ts +13 -0
- package/src/core/cast.js +18 -1
- package/src/core/guarded-fetch.d.ts +11 -3
- package/src/core/guarded-fetch.js +19 -7
- package/src/core/provider-scenarios.js +67 -13
- package/src/core/remote-http.d.ts +33 -0
- package/src/core/remote-http.js +104 -0
- package/src/core/request.d.ts +1 -0
- package/src/core/request.js +11 -1
- package/src/core/types.d.ts +5 -1
- package/src/marketplace/marketplace-service.d.ts +0 -1
- package/src/marketplace/marketplace-service.js +80 -92
- package/src/mcp.js +26 -9
- package/src/oauth/oauth-client-config-service.d.ts +16 -1
- package/src/oauth/oauth-client-config-service.js +59 -3
- package/src/oauth/oauth-flow-service.d.ts +14 -1
- package/src/oauth/oauth-flow-service.js +14 -6
- package/src/providers/17track/runtime.js +1 -1
- package/src/providers/action-contracts.generated.d.ts +20 -6
- package/src/providers/aifinmarket/runtime.js +1 -1
- package/src/providers/airtable/executors.d.ts +3 -0
- package/src/providers/airtable/executors.js +2 -0
- package/src/providers/airtable/trigger-on-record-changed.d.ts +2 -0
- package/src/providers/airtable/trigger-on-record-changed.definition.d.ts +4 -0
- package/src/providers/airtable/trigger-on-record-changed.definition.js +54 -0
- package/src/providers/airtable/trigger-on-record-changed.js +235 -0
- package/src/providers/aisa/executors.js +912 -50
- package/src/providers/aliyun_ack/runtime.js +1 -1
- package/src/providers/aliyun_sls/runtime.js +1 -1
- package/src/providers/app_store_server/runtime-helpers.js +1 -1
- package/src/providers/baizhi_mcp/actions.d.ts +2 -0
- package/src/providers/baizhi_mcp/actions.js +40 -0
- package/src/providers/baizhi_mcp/executors.d.ts +3 -0
- package/src/providers/baizhi_mcp/executors.js +102 -0
- package/src/providers/bazhuayu/runtime.js +2 -2
- package/src/providers/bilibili/runtime.js +2 -4
- package/src/providers/bilibili/upload.js +9 -7
- package/src/providers/cal/actions.js +5 -1
- package/src/providers/cloudflare_browser_rendering/executors.js +1 -1
- package/src/providers/cloudflare_dns/executors.js +1 -1
- package/src/providers/{cloudflare-current-user.js → cloudflare_dns/runtime-user.js} +2 -2
- package/src/providers/cloudflare_dns/runtime.d.ts +1 -1
- package/src/providers/cloudflare_dns/runtime.js +1 -1
- package/src/providers/cloudflare_r2/executors.js +1 -1
- package/src/providers/cloudflare_r2/runtime.d.ts +1 -1
- package/src/providers/cloudflare_r2/runtime.js +1 -1
- package/src/providers/cloudflare_worker/executors.js +1 -1
- package/src/providers/cloudflare_worker/runtime.d.ts +1 -1
- package/src/providers/cloudflare_worker/runtime.js +1 -1
- package/src/providers/dingtalk_mcp/runtime.js +1 -1
- package/src/providers/discordbot/executors.d.ts +0 -9
- package/src/providers/discordbot/executors.js +9 -101
- package/src/providers/discordbot/runtime-guilds.d.ts +3 -0
- package/src/providers/discordbot/runtime-guilds.js +464 -0
- package/src/providers/discordbot/runtime.d.ts +42 -0
- package/src/providers/discordbot/runtime.js +124 -0
- package/src/providers/drawio_mcp/executors.d.ts +3 -0
- package/src/providers/drawio_mcp/executors.js +19 -0
- package/src/providers/drawio_mcp/runtime.d.ts +8 -0
- package/src/providers/drawio_mcp/runtime.js +175 -0
- package/src/providers/enormail/executors.d.ts +4 -0
- package/src/providers/enormail/executors.js +97 -0
- package/src/providers/fastmoss_mcp/executors.js +2 -2
- package/src/providers/feishu_app_bot/executors.d.ts +3 -0
- package/src/providers/feishu_app_bot/executors.js +2 -0
- package/src/providers/feishu_app_bot/trigger-config.d.ts +1 -0
- package/src/providers/feishu_app_bot/trigger-config.js +10 -0
- package/src/providers/feishu_app_bot/trigger-on-event.d.ts +2 -0
- package/src/providers/feishu_app_bot/trigger-on-event.definition.d.ts +4 -0
- package/src/providers/feishu_app_bot/trigger-on-event.definition.js +63 -0
- package/src/providers/feishu_app_bot/trigger-on-event.js +29 -0
- package/src/providers/feishu_app_bot/trigger-subscriptions.d.ts +5 -0
- package/src/providers/feishu_app_bot/trigger-subscriptions.js +70 -0
- package/src/providers/finchina/executors.js +1 -1
- package/src/providers/framejet/executors.d.ts +4 -0
- package/src/providers/framejet/executors.js +19 -0
- package/src/providers/framejet/runtime.d.ts +16 -0
- package/src/providers/framejet/runtime.js +148 -0
- package/src/providers/futunn/actions.d.ts +2 -0
- package/src/providers/futunn/actions.js +152 -0
- package/src/providers/futunn/actions.research.d.ts +2 -0
- package/src/providers/futunn/actions.research.js +423 -0
- package/src/providers/futunn/actions.trading.d.ts +2 -0
- package/src/providers/futunn/actions.trading.js +204 -0
- package/src/providers/futunn/executors.d.ts +3 -0
- package/src/providers/futunn/executors.js +24 -0
- package/src/providers/futunn/runtime-research.d.ts +3 -0
- package/src/providers/futunn/runtime-research.js +133 -0
- package/src/providers/futunn/runtime-trading.d.ts +3 -0
- package/src/providers/futunn/runtime-trading.js +39 -0
- package/src/providers/futunn/runtime.d.ts +2 -0
- package/src/providers/futunn/runtime.js +50 -0
- package/src/providers/futunn/transport.d.ts +11 -0
- package/src/providers/futunn/transport.js +76 -0
- package/src/providers/gildata/executors.js +1 -1
- package/src/providers/github/executors.d.ts +3 -0
- package/src/providers/github/executors.js +6 -0
- package/src/providers/github/trigger-on-repo-event.d.ts +2 -0
- package/src/providers/github/trigger-on-repo-event.definition.d.ts +4 -0
- package/src/providers/github/trigger-on-repo-event.definition.js +94 -0
- package/src/providers/github/trigger-on-repo-event.js +168 -0
- package/src/providers/github/trigger-watch-pull-request.d.ts +2 -0
- package/src/providers/github/trigger-watch-pull-request.definition.d.ts +4 -0
- package/src/providers/github/trigger-watch-pull-request.definition.js +49 -0
- package/src/providers/github/trigger-watch-pull-request.js +106 -0
- package/src/providers/gitlab/executors.d.ts +3 -0
- package/src/providers/gitlab/executors.js +2 -0
- package/src/providers/gitlab/trigger-on-project-event.d.ts +2 -0
- package/src/providers/gitlab/trigger-on-project-event.definition.d.ts +5 -0
- package/src/providers/gitlab/trigger-on-project-event.definition.js +63 -0
- package/src/providers/gitlab/trigger-on-project-event.js +186 -0
- package/src/providers/gmail/executors.d.ts +3 -0
- package/src/providers/gmail/executors.js +5 -3
- package/src/providers/gmail/message.d.ts +6 -8
- package/src/providers/gmail/message.js +4 -0
- package/src/providers/gmail/scopes.d.ts +32 -0
- package/src/providers/gmail/scopes.js +37 -0
- package/src/providers/gmail/trigger-on-message-received.d.ts +2 -0
- package/src/providers/gmail/trigger-on-message-received.definition.d.ts +4 -0
- package/src/providers/gmail/trigger-on-message-received.definition.js +74 -0
- package/src/providers/gmail/trigger-on-message-received.js +232 -0
- package/src/providers/google_analytics/executors.js +2 -2
- package/src/providers/google_analytics/scopes.js +6 -1
- package/src/providers/google_bigquery/executors.js +2 -2
- package/src/providers/google_bigquery/scopes.js +2 -0
- package/src/providers/google_search_console/executors.js +2 -2
- package/src/providers/google_search_console/scopes.js +2 -0
- package/src/providers/googleads/executors.js +1 -1
- package/src/providers/googleads/scopes.d.ts +1 -3
- package/src/providers/googleads/scopes.js +2 -4
- package/src/providers/googlecalendar/executors.d.ts +3 -0
- package/src/providers/googlecalendar/executors.js +3 -1
- package/src/providers/googlecalendar/runtime-shared.js +2 -2
- package/src/providers/googlecalendar/scopes.js +2 -0
- package/src/providers/googlecalendar/trigger-on-event-changed.d.ts +2 -0
- package/src/providers/googlecalendar/trigger-on-event-changed.definition.d.ts +4 -0
- package/src/providers/googlecalendar/trigger-on-event-changed.definition.js +74 -0
- package/src/providers/googlecalendar/trigger-on-event-changed.js +233 -0
- package/src/providers/googlechat/executors.d.ts +1 -3
- package/src/providers/googlechat/executors.js +219 -28
- package/src/providers/googlechat/members.d.ts +55 -0
- package/src/providers/googlechat/members.js +293 -0
- package/src/providers/googlechat/runtime.d.ts +16 -0
- package/src/providers/googlechat/runtime.js +25 -0
- package/src/providers/googlechat/scopes.d.ts +22 -3
- package/src/providers/googlechat/scopes.js +30 -7
- package/src/providers/googledocs/executors.js +1 -1
- package/src/providers/googledrive/executors.d.ts +3 -0
- package/src/providers/googledrive/executors.js +9 -2
- package/src/providers/{google-auth.d.ts → googledrive/runtime-auth.d.ts} +2 -2
- package/src/providers/{google-auth.js → googledrive/runtime-auth.js} +3 -3
- package/src/providers/googledrive/runtime-collaboration.js +1 -1
- package/src/providers/{google-runtime.d.ts → googledrive/runtime-request.d.ts} +1 -1
- package/src/providers/{google-runtime.js → googledrive/runtime-request.js} +2 -2
- package/src/providers/googledrive/trigger-changes.d.ts +12 -0
- package/src/providers/googledrive/trigger-changes.definition.d.ts +7 -0
- package/src/providers/googledrive/trigger-changes.definition.js +101 -0
- package/src/providers/googledrive/trigger-changes.js +452 -0
- package/src/providers/googledrive/trigger-on-file-change.d.ts +2 -0
- package/src/providers/googledrive/trigger-on-file-change.definition.d.ts +4 -0
- package/src/providers/googledrive/trigger-on-file-change.definition.js +77 -0
- package/src/providers/googledrive/trigger-on-file-change.js +258 -0
- package/src/providers/googleforms/executors.js +2 -2
- package/src/providers/googleforms/scopes.d.ts +0 -3
- package/src/providers/googleforms/scopes.js +2 -6
- package/src/providers/googlemeet/executors.js +2 -2
- package/src/providers/googlemeet/scopes.d.ts +0 -3
- package/src/providers/googlemeet/scopes.js +2 -6
- package/src/providers/googlesheets/executors.d.ts +3 -0
- package/src/providers/googlesheets/executors.js +3 -1
- package/src/providers/googlesheets/scopes.js +2 -0
- package/src/providers/googlesheets/trigger-on-row-added.d.ts +2 -0
- package/src/providers/googlesheets/trigger-on-row-added.definition.d.ts +4 -0
- package/src/providers/googlesheets/trigger-on-row-added.definition.js +54 -0
- package/src/providers/googlesheets/trigger-on-row-added.js +234 -0
- package/src/providers/googleslides/executors.js +2 -2
- package/src/providers/googleslides/scopes.d.ts +0 -3
- package/src/providers/googleslides/scopes.js +2 -6
- package/src/providers/googletasks/executors.js +2 -2
- package/src/providers/googletasks/scopes.d.ts +0 -3
- package/src/providers/googletasks/scopes.js +2 -6
- package/src/providers/granola/actions.js +2 -0
- package/src/providers/granola/runtime-mcp.js +2 -0
- package/src/providers/granola/runtime.js +2 -2
- package/src/providers/hithink_finance/runtime.js +1 -1
- package/src/providers/indexed/executors.d.ts +4 -0
- package/src/providers/indexed/executors.js +16 -0
- package/src/providers/indexed/runtime.d.ts +26 -0
- package/src/providers/indexed/runtime.js +129 -0
- package/src/providers/indiegogo/executors.js +1 -1
- package/src/providers/investoday_mcp/executors.js +2 -2
- package/src/providers/iyunbiao/runtime.js +2 -2
- package/src/providers/keepa/actions.d.ts +1 -1
- package/src/providers/keepa/actions.js +371 -149
- package/src/providers/keepa/deal-attributes.d.ts +1 -0
- package/src/providers/keepa/deal-attributes.js +26 -0
- package/src/providers/keepa/runtime.js +212 -18
- package/src/providers/kingdee/executors.js +1 -1
- package/src/providers/kingdee/runtime.js +2 -2
- package/src/providers/kuaidi100/runtime.js +1 -1
- package/src/providers/linear/executors.d.ts +3 -0
- package/src/providers/linear/executors.js +14 -9
- package/src/providers/linear/trigger-on-issue-changed.d.ts +2 -0
- package/src/providers/linear/trigger-on-issue-changed.definition.d.ts +5 -0
- package/src/providers/linear/trigger-on-issue-changed.definition.js +43 -0
- package/src/providers/linear/trigger-on-issue-changed.js +215 -0
- package/src/providers/linear_mcp/actions.d.ts +47 -0
- package/src/providers/linear_mcp/actions.js +102 -0
- package/src/providers/linear_mcp/endpoints.d.ts +3 -0
- package/src/providers/linear_mcp/endpoints.js +3 -0
- package/src/providers/linear_mcp/executors.d.ts +3 -0
- package/src/providers/linear_mcp/executors.js +9 -0
- package/src/providers/linear_mcp/runtime-mcp.d.ts +15 -0
- package/src/providers/linear_mcp/runtime-mcp.js +238 -0
- package/src/providers/lingxing_mcp/runtime.js +1 -1
- package/src/providers/mcdonalds_cn_mcp/runtime.js +1 -1
- package/src/providers/metabase/mcp-runtime.js +1 -1
- package/src/providers/moneyforward_mcp/executors.d.ts +3 -0
- package/src/providers/moneyforward_mcp/executors.js +11 -0
- package/src/providers/moneyforward_mcp/manifest.d.ts +31 -0
- package/src/providers/moneyforward_mcp/manifest.js +204 -0
- package/src/providers/moneyforward_mcp/runtime.d.ts +18 -0
- package/src/providers/moneyforward_mcp/runtime.js +296 -0
- package/src/providers/notion/executors.d.ts +3 -0
- package/src/providers/notion/executors.js +41 -3
- package/src/providers/notion/trigger-on-database-page-event.d.ts +2 -0
- package/src/providers/notion/trigger-on-database-page-event.definition.d.ts +4 -0
- package/src/providers/notion/trigger-on-database-page-event.definition.js +63 -0
- package/src/providers/notion/trigger-on-database-page-event.js +293 -0
- package/src/providers/notion_mcp/endpoints.d.ts +3 -0
- package/src/providers/notion_mcp/endpoints.js +3 -0
- package/src/providers/notion_mcp/executors.d.ts +3 -0
- package/src/providers/notion_mcp/executors.js +176 -0
- package/src/providers/notion_mcp/mcp-response.d.ts +86 -0
- package/src/providers/notion_mcp/mcp-response.js +314 -0
- package/src/providers/odoo/executors.d.ts +3 -0
- package/src/providers/odoo/executors.js +32 -0
- package/src/providers/odoo/runtime.d.ts +16 -0
- package/src/providers/odoo/runtime.js +140 -0
- package/src/providers/one_drive/executors.d.ts +3 -0
- package/src/providers/one_drive/executors.js +2 -0
- package/src/providers/one_drive/trigger-on-item-changed.d.ts +2 -0
- package/src/providers/one_drive/trigger-on-item-changed.definition.d.ts +4 -0
- package/src/providers/one_drive/trigger-on-item-changed.definition.js +63 -0
- package/src/providers/one_drive/trigger-on-item-changed.js +214 -0
- package/src/providers/outlook/executors.d.ts +3 -0
- package/src/providers/outlook/executors.js +29 -6
- package/src/providers/outlook/microsoft-graph.js +17 -6
- package/src/providers/outlook/trigger-on-message-received.d.ts +2 -0
- package/src/providers/outlook/trigger-on-message-received.definition.d.ts +4 -0
- package/src/providers/outlook/trigger-on-message-received.definition.js +93 -0
- package/src/providers/outlook/trigger-on-message-received.js +226 -0
- package/src/providers/outlook_calendar/executors.js +30 -7
- package/src/providers/patsnap_mcp/executors.js +2 -2
- package/src/providers/postiz/executors.d.ts +4 -0
- package/src/providers/postiz/executors.js +83 -0
- package/src/providers/provider-loader.d.ts +5 -0
- package/src/providers/provider-loader.js +4 -0
- package/src/providers/provider-runtime.d.ts +15 -0
- package/src/providers/provider-runtime.js +57 -4
- package/src/providers/proworkflow/executors.d.ts +4 -0
- package/src/providers/proworkflow/executors.js +135 -0
- package/src/providers/registry.generated.js +14 -0
- package/src/providers/scrape_creators/catalog.js +1 -1
- package/src/providers/scrape_creators/runtime.js +1 -1
- package/src/providers/sellersprite_mcp/executors.js +2 -2
- package/src/providers/sellersprite_mcp/official-actions.js +3 -2
- package/src/providers/sentry/runtime.js +6 -7
- package/src/providers/shopify/executors.d.ts +3 -0
- package/src/providers/shopify/executors.js +2 -0
- package/src/providers/shopify/trigger-on-shop-event.d.ts +2 -0
- package/src/providers/shopify/trigger-on-shop-event.definition.d.ts +4 -0
- package/src/providers/shopify/trigger-on-shop-event.definition.js +214 -0
- package/src/providers/shopify/trigger-on-shop-event.js +165 -0
- package/src/providers/slack/actions.js +52 -3
- package/src/providers/slack/executors.d.ts +3 -0
- package/src/providers/slack/executors.js +2 -0
- package/src/providers/slack/runtime.js +58 -21
- package/src/providers/slack/trigger-on-message-posted.d.ts +2 -0
- package/src/providers/slack/trigger-on-message-posted.definition.d.ts +4 -0
- package/src/providers/slack/trigger-on-message-posted.definition.js +80 -0
- package/src/providers/slack/trigger-on-message-posted.js +176 -0
- package/src/providers/slickdeals/runtime.js +1 -1
- package/src/providers/sorftime_mcp/executors.js +2 -2
- package/src/providers/spotify/runtime.js +15 -4
- package/src/providers/stripe/executors.d.ts +3 -0
- package/src/providers/stripe/executors.js +2 -0
- package/src/providers/stripe/trigger-on-event.d.ts +2 -0
- package/src/providers/stripe/trigger-on-event.definition.d.ts +4 -0
- package/src/providers/stripe/trigger-on-event.definition.js +43 -0
- package/src/providers/stripe/trigger-on-event.js +212 -0
- package/src/providers/telegram/executors.d.ts +3 -0
- package/src/providers/telegram/executors.js +2 -0
- package/src/providers/telegram/trigger-on-update.d.ts +2 -0
- package/src/providers/telegram/trigger-on-update.definition.d.ts +5 -0
- package/src/providers/telegram/trigger-on-update.definition.js +78 -0
- package/src/providers/telegram/trigger-on-update.js +141 -0
- package/src/providers/tikhub/bounded-response.d.ts +1 -1
- package/src/providers/tikhub/bounded-response.js +8 -34
- package/src/providers/tikhub/endpoint-catalog.js +1 -1
- package/src/providers/tikhub/runtime.js +2 -2
- package/src/providers/tongdaxin/executors.js +79 -15
- package/src/providers/uspto/executors.js +1 -1
- package/src/providers/waffo/executors.js +1 -1
- package/src/providers/waffo/runtime.js +1 -1
- package/src/providers/wecom_mcp/runtime.js +1 -1
- package/src/providers/weixin_store/access-token.d.ts +2 -1
- package/src/providers/weixin_store/access-token.js +15 -4
- package/src/providers/weixin_store/executors.js +97 -12
- package/src/providers/wisburg/executors.d.ts +4 -0
- package/src/providers/wisburg/executors.js +13 -0
- package/src/providers/wisburg/runtime.d.ts +12 -0
- package/src/providers/wisburg/runtime.js +133 -0
- package/src/providers/woocommerce/executors.d.ts +3 -0
- package/src/providers/woocommerce/executors.js +2 -0
- package/src/providers/woocommerce/trigger-on-store-event.d.ts +2 -0
- package/src/providers/woocommerce/trigger-on-store-event.definition.d.ts +4 -0
- package/src/providers/woocommerce/trigger-on-store-event.definition.js +55 -0
- package/src/providers/woocommerce/trigger-on-store-event.js +179 -0
- package/src/providers/xydc_mcp/executors.js +2 -2
- package/src/providers/youtube/executors.js +1 -1
- package/src/providers/youtube/runtime.js +1 -1
- package/src/providers/zendesk/executors.d.ts +3 -0
- package/src/providers/zendesk/executors.js +2 -0
- package/src/providers/zendesk/trigger-on-event.d.ts +2 -0
- package/src/providers/zendesk/trigger-on-event.definition.d.ts +5 -0
- package/src/providers/zendesk/trigger-on-event.definition.js +101 -0
- package/src/providers/zendesk/trigger-on-event.js +188 -0
- package/src/providers/zerotier/executors.d.ts +9 -0
- package/src/providers/zerotier/executors.js +629 -0
- package/src/providers/zerotier/runtime.d.ts +54 -0
- package/src/providers/zerotier/runtime.js +207 -0
- package/src/saas/saas-cleanup-service.d.ts +26 -0
- package/src/saas/saas-cleanup-service.js +124 -0
- package/src/saas/saas-client.d.ts +86 -0
- package/src/saas/saas-client.js +369 -0
- package/src/saas/saas-execution-service.d.ts +15 -0
- package/src/saas/saas-execution-service.js +21 -0
- package/src/saas/saas-oauth-service.d.ts +25 -0
- package/src/saas/saas-oauth-service.js +197 -0
- package/src/saas/saas-project-service.d.ts +61 -0
- package/src/saas/saas-project-service.js +211 -0
- package/src/server/actions/action-idempotency.d.ts +1 -0
- package/src/server/actions/action-idempotency.js +1 -0
- package/src/server/actions/action-runner.d.ts +7 -0
- package/src/server/actions/action-runner.js +43 -7
- package/src/server/actions/run-log-summary.js +9 -0
- package/src/server/api/auth.d.ts +1 -0
- package/src/server/api/auth.js +13 -2
- package/src/server/api/cache-policy.js +4 -1
- package/src/server/api/connection-input.d.ts +7 -1
- package/src/server/api/connection-input.js +7 -1
- package/src/server/api/connection-routes.d.ts +3 -1
- package/src/server/api/connection-routes.js +21 -3
- package/src/server/api/http-utils.d.ts +4 -3
- package/src/server/api/oauth-completion-page.d.ts +124 -0
- package/src/server/api/oauth-completion-page.js +113 -18
- package/src/server/api/openapi.js +123 -15
- package/src/server/api/policy-input.js +6 -0
- package/src/server/api/runtime-api.d.ts +18 -3
- package/src/server/api/runtime-api.js +36 -5
- package/src/server/api/saas-completion-page.d.ts +2 -0
- package/src/server/api/saas-completion-page.js +103 -0
- package/src/server/connect-app.d.ts +5 -0
- package/src/server/connect-app.js +50 -0
- package/src/server/connect-server.d.ts +12 -0
- package/src/server/connect-server.js +157 -15
- package/src/server/connector-runtime.d.ts +3 -1
- package/src/server/connector-runtime.js +5 -2
- package/src/server/files/transit-files.js +16 -7
- package/src/server/proxy/proxy-runner.d.ts +5 -1
- package/src/server/proxy/proxy-runner.js +72 -26
- package/src/server/storage/connection-request-store.d.ts +41 -1
- package/src/server/storage/connection-request-store.js +245 -20
- package/src/server/storage/connection-store.d.ts +16 -0
- package/src/server/storage/connection-store.js +119 -0
- package/src/server/storage/node-runtime-database.js +3 -3
- package/src/server/storage/{postgres-migrations.d.ts → postgres/migrations.d.ts} +2 -2
- package/src/server/storage/{postgres-migrations.js → postgres/migrations.js} +1 -1
- package/src/server/storage/postgres/runtime-store.d.ts +43 -0
- package/src/server/storage/{postgres-runtime-store.js → postgres/runtime-store.js} +59 -94
- package/src/server/storage/runtime-database.d.ts +4 -0
- package/src/server/storage/runtime-sql.d.ts +1 -1
- package/src/server/storage/runtime-sql.js +2 -1
- package/src/server/storage/runtime-store.d.ts +1 -0
- package/src/server/storage/runtime-token-service.d.ts +2 -0
- package/src/server/storage/runtime-token-service.js +3 -0
- package/src/server/storage/saas-project-store.d.ts +77 -0
- package/src/server/storage/saas-project-store.js +273 -0
- package/src/server/storage/{sqlite-runtime-store.d.ts → sqlite/runtime-store.d.ts} +21 -25
- package/src/server/storage/{sqlite-runtime-store.js → sqlite/runtime-store.js} +100 -115
- package/src/server/storage/trigger-store.d.ts +16 -0
- package/src/server/storage/trigger-store.js +96 -0
- package/src/triggers/common/config.d.ts +2 -0
- package/src/triggers/common/config.js +17 -0
- package/src/triggers/common/configOptions.d.ts +13 -0
- package/src/triggers/common/configOptions.js +1 -0
- package/src/triggers/common/encoding.d.ts +3 -0
- package/src/triggers/common/encoding.js +19 -0
- package/src/triggers/common/integration.d.ts +115 -0
- package/src/triggers/common/integration.js +31 -0
- package/src/triggers/common/json.d.ts +6 -0
- package/src/triggers/common/json.js +91 -0
- package/src/triggers/common/poll.d.ts +41 -0
- package/src/triggers/common/poll.js +15 -0
- package/src/triggers/common/proxy.d.ts +14 -0
- package/src/triggers/common/proxy.js +1 -0
- package/src/triggers/common/types.d.ts +42 -0
- package/src/triggers/common/types.js +1 -0
- package/src/triggers/maintenance.d.ts +40 -0
- package/src/triggers/maintenance.js +120 -0
- package/src/triggers/metadata.d.ts +8 -0
- package/src/triggers/metadata.js +1 -0
- package/src/triggers/request.d.ts +33 -0
- package/src/triggers/request.js +52 -0
- package/src/triggers/resources.d.ts +12 -0
- package/src/triggers/resources.js +121 -0
- package/src/triggers/signature.d.ts +4 -0
- package/src/triggers/signature.js +48 -0
- package/src/triggers/store.d.ts +29 -0
- package/src/triggers/store.js +1 -0
- package/src/triggers/subscriptions.d.ts +22 -0
- package/src/triggers/subscriptions.js +220 -0
- package/src/triggers/trigger-runner.d.ts +34 -0
- package/src/triggers/trigger-runner.js +169 -0
- package/src/providers/sentry/scopes.d.ts +0 -1
- package/src/providers/sentry/scopes.js +0 -7
- package/src/server/storage/postgres-runtime-store.d.ts +0 -39
- /package/src/providers/{cloudflare-current-user.d.ts → cloudflare_dns/runtime-user.d.ts} +0 -0
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { eventsPollOutputs, maximumPollEventsPerPage, PermanentPollError, PollConnectionError, TransientPollError, } from "../../triggers/common/poll.js";
|
|
2
|
+
import { snapshot } from "./trigger-on-event-changed.definition.js";
|
|
3
|
+
const quotaReasons = new Set(["rateLimitExceeded", "userRateLimitExceeded", "quotaExceeded", "usageLimits"]);
|
|
4
|
+
export const googleCalendarEventChanged = {
|
|
5
|
+
buildOutputs: eventsPollOutputs,
|
|
6
|
+
snapshot,
|
|
7
|
+
async poll(context) {
|
|
8
|
+
const config = resolveConfig(context.config);
|
|
9
|
+
if (context.checkpoint === null)
|
|
10
|
+
return seed(context, config, context.now.toISOString());
|
|
11
|
+
const checkpoint = readCheckpoint(context.checkpoint);
|
|
12
|
+
if (checkpoint.calendarId !== config.calendarId)
|
|
13
|
+
return seed(context, config, context.now.toISOString());
|
|
14
|
+
if ("seedTimeMin" in checkpoint)
|
|
15
|
+
return seed(context, config, checkpoint.seedTimeMin, checkpoint.pageToken);
|
|
16
|
+
return incremental(context, config, checkpoint);
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
function resolveConfig(value) {
|
|
20
|
+
return {
|
|
21
|
+
calendarId: value.calendarId,
|
|
22
|
+
changes: new Set(value.changes),
|
|
23
|
+
matchTerm: value.matchTerm.trim(),
|
|
24
|
+
maxEventsPerPoll: value.maxEventsPerPoll,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function readCheckpoint(value) {
|
|
28
|
+
const checkpoint = record(value);
|
|
29
|
+
const pageToken = typeof checkpoint?.pageToken == "string" ? checkpoint.pageToken : undefined;
|
|
30
|
+
const calendarId = typeof checkpoint?.calendarId == "string" ? checkpoint.calendarId : undefined;
|
|
31
|
+
if (typeof checkpoint?.syncToken == "string" && checkpoint.syncToken.length > 0) {
|
|
32
|
+
return {
|
|
33
|
+
calendarId,
|
|
34
|
+
...(pageToken == null ? {} : { pageToken }),
|
|
35
|
+
syncToken: checkpoint.syncToken,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
if (typeof checkpoint?.seedTimeMin == "string" && checkpoint.seedTimeMin.length > 0) {
|
|
39
|
+
return {
|
|
40
|
+
calendarId,
|
|
41
|
+
...(pageToken == null ? {} : { pageToken }),
|
|
42
|
+
seedTimeMin: checkpoint.seedTimeMin,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
throw new PermanentPollError("Google Calendar checkpoint is invalid; recreate the Trigger.");
|
|
46
|
+
}
|
|
47
|
+
async function seed(context, config, timeMin, startPageToken) {
|
|
48
|
+
let pageToken = startPageToken;
|
|
49
|
+
for (let page = 0; page < 2; page += 1) {
|
|
50
|
+
const result = await list(context, config.calendarId, {
|
|
51
|
+
maxResults: 2_500,
|
|
52
|
+
pageToken,
|
|
53
|
+
showDeleted: "true",
|
|
54
|
+
singleEvents: "false",
|
|
55
|
+
timeMin,
|
|
56
|
+
});
|
|
57
|
+
if (pageToken != null && stalePage(result))
|
|
58
|
+
return { checkpoint: { calendarId: config.calendarId, seedTimeMin: timeMin }, events: [] };
|
|
59
|
+
success(context, result, "seed full sync");
|
|
60
|
+
const parsed = (record(result.data) ?? {});
|
|
61
|
+
if (parsed.nextSyncToken)
|
|
62
|
+
return {
|
|
63
|
+
checkpoint: { calendarId: config.calendarId, syncToken: parsed.nextSyncToken },
|
|
64
|
+
events: [],
|
|
65
|
+
};
|
|
66
|
+
if (!parsed.nextPageToken)
|
|
67
|
+
throw new TransientPollError("Google Calendar seed response has no continuation token.");
|
|
68
|
+
pageToken = parsed.nextPageToken;
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
checkpoint: {
|
|
72
|
+
calendarId: config.calendarId,
|
|
73
|
+
...(pageToken == null ? {} : { pageToken }),
|
|
74
|
+
seedTimeMin: timeMin,
|
|
75
|
+
},
|
|
76
|
+
events: [],
|
|
77
|
+
hasMore: true,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
async function incremental(context, config, checkpoint) {
|
|
81
|
+
const events = [];
|
|
82
|
+
let filtered = 0;
|
|
83
|
+
const result = await list(context, config.calendarId, {
|
|
84
|
+
maxResults: Math.min(config.maxEventsPerPoll, maximumPollEventsPerPage),
|
|
85
|
+
pageToken: checkpoint.pageToken,
|
|
86
|
+
showDeleted: "true",
|
|
87
|
+
singleEvents: "false",
|
|
88
|
+
syncToken: checkpoint.syncToken,
|
|
89
|
+
});
|
|
90
|
+
if (checkpoint.pageToken != null && stalePage(result)) {
|
|
91
|
+
return {
|
|
92
|
+
checkpoint: { calendarId: config.calendarId, syncToken: checkpoint.syncToken },
|
|
93
|
+
events,
|
|
94
|
+
filtered,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
success(context, result, "incremental sync");
|
|
98
|
+
const parsed = (record(result.data) ?? {});
|
|
99
|
+
for (const item of parsed.items ?? []) {
|
|
100
|
+
if (item.id == null || item.id.length == 0)
|
|
101
|
+
continue;
|
|
102
|
+
const change = classify(item);
|
|
103
|
+
if (!config.changes.has(change) || !matches(item, config.matchTerm)) {
|
|
104
|
+
filtered += 1;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
events.push(event(item, item.id, change, config.calendarId));
|
|
108
|
+
}
|
|
109
|
+
if (parsed.nextSyncToken) {
|
|
110
|
+
return {
|
|
111
|
+
checkpoint: { calendarId: config.calendarId, syncToken: parsed.nextSyncToken },
|
|
112
|
+
events,
|
|
113
|
+
filtered,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
if (!parsed.nextPageToken)
|
|
117
|
+
throw new TransientPollError("Google Calendar sync response has no continuation token.");
|
|
118
|
+
return {
|
|
119
|
+
checkpoint: {
|
|
120
|
+
calendarId: config.calendarId,
|
|
121
|
+
pageToken: parsed.nextPageToken,
|
|
122
|
+
syncToken: checkpoint.syncToken,
|
|
123
|
+
},
|
|
124
|
+
events,
|
|
125
|
+
filtered,
|
|
126
|
+
hasMore: true,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function classify(value) {
|
|
130
|
+
if (value.status == "cancelled")
|
|
131
|
+
return "cancelled";
|
|
132
|
+
const created = epochSecond(value.created);
|
|
133
|
+
const updated = epochSecond(value.updated);
|
|
134
|
+
return created != null && created == updated ? "created" : "updated";
|
|
135
|
+
}
|
|
136
|
+
function matches(value, term) {
|
|
137
|
+
if (term.length == 0)
|
|
138
|
+
return true;
|
|
139
|
+
const needle = term.toLowerCase();
|
|
140
|
+
return [value.summary, value.description, value.location, ...(value.attendees ?? []).map(({ email }) => email)].some((candidate) => typeof candidate == "string" && candidate.toLowerCase().includes(needle));
|
|
141
|
+
}
|
|
142
|
+
function event(item, eventId, change, calendarId) {
|
|
143
|
+
return {
|
|
144
|
+
dedupeKey: `${eventId}:${item.updated ?? item.etag ?? ""}`,
|
|
145
|
+
payload: {
|
|
146
|
+
attendeeEmails: (item.attendees ?? []).flatMap(({ email }) => email == null || email.length == 0 ? [] : [email]),
|
|
147
|
+
calendarId,
|
|
148
|
+
changeType: change,
|
|
149
|
+
created: iso(item.created),
|
|
150
|
+
creatorEmail: item.creator?.email ?? null,
|
|
151
|
+
description: item.description ?? null,
|
|
152
|
+
end: item.end ?? null,
|
|
153
|
+
eventId,
|
|
154
|
+
eventType: item.eventType ?? null,
|
|
155
|
+
htmlLink: item.htmlLink ?? null,
|
|
156
|
+
isAllDay: item.start?.date != null,
|
|
157
|
+
location: item.location ?? null,
|
|
158
|
+
organizerEmail: item.organizer?.email ?? null,
|
|
159
|
+
recurringEventId: item.recurringEventId ?? null,
|
|
160
|
+
start: item.start ?? null,
|
|
161
|
+
status: item.status ?? "",
|
|
162
|
+
summary: item.summary ?? null,
|
|
163
|
+
updated: iso(item.updated),
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
async function list(context, calendarId, query) {
|
|
168
|
+
const endpoint = `/calendars/${encodeURIComponent(calendarId)}/events`;
|
|
169
|
+
try {
|
|
170
|
+
return await context.connector.execute({
|
|
171
|
+
endpoint,
|
|
172
|
+
method: "GET",
|
|
173
|
+
query: Object.fromEntries(Object.entries(query).filter((entry) => entry[1] != null)),
|
|
174
|
+
}, context.signal);
|
|
175
|
+
}
|
|
176
|
+
catch (cause) {
|
|
177
|
+
throw new TransientPollError(`Google Calendar proxy request to ${endpoint} failed.`, { cause });
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
function success(context, result, operation) {
|
|
181
|
+
if (result.status >= 200 && result.status < 300)
|
|
182
|
+
return;
|
|
183
|
+
if (result.status == 410 || (result.status == 400 && fullSyncRequired(result.data))) {
|
|
184
|
+
throw new PermanentPollError("Google Calendar sync token expired; recreate the Trigger.");
|
|
185
|
+
}
|
|
186
|
+
if (result.status == 400 || (result.status == 404 && context.checkpoint === null)) {
|
|
187
|
+
throw new PermanentPollError(`Google Calendar ${operation} rejected the configuration.`);
|
|
188
|
+
}
|
|
189
|
+
if (result.status == 401)
|
|
190
|
+
throw new PollConnectionError(`Google Calendar ${operation} rejected the Connection.`);
|
|
191
|
+
if (result.status == 403) {
|
|
192
|
+
if (reasons(result.data).some((reason) => quotaReasons.has(reason))) {
|
|
193
|
+
throw new TransientPollError(`Google Calendar ${operation} was rate limited.`);
|
|
194
|
+
}
|
|
195
|
+
throw new PollConnectionError(`Google Calendar ${operation} rejected the Connection.`);
|
|
196
|
+
}
|
|
197
|
+
throw new TransientPollError(`Google Calendar ${operation} failed with status ${result.status}.`);
|
|
198
|
+
}
|
|
199
|
+
function stalePage(result) {
|
|
200
|
+
return result.status == 400 && !fullSyncRequired(result.data);
|
|
201
|
+
}
|
|
202
|
+
function reasons(data) {
|
|
203
|
+
const errors = record(record(data)?.error)?.errors;
|
|
204
|
+
if (!Array.isArray(errors))
|
|
205
|
+
return [];
|
|
206
|
+
return errors.flatMap((value) => {
|
|
207
|
+
const reason = record(value)?.reason;
|
|
208
|
+
return typeof reason == "string" ? [reason] : [];
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
function fullSyncRequired(data) {
|
|
212
|
+
if (reasons(data).includes("fullSyncRequired"))
|
|
213
|
+
return true;
|
|
214
|
+
const message = record(record(data)?.error)?.message;
|
|
215
|
+
return typeof message == "string" && message.includes("fullSyncRequired");
|
|
216
|
+
}
|
|
217
|
+
function iso(value) {
|
|
218
|
+
if (value == null || value.length == 0)
|
|
219
|
+
return null;
|
|
220
|
+
const milliseconds = Date.parse(value);
|
|
221
|
+
return Number.isNaN(milliseconds) ? null : new Date(milliseconds).toISOString();
|
|
222
|
+
}
|
|
223
|
+
function epochSecond(value) {
|
|
224
|
+
if (value == null || value.length == 0)
|
|
225
|
+
return null;
|
|
226
|
+
const milliseconds = Date.parse(value);
|
|
227
|
+
return Number.isNaN(milliseconds) ? null : Math.floor(milliseconds / 1_000);
|
|
228
|
+
}
|
|
229
|
+
function record(value) {
|
|
230
|
+
return value != null && typeof value == "object" && !Array.isArray(value)
|
|
231
|
+
? value
|
|
232
|
+
: undefined;
|
|
233
|
+
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import type { CredentialValidators, ProviderExecutors, ProviderProxyExecutor } from "../../core/types.ts";
|
|
2
2
|
import type { ProviderActionHandlers } from "../provider-runtime.ts";
|
|
3
|
-
import type {
|
|
4
|
-
export declare const googleChatApiBaseUrl = "https://chat.googleapis.com/v1";
|
|
5
|
-
type GoogleChatRuntimeContext = OAuthProviderContext;
|
|
3
|
+
import type { GoogleChatRuntimeContext } from "./runtime.ts";
|
|
6
4
|
type GoogleChatActionHandler = (input: Record<string, unknown>, context: GoogleChatRuntimeContext) => Promise<unknown>;
|
|
7
5
|
export declare const googleChatActionHandlers: ProviderActionHandlers<"googlechat", GoogleChatActionHandler>;
|
|
8
6
|
export declare const executors: ProviderExecutors;
|
|
@@ -1,27 +1,50 @@
|
|
|
1
1
|
import { compactObject, optionalBoolean, optionalInteger, optionalRawString, optionalRecord, optionalString, } from "../../core/cast.js";
|
|
2
|
-
import { defineGoogleProviderExecutors, googleBearerProxyAuth, googleServiceAccountValidator } from "../
|
|
3
|
-
import { googleJsonRequest } from "../
|
|
2
|
+
import { defineGoogleProviderExecutors, googleBearerProxyAuth, googleServiceAccountValidator, } from "../googledrive/runtime-auth.js";
|
|
3
|
+
import { googleJsonRequest } from "../googledrive/runtime-request.js";
|
|
4
4
|
import { asObject } from "../googledrive/runtime-shared.js";
|
|
5
|
-
import { defineProviderProxy, ProviderRequestError } from "../provider-runtime.js";
|
|
6
|
-
import {
|
|
7
|
-
|
|
5
|
+
import { defineProviderProxy, ProviderRequestError, providerResponseError, requiredResponseRecord, } from "../provider-runtime.js";
|
|
6
|
+
import { attachSenderProfiles, listSpaceMembersPage, maxProfilesPerLookup, resolveDirectMessagePeer, } from "./members.js";
|
|
7
|
+
import { encodeResourceName, googleChatApiBaseUrl, googleChatJsonRequest, stripPrefix } from "./runtime.js";
|
|
8
|
+
import { googleChatServiceAccountScopes } from "./scopes.js";
|
|
8
9
|
const service = "googlechat";
|
|
10
|
+
const defaultMemberPageSize = 100;
|
|
9
11
|
const googleUserInfoUrl = "https://www.googleapis.com/oauth2/v3/userinfo";
|
|
10
12
|
const spaceNamePattern = /^spaces\/[^/]+$/;
|
|
11
13
|
const messageNamePattern = /^spaces\/[^/]+\/messages\/[^/]+$/;
|
|
14
|
+
const threadNamePattern = /^spaces\/[^/]+\/threads\/[^/]+$/;
|
|
15
|
+
// findDirectMessage takes the user name as a query parameter, not a path segment,
|
|
16
|
+
// so it is deliberately NOT percent-encoded here: googleRequest already encodes it
|
|
17
|
+
// once through URLSearchParams.set(), and encoding it again would turn a@b.com into
|
|
18
|
+
// a%2540b.com, which Google reads as a literal rather than an email address.
|
|
19
|
+
//
|
|
20
|
+
// Both patterns are allowlists of the expected structure, not denylists, so
|
|
21
|
+
// zero-width and control characters, slashes, backslashes, and inner whitespace
|
|
22
|
+
// all fall outside them without being rejected one by one. Domains accept only
|
|
23
|
+
// ASCII or punycode.
|
|
24
|
+
const userIdPattern = /^[0-9]{1,64}$/;
|
|
25
|
+
// RFC 5322 allows "/" in the local part, but it is deliberately excluded here:
|
|
26
|
+
// otherwise "users/person@example.com" would pass as one valid address and be sent
|
|
27
|
+
// to Google as "users/users/person@example.com". A test pins this down.
|
|
28
|
+
const emailLocalPart = "[A-Za-z0-9!#$%&'*+=?^_`{|}~-]+(?:\\.[A-Za-z0-9!#$%&'*+=?^_`{|}~-]+)*";
|
|
29
|
+
const emailDomainLabel = "[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?";
|
|
30
|
+
const userEmailPattern = new RegExp(`^${emailLocalPart}@${emailDomainLabel}(?:\\.${emailDomainLabel})+$`);
|
|
12
31
|
export const googleChatActionHandlers = {
|
|
13
32
|
list_spaces: listSpaces,
|
|
14
33
|
get_space: getSpace,
|
|
15
34
|
list_messages: listMessages,
|
|
16
35
|
get_message: getMessage,
|
|
36
|
+
create_message: createMessage,
|
|
37
|
+
find_direct_message: findDirectMessage,
|
|
38
|
+
get_direct_message_peer: getDirectMessagePeer,
|
|
39
|
+
list_space_members: listSpaceMembers,
|
|
17
40
|
};
|
|
18
41
|
export const executors = defineGoogleProviderExecutors(service, googleChatActionHandlers, {
|
|
19
|
-
scopes:
|
|
42
|
+
scopes: googleChatServiceAccountScopes,
|
|
20
43
|
});
|
|
21
44
|
export const proxy = defineProviderProxy({
|
|
22
45
|
service,
|
|
23
46
|
baseUrl: googleChatApiBaseUrl,
|
|
24
|
-
auth: googleBearerProxyAuth(
|
|
47
|
+
auth: googleBearerProxyAuth(googleChatServiceAccountScopes),
|
|
25
48
|
skipDnsValidation: true,
|
|
26
49
|
});
|
|
27
50
|
export const credentialValidators = {
|
|
@@ -42,7 +65,7 @@ export const credentialValidators = {
|
|
|
42
65
|
},
|
|
43
66
|
};
|
|
44
67
|
},
|
|
45
|
-
customCredential: googleServiceAccountValidator(service,
|
|
68
|
+
customCredential: googleServiceAccountValidator(service, googleChatServiceAccountScopes),
|
|
46
69
|
};
|
|
47
70
|
async function listSpaces(input, context) {
|
|
48
71
|
const payload = await googleChatJsonRequest(`${googleChatApiBaseUrl}/spaces`, {
|
|
@@ -65,6 +88,129 @@ async function getSpace(input, context) {
|
|
|
65
88
|
});
|
|
66
89
|
return normalizeSpace(payload);
|
|
67
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* Locate the existing direct message space between the authenticated user and
|
|
93
|
+
* another user. This is the only way to address a person by identity rather than
|
|
94
|
+
* by an opaque space id: a DIRECT_MESSAGE space carries no displayName, so
|
|
95
|
+
* `list_spaces` alone can never tell you who a DM is with.
|
|
96
|
+
*
|
|
97
|
+
* Finding the space needs nothing beyond chat.spaces.readonly, which the read
|
|
98
|
+
* actions already use. Naming its peer needs more, so that part is best effort.
|
|
99
|
+
*/
|
|
100
|
+
async function findDirectMessage(input, context) {
|
|
101
|
+
const name = resolveUserName(input.user);
|
|
102
|
+
let payload;
|
|
103
|
+
try {
|
|
104
|
+
payload = await googleChatJsonRequest(`${googleChatApiBaseUrl}/spaces:findDirectMessage`, {
|
|
105
|
+
context,
|
|
106
|
+
query: { name },
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
// Google answers 404 for "no such DM", but also for an address that does not
|
|
111
|
+
// resolve or is not visible to this account. Don't collapse those into
|
|
112
|
+
// "you haven't talked yet" — say what is actually known.
|
|
113
|
+
if (error instanceof ProviderRequestError && error.status === 404) {
|
|
114
|
+
throw new ProviderRequestError(404, `no existing direct message space with ${name}. Either the two of you have never started a conversation, or the identifier is invalid or not visible to this account.`, error.details);
|
|
115
|
+
}
|
|
116
|
+
// An address Google cannot resolve to an account comes back as 400
|
|
117
|
+
// "Missing or malformed user resource name ... must follow this format:
|
|
118
|
+
// users/{user}". The format was not the problem — that is Google's wording
|
|
119
|
+
// for "no such user", and taken at face value it sends the caller off to add
|
|
120
|
+
// a users/ prefix, which this action deliberately rejects. So relabel it.
|
|
121
|
+
//
|
|
122
|
+
// Deliberately matched on that specific wording rather than on "any 400":
|
|
123
|
+
// our own validation already ran, so a 400 almost always concerns the
|
|
124
|
+
// address, but "almost always" is not "always", and mislabelling some other
|
|
125
|
+
// 400 as a bad address would point debugging in the wrong direction. If
|
|
126
|
+
// Google ever rewords this, the raw error comes through unchanged — the
|
|
127
|
+
// status quo, not a regression.
|
|
128
|
+
if (error instanceof ProviderRequestError && error.status === 400 && /user resource name/i.test(error.message)) {
|
|
129
|
+
throw new ProviderRequestError(400, `Google did not accept ${name} as a user identifier. The value is well-formed here, so this usually means it does not resolve to a Google account that this connection can see — check the address. Google's own wording asks for users/{user}; do not add that prefix, this action takes the bare address or id.`, error.details);
|
|
130
|
+
}
|
|
131
|
+
throw error;
|
|
132
|
+
}
|
|
133
|
+
const space = normalizeSpace(payload);
|
|
134
|
+
const spaceName = requirePayloadString(space.name, "Google Chat returned a space without a resource name");
|
|
135
|
+
try {
|
|
136
|
+
return { ...space, peer: await resolveDirectMessagePeer(spaceName, context) };
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
// The space was found; failing to name its other member must not hide that.
|
|
140
|
+
// Report why instead, so the caller knows the recipient is unconfirmed. Only a
|
|
141
|
+
// cancelled request stops the action. Listing the members and reading the
|
|
142
|
+
// caller's own id already say which of them failed, including a network error
|
|
143
|
+
// or a response that is not JSON as a 502; the prefix below only covers a
|
|
144
|
+
// failure neither of them anticipated.
|
|
145
|
+
if (context.signal?.aborted) {
|
|
146
|
+
throw error;
|
|
147
|
+
}
|
|
148
|
+
const failure = error instanceof ProviderRequestError
|
|
149
|
+
? error
|
|
150
|
+
: providerResponseError(`could not resolve the direct message peer: ${error instanceof Error ? error.message : String(error)}`);
|
|
151
|
+
return { ...space, peer: null, peerError: { status: failure.status, message: failure.message } };
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Name the other participant of a direct message space. Under user authentication
|
|
156
|
+
* Chat may report a member only as `users/{id}`, so whatever it leaves out is
|
|
157
|
+
* looked up in the Workspace directory through the People API, where the same id
|
|
158
|
+
* names the person.
|
|
159
|
+
*/
|
|
160
|
+
async function getDirectMessagePeer(input, context) {
|
|
161
|
+
const spaceName = resolveSpaceName(input.space, "space is required");
|
|
162
|
+
const space = requiredResponseRecord(await googleChatJsonRequest(`${googleChatApiBaseUrl}/${encodeResourceName(spaceName)}`, { context }), "Google Chat space");
|
|
163
|
+
// Google always reports the type of a space it returns, so a missing one is a
|
|
164
|
+
// malformed response rather than something wrong with the caller's input.
|
|
165
|
+
const spaceType = requirePayloadString(space.spaceType, `Google Chat returned ${spaceName} without a space type`);
|
|
166
|
+
if (spaceType !== "DIRECT_MESSAGE") {
|
|
167
|
+
// Every member of a named space would otherwise be a "peer" candidate, and
|
|
168
|
+
// calling one of them the peer would be a guess presented as a fact.
|
|
169
|
+
throw new ProviderRequestError(400, `${spaceName} is ${spaceType}, not a direct message`);
|
|
170
|
+
}
|
|
171
|
+
return { space: spaceName, peer: await resolveDirectMessagePeer(spaceName, context) };
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* List a space's members with their directory names, one page at a time. Works
|
|
175
|
+
* for any space type; unlike get_direct_message_peer it names everyone and makes
|
|
176
|
+
* no claim about who "the" other participant is.
|
|
177
|
+
*/
|
|
178
|
+
async function listSpaceMembers(input, context) {
|
|
179
|
+
const spaceName = resolveSpaceName(input.space, "space is required");
|
|
180
|
+
const pageSize = resolvePageSize(input.pageSize);
|
|
181
|
+
const page = await listSpaceMembersPage(spaceName, { pageSize, pageToken: optionalString(input.pageToken) }, context);
|
|
182
|
+
return { space: spaceName, ...page };
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Chat allows up to 1000 members per page, but every human on a page is named in
|
|
186
|
+
* one People batch that takes at most 200, so larger pages are refused rather than
|
|
187
|
+
* silently split into several lookups.
|
|
188
|
+
*/
|
|
189
|
+
function resolvePageSize(value) {
|
|
190
|
+
if (value === undefined || value === null) {
|
|
191
|
+
return defaultMemberPageSize;
|
|
192
|
+
}
|
|
193
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value < 1 || value > maxProfilesPerLookup) {
|
|
194
|
+
throw new ProviderRequestError(400, `pageSize must be an integer from 1 to ${maxProfilesPerLookup}`);
|
|
195
|
+
}
|
|
196
|
+
return value;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Accept a bare user id or a bare email address and build `users/{user}`.
|
|
200
|
+
*
|
|
201
|
+
* Deliberately narrow: no `users/` prefix (one input shape, no ambiguity), no
|
|
202
|
+
* `me`/`app` aliases, nothing containing a path separator or whitespace. Case is
|
|
203
|
+
* preserved and nothing is percent-decoded — the value is passed through as-is.
|
|
204
|
+
*/
|
|
205
|
+
function resolveUserName(value) {
|
|
206
|
+
const raw = requireString(value, "user is required");
|
|
207
|
+
const trimmed = raw.trim();
|
|
208
|
+
const wellFormed = userIdPattern.test(trimmed) || userEmailPattern.test(trimmed);
|
|
209
|
+
if (trimmed.length > 320 || !wellFormed) {
|
|
210
|
+
throw new ProviderRequestError(400, `user must be an email address or a numeric user id, received "${raw}"`);
|
|
211
|
+
}
|
|
212
|
+
return `users/${trimmed}`;
|
|
213
|
+
}
|
|
68
214
|
async function listMessages(input, context) {
|
|
69
215
|
const spaceName = resolveSpaceName(input.space, "space is required");
|
|
70
216
|
const payload = await googleChatJsonRequest(`${googleChatApiBaseUrl}/${encodeResourceName(spaceName)}/messages`, {
|
|
@@ -78,7 +224,7 @@ async function listMessages(input, context) {
|
|
|
78
224
|
}),
|
|
79
225
|
});
|
|
80
226
|
return {
|
|
81
|
-
messages: Array.isArray(payload.messages) ? payload.messages.map((item) => normalizeMessage(item)) : [],
|
|
227
|
+
messages: await attachSenderProfiles(Array.isArray(payload.messages) ? payload.messages.map((item) => normalizeMessage(item)) : [], context),
|
|
82
228
|
nextPageToken: optionalString(payload.nextPageToken) ?? null,
|
|
83
229
|
};
|
|
84
230
|
}
|
|
@@ -87,6 +233,36 @@ async function getMessage(input, context) {
|
|
|
87
233
|
const payload = await googleChatJsonRequest(`${googleChatApiBaseUrl}/${encodeResourceName(messageName)}`, {
|
|
88
234
|
context,
|
|
89
235
|
});
|
|
236
|
+
const [message] = await attachSenderProfiles([normalizeMessage(payload)], context);
|
|
237
|
+
return message;
|
|
238
|
+
}
|
|
239
|
+
async function createMessage(input, context) {
|
|
240
|
+
const spaceName = resolveSpaceName(input.space, "space is required");
|
|
241
|
+
const text = requireRawText(input.text, "text is required");
|
|
242
|
+
// Read the thread raw: optionalString() trims and then treats the result as
|
|
243
|
+
// falsy, which would turn a whitespace-only thread into "no thread given" and
|
|
244
|
+
// silently post a new message instead of the requested reply. Anything the
|
|
245
|
+
// caller actually supplied has to reach resolveThreadName and fail loudly.
|
|
246
|
+
const rawThread = optionalRawString(input.thread);
|
|
247
|
+
const threadName = rawThread === undefined ? undefined : resolveThreadName(rawThread, spaceName);
|
|
248
|
+
const replyOption = optionalString(input.messageReplyOption);
|
|
249
|
+
if (replyOption && !threadName) {
|
|
250
|
+
throw new ProviderRequestError(400, "messageReplyOption is only allowed together with thread");
|
|
251
|
+
}
|
|
252
|
+
const payload = await googleChatJsonRequest(`${googleChatApiBaseUrl}/${encodeResourceName(spaceName)}/messages`, {
|
|
253
|
+
context,
|
|
254
|
+
method: "POST",
|
|
255
|
+
query: compactObject({
|
|
256
|
+
// Google's own default silently ignores `thread` and starts a new one, so a
|
|
257
|
+
// caller that supplied a thread gets an explicit failure instead.
|
|
258
|
+
messageReplyOption: replyOption ?? (threadName ? "REPLY_MESSAGE_OR_FAIL" : undefined),
|
|
259
|
+
requestId: optionalString(input.requestId),
|
|
260
|
+
}),
|
|
261
|
+
body: compactObject({
|
|
262
|
+
text,
|
|
263
|
+
thread: threadName ? { name: threadName } : undefined,
|
|
264
|
+
}),
|
|
265
|
+
});
|
|
90
266
|
return normalizeMessage(payload);
|
|
91
267
|
}
|
|
92
268
|
function normalizeSpace(value) {
|
|
@@ -134,6 +310,7 @@ function normalizeMessage(value) {
|
|
|
134
310
|
? compactObject({
|
|
135
311
|
name: optionalString(sender.name),
|
|
136
312
|
displayName: optionalString(sender.displayName),
|
|
313
|
+
email: optionalString(sender.email),
|
|
137
314
|
type: optionalString(sender.type),
|
|
138
315
|
domainId: optionalString(sender.domainId),
|
|
139
316
|
isAnonymous: optionalBoolean(sender.isAnonymous),
|
|
@@ -186,25 +363,27 @@ function resolveMessageName(input) {
|
|
|
186
363
|
}
|
|
187
364
|
return name;
|
|
188
365
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
.
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
|
|
366
|
+
/**
|
|
367
|
+
* Accept only the full `spaces/{space}/threads/{thread}` resource name, and require
|
|
368
|
+
* it to belong to the space being posted into. The thread travels in the request
|
|
369
|
+
* body rather than the URL, so this is a contract check rather than traversal
|
|
370
|
+
* defence: it turns a cross-space or malformed thread into a local 400 instead of
|
|
371
|
+
* an opaque remote error.
|
|
372
|
+
*/
|
|
373
|
+
function resolveThreadName(value, parentSpaceName) {
|
|
374
|
+
const trimmed = trimSlashes(value.trim());
|
|
375
|
+
const [, spaceId, , threadId] = trimmed.split("/");
|
|
376
|
+
if (!threadNamePattern.test(trimmed) ||
|
|
377
|
+
spaceId === "." ||
|
|
378
|
+
spaceId === ".." ||
|
|
379
|
+
threadId === "." ||
|
|
380
|
+
threadId === "..") {
|
|
381
|
+
throw new ProviderRequestError(400, `thread must be spaces/{space}/threads/{thread}, received "${value}"`);
|
|
382
|
+
}
|
|
383
|
+
if (`spaces/${spaceId}` !== parentSpaceName) {
|
|
384
|
+
throw new ProviderRequestError(400, `thread must belong to ${parentSpaceName}, received "${value}"`);
|
|
385
|
+
}
|
|
386
|
+
return trimmed;
|
|
208
387
|
}
|
|
209
388
|
function trimSlashes(value) {
|
|
210
389
|
return value.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
@@ -224,6 +403,18 @@ function requireString(value, message) {
|
|
|
224
403
|
}
|
|
225
404
|
return resolved;
|
|
226
405
|
}
|
|
406
|
+
/**
|
|
407
|
+
* Like `requireString`, but keeps the value exactly as provided. Message bodies
|
|
408
|
+
* carry meaningful indentation, so the outgoing text must not be trimmed — while a
|
|
409
|
+
* body that is only whitespace is still rejected.
|
|
410
|
+
*/
|
|
411
|
+
function requireRawText(value, message) {
|
|
412
|
+
const resolved = optionalRawString(value);
|
|
413
|
+
if (resolved === undefined || resolved.trim().length === 0) {
|
|
414
|
+
throw new ProviderRequestError(400, message);
|
|
415
|
+
}
|
|
416
|
+
return resolved;
|
|
417
|
+
}
|
|
227
418
|
function requirePayloadString(value, message) {
|
|
228
419
|
const resolved = optionalString(value);
|
|
229
420
|
if (!resolved) {
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { GoogleChatRuntimeContext } from "./runtime.ts";
|
|
2
|
+
/** people:batchGet accepts at most this many resource names per call. */
|
|
3
|
+
export declare const maxProfilesPerLookup = 200;
|
|
4
|
+
type ProfileUnavailableReason = "profile_name_missing" | "people_forbidden" | "people_not_found" | "people_request_failed";
|
|
5
|
+
interface MemberProfile {
|
|
6
|
+
displayName: string | null;
|
|
7
|
+
email: string | null;
|
|
8
|
+
profileUnavailableReason?: ProfileUnavailableReason;
|
|
9
|
+
}
|
|
10
|
+
type DirectMessagePeerKind = "HUMAN" | "BOT" | "SELF" | "AMBIGUOUS";
|
|
11
|
+
interface DirectMessagePeer extends MemberProfile {
|
|
12
|
+
kind: DirectMessagePeerKind;
|
|
13
|
+
user: string | null;
|
|
14
|
+
candidates?: string[];
|
|
15
|
+
}
|
|
16
|
+
interface SpaceMember extends MemberProfile {
|
|
17
|
+
user: string;
|
|
18
|
+
kind: string | undefined;
|
|
19
|
+
role: string | undefined;
|
|
20
|
+
isSelf: boolean;
|
|
21
|
+
}
|
|
22
|
+
interface SpaceMembersPage {
|
|
23
|
+
members: SpaceMember[];
|
|
24
|
+
nextPageToken: string | null;
|
|
25
|
+
}
|
|
26
|
+
interface SpaceMembersPageRequest {
|
|
27
|
+
pageSize: number;
|
|
28
|
+
pageToken: string | undefined;
|
|
29
|
+
/** Also list members who were invited but have not joined yet. */
|
|
30
|
+
showInvited?: boolean;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Name the other participant of a direct message. The authenticated user and the
|
|
34
|
+
* peer are told apart by id, because a Chat membership never says which member is
|
|
35
|
+
* "me". BOT and SELF are ordinary outcomes, not failures: they keep whatever name
|
|
36
|
+
* and email Chat reports for the membership and skip the directory.
|
|
37
|
+
*/
|
|
38
|
+
export declare function resolveDirectMessagePeer(spaceName: string, context: GoogleChatRuntimeContext): Promise<DirectMessagePeer>;
|
|
39
|
+
/**
|
|
40
|
+
* One page of a space's members. Every human Google Chat left without a name or
|
|
41
|
+
* email is looked up in a single batched directory call; the page size is capped
|
|
42
|
+
* so one call always covers the page.
|
|
43
|
+
*/
|
|
44
|
+
export declare function listSpaceMembersPage(spaceName: string, request: SpaceMembersPageRequest, context: GoogleChatRuntimeContext): Promise<SpaceMembersPage>;
|
|
45
|
+
/**
|
|
46
|
+
* Fill in each human sender's name and email on normalized messages. Under user
|
|
47
|
+
* authentication Chat reports them itself only for members of the space and users
|
|
48
|
+
* with prior affinity to the caller, so every human sender missing either is
|
|
49
|
+
* looked up in the directory. Distinct senders are looked up together, so a page
|
|
50
|
+
* costs one extra request per 200 senders. A failed lookup leaves the message
|
|
51
|
+
* intact with a null name and a reason; bots and messages without a sender are
|
|
52
|
+
* left as they are.
|
|
53
|
+
*/
|
|
54
|
+
export declare function attachSenderProfiles(messages: Record<string, unknown>[], context: GoogleChatRuntimeContext): Promise<Record<string, unknown>[]>;
|
|
55
|
+
export {};
|