← back to Ventura Claw

scripts/build-connectors.sh

152 lines

#!/usr/bin/env bash
# Generate one Zapier-style connector module per registered connector.
# Each gets stub triggers + actions + auth; EXA research will fill in real specs later.
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
EMIT="$ROOT/scripts/emit.sh"
OUT="$ROOT/app/lib/mcp/connectors"
mkdir -p "$OUT"

# slug | name | category | docs | auth_method | env_keys | triggers (csv) | actions (csv)
read -r -d '' MANIFEST <<'EOF' || true
shopify|Shopify|commerce|https://shopify.dev/docs/api|oauth2|SHOPIFY_API_KEY,SHOPIFY_API_SECRET,SHOPIFY_ACCESS_TOKEN|order.created,order.paid,product.updated,refund.created|product.create,product.update,product.delete,order.fulfill,inventory.adjust,collection.create,customer.upsert,discount.create
etsy|Etsy|commerce|https://developers.etsy.com/documentation|oauth2|ETSY_KEYSTRING,ETSY_SHARED_SECRET,ETSY_ACCESS_TOKEN|listing.created,order.received|listing.create,listing.update,listing.deactivate,order.ship
woocommerce|WooCommerce|commerce|https://woocommerce.github.io/woocommerce-rest-api-docs/|api_key|WC_URL,WC_CONSUMER_KEY,WC_CONSUMER_SECRET|order.created,product.updated|product.create,product.update,order.refund
stripe|Stripe|payments|https://stripe.com/docs/api|api_key|STRIPE_SECRET_KEY,STRIPE_WEBHOOK_SECRET|charge.succeeded,charge.refunded,subscription.created,invoice.paid|charge.create,refund.create,customer.create,subscription.cancel,payment_link.create
paypal|PayPal|payments|https://developer.paypal.com/api/rest/|oauth2|PAYPAL_CLIENT_ID,PAYPAL_CLIENT_SECRET|order.completed,refund.completed|order.create,order.capture,refund.create,payout.create
shopify_payments|Shopify Payments|payments|https://shopify.dev/docs/api/admin-rest/2024-10/resources/shopifypayments|oauth2|SHOPIFY_ACCESS_TOKEN|payout.scheduled|payout.list
square|Square|payments|https://developer.squareup.com/reference/square|oauth2|SQUARE_ACCESS_TOKEN|payment.created|payment.create,refund.create,catalog.upsert
gmail|Gmail|email_office|https://developers.google.com/gmail/api|oauth2|GOOGLE_CLIENT_ID,GOOGLE_CLIENT_SECRET,GOOGLE_REFRESH_TOKEN|message.received,thread.new|message.send,message.search,draft.create,label.apply
google_sheets|Google Sheets|email_office|https://developers.google.com/sheets/api|oauth2|GOOGLE_CLIENT_ID,GOOGLE_CLIENT_SECRET,GOOGLE_REFRESH_TOKEN|row.added|row.append,row.update,sheet.create,range.read
google_drive|Google Drive|email_office|https://developers.google.com/drive/api|oauth2|GOOGLE_CLIENT_ID,GOOGLE_CLIENT_SECRET,GOOGLE_REFRESH_TOKEN|file.created|file.upload,file.move,file.share
outlook|Outlook|email_office|https://learn.microsoft.com/en-us/graph/api/overview|oauth2|MS_CLIENT_ID,MS_CLIENT_SECRET,MS_REFRESH_TOKEN|message.received,event.created|message.send,calendar.create,event.create
purelymail|Purelymail|email_office|https://purelymail.com/docs/api|api_key|PURELYMAIL_API_TOKEN|none|smtp.send,domain.add,mailbox.create
slack|Slack|communication|https://api.slack.com/|oauth2|SLACK_BOT_TOKEN,SLACK_SIGNING_SECRET|message.posted,channel.created|chat.postMessage,channel.create,reaction.add,user.lookup
ringcentral|RingCentral|communication|https://developers.ringcentral.com/|oauth2|RC_CLIENT_ID,RC_CLIENT_SECRET,RC_JWT|sms.received,call.completed|sms.send,fax.send,call.log
twilio|Twilio|communication|https://www.twilio.com/docs/usage/api|api_key|TWILIO_ACCOUNT_SID,TWILIO_AUTH_TOKEN|sms.received|sms.send,voice.call,whatsapp.send
discord|Discord|communication|https://discord.com/developers/docs|api_key|DISCORD_BOT_TOKEN|message.created|channel.message,role.assign,thread.create
instagram|Instagram|social|https://developers.facebook.com/docs/instagram-api|oauth2|META_APP_ID,META_APP_SECRET,IG_BUSINESS_TOKEN|comment.received|media.publish,story.publish,reply.dm
facebook|Facebook Pages|social|https://developers.facebook.com/docs/pages-api|oauth2|META_APP_ID,META_APP_SECRET,FB_PAGE_TOKEN|comment.received|post.create,reply.comment,event.create
tiktok|TikTok|social|https://developers.tiktok.com/doc/content-posting-api|oauth2|TIKTOK_CLIENT_KEY,TIKTOK_CLIENT_SECRET|video.published|video.publish,photo.publish
pinterest|Pinterest|social|https://developers.pinterest.com/docs/api/v5/|oauth2|PINTEREST_APP_ID,PINTEREST_APP_SECRET,PINTEREST_TOKEN|pin.created|pin.create,board.create
linkedin|LinkedIn|social|https://learn.microsoft.com/en-us/linkedin/|oauth2|LI_CLIENT_ID,LI_CLIENT_SECRET,LI_TOKEN|post.published|post.create,share.create
youtube_shorts|YouTube Shorts|social|https://developers.google.com/youtube/v3|oauth2|GOOGLE_CLIENT_ID,GOOGLE_CLIENT_SECRET,GOOGLE_REFRESH_TOKEN|video.uploaded|short.upload,playlist.add
x_twitter|X / Twitter|social|https://developer.x.com/en/docs|oauth2|X_API_KEY,X_API_SECRET,X_BEARER_TOKEN|mention.received|post.create,dm.send
threads|Threads|social|https://developers.facebook.com/docs/threads|oauth2|META_APP_ID,META_APP_SECRET,THREADS_TOKEN|post.published|post.create,reply.create
bluesky|Bluesky|social|https://docs.bsky.app/|api_key|BLUESKY_HANDLE,BLUESKY_APP_PASSWORD|post.received|post.create,follow.add
reddit|Reddit|social|https://www.reddit.com/dev/api|oauth2|REDDIT_CLIENT_ID,REDDIT_CLIENT_SECRET,REDDIT_REFRESH_TOKEN|new_submission,comment.received|submission.create,comment.reply
mailchimp|Mailchimp|marketing_email|https://mailchimp.com/developer/marketing/api/|api_key|MAILCHIMP_API_KEY,MAILCHIMP_DC|subscriber.added,campaign.sent|campaign.send,member.upsert,segment.update
klaviyo|Klaviyo|marketing_email|https://developers.klaviyo.com/en/reference|api_key|KLAVIYO_PRIVATE_KEY|profile.created|event.track,profile.upsert,flow.trigger
constant_contact|Constant Contact|marketing_email|https://developer.constantcontact.com/|oauth2|CTCT_CLIENT_ID,CTCT_CLIENT_SECRET,CTCT_REFRESH_TOKEN|contact.added|contact.upsert,campaign.send
action_network|Action Network|marketing_email|https://actionnetwork.org/docs/|api_key|AN_API_KEY|signup.received,donation.received|person.create,outreach.send,event.create
clickup|ClickUp|project_task|https://clickup.com/api|oauth2|CLICKUP_CLIENT_ID,CLICKUP_CLIENT_SECRET,CLICKUP_TOKEN|task.created,task.updated|task.create,task.update,comment.add
asana|Asana|project_task|https://developers.asana.com/|oauth2|ASANA_CLIENT_ID,ASANA_CLIENT_SECRET,ASANA_PAT|task.created,task.completed|task.create,task.update,project.create
trello|Trello|project_task|https://developer.atlassian.com/cloud/trello/|api_key|TRELLO_KEY,TRELLO_TOKEN|card.created|card.create,card.move,checklist.add
monday|Monday|project_task|https://developer.monday.com/|api_key|MONDAY_API_TOKEN|item.created|item.create,column.update,update.post
notion|Notion|project_task|https://developers.notion.com/|oauth2|NOTION_CLIENT_ID,NOTION_CLIENT_SECRET,NOTION_TOKEN|page.created,db.row.added|page.create,db.row.append,block.append
hubspot|HubSpot|crm_support|https://developers.hubspot.com/docs/api/overview|oauth2|HUBSPOT_CLIENT_ID,HUBSPOT_CLIENT_SECRET,HUBSPOT_TOKEN|contact.created,deal.stage.changed|contact.upsert,deal.create,task.create
salesforce|Salesforce|crm_support|https://developer.salesforce.com/docs|oauth2|SF_CLIENT_ID,SF_CLIENT_SECRET,SF_REFRESH_TOKEN|lead.created,opportunity.won|lead.create,contact.upsert,opportunity.create
zendesk|Zendesk|crm_support|https://developer.zendesk.com/api-reference/|api_key|ZENDESK_SUBDOMAIN,ZENDESK_EMAIL,ZENDESK_TOKEN|ticket.created|ticket.reply,ticket.tag,macro.apply
gorgias|Gorgias|crm_support|https://developers.gorgias.com/|api_key|GORGIAS_DOMAIN,GORGIAS_USERNAME,GORGIAS_API_KEY|ticket.created|ticket.reply,ticket.tag,customer.upsert
intercom|Intercom|crm_support|https://developers.intercom.com/|oauth2|INTERCOM_CLIENT_ID,INTERCOM_CLIENT_SECRET,INTERCOM_TOKEN|conversation.created|conversation.reply,user.upsert,article.create
canva|Canva|creative|https://www.canva.dev/docs/connect/|oauth2|CANVA_CLIENT_ID,CANVA_CLIENT_SECRET,CANVA_TOKEN|design.exported|design.create,asset.upload,export.start
figma|Figma|creative|https://www.figma.com/developers/api|oauth2|FIGMA_CLIENT_ID,FIGMA_CLIENT_SECRET,FIGMA_TOKEN|file.updated|file.read,comment.add,export.image
adobe|Adobe|creative|https://developer.adobe.com/|oauth2|ADOBE_CLIENT_ID,ADOBE_CLIENT_SECRET,ADOBE_TOKEN|asset.created|asset.export,asset.upload
paper|Paper|creative|https://paper.design/|oauth2|PAPER_CLIENT_ID,PAPER_CLIENT_SECRET,PAPER_TOKEN|doc.updated|doc.create,doc.share
cloudflare|Cloudflare|security_hosting|https://developers.cloudflare.com/api/|api_key|CF_API_TOKEN|alert.received|dns.update,zone.list,firewall.rule.create,page.purge,worker.deploy
godaddy|GoDaddy|security_hosting|https://developer.godaddy.com/doc|api_key|GODADDY_API_KEY,GODADDY_API_SECRET|none|domain.list,dns.update,domain.renew
vercel|Vercel|security_hosting|https://vercel.com/docs/rest-api|api_key|VERCEL_TOKEN|deploy.completed|deploy.create,deploy.list,domain.add
aws|AWS|security_hosting|https://docs.aws.amazon.com/|api_key|AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AWS_REGION|none|s3.upload,ses.send,sqs.send
sucuri|Sucuri|security_hosting|https://docs.sucuri.net/api/|api_key|SUCURI_API_KEY,SUCURI_API_SECRET|alert.received|scan.run,firewall.update,site.add
n8n|n8n|automation_data|https://docs.n8n.io/api/|api_key|N8N_BASE_URL,N8N_API_KEY|workflow.completed|workflow.run,workflow.activate,credentials.list
zapier|Zapier|automation_data|https://platform.zapier.com/|api_key|ZAPIER_NLA_API_KEY|none|zap.trigger,nla.search
make|Make|automation_data|https://www.make.com/en/api-documentation|api_key|MAKE_API_TOKEN|scenario.completed|scenario.run,scenario.create
browserbase|Browserbase|automation_data|https://docs.browserbase.com/|api_key|BROWSERBASE_API_KEY,BROWSERBASE_PROJECT_ID|none|session.create,page.goto,page.screenshot,page.scrape
postgresql|PostgreSQL|automation_data|https://www.postgresql.org/docs/|basic|PG_HOST,PG_PORT,PG_DB,PG_USER,PG_PASSWORD|listen.notify|query.run,row.insert,row.upsert,row.delete
supabase|Supabase|automation_data|https://supabase.com/docs/reference/api|api_key|SUPABASE_URL,SUPABASE_SERVICE_ROLE_KEY|row.inserted|row.insert,row.update,storage.upload,auth.invite
airtable|Airtable|automation_data|https://airtable.com/developers/web/api|api_key|AIRTABLE_PAT,AIRTABLE_BASE_ID|record.created|record.create,record.update,record.delete
EOF

count=0
while IFS='|' read -r slug name category docs auth env triggers actions; do
  [ -z "$slug" ] && continue
  count=$((count+1))
  IFS=',' read -ra TRIGGERS_ARR <<< "$triggers"
  IFS=',' read -ra ACTIONS_ARR <<< "$actions"
  IFS=',' read -ra ENV_ARR <<< "$env"

  # build trigger entries
  trig_block=""
  for t in "${TRIGGERS_ARR[@]}"; do
    [ "$t" = "none" ] && continue
    [ -z "$t" ] && continue
    trig_block+="    { id:\"${slug}.${t}\", label:\"${t//./ }\", kind:\"polling\", inputs:[], sample:{}, async poll(){ return []; } },
"
  done
  # build action entries — heuristic: writes/sends/refunds/deletes are sensitive
  act_block=""
  for a in "${ACTIONS_ARR[@]}"; do
    [ "$a" = "none" ] && continue
    [ -z "$a" ] && continue
    sensitive="false"
    case "$a" in
      *send|*publish|*create|*update|*delete|*refund|*cancel|*adjust|*purge|*deploy|*move|*share|*ship|*assign|*tag|*reply|*upload|*invite|*upsert|*post|*trigger|*deactivate|*fulfill|*share|*activate)
        sensitive="true";;
    esac
    act_block+="    { id:\"${slug}.${a}\", label:\"${a//./ }\", sensitive:${sensitive}, inputs:[], sample:{}, async run(ctx,input){ ctx.log(\"[${slug}.${a}] mock\",\"info\"); return { mocked:true, input }; } },
"
  done

  # env array
  env_json=""
  for e in "${ENV_ARR[@]}"; do env_json+="\"$e\","; done
  env_json="${env_json%,}"

  cat > "$OUT/${slug}.ts" <<TS
// AUTO-GENERATED by build-connectors.sh — VenturaClaw
// Connector: ${name} (${slug})
import { register, type Connector } from "../framework";

export const ${slug//[-]/_}: Connector = register({
  meta: {
    id: "${slug}",
    name: "${name}",
    category: "${category}",
    homepage: "${docs%/*}",
    docsUrl: "${docs}",
    difficulty: "medium",
    priority: "v1",
    mcpServer: null,
    rateLimit: "TBD",
    webhookSupport: false
  },
  auth: {
    method: "${auth}",
    envKeys: [${env_json}],
    docsUrl: "${docs}"
  },
  triggers: [
${trig_block}  ],
  actions: [
${act_block}  ]
});

export default ${slug//[-]/_};
TS

  "$EMIT" --kind log --level info --msg "[connector] ${slug} → ${name}: $(echo "$triggers" | tr ',' '\n' | grep -cv '^none$\|^$') triggers, $(echo "$actions" | tr ',' '\n' | grep -cv '^none$\|^$') actions"
done <<< "$MANIFEST"

# index file
{
  echo "// AUTO-GENERATED — VenturaClaw connector index"
  for f in "$OUT"/*.ts; do
    [ "$(basename "$f")" = "index.ts" ] && continue
    base="$(basename "$f" .ts)"
    echo "export { default as ${base//[-]/_} } from \"./${base}\";"
  done
} > "$OUT/index.ts"

"$EMIT" --kind log --level ok --msg "[connector] generated ${count} typed connector modules"
echo "generated $count connectors → $OUT"