@hasna/connectors 0.4.0 → 0.4.2
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/bin/index.js +189 -2
- package/bin/mcp.js +176 -1
- package/bin/serve.js +175 -0
- package/connectors/connect-airtable/.env.example +11 -0
- package/connectors/connect-airtable/CLAUDE.md +121 -0
- package/connectors/connect-airtable/README.md +193 -0
- package/connectors/connect-airtable/package.json +50 -0
- package/connectors/connect-airtable/src/api/client.ts +139 -0
- package/connectors/connect-airtable/src/api/index.ts +405 -0
- package/connectors/connect-airtable/src/cli/index.ts +637 -0
- package/connectors/connect-airtable/src/index.ts +20 -0
- package/connectors/connect-airtable/src/types/index.ts +349 -0
- package/connectors/connect-airtable/src/utils/config.ts +197 -0
- package/connectors/connect-airtable/tsconfig.json +16 -0
- package/connectors/connect-amplitude/.env.example +11 -0
- package/connectors/connect-amplitude/CLAUDE.md +121 -0
- package/connectors/connect-amplitude/README.md +193 -0
- package/connectors/connect-amplitude/package.json +51 -0
- package/connectors/connect-amplitude/src/api/client.ts +144 -0
- package/connectors/connect-amplitude/src/api/index.ts +215 -0
- package/connectors/connect-amplitude/src/cli/index.ts +532 -0
- package/connectors/connect-amplitude/src/index.ts +22 -0
- package/connectors/connect-amplitude/src/types/index.ts +329 -0
- package/connectors/connect-amplitude/src/utils/config.ts +208 -0
- package/connectors/connect-amplitude/tsconfig.json +16 -0
- package/connectors/connect-calendly/.env.example +11 -0
- package/connectors/connect-calendly/CLAUDE.md +272 -0
- package/connectors/connect-calendly/README.md +193 -0
- package/connectors/connect-calendly/package.json +51 -0
- package/connectors/connect-calendly/scripts/release.ts +179 -0
- package/connectors/connect-calendly/src/api/client.ts +213 -0
- package/connectors/connect-calendly/src/api/example.ts +48 -0
- package/connectors/connect-calendly/src/api/index.ts +51 -0
- package/connectors/connect-calendly/src/cli/index.ts +254 -0
- package/connectors/connect-calendly/src/index.ts +103 -0
- package/connectors/connect-calendly/src/types/index.ts +237 -0
- package/connectors/connect-calendly/src/utils/auth.ts +274 -0
- package/connectors/connect-calendly/src/utils/bulk.ts +212 -0
- package/connectors/connect-calendly/src/utils/config.ts +326 -0
- package/connectors/connect-calendly/src/utils/output.ts +175 -0
- package/connectors/connect-calendly/src/utils/settings.ts +114 -0
- package/connectors/connect-calendly/src/utils/storage.ts +198 -0
- package/connectors/connect-calendly/tsconfig.json +16 -0
- package/connectors/connect-convertkit/.env.example +11 -0
- package/connectors/connect-convertkit/CLAUDE.md +272 -0
- package/connectors/connect-convertkit/README.md +193 -0
- package/connectors/connect-convertkit/package.json +51 -0
- package/connectors/connect-convertkit/scripts/release.ts +179 -0
- package/connectors/connect-convertkit/src/api/client.ts +213 -0
- package/connectors/connect-convertkit/src/api/example.ts +48 -0
- package/connectors/connect-convertkit/src/api/index.ts +51 -0
- package/connectors/connect-convertkit/src/cli/index.ts +254 -0
- package/connectors/connect-convertkit/src/index.ts +103 -0
- package/connectors/connect-convertkit/src/types/index.ts +237 -0
- package/connectors/connect-convertkit/src/utils/auth.ts +274 -0
- package/connectors/connect-convertkit/src/utils/bulk.ts +212 -0
- package/connectors/connect-convertkit/src/utils/config.ts +326 -0
- package/connectors/connect-convertkit/src/utils/output.ts +175 -0
- package/connectors/connect-convertkit/src/utils/settings.ts +114 -0
- package/connectors/connect-convertkit/src/utils/storage.ts +198 -0
- package/connectors/connect-convertkit/tsconfig.json +16 -0
- package/connectors/connect-crisp/.env.example +11 -0
- package/connectors/connect-crisp/CLAUDE.md +272 -0
- package/connectors/connect-crisp/README.md +193 -0
- package/connectors/connect-crisp/package.json +51 -0
- package/connectors/connect-crisp/scripts/release.ts +179 -0
- package/connectors/connect-crisp/src/api/client.ts +213 -0
- package/connectors/connect-crisp/src/api/example.ts +48 -0
- package/connectors/connect-crisp/src/api/index.ts +51 -0
- package/connectors/connect-crisp/src/cli/index.ts +254 -0
- package/connectors/connect-crisp/src/index.ts +103 -0
- package/connectors/connect-crisp/src/types/index.ts +237 -0
- package/connectors/connect-crisp/src/utils/auth.ts +274 -0
- package/connectors/connect-crisp/src/utils/bulk.ts +212 -0
- package/connectors/connect-crisp/src/utils/config.ts +326 -0
- package/connectors/connect-crisp/src/utils/output.ts +175 -0
- package/connectors/connect-crisp/src/utils/settings.ts +114 -0
- package/connectors/connect-crisp/src/utils/storage.ts +198 -0
- package/connectors/connect-crisp/tsconfig.json +16 -0
- package/connectors/connect-docusign/.env.example +11 -0
- package/connectors/connect-docusign/CLAUDE.md +128 -0
- package/connectors/connect-docusign/README.md +193 -0
- package/connectors/connect-docusign/package.json +52 -0
- package/connectors/connect-docusign/src/api/client.ts +133 -0
- package/connectors/connect-docusign/src/api/index.ts +178 -0
- package/connectors/connect-docusign/src/cli/index.ts +381 -0
- package/connectors/connect-docusign/src/index.ts +23 -0
- package/connectors/connect-docusign/src/types/index.ts +208 -0
- package/connectors/connect-docusign/src/utils/config.ts +125 -0
- package/connectors/connect-docusign/src/utils/output.ts +119 -0
- package/connectors/connect-docusign/tsconfig.json +16 -0
- package/connectors/connect-drift/.env.example +11 -0
- package/connectors/connect-drift/CLAUDE.md +272 -0
- package/connectors/connect-drift/README.md +193 -0
- package/connectors/connect-drift/package.json +51 -0
- package/connectors/connect-drift/scripts/release.ts +179 -0
- package/connectors/connect-drift/src/api/client.ts +213 -0
- package/connectors/connect-drift/src/api/example.ts +48 -0
- package/connectors/connect-drift/src/api/index.ts +51 -0
- package/connectors/connect-drift/src/cli/index.ts +254 -0
- package/connectors/connect-drift/src/index.ts +103 -0
- package/connectors/connect-drift/src/types/index.ts +237 -0
- package/connectors/connect-drift/src/utils/auth.ts +274 -0
- package/connectors/connect-drift/src/utils/bulk.ts +212 -0
- package/connectors/connect-drift/src/utils/config.ts +326 -0
- package/connectors/connect-drift/src/utils/output.ts +175 -0
- package/connectors/connect-drift/src/utils/settings.ts +114 -0
- package/connectors/connect-drift/src/utils/storage.ts +198 -0
- package/connectors/connect-drift/tsconfig.json +16 -0
- package/connectors/connect-freshdesk/.env.example +11 -0
- package/connectors/connect-freshdesk/CLAUDE.md +272 -0
- package/connectors/connect-freshdesk/README.md +193 -0
- package/connectors/connect-freshdesk/package.json +51 -0
- package/connectors/connect-freshdesk/scripts/release.ts +179 -0
- package/connectors/connect-freshdesk/src/api/client.ts +213 -0
- package/connectors/connect-freshdesk/src/api/example.ts +48 -0
- package/connectors/connect-freshdesk/src/api/index.ts +51 -0
- package/connectors/connect-freshdesk/src/cli/index.ts +254 -0
- package/connectors/connect-freshdesk/src/index.ts +103 -0
- package/connectors/connect-freshdesk/src/types/index.ts +237 -0
- package/connectors/connect-freshdesk/src/utils/auth.ts +274 -0
- package/connectors/connect-freshdesk/src/utils/bulk.ts +212 -0
- package/connectors/connect-freshdesk/src/utils/config.ts +326 -0
- package/connectors/connect-freshdesk/src/utils/output.ts +175 -0
- package/connectors/connect-freshdesk/src/utils/settings.ts +114 -0
- package/connectors/connect-freshdesk/src/utils/storage.ts +198 -0
- package/connectors/connect-freshdesk/tsconfig.json +16 -0
- package/connectors/connect-gumroad/.env.example +11 -0
- package/connectors/connect-gumroad/CLAUDE.md +272 -0
- package/connectors/connect-gumroad/README.md +193 -0
- package/connectors/connect-gumroad/package.json +51 -0
- package/connectors/connect-gumroad/scripts/release.ts +179 -0
- package/connectors/connect-gumroad/src/api/client.ts +213 -0
- package/connectors/connect-gumroad/src/api/example.ts +48 -0
- package/connectors/connect-gumroad/src/api/index.ts +51 -0
- package/connectors/connect-gumroad/src/cli/index.ts +254 -0
- package/connectors/connect-gumroad/src/index.ts +103 -0
- package/connectors/connect-gumroad/src/types/index.ts +237 -0
- package/connectors/connect-gumroad/src/utils/auth.ts +274 -0
- package/connectors/connect-gumroad/src/utils/bulk.ts +212 -0
- package/connectors/connect-gumroad/src/utils/config.ts +326 -0
- package/connectors/connect-gumroad/src/utils/output.ts +175 -0
- package/connectors/connect-gumroad/src/utils/settings.ts +114 -0
- package/connectors/connect-gumroad/src/utils/storage.ts +198 -0
- package/connectors/connect-gumroad/tsconfig.json +16 -0
- package/connectors/connect-hubspot/.env.example +11 -0
- package/connectors/connect-hubspot/CLAUDE.md +128 -0
- package/connectors/connect-hubspot/README.md +193 -0
- package/connectors/connect-hubspot/package.json +52 -0
- package/connectors/connect-hubspot/src/api/client.ts +136 -0
- package/connectors/connect-hubspot/src/api/index.ts +379 -0
- package/connectors/connect-hubspot/src/cli/index.ts +589 -0
- package/connectors/connect-hubspot/src/index.ts +21 -0
- package/connectors/connect-hubspot/src/types/index.ts +285 -0
- package/connectors/connect-hubspot/src/utils/config.ts +205 -0
- package/connectors/connect-hubspot/src/utils/output.ts +119 -0
- package/connectors/connect-hubspot/tsconfig.json +16 -0
- package/connectors/connect-intercom/.env.example +11 -0
- package/connectors/connect-intercom/CLAUDE.md +131 -0
- package/connectors/connect-intercom/README.md +193 -0
- package/connectors/connect-intercom/package.json +52 -0
- package/connectors/connect-intercom/src/api/client.ts +132 -0
- package/connectors/connect-intercom/src/api/index.ts +366 -0
- package/connectors/connect-intercom/src/cli/index.ts +831 -0
- package/connectors/connect-intercom/src/index.ts +21 -0
- package/connectors/connect-intercom/src/types/index.ts +650 -0
- package/connectors/connect-intercom/src/utils/config.ts +157 -0
- package/connectors/connect-intercom/src/utils/output.ts +119 -0
- package/connectors/connect-intercom/tsconfig.json +16 -0
- package/connectors/connect-lemonsqueezy/.env.example +11 -0
- package/connectors/connect-lemonsqueezy/CLAUDE.md +128 -0
- package/connectors/connect-lemonsqueezy/README.md +193 -0
- package/connectors/connect-lemonsqueezy/package.json +52 -0
- package/connectors/connect-lemonsqueezy/src/api/client.ts +133 -0
- package/connectors/connect-lemonsqueezy/src/api/index.ts +502 -0
- package/connectors/connect-lemonsqueezy/src/cli/index.ts +723 -0
- package/connectors/connect-lemonsqueezy/src/index.ts +21 -0
- package/connectors/connect-lemonsqueezy/src/types/index.ts +353 -0
- package/connectors/connect-lemonsqueezy/src/utils/config.ts +205 -0
- package/connectors/connect-lemonsqueezy/src/utils/output.ts +119 -0
- package/connectors/connect-lemonsqueezy/tsconfig.json +16 -0
- package/connectors/connect-linkedin/.env.example +11 -0
- package/connectors/connect-linkedin/CLAUDE.md +124 -0
- package/connectors/connect-linkedin/README.md +193 -0
- package/connectors/connect-linkedin/package.json +52 -0
- package/connectors/connect-linkedin/src/api/client.ts +132 -0
- package/connectors/connect-linkedin/src/api/index.ts +313 -0
- package/connectors/connect-linkedin/src/cli/index.ts +548 -0
- package/connectors/connect-linkedin/src/index.ts +21 -0
- package/connectors/connect-linkedin/src/types/index.ts +472 -0
- package/connectors/connect-linkedin/src/utils/config.ts +157 -0
- package/connectors/connect-linkedin/src/utils/output.ts +119 -0
- package/connectors/connect-linkedin/tsconfig.json +16 -0
- package/connectors/connect-mailchimp/.env.example +11 -0
- package/connectors/connect-mailchimp/CLAUDE.md +127 -0
- package/connectors/connect-mailchimp/README.md +193 -0
- package/connectors/connect-mailchimp/package.json +52 -0
- package/connectors/connect-mailchimp/src/api/client.ts +162 -0
- package/connectors/connect-mailchimp/src/api/index.ts +580 -0
- package/connectors/connect-mailchimp/src/cli/index.ts +822 -0
- package/connectors/connect-mailchimp/src/index.ts +23 -0
- package/connectors/connect-mailchimp/src/types/index.ts +585 -0
- package/connectors/connect-mailchimp/src/utils/config.ts +208 -0
- package/connectors/connect-mailchimp/src/utils/output.ts +119 -0
- package/connectors/connect-mailchimp/tsconfig.json +16 -0
- package/connectors/connect-mongodb/.env.example +11 -0
- package/connectors/connect-mongodb/CLAUDE.md +272 -0
- package/connectors/connect-mongodb/README.md +193 -0
- package/connectors/connect-mongodb/package.json +51 -0
- package/connectors/connect-mongodb/scripts/release.ts +179 -0
- package/connectors/connect-mongodb/src/api/client.ts +213 -0
- package/connectors/connect-mongodb/src/api/example.ts +48 -0
- package/connectors/connect-mongodb/src/api/index.ts +51 -0
- package/connectors/connect-mongodb/src/cli/index.ts +254 -0
- package/connectors/connect-mongodb/src/index.ts +103 -0
- package/connectors/connect-mongodb/src/types/index.ts +237 -0
- package/connectors/connect-mongodb/src/utils/auth.ts +274 -0
- package/connectors/connect-mongodb/src/utils/bulk.ts +212 -0
- package/connectors/connect-mongodb/src/utils/config.ts +326 -0
- package/connectors/connect-mongodb/src/utils/output.ts +175 -0
- package/connectors/connect-mongodb/src/utils/settings.ts +114 -0
- package/connectors/connect-mongodb/src/utils/storage.ts +198 -0
- package/connectors/connect-mongodb/tsconfig.json +16 -0
- package/connectors/connect-netlify/.env.example +11 -0
- package/connectors/connect-netlify/CLAUDE.md +170 -0
- package/connectors/connect-netlify/README.md +193 -0
- package/connectors/connect-netlify/package.json +53 -0
- package/connectors/connect-netlify/src/api/client.ts +132 -0
- package/connectors/connect-netlify/src/api/index.ts +533 -0
- package/connectors/connect-netlify/src/cli/index.ts +985 -0
- package/connectors/connect-netlify/src/index.ts +22 -0
- package/connectors/connect-netlify/src/types/index.ts +423 -0
- package/connectors/connect-netlify/src/utils/config.ts +171 -0
- package/connectors/connect-netlify/src/utils/output.ts +119 -0
- package/connectors/connect-netlify/tsconfig.json +16 -0
- package/connectors/connect-paypal/.env.example +11 -0
- package/connectors/connect-paypal/CLAUDE.md +128 -0
- package/connectors/connect-paypal/README.md +193 -0
- package/connectors/connect-paypal/package.json +51 -0
- package/connectors/connect-paypal/src/api/client.ts +182 -0
- package/connectors/connect-paypal/src/api/index.ts +235 -0
- package/connectors/connect-paypal/src/cli/index.ts +559 -0
- package/connectors/connect-paypal/src/index.ts +23 -0
- package/connectors/connect-paypal/src/types/index.ts +377 -0
- package/connectors/connect-paypal/src/utils/config.ts +125 -0
- package/connectors/connect-paypal/src/utils/output.ts +119 -0
- package/connectors/connect-paypal/tsconfig.json +16 -0
- package/connectors/connect-pinterest/.env.example +11 -0
- package/connectors/connect-pinterest/CLAUDE.md +115 -0
- package/connectors/connect-pinterest/README.md +193 -0
- package/connectors/connect-pinterest/package.json +52 -0
- package/connectors/connect-pinterest/src/api/client.ts +125 -0
- package/connectors/connect-pinterest/src/api/index.ts +203 -0
- package/connectors/connect-pinterest/src/cli/index.ts +653 -0
- package/connectors/connect-pinterest/src/index.ts +21 -0
- package/connectors/connect-pinterest/src/types/index.ts +268 -0
- package/connectors/connect-pinterest/src/utils/config.ts +157 -0
- package/connectors/connect-pinterest/src/utils/output.ts +119 -0
- package/connectors/connect-pinterest/tsconfig.json +16 -0
- package/connectors/connect-posthog/.env.example +11 -0
- package/connectors/connect-posthog/CLAUDE.md +272 -0
- package/connectors/connect-posthog/README.md +193 -0
- package/connectors/connect-posthog/package.json +51 -0
- package/connectors/connect-posthog/scripts/release.ts +179 -0
- package/connectors/connect-posthog/src/api/client.ts +213 -0
- package/connectors/connect-posthog/src/api/example.ts +48 -0
- package/connectors/connect-posthog/src/api/index.ts +51 -0
- package/connectors/connect-posthog/src/cli/index.ts +254 -0
- package/connectors/connect-posthog/src/index.ts +103 -0
- package/connectors/connect-posthog/src/types/index.ts +237 -0
- package/connectors/connect-posthog/src/utils/auth.ts +274 -0
- package/connectors/connect-posthog/src/utils/bulk.ts +212 -0
- package/connectors/connect-posthog/src/utils/config.ts +326 -0
- package/connectors/connect-posthog/src/utils/output.ts +175 -0
- package/connectors/connect-posthog/src/utils/settings.ts +114 -0
- package/connectors/connect-posthog/src/utils/storage.ts +198 -0
- package/connectors/connect-posthog/tsconfig.json +16 -0
- package/connectors/connect-salesforce/.env.example +11 -0
- package/connectors/connect-salesforce/CLAUDE.md +128 -0
- package/connectors/connect-salesforce/README.md +193 -0
- package/connectors/connect-salesforce/package.json +53 -0
- package/connectors/connect-salesforce/src/api/client.ts +150 -0
- package/connectors/connect-salesforce/src/api/index.ts +367 -0
- package/connectors/connect-salesforce/src/cli/index.ts +594 -0
- package/connectors/connect-salesforce/src/index.ts +21 -0
- package/connectors/connect-salesforce/src/types/index.ts +292 -0
- package/connectors/connect-salesforce/src/utils/config.ts +208 -0
- package/connectors/connect-salesforce/src/utils/output.ts +119 -0
- package/connectors/connect-salesforce/tsconfig.json +16 -0
- package/connectors/connect-segment/.env.example +11 -0
- package/connectors/connect-segment/CLAUDE.md +272 -0
- package/connectors/connect-segment/README.md +193 -0
- package/connectors/connect-segment/package.json +51 -0
- package/connectors/connect-segment/scripts/release.ts +179 -0
- package/connectors/connect-segment/src/api/client.ts +213 -0
- package/connectors/connect-segment/src/api/example.ts +48 -0
- package/connectors/connect-segment/src/api/index.ts +51 -0
- package/connectors/connect-segment/src/cli/index.ts +254 -0
- package/connectors/connect-segment/src/index.ts +103 -0
- package/connectors/connect-segment/src/types/index.ts +237 -0
- package/connectors/connect-segment/src/utils/auth.ts +274 -0
- package/connectors/connect-segment/src/utils/bulk.ts +212 -0
- package/connectors/connect-segment/src/utils/config.ts +326 -0
- package/connectors/connect-segment/src/utils/output.ts +175 -0
- package/connectors/connect-segment/src/utils/settings.ts +114 -0
- package/connectors/connect-segment/src/utils/storage.ts +198 -0
- package/connectors/connect-segment/tsconfig.json +16 -0
- package/connectors/connect-sendgrid/.env.example +11 -0
- package/connectors/connect-sendgrid/CLAUDE.md +125 -0
- package/connectors/connect-sendgrid/README.md +193 -0
- package/connectors/connect-sendgrid/package.json +53 -0
- package/connectors/connect-sendgrid/src/api/client.ts +137 -0
- package/connectors/connect-sendgrid/src/api/index.ts +588 -0
- package/connectors/connect-sendgrid/src/cli/index.ts +764 -0
- package/connectors/connect-sendgrid/src/index.ts +21 -0
- package/connectors/connect-sendgrid/src/types/index.ts +403 -0
- package/connectors/connect-sendgrid/src/utils/config.ts +197 -0
- package/connectors/connect-sendgrid/src/utils/output.ts +119 -0
- package/connectors/connect-sendgrid/tsconfig.json +16 -0
- package/connectors/connect-supabase/.env.example +11 -0
- package/connectors/connect-supabase/CLAUDE.md +132 -0
- package/connectors/connect-supabase/README.md +193 -0
- package/connectors/connect-supabase/package.json +52 -0
- package/connectors/connect-supabase/src/api/client.ts +231 -0
- package/connectors/connect-supabase/src/api/index.ts +439 -0
- package/connectors/connect-supabase/src/cli/index.ts +691 -0
- package/connectors/connect-supabase/src/index.ts +24 -0
- package/connectors/connect-supabase/src/types/index.ts +215 -0
- package/connectors/connect-supabase/src/utils/config.ts +219 -0
- package/connectors/connect-supabase/tsconfig.json +16 -0
- package/connectors/connect-vercel/.env.example +11 -0
- package/connectors/connect-vercel/CLAUDE.md +142 -0
- package/connectors/connect-vercel/README.md +193 -0
- package/connectors/connect-vercel/package.json +52 -0
- package/connectors/connect-vercel/src/api/client.ts +139 -0
- package/connectors/connect-vercel/src/api/index.ts +384 -0
- package/connectors/connect-vercel/src/cli/index.ts +740 -0
- package/connectors/connect-vercel/src/index.ts +24 -0
- package/connectors/connect-vercel/src/types/index.ts +350 -0
- package/connectors/connect-vercel/src/utils/config.ts +182 -0
- package/connectors/connect-vercel/src/utils/output.ts +119 -0
- package/connectors/connect-vercel/tsconfig.json +16 -0
- package/connectors/connect-zendesk/.env.example +10 -0
- package/connectors/connect-zendesk/.github/workflows/deploy.yml +51 -0
- package/connectors/connect-zendesk/CLAUDE.md +78 -0
- package/connectors/connect-zendesk/Makefile +129 -0
- package/connectors/connect-zendesk/README.md +295 -0
- package/connectors/connect-zendesk/SCAFFOLD.md +178 -0
- package/connectors/connect-zendesk/nginx-connector.conf +218 -0
- package/connectors/connect-zendesk/nginx.conf +61 -0
- package/connectors/connect-zendesk/package.json +71 -0
- package/connectors/connect-zendesk/scripts/init.sh +62 -0
- package/connectors/connect-zendesk/scripts/publish.ts +210 -0
- package/connectors/connect-zendesk/server/index.js +142 -0
- package/connectors/connect-zendesk/src/api/automations.ts +95 -0
- package/connectors/connect-zendesk/src/api/brands.ts +80 -0
- package/connectors/connect-zendesk/src/api/bulk.ts +838 -0
- package/connectors/connect-zendesk/src/api/client.test.ts +315 -0
- package/connectors/connect-zendesk/src/api/client.ts +173 -0
- package/connectors/connect-zendesk/src/api/example.ts +59 -0
- package/connectors/connect-zendesk/src/api/groups.ts +60 -0
- package/connectors/connect-zendesk/src/api/index.test.ts +111 -0
- package/connectors/connect-zendesk/src/api/index.ts +131 -0
- package/connectors/connect-zendesk/src/api/macros.ts +124 -0
- package/connectors/connect-zendesk/src/api/organizations.ts +85 -0
- package/connectors/connect-zendesk/src/api/slas.ts +80 -0
- package/connectors/connect-zendesk/src/api/ticket-fields.ts +98 -0
- package/connectors/connect-zendesk/src/api/tickets.test.ts +215 -0
- package/connectors/connect-zendesk/src/api/tickets.ts +103 -0
- package/connectors/connect-zendesk/src/api/triggers.test.ts +204 -0
- package/connectors/connect-zendesk/src/api/triggers.ts +125 -0
- package/connectors/connect-zendesk/src/api/users.test.ts +180 -0
- package/connectors/connect-zendesk/src/api/users.ts +108 -0
- package/connectors/connect-zendesk/src/api/views.test.ts +223 -0
- package/connectors/connect-zendesk/src/api/views.ts +145 -0
- package/connectors/connect-zendesk/src/api/webhooks.test.ts +208 -0
- package/connectors/connect-zendesk/src/api/webhooks.ts +118 -0
- package/connectors/connect-zendesk/src/cli/index.ts +1478 -0
- package/connectors/connect-zendesk/src/index.ts +36 -0
- package/connectors/connect-zendesk/src/server/index.ts +204 -0
- package/connectors/connect-zendesk/src/types/index.ts +910 -0
- package/connectors/connect-zendesk/src/utils/config.test.ts +193 -0
- package/connectors/connect-zendesk/src/utils/config.ts +526 -0
- package/connectors/connect-zendesk/src/utils/export.ts +338 -0
- package/connectors/connect-zendesk/src/utils/logger.ts +105 -0
- package/connectors/connect-zendesk/src/utils/output.test.ts +137 -0
- package/connectors/connect-zendesk/src/utils/output.ts +119 -0
- package/connectors/connect-zendesk/tsconfig.json +31 -0
- package/dist/index.js +175 -0
- package/package.json +1 -1
|
@@ -0,0 +1,1478 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { Zendesk } from '../api';
|
|
5
|
+
import {
|
|
6
|
+
getEmail,
|
|
7
|
+
getApiToken,
|
|
8
|
+
getBaseUrl,
|
|
9
|
+
setEmail,
|
|
10
|
+
setApiToken,
|
|
11
|
+
setBaseUrl,
|
|
12
|
+
setDefaultAccount,
|
|
13
|
+
getDefaultAccount,
|
|
14
|
+
clearConfig,
|
|
15
|
+
initConfigDir,
|
|
16
|
+
getConfigDir,
|
|
17
|
+
getBaseConfigDir,
|
|
18
|
+
getExportsDir,
|
|
19
|
+
getRemoteApiUrl,
|
|
20
|
+
setRemoteApiUrl,
|
|
21
|
+
setProfileOverride,
|
|
22
|
+
getCurrentProfile,
|
|
23
|
+
setCurrentProfile,
|
|
24
|
+
listProfiles,
|
|
25
|
+
createProfile,
|
|
26
|
+
deleteProfile,
|
|
27
|
+
profileExists,
|
|
28
|
+
isAuthenticated,
|
|
29
|
+
} from '../utils/config';
|
|
30
|
+
import type { OutputFormat } from '../utils/output';
|
|
31
|
+
import { success, error, info, print } from '../utils/output';
|
|
32
|
+
import { logger } from '../utils/logger';
|
|
33
|
+
import {
|
|
34
|
+
exportData,
|
|
35
|
+
exportTicketsToCSV,
|
|
36
|
+
exportUsersToCSV,
|
|
37
|
+
exportOrganizationsToCSV,
|
|
38
|
+
exportGroupsToCSV,
|
|
39
|
+
exportViewsToCSV,
|
|
40
|
+
exportTriggersToCSV,
|
|
41
|
+
exportAutomationsToCSV,
|
|
42
|
+
exportMacrosToCSV,
|
|
43
|
+
exportWebhooksToCSV,
|
|
44
|
+
exportBrandsToCSV,
|
|
45
|
+
} from '../utils/export';
|
|
46
|
+
|
|
47
|
+
const program = new Command();
|
|
48
|
+
|
|
49
|
+
program
|
|
50
|
+
.name('connect-zendesk')
|
|
51
|
+
.description('Zendesk API connector CLI')
|
|
52
|
+
.version('1.0.0')
|
|
53
|
+
.option('-p, --profile <name>', 'Use specific profile')
|
|
54
|
+
.option('-e, --email <email>', 'Zendesk email address')
|
|
55
|
+
.option('-t, --api-token <token>', 'Zendesk API token')
|
|
56
|
+
.option('-u, --base-url <url>', 'Zendesk base URL (e.g., https://your-subdomain.zendesk.com/api/v2)')
|
|
57
|
+
.option('-f, --format <format>', 'Output format (json, table, pretty)', 'pretty')
|
|
58
|
+
.hook('preAction', (thisCommand) => {
|
|
59
|
+
const opts = thisCommand.opts();
|
|
60
|
+
if (opts.profile) {
|
|
61
|
+
setProfileOverride(opts.profile);
|
|
62
|
+
}
|
|
63
|
+
if (opts.email) {
|
|
64
|
+
process.env.ZENDESK_EMAIL = opts.email;
|
|
65
|
+
}
|
|
66
|
+
if (opts.apiToken) {
|
|
67
|
+
process.env.ZENDESK_API_TOKEN = opts.apiToken;
|
|
68
|
+
}
|
|
69
|
+
if (opts.baseUrl) {
|
|
70
|
+
process.env.ZENDESK_BASE_URL = opts.baseUrl;
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// ============================================
|
|
75
|
+
// Init Command
|
|
76
|
+
// ============================================
|
|
77
|
+
program
|
|
78
|
+
.command('init')
|
|
79
|
+
.description('Initialize the connect-zendesk configuration directory')
|
|
80
|
+
.action(() => {
|
|
81
|
+
logger.command('init');
|
|
82
|
+
const result = initConfigDir();
|
|
83
|
+
|
|
84
|
+
if (result.created.length > 0) {
|
|
85
|
+
success('Created the following:');
|
|
86
|
+
result.created.forEach(path => info(` ${chalk.green('+')} ${path}`));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (result.existing.length > 0) {
|
|
90
|
+
info('Already exists:');
|
|
91
|
+
result.existing.forEach(path => info(` ${chalk.gray('-')} ${path}`));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
info(`\nConfiguration directory: ${getBaseConfigDir()}`);
|
|
95
|
+
info(`Current profile: ${getCurrentProfile()}`);
|
|
96
|
+
info(`Profile config: ${getConfigDir()}`);
|
|
97
|
+
info(`Exports directory: ${getExportsDir()}`);
|
|
98
|
+
success('\nRun "connect-zendesk config set-email <email>" and "connect-zendesk config set-token <token>" to configure your credentials.');
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// Helper to get Zendesk client
|
|
102
|
+
function getClient(): Zendesk {
|
|
103
|
+
const email = getEmail();
|
|
104
|
+
const apiToken = getApiToken();
|
|
105
|
+
const baseUrl = getBaseUrl();
|
|
106
|
+
|
|
107
|
+
if (!email || !apiToken) {
|
|
108
|
+
error('Email and API token are required. Run "connect-zendesk config set-email <email>" and "connect-zendesk config set-token <token>" or set ZENDESK_EMAIL and ZENDESK_API_TOKEN environment variables.');
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return new Zendesk({ email, apiToken, baseUrl });
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Helper to get output format
|
|
116
|
+
function getFormat(cmd: Command): OutputFormat {
|
|
117
|
+
const parent = cmd.parent;
|
|
118
|
+
return (parent?.opts().format || 'pretty') as OutputFormat;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// ============================================
|
|
122
|
+
// Profile Commands
|
|
123
|
+
// ============================================
|
|
124
|
+
const profileCmd = program
|
|
125
|
+
.command('profile')
|
|
126
|
+
.description('Manage profiles for multiple Zendesk accounts');
|
|
127
|
+
|
|
128
|
+
profileCmd
|
|
129
|
+
.command('list')
|
|
130
|
+
.description('List all profiles')
|
|
131
|
+
.action(() => {
|
|
132
|
+
const profiles = listProfiles();
|
|
133
|
+
const current = getCurrentProfile();
|
|
134
|
+
|
|
135
|
+
if (profiles.length === 0) {
|
|
136
|
+
info('No profiles found. Using default.');
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
info('Profiles:');
|
|
141
|
+
profiles.forEach(p => {
|
|
142
|
+
const marker = p === current ? chalk.green(' (active)') : '';
|
|
143
|
+
console.log(` ${p}${marker}`);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
profileCmd
|
|
148
|
+
.command('use <name>')
|
|
149
|
+
.description('Switch to a profile')
|
|
150
|
+
.action((name: string) => {
|
|
151
|
+
if (!profileExists(name)) {
|
|
152
|
+
error(`Profile "${name}" does not exist`);
|
|
153
|
+
process.exit(1);
|
|
154
|
+
}
|
|
155
|
+
setCurrentProfile(name);
|
|
156
|
+
success(`Switched to profile "${name}"`);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
profileCmd
|
|
160
|
+
.command('create <name>')
|
|
161
|
+
.description('Create a new profile')
|
|
162
|
+
.action((name: string) => {
|
|
163
|
+
try {
|
|
164
|
+
createProfile(name);
|
|
165
|
+
success(`Profile "${name}" created`);
|
|
166
|
+
info(`Switch to it with: connect-zendesk profile use ${name}`);
|
|
167
|
+
} catch (e) {
|
|
168
|
+
error((e as Error).message);
|
|
169
|
+
process.exit(1);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
profileCmd
|
|
174
|
+
.command('delete <name>')
|
|
175
|
+
.description('Delete a profile')
|
|
176
|
+
.action((name: string) => {
|
|
177
|
+
try {
|
|
178
|
+
deleteProfile(name);
|
|
179
|
+
success(`Profile "${name}" deleted`);
|
|
180
|
+
} catch (e) {
|
|
181
|
+
error((e as Error).message);
|
|
182
|
+
process.exit(1);
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
profileCmd
|
|
187
|
+
.command('show')
|
|
188
|
+
.description('Show current profile name and info')
|
|
189
|
+
.action(() => {
|
|
190
|
+
const profile = getCurrentProfile();
|
|
191
|
+
const email = getEmail();
|
|
192
|
+
const baseUrl = getBaseUrl();
|
|
193
|
+
|
|
194
|
+
info(`Current profile: ${chalk.cyan(profile)}`);
|
|
195
|
+
info(`Email: ${email || chalk.gray('not set')}`);
|
|
196
|
+
info(`Base URL: ${baseUrl || chalk.gray('not set')}`);
|
|
197
|
+
info(`Authenticated: ${isAuthenticated() ? chalk.green('yes') : chalk.red('no')}`);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
// ============================================
|
|
201
|
+
// Config Commands
|
|
202
|
+
// ============================================
|
|
203
|
+
const configCmd = program
|
|
204
|
+
.command('config')
|
|
205
|
+
.description('Manage CLI configuration');
|
|
206
|
+
|
|
207
|
+
configCmd
|
|
208
|
+
.command('set-email <email>')
|
|
209
|
+
.description('Set Zendesk email address')
|
|
210
|
+
.action((email: string) => {
|
|
211
|
+
setEmail(email);
|
|
212
|
+
success(`Email saved to profile "${getCurrentProfile()}"`);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
configCmd
|
|
216
|
+
.command('set-token <apiToken>')
|
|
217
|
+
.description('Set Zendesk API token')
|
|
218
|
+
.action((apiToken: string) => {
|
|
219
|
+
setApiToken(apiToken);
|
|
220
|
+
success(`API token saved to profile "${getCurrentProfile()}"`);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
configCmd
|
|
224
|
+
.command('set-base-url <baseUrl>')
|
|
225
|
+
.description('Set Zendesk base URL (e.g., https://your-subdomain.zendesk.com/api/v2)')
|
|
226
|
+
.action((baseUrl: string) => {
|
|
227
|
+
setBaseUrl(baseUrl);
|
|
228
|
+
success(`Base URL saved to profile "${getCurrentProfile()}"`);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
configCmd
|
|
232
|
+
.command('set-account <account>')
|
|
233
|
+
.description('Set default account')
|
|
234
|
+
.action((account: string) => {
|
|
235
|
+
setDefaultAccount(account);
|
|
236
|
+
success(`Default account set to: ${account}`);
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
configCmd
|
|
240
|
+
.command('set-remote-url <url>')
|
|
241
|
+
.description('Set remote API URL (default: https://connect.hasna.com/zendesk)')
|
|
242
|
+
.action((url: string) => {
|
|
243
|
+
setRemoteApiUrl(url);
|
|
244
|
+
success(`Remote API URL set to: ${url}`);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
configCmd
|
|
248
|
+
.command('show')
|
|
249
|
+
.description('Show current configuration')
|
|
250
|
+
.action(() => {
|
|
251
|
+
const profile = getCurrentProfile();
|
|
252
|
+
const email = getEmail();
|
|
253
|
+
const apiToken = getApiToken();
|
|
254
|
+
const baseUrl = getBaseUrl();
|
|
255
|
+
const account = getDefaultAccount();
|
|
256
|
+
const remoteUrl = getRemoteApiUrl();
|
|
257
|
+
info(`Profile: ${chalk.cyan(profile)}`);
|
|
258
|
+
info(`Email: ${email || chalk.gray('not set')}`);
|
|
259
|
+
info(`API Token: ${apiToken ? `${apiToken.substring(0, 6)}...${apiToken.substring(apiToken.length - 4)}` : chalk.gray('not set')}`);
|
|
260
|
+
info(`Base URL: ${baseUrl || chalk.gray('not set')}`);
|
|
261
|
+
info(`Default Account: ${account || chalk.gray('not set')}`);
|
|
262
|
+
info(`Remote API URL: ${remoteUrl}`);
|
|
263
|
+
info(`Config Directory: ${getBaseConfigDir()}`);
|
|
264
|
+
info(`Profile Config: ${getConfigDir()}`);
|
|
265
|
+
info(`Exports Directory: ${getExportsDir()}`);
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
configCmd
|
|
269
|
+
.command('clear')
|
|
270
|
+
.description('Clear all configuration for current profile')
|
|
271
|
+
.action(() => {
|
|
272
|
+
clearConfig();
|
|
273
|
+
success(`Configuration cleared for profile "${getCurrentProfile()}"`);
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
// ============================================
|
|
277
|
+
// Remote API Commands (connect.hasna.com)
|
|
278
|
+
// ============================================
|
|
279
|
+
const remoteCmd = program
|
|
280
|
+
.command('remote')
|
|
281
|
+
.description('Interact with the remote Zendesk connector API');
|
|
282
|
+
|
|
283
|
+
remoteCmd
|
|
284
|
+
.command('status')
|
|
285
|
+
.description('Check remote API status')
|
|
286
|
+
.action(async () => {
|
|
287
|
+
const remoteUrl = getRemoteApiUrl();
|
|
288
|
+
logger.command('remote status', { remoteUrl });
|
|
289
|
+
try {
|
|
290
|
+
const response = await fetch(`${remoteUrl}/status`);
|
|
291
|
+
const data = await response.json();
|
|
292
|
+
print(data, getFormat(remoteCmd));
|
|
293
|
+
} catch (err) {
|
|
294
|
+
error(`Failed to connect to remote API at ${remoteUrl}: ${String(err)}`);
|
|
295
|
+
logger.error('Remote status check failed', { remoteUrl, error: String(err) });
|
|
296
|
+
process.exit(1);
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
remoteCmd
|
|
301
|
+
.command('health')
|
|
302
|
+
.description('Check remote API health')
|
|
303
|
+
.action(async () => {
|
|
304
|
+
const remoteUrl = getRemoteApiUrl();
|
|
305
|
+
logger.command('remote health', { remoteUrl });
|
|
306
|
+
try {
|
|
307
|
+
const response = await fetch(`${remoteUrl}/health`);
|
|
308
|
+
if (response.ok) {
|
|
309
|
+
success(`Remote API at ${remoteUrl} is healthy`);
|
|
310
|
+
} else {
|
|
311
|
+
error(`Remote API returned status: ${response.status}`);
|
|
312
|
+
}
|
|
313
|
+
} catch (err) {
|
|
314
|
+
error(`Failed to connect to remote API at ${remoteUrl}: ${String(err)}`);
|
|
315
|
+
logger.error('Remote health check failed', { remoteUrl, error: String(err) });
|
|
316
|
+
process.exit(1);
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
remoteCmd
|
|
321
|
+
.command('url')
|
|
322
|
+
.description('Show current remote API URL')
|
|
323
|
+
.action(() => {
|
|
324
|
+
info(`Remote API URL: ${getRemoteApiUrl()}`);
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
// ============================================
|
|
328
|
+
// Tickets Commands
|
|
329
|
+
// ============================================
|
|
330
|
+
const ticketsCmd = program
|
|
331
|
+
.command('tickets')
|
|
332
|
+
.description('Manage Zendesk tickets');
|
|
333
|
+
|
|
334
|
+
ticketsCmd
|
|
335
|
+
.command('list')
|
|
336
|
+
.description('List tickets')
|
|
337
|
+
.option('-p, --page <page>', 'Page number')
|
|
338
|
+
.option('-l, --per-page <perPage>', 'Items per page')
|
|
339
|
+
.option('-s, --sort-by <sortBy>', 'Sort by field (created_at, updated_at, priority, status, ticket_type)')
|
|
340
|
+
.option('-o, --sort-order <sortOrder>', 'Sort order (asc, desc)')
|
|
341
|
+
.action(async (opts) => {
|
|
342
|
+
try {
|
|
343
|
+
const client = getClient();
|
|
344
|
+
const tickets = await client.tickets.list({
|
|
345
|
+
page: opts.page ? parseInt(opts.page) : undefined,
|
|
346
|
+
per_page: opts.perPage ? parseInt(opts.perPage) : undefined,
|
|
347
|
+
sort_by: opts.sortBy,
|
|
348
|
+
sort_order: opts.sortOrder,
|
|
349
|
+
});
|
|
350
|
+
print(tickets, getFormat(ticketsCmd));
|
|
351
|
+
} catch (err) {
|
|
352
|
+
error(String(err));
|
|
353
|
+
process.exit(1);
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
ticketsCmd
|
|
358
|
+
.command('get <id>')
|
|
359
|
+
.description('Get ticket by ID')
|
|
360
|
+
.action(async (id: string) => {
|
|
361
|
+
try {
|
|
362
|
+
const client = getClient();
|
|
363
|
+
const ticket = await client.tickets.get(parseInt(id));
|
|
364
|
+
print(ticket, getFormat(ticketsCmd));
|
|
365
|
+
} catch (err) {
|
|
366
|
+
error(String(err));
|
|
367
|
+
process.exit(1);
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
ticketsCmd
|
|
372
|
+
.command('create')
|
|
373
|
+
.description('Create a new ticket')
|
|
374
|
+
.requiredOption('-s, --subject <subject>', 'Ticket subject')
|
|
375
|
+
.requiredOption('-b, --body <body>', 'Ticket description')
|
|
376
|
+
.option('-p, --priority <priority>', 'Priority (urgent, high, normal, low)')
|
|
377
|
+
.option('-t, --type <type>', 'Type (problem, incident, question, task)')
|
|
378
|
+
.option('--requester-id <requesterId>', 'Requester user ID')
|
|
379
|
+
.option('--assignee-id <assigneeId>', 'Assignee user ID')
|
|
380
|
+
.action(async (opts) => {
|
|
381
|
+
try {
|
|
382
|
+
const client = getClient();
|
|
383
|
+
const ticket = await client.tickets.create({
|
|
384
|
+
ticket: {
|
|
385
|
+
subject: opts.subject,
|
|
386
|
+
comment: { body: opts.body },
|
|
387
|
+
priority: opts.priority,
|
|
388
|
+
type: opts.type,
|
|
389
|
+
requester_id: opts.requesterId ? parseInt(opts.requesterId) : undefined,
|
|
390
|
+
assignee_id: opts.assigneeId ? parseInt(opts.assigneeId) : undefined,
|
|
391
|
+
},
|
|
392
|
+
});
|
|
393
|
+
success('Ticket created successfully');
|
|
394
|
+
print(ticket, getFormat(ticketsCmd));
|
|
395
|
+
} catch (err) {
|
|
396
|
+
error(String(err));
|
|
397
|
+
process.exit(1);
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
ticketsCmd
|
|
402
|
+
.command('update <id>')
|
|
403
|
+
.description('Update a ticket')
|
|
404
|
+
.option('-s, --subject <subject>', 'Ticket subject')
|
|
405
|
+
.option('-p, --priority <priority>', 'Priority (urgent, high, normal, low)')
|
|
406
|
+
.option('--status <status>', 'Status (new, open, pending, hold, solved, closed)')
|
|
407
|
+
.option('-c, --comment <comment>', 'Add a comment')
|
|
408
|
+
.action(async (id: string, opts) => {
|
|
409
|
+
try {
|
|
410
|
+
const client = getClient();
|
|
411
|
+
const updateData: any = { ticket: {} };
|
|
412
|
+
|
|
413
|
+
if (opts.subject) updateData.ticket.subject = opts.subject;
|
|
414
|
+
if (opts.priority) updateData.ticket.priority = opts.priority;
|
|
415
|
+
if (opts.status) updateData.ticket.status = opts.status;
|
|
416
|
+
if (opts.comment) updateData.ticket.comment = { body: opts.comment };
|
|
417
|
+
|
|
418
|
+
const ticket = await client.tickets.update(parseInt(id), updateData);
|
|
419
|
+
success('Ticket updated successfully');
|
|
420
|
+
print(ticket, getFormat(ticketsCmd));
|
|
421
|
+
} catch (err) {
|
|
422
|
+
error(String(err));
|
|
423
|
+
process.exit(1);
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
ticketsCmd
|
|
428
|
+
.command('delete <id>')
|
|
429
|
+
.description('Delete a ticket')
|
|
430
|
+
.action(async (id: string) => {
|
|
431
|
+
try {
|
|
432
|
+
const client = getClient();
|
|
433
|
+
await client.tickets.delete(parseInt(id));
|
|
434
|
+
success(`Ticket ${id} deleted successfully`);
|
|
435
|
+
} catch (err) {
|
|
436
|
+
error(String(err));
|
|
437
|
+
process.exit(1);
|
|
438
|
+
}
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
ticketsCmd
|
|
442
|
+
.command('export')
|
|
443
|
+
.description('Export tickets to CSV or JSON')
|
|
444
|
+
.option('-f, --format <format>', 'Export format (csv, json)', 'csv')
|
|
445
|
+
.option('-o, --output <filename>', 'Output filename', 'tickets')
|
|
446
|
+
.option('-l, --limit <limit>', 'Maximum number of tickets to export')
|
|
447
|
+
.action(async (opts) => {
|
|
448
|
+
try {
|
|
449
|
+
const client = getClient();
|
|
450
|
+
logger.command('tickets export', { format: opts.format, output: opts.output });
|
|
451
|
+
info('Fetching tickets...');
|
|
452
|
+
|
|
453
|
+
const allTickets: unknown[] = [];
|
|
454
|
+
let page = 1;
|
|
455
|
+
const limit = opts.limit ? parseInt(opts.limit) : undefined;
|
|
456
|
+
|
|
457
|
+
while (true) {
|
|
458
|
+
const response = await client.tickets.list({ page, per_page: 100 });
|
|
459
|
+
allTickets.push(...response.tickets);
|
|
460
|
+
|
|
461
|
+
if (limit && allTickets.length >= limit) {
|
|
462
|
+
allTickets.splice(limit);
|
|
463
|
+
break;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
if (!response.next_page) break;
|
|
467
|
+
page++;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
const filepath = exportData(allTickets, opts.output, opts.format);
|
|
471
|
+
logger.export('tickets', opts.format, filepath, allTickets.length);
|
|
472
|
+
success(`Exported ${allTickets.length} tickets to ${filepath}`);
|
|
473
|
+
} catch (err) {
|
|
474
|
+
error(String(err));
|
|
475
|
+
logger.error('Tickets export failed', { error: String(err) });
|
|
476
|
+
process.exit(1);
|
|
477
|
+
}
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
// ============================================
|
|
481
|
+
// Users Commands
|
|
482
|
+
// ============================================
|
|
483
|
+
const usersCmd = program
|
|
484
|
+
.command('users')
|
|
485
|
+
.description('Manage Zendesk users');
|
|
486
|
+
|
|
487
|
+
usersCmd
|
|
488
|
+
.command('list')
|
|
489
|
+
.description('List users')
|
|
490
|
+
.option('-p, --page <page>', 'Page number')
|
|
491
|
+
.option('-l, --per-page <perPage>', 'Items per page')
|
|
492
|
+
.option('-r, --role <role>', 'Filter by role (end-user, agent, admin)')
|
|
493
|
+
.action(async (opts) => {
|
|
494
|
+
try {
|
|
495
|
+
const client = getClient();
|
|
496
|
+
const users = await client.users.list({
|
|
497
|
+
page: opts.page ? parseInt(opts.page) : undefined,
|
|
498
|
+
per_page: opts.perPage ? parseInt(opts.perPage) : undefined,
|
|
499
|
+
role: opts.role,
|
|
500
|
+
});
|
|
501
|
+
print(users, getFormat(usersCmd));
|
|
502
|
+
} catch (err) {
|
|
503
|
+
error(String(err));
|
|
504
|
+
process.exit(1);
|
|
505
|
+
}
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
usersCmd
|
|
509
|
+
.command('get <id>')
|
|
510
|
+
.description('Get user by ID')
|
|
511
|
+
.action(async (id: string) => {
|
|
512
|
+
try {
|
|
513
|
+
const client = getClient();
|
|
514
|
+
const user = await client.users.get(parseInt(id));
|
|
515
|
+
print(user, getFormat(usersCmd));
|
|
516
|
+
} catch (err) {
|
|
517
|
+
error(String(err));
|
|
518
|
+
process.exit(1);
|
|
519
|
+
}
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
usersCmd
|
|
523
|
+
.command('me')
|
|
524
|
+
.description('Get current authenticated user')
|
|
525
|
+
.action(async () => {
|
|
526
|
+
try {
|
|
527
|
+
const client = getClient();
|
|
528
|
+
const user = await client.users.me();
|
|
529
|
+
print(user, getFormat(usersCmd));
|
|
530
|
+
} catch (err) {
|
|
531
|
+
error(String(err));
|
|
532
|
+
process.exit(1);
|
|
533
|
+
}
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
usersCmd
|
|
537
|
+
.command('create')
|
|
538
|
+
.description('Create a new user')
|
|
539
|
+
.requiredOption('-n, --name <name>', 'User name')
|
|
540
|
+
.option('-e, --email <email>', 'User email')
|
|
541
|
+
.option('-r, --role <role>', 'User role (end-user, agent, admin)')
|
|
542
|
+
.action(async (opts) => {
|
|
543
|
+
try {
|
|
544
|
+
const client = getClient();
|
|
545
|
+
const user = await client.users.create({
|
|
546
|
+
user: {
|
|
547
|
+
name: opts.name,
|
|
548
|
+
email: opts.email,
|
|
549
|
+
role: opts.role,
|
|
550
|
+
},
|
|
551
|
+
});
|
|
552
|
+
success('User created successfully');
|
|
553
|
+
print(user, getFormat(usersCmd));
|
|
554
|
+
} catch (err) {
|
|
555
|
+
error(String(err));
|
|
556
|
+
process.exit(1);
|
|
557
|
+
}
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
usersCmd
|
|
561
|
+
.command('search')
|
|
562
|
+
.description('Search users by email or name')
|
|
563
|
+
.requiredOption('-q, --query <query>', 'Search query (email or name)')
|
|
564
|
+
.action(async (opts) => {
|
|
565
|
+
try {
|
|
566
|
+
const client = getClient();
|
|
567
|
+
const users = await client.users.searchByEmail(opts.query);
|
|
568
|
+
print(users, getFormat(usersCmd));
|
|
569
|
+
} catch (err) {
|
|
570
|
+
error(String(err));
|
|
571
|
+
process.exit(1);
|
|
572
|
+
}
|
|
573
|
+
});
|
|
574
|
+
|
|
575
|
+
usersCmd
|
|
576
|
+
.command('export')
|
|
577
|
+
.description('Export users to CSV or JSON')
|
|
578
|
+
.option('-f, --format <format>', 'Export format (csv, json)', 'csv')
|
|
579
|
+
.option('-o, --output <filename>', 'Output filename', 'users')
|
|
580
|
+
.option('-l, --limit <limit>', 'Maximum number of users to export')
|
|
581
|
+
.option('-r, --role <role>', 'Filter by role (end-user, agent, admin)')
|
|
582
|
+
.action(async (opts) => {
|
|
583
|
+
try {
|
|
584
|
+
const client = getClient();
|
|
585
|
+
logger.command('users export', { format: opts.format, output: opts.output, role: opts.role });
|
|
586
|
+
info('Fetching users...');
|
|
587
|
+
|
|
588
|
+
const allUsers: unknown[] = [];
|
|
589
|
+
let page = 1;
|
|
590
|
+
const limit = opts.limit ? parseInt(opts.limit) : undefined;
|
|
591
|
+
|
|
592
|
+
while (true) {
|
|
593
|
+
const response = await client.users.list({ page, per_page: 100, role: opts.role });
|
|
594
|
+
allUsers.push(...response.users);
|
|
595
|
+
|
|
596
|
+
if (limit && allUsers.length >= limit) {
|
|
597
|
+
allUsers.splice(limit);
|
|
598
|
+
break;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
if (!response.next_page) break;
|
|
602
|
+
page++;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
const filepath = exportData(allUsers, opts.output, opts.format);
|
|
606
|
+
logger.export('users', opts.format, filepath, allUsers.length);
|
|
607
|
+
success(`Exported ${allUsers.length} users to ${filepath}`);
|
|
608
|
+
} catch (err) {
|
|
609
|
+
error(String(err));
|
|
610
|
+
logger.error('Users export failed', { error: String(err) });
|
|
611
|
+
process.exit(1);
|
|
612
|
+
}
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
// ============================================
|
|
616
|
+
// Organizations Commands
|
|
617
|
+
// ============================================
|
|
618
|
+
const organizationsCmd = program
|
|
619
|
+
.command('organizations')
|
|
620
|
+
.alias('orgs')
|
|
621
|
+
.description('Manage Zendesk organizations');
|
|
622
|
+
|
|
623
|
+
organizationsCmd
|
|
624
|
+
.command('list')
|
|
625
|
+
.description('List organizations')
|
|
626
|
+
.option('-p, --page <page>', 'Page number')
|
|
627
|
+
.option('-l, --per-page <perPage>', 'Items per page')
|
|
628
|
+
.action(async (opts) => {
|
|
629
|
+
try {
|
|
630
|
+
const client = getClient();
|
|
631
|
+
const organizations = await client.organizations.list({
|
|
632
|
+
page: opts.page ? parseInt(opts.page) : undefined,
|
|
633
|
+
per_page: opts.perPage ? parseInt(opts.perPage) : undefined,
|
|
634
|
+
});
|
|
635
|
+
print(organizations, getFormat(organizationsCmd));
|
|
636
|
+
} catch (err) {
|
|
637
|
+
error(String(err));
|
|
638
|
+
process.exit(1);
|
|
639
|
+
}
|
|
640
|
+
});
|
|
641
|
+
|
|
642
|
+
organizationsCmd
|
|
643
|
+
.command('get <id>')
|
|
644
|
+
.description('Get organization by ID')
|
|
645
|
+
.action(async (id: string) => {
|
|
646
|
+
try {
|
|
647
|
+
const client = getClient();
|
|
648
|
+
const organization = await client.organizations.get(parseInt(id));
|
|
649
|
+
print(organization, getFormat(organizationsCmd));
|
|
650
|
+
} catch (err) {
|
|
651
|
+
error(String(err));
|
|
652
|
+
process.exit(1);
|
|
653
|
+
}
|
|
654
|
+
});
|
|
655
|
+
|
|
656
|
+
organizationsCmd
|
|
657
|
+
.command('create')
|
|
658
|
+
.description('Create a new organization')
|
|
659
|
+
.requiredOption('-n, --name <name>', 'Organization name')
|
|
660
|
+
.option('-d, --details <details>', 'Organization details')
|
|
661
|
+
.action(async (opts) => {
|
|
662
|
+
try {
|
|
663
|
+
const client = getClient();
|
|
664
|
+
const organization = await client.organizations.create({
|
|
665
|
+
organization: {
|
|
666
|
+
name: opts.name,
|
|
667
|
+
details: opts.details,
|
|
668
|
+
},
|
|
669
|
+
});
|
|
670
|
+
success('Organization created successfully');
|
|
671
|
+
print(organization, getFormat(organizationsCmd));
|
|
672
|
+
} catch (err) {
|
|
673
|
+
error(String(err));
|
|
674
|
+
process.exit(1);
|
|
675
|
+
}
|
|
676
|
+
});
|
|
677
|
+
|
|
678
|
+
organizationsCmd
|
|
679
|
+
.command('search')
|
|
680
|
+
.description('Search organizations by name')
|
|
681
|
+
.requiredOption('-q, --query <query>', 'Search query (organization name)')
|
|
682
|
+
.action(async (opts) => {
|
|
683
|
+
try {
|
|
684
|
+
const client = getClient();
|
|
685
|
+
const organizations = await client.organizations.search(opts.query);
|
|
686
|
+
print(organizations, getFormat(organizationsCmd));
|
|
687
|
+
} catch (err) {
|
|
688
|
+
error(String(err));
|
|
689
|
+
process.exit(1);
|
|
690
|
+
}
|
|
691
|
+
});
|
|
692
|
+
|
|
693
|
+
organizationsCmd
|
|
694
|
+
.command('export')
|
|
695
|
+
.description('Export organizations to CSV or JSON')
|
|
696
|
+
.option('-f, --format <format>', 'Export format (csv, json)', 'csv')
|
|
697
|
+
.option('-o, --output <filename>', 'Output filename', 'organizations')
|
|
698
|
+
.option('-l, --limit <limit>', 'Maximum number of organizations to export')
|
|
699
|
+
.action(async (opts) => {
|
|
700
|
+
try {
|
|
701
|
+
const client = getClient();
|
|
702
|
+
logger.command('organizations export', { format: opts.format, output: opts.output });
|
|
703
|
+
info('Fetching organizations...');
|
|
704
|
+
|
|
705
|
+
const allOrgs: unknown[] = [];
|
|
706
|
+
let page = 1;
|
|
707
|
+
const limit = opts.limit ? parseInt(opts.limit) : undefined;
|
|
708
|
+
|
|
709
|
+
while (true) {
|
|
710
|
+
const response = await client.organizations.list({ page, per_page: 100 });
|
|
711
|
+
allOrgs.push(...response.organizations);
|
|
712
|
+
|
|
713
|
+
if (limit && allOrgs.length >= limit) {
|
|
714
|
+
allOrgs.splice(limit);
|
|
715
|
+
break;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
if (!response.next_page) break;
|
|
719
|
+
page++;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
const filepath = exportData(allOrgs, opts.output, opts.format);
|
|
723
|
+
logger.export('organizations', opts.format, filepath, allOrgs.length);
|
|
724
|
+
success(`Exported ${allOrgs.length} organizations to ${filepath}`);
|
|
725
|
+
} catch (err) {
|
|
726
|
+
error(String(err));
|
|
727
|
+
logger.error('Organizations export failed', { error: String(err) });
|
|
728
|
+
process.exit(1);
|
|
729
|
+
}
|
|
730
|
+
});
|
|
731
|
+
|
|
732
|
+
// ============================================
|
|
733
|
+
// Groups Commands
|
|
734
|
+
// ============================================
|
|
735
|
+
const groupsCmd = program
|
|
736
|
+
.command('groups')
|
|
737
|
+
.description('Manage Zendesk groups');
|
|
738
|
+
|
|
739
|
+
groupsCmd
|
|
740
|
+
.command('list')
|
|
741
|
+
.description('List groups')
|
|
742
|
+
.option('-p, --page <page>', 'Page number')
|
|
743
|
+
.option('-l, --per-page <perPage>', 'Items per page')
|
|
744
|
+
.action(async (opts) => {
|
|
745
|
+
try {
|
|
746
|
+
const client = getClient();
|
|
747
|
+
const groups = await client.groups.list({
|
|
748
|
+
page: opts.page ? parseInt(opts.page) : undefined,
|
|
749
|
+
per_page: opts.perPage ? parseInt(opts.perPage) : undefined,
|
|
750
|
+
});
|
|
751
|
+
print(groups, getFormat(groupsCmd));
|
|
752
|
+
} catch (err) {
|
|
753
|
+
error(String(err));
|
|
754
|
+
process.exit(1);
|
|
755
|
+
}
|
|
756
|
+
});
|
|
757
|
+
|
|
758
|
+
groupsCmd
|
|
759
|
+
.command('get <id>')
|
|
760
|
+
.description('Get group by ID')
|
|
761
|
+
.action(async (id: string) => {
|
|
762
|
+
try {
|
|
763
|
+
const client = getClient();
|
|
764
|
+
const group = await client.groups.get(parseInt(id));
|
|
765
|
+
print(group, getFormat(groupsCmd));
|
|
766
|
+
} catch (err) {
|
|
767
|
+
error(String(err));
|
|
768
|
+
process.exit(1);
|
|
769
|
+
}
|
|
770
|
+
});
|
|
771
|
+
|
|
772
|
+
groupsCmd
|
|
773
|
+
.command('export')
|
|
774
|
+
.description('Export groups to CSV or JSON')
|
|
775
|
+
.option('-f, --format <format>', 'Export format (csv, json)', 'csv')
|
|
776
|
+
.option('-o, --output <filename>', 'Output filename', 'groups')
|
|
777
|
+
.action(async (opts) => {
|
|
778
|
+
try {
|
|
779
|
+
const client = getClient();
|
|
780
|
+
logger.command('groups export', { format: opts.format, output: opts.output });
|
|
781
|
+
info('Fetching groups...');
|
|
782
|
+
|
|
783
|
+
const allGroups: unknown[] = [];
|
|
784
|
+
let page = 1;
|
|
785
|
+
|
|
786
|
+
while (true) {
|
|
787
|
+
const response = await client.groups.list({ page, per_page: 100 });
|
|
788
|
+
allGroups.push(...response.groups);
|
|
789
|
+
|
|
790
|
+
if (!response.next_page) break;
|
|
791
|
+
page++;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
const filepath = exportData(allGroups, opts.output, opts.format);
|
|
795
|
+
logger.export('groups', opts.format, filepath, allGroups.length);
|
|
796
|
+
success(`Exported ${allGroups.length} groups to ${filepath}`);
|
|
797
|
+
} catch (err) {
|
|
798
|
+
error(String(err));
|
|
799
|
+
logger.error('Groups export failed', { error: String(err) });
|
|
800
|
+
process.exit(1);
|
|
801
|
+
}
|
|
802
|
+
});
|
|
803
|
+
|
|
804
|
+
// ============================================
|
|
805
|
+
// Views Commands
|
|
806
|
+
// ============================================
|
|
807
|
+
const viewsCmd = program
|
|
808
|
+
.command('views')
|
|
809
|
+
.description('Manage Zendesk views');
|
|
810
|
+
|
|
811
|
+
viewsCmd
|
|
812
|
+
.command('list')
|
|
813
|
+
.description('List views')
|
|
814
|
+
.option('-a, --active', 'Only show active views')
|
|
815
|
+
.action(async (opts) => {
|
|
816
|
+
try {
|
|
817
|
+
const client = getClient();
|
|
818
|
+
const views = opts.active
|
|
819
|
+
? await client.views.listActive()
|
|
820
|
+
: await client.views.list();
|
|
821
|
+
print(views, getFormat(viewsCmd));
|
|
822
|
+
} catch (err) {
|
|
823
|
+
error(String(err));
|
|
824
|
+
process.exit(1);
|
|
825
|
+
}
|
|
826
|
+
});
|
|
827
|
+
|
|
828
|
+
viewsCmd
|
|
829
|
+
.command('get <id>')
|
|
830
|
+
.description('Get view by ID')
|
|
831
|
+
.action(async (id: string) => {
|
|
832
|
+
try {
|
|
833
|
+
const client = getClient();
|
|
834
|
+
const view = await client.views.get(parseInt(id));
|
|
835
|
+
print(view, getFormat(viewsCmd));
|
|
836
|
+
} catch (err) {
|
|
837
|
+
error(String(err));
|
|
838
|
+
process.exit(1);
|
|
839
|
+
}
|
|
840
|
+
});
|
|
841
|
+
|
|
842
|
+
viewsCmd
|
|
843
|
+
.command('export')
|
|
844
|
+
.description('Export views to CSV or JSON')
|
|
845
|
+
.option('-f, --format <format>', 'Export format (csv, json)', 'csv')
|
|
846
|
+
.option('-o, --output <filename>', 'Output filename', 'views')
|
|
847
|
+
.action(async (opts) => {
|
|
848
|
+
try {
|
|
849
|
+
const client = getClient();
|
|
850
|
+
logger.command('views export', { format: opts.format, output: opts.output });
|
|
851
|
+
info('Fetching views...');
|
|
852
|
+
|
|
853
|
+
const response = await client.views.list();
|
|
854
|
+
const filepath = exportData(response.views, opts.output, opts.format);
|
|
855
|
+
logger.export('views', opts.format, filepath, response.views.length);
|
|
856
|
+
success(`Exported ${response.views.length} views to ${filepath}`);
|
|
857
|
+
} catch (err) {
|
|
858
|
+
error(String(err));
|
|
859
|
+
logger.error('Views export failed', { error: String(err) });
|
|
860
|
+
process.exit(1);
|
|
861
|
+
}
|
|
862
|
+
});
|
|
863
|
+
|
|
864
|
+
// ============================================
|
|
865
|
+
// Triggers Commands
|
|
866
|
+
// ============================================
|
|
867
|
+
const triggersCmd = program
|
|
868
|
+
.command('triggers')
|
|
869
|
+
.description('Manage Zendesk triggers');
|
|
870
|
+
|
|
871
|
+
triggersCmd
|
|
872
|
+
.command('list')
|
|
873
|
+
.description('List triggers')
|
|
874
|
+
.option('-a, --active', 'Only show active triggers')
|
|
875
|
+
.action(async (opts) => {
|
|
876
|
+
try {
|
|
877
|
+
const client = getClient();
|
|
878
|
+
const triggers = opts.active
|
|
879
|
+
? await client.triggers.listActive()
|
|
880
|
+
: await client.triggers.list();
|
|
881
|
+
print(triggers, getFormat(triggersCmd));
|
|
882
|
+
} catch (err) {
|
|
883
|
+
error(String(err));
|
|
884
|
+
process.exit(1);
|
|
885
|
+
}
|
|
886
|
+
});
|
|
887
|
+
|
|
888
|
+
triggersCmd
|
|
889
|
+
.command('get <id>')
|
|
890
|
+
.description('Get trigger by ID')
|
|
891
|
+
.action(async (id: string) => {
|
|
892
|
+
try {
|
|
893
|
+
const client = getClient();
|
|
894
|
+
const trigger = await client.triggers.get(parseInt(id));
|
|
895
|
+
print(trigger, getFormat(triggersCmd));
|
|
896
|
+
} catch (err) {
|
|
897
|
+
error(String(err));
|
|
898
|
+
process.exit(1);
|
|
899
|
+
}
|
|
900
|
+
});
|
|
901
|
+
|
|
902
|
+
triggersCmd
|
|
903
|
+
.command('export')
|
|
904
|
+
.description('Export triggers to CSV or JSON')
|
|
905
|
+
.option('-f, --format <format>', 'Export format (csv, json)', 'csv')
|
|
906
|
+
.option('-o, --output <filename>', 'Output filename', 'triggers')
|
|
907
|
+
.action(async (opts) => {
|
|
908
|
+
try {
|
|
909
|
+
const client = getClient();
|
|
910
|
+
logger.command('triggers export', { format: opts.format, output: opts.output });
|
|
911
|
+
info('Fetching triggers...');
|
|
912
|
+
|
|
913
|
+
const response = await client.triggers.list();
|
|
914
|
+
const filepath = exportData(response.triggers, opts.output, opts.format);
|
|
915
|
+
logger.export('triggers', opts.format, filepath, response.triggers.length);
|
|
916
|
+
success(`Exported ${response.triggers.length} triggers to ${filepath}`);
|
|
917
|
+
} catch (err) {
|
|
918
|
+
error(String(err));
|
|
919
|
+
logger.error('Triggers export failed', { error: String(err) });
|
|
920
|
+
process.exit(1);
|
|
921
|
+
}
|
|
922
|
+
});
|
|
923
|
+
|
|
924
|
+
// ============================================
|
|
925
|
+
// Automations Commands
|
|
926
|
+
// ============================================
|
|
927
|
+
const automationsCmd = program
|
|
928
|
+
.command('automations')
|
|
929
|
+
.description('Manage Zendesk automations');
|
|
930
|
+
|
|
931
|
+
automationsCmd
|
|
932
|
+
.command('list')
|
|
933
|
+
.description('List automations')
|
|
934
|
+
.option('-a, --active', 'Only show active automations')
|
|
935
|
+
.action(async (opts) => {
|
|
936
|
+
try {
|
|
937
|
+
const client = getClient();
|
|
938
|
+
const automations = opts.active
|
|
939
|
+
? await client.automations.listActive()
|
|
940
|
+
: await client.automations.list();
|
|
941
|
+
print(automations, getFormat(automationsCmd));
|
|
942
|
+
} catch (err) {
|
|
943
|
+
error(String(err));
|
|
944
|
+
process.exit(1);
|
|
945
|
+
}
|
|
946
|
+
});
|
|
947
|
+
|
|
948
|
+
automationsCmd
|
|
949
|
+
.command('get <id>')
|
|
950
|
+
.description('Get automation by ID')
|
|
951
|
+
.action(async (id: string) => {
|
|
952
|
+
try {
|
|
953
|
+
const client = getClient();
|
|
954
|
+
const automation = await client.automations.get(parseInt(id));
|
|
955
|
+
print(automation, getFormat(automationsCmd));
|
|
956
|
+
} catch (err) {
|
|
957
|
+
error(String(err));
|
|
958
|
+
process.exit(1);
|
|
959
|
+
}
|
|
960
|
+
});
|
|
961
|
+
|
|
962
|
+
automationsCmd
|
|
963
|
+
.command('export')
|
|
964
|
+
.description('Export automations to CSV or JSON')
|
|
965
|
+
.option('-f, --format <format>', 'Export format (csv, json)', 'csv')
|
|
966
|
+
.option('-o, --output <filename>', 'Output filename', 'automations')
|
|
967
|
+
.action(async (opts) => {
|
|
968
|
+
try {
|
|
969
|
+
const client = getClient();
|
|
970
|
+
logger.command('automations export', { format: opts.format, output: opts.output });
|
|
971
|
+
info('Fetching automations...');
|
|
972
|
+
|
|
973
|
+
const response = await client.automations.list();
|
|
974
|
+
const filepath = exportData(response.automations, opts.output, opts.format);
|
|
975
|
+
logger.export('automations', opts.format, filepath, response.automations.length);
|
|
976
|
+
success(`Exported ${response.automations.length} automations to ${filepath}`);
|
|
977
|
+
} catch (err) {
|
|
978
|
+
error(String(err));
|
|
979
|
+
logger.error('Automations export failed', { error: String(err) });
|
|
980
|
+
process.exit(1);
|
|
981
|
+
}
|
|
982
|
+
});
|
|
983
|
+
|
|
984
|
+
// ============================================
|
|
985
|
+
// Macros Commands
|
|
986
|
+
// ============================================
|
|
987
|
+
const macrosCmd = program
|
|
988
|
+
.command('macros')
|
|
989
|
+
.description('Manage Zendesk macros');
|
|
990
|
+
|
|
991
|
+
macrosCmd
|
|
992
|
+
.command('list')
|
|
993
|
+
.description('List macros')
|
|
994
|
+
.option('-a, --active', 'Only show active macros')
|
|
995
|
+
.action(async (opts) => {
|
|
996
|
+
try {
|
|
997
|
+
const client = getClient();
|
|
998
|
+
const macros = opts.active
|
|
999
|
+
? await client.macros.listActive()
|
|
1000
|
+
: await client.macros.list();
|
|
1001
|
+
print(macros, getFormat(macrosCmd));
|
|
1002
|
+
} catch (err) {
|
|
1003
|
+
error(String(err));
|
|
1004
|
+
process.exit(1);
|
|
1005
|
+
}
|
|
1006
|
+
});
|
|
1007
|
+
|
|
1008
|
+
macrosCmd
|
|
1009
|
+
.command('get <id>')
|
|
1010
|
+
.description('Get macro by ID')
|
|
1011
|
+
.action(async (id: string) => {
|
|
1012
|
+
try {
|
|
1013
|
+
const client = getClient();
|
|
1014
|
+
const macro = await client.macros.get(parseInt(id));
|
|
1015
|
+
print(macro, getFormat(macrosCmd));
|
|
1016
|
+
} catch (err) {
|
|
1017
|
+
error(String(err));
|
|
1018
|
+
process.exit(1);
|
|
1019
|
+
}
|
|
1020
|
+
});
|
|
1021
|
+
|
|
1022
|
+
macrosCmd
|
|
1023
|
+
.command('export')
|
|
1024
|
+
.description('Export macros to CSV or JSON')
|
|
1025
|
+
.option('-f, --format <format>', 'Export format (csv, json)', 'csv')
|
|
1026
|
+
.option('-o, --output <filename>', 'Output filename', 'macros')
|
|
1027
|
+
.action(async (opts) => {
|
|
1028
|
+
try {
|
|
1029
|
+
const client = getClient();
|
|
1030
|
+
logger.command('macros export', { format: opts.format, output: opts.output });
|
|
1031
|
+
info('Fetching macros...');
|
|
1032
|
+
|
|
1033
|
+
const response = await client.macros.list();
|
|
1034
|
+
const filepath = exportData(response.macros, opts.output, opts.format);
|
|
1035
|
+
logger.export('macros', opts.format, filepath, response.macros.length);
|
|
1036
|
+
success(`Exported ${response.macros.length} macros to ${filepath}`);
|
|
1037
|
+
} catch (err) {
|
|
1038
|
+
error(String(err));
|
|
1039
|
+
logger.error('Macros export failed', { error: String(err) });
|
|
1040
|
+
process.exit(1);
|
|
1041
|
+
}
|
|
1042
|
+
});
|
|
1043
|
+
|
|
1044
|
+
// ============================================
|
|
1045
|
+
// Webhooks Commands
|
|
1046
|
+
// ============================================
|
|
1047
|
+
const webhooksCmd = program
|
|
1048
|
+
.command('webhooks')
|
|
1049
|
+
.description('Manage Zendesk webhooks');
|
|
1050
|
+
|
|
1051
|
+
webhooksCmd
|
|
1052
|
+
.command('list')
|
|
1053
|
+
.description('List webhooks')
|
|
1054
|
+
.action(async () => {
|
|
1055
|
+
try {
|
|
1056
|
+
const client = getClient();
|
|
1057
|
+
const webhooks = await client.webhooks.list();
|
|
1058
|
+
print(webhooks, getFormat(webhooksCmd));
|
|
1059
|
+
} catch (err) {
|
|
1060
|
+
error(String(err));
|
|
1061
|
+
process.exit(1);
|
|
1062
|
+
}
|
|
1063
|
+
});
|
|
1064
|
+
|
|
1065
|
+
webhooksCmd
|
|
1066
|
+
.command('get <id>')
|
|
1067
|
+
.description('Get webhook by ID')
|
|
1068
|
+
.action(async (id: string) => {
|
|
1069
|
+
try {
|
|
1070
|
+
const client = getClient();
|
|
1071
|
+
const webhook = await client.webhooks.get(id);
|
|
1072
|
+
print(webhook, getFormat(webhooksCmd));
|
|
1073
|
+
} catch (err) {
|
|
1074
|
+
error(String(err));
|
|
1075
|
+
process.exit(1);
|
|
1076
|
+
}
|
|
1077
|
+
});
|
|
1078
|
+
|
|
1079
|
+
webhooksCmd
|
|
1080
|
+
.command('export')
|
|
1081
|
+
.description('Export webhooks to CSV or JSON')
|
|
1082
|
+
.option('-f, --format <format>', 'Export format (csv, json)', 'csv')
|
|
1083
|
+
.option('-o, --output <filename>', 'Output filename', 'webhooks')
|
|
1084
|
+
.action(async (opts) => {
|
|
1085
|
+
try {
|
|
1086
|
+
const client = getClient();
|
|
1087
|
+
logger.command('webhooks export', { format: opts.format, output: opts.output });
|
|
1088
|
+
info('Fetching webhooks...');
|
|
1089
|
+
|
|
1090
|
+
const response = await client.webhooks.list();
|
|
1091
|
+
const filepath = exportData(response.webhooks, opts.output, opts.format);
|
|
1092
|
+
logger.export('webhooks', opts.format, filepath, response.webhooks.length);
|
|
1093
|
+
success(`Exported ${response.webhooks.length} webhooks to ${filepath}`);
|
|
1094
|
+
} catch (err) {
|
|
1095
|
+
error(String(err));
|
|
1096
|
+
logger.error('Webhooks export failed', { error: String(err) });
|
|
1097
|
+
process.exit(1);
|
|
1098
|
+
}
|
|
1099
|
+
});
|
|
1100
|
+
|
|
1101
|
+
// ============================================
|
|
1102
|
+
// Brands Commands
|
|
1103
|
+
// ============================================
|
|
1104
|
+
const brandsCmd = program
|
|
1105
|
+
.command('brands')
|
|
1106
|
+
.description('Manage Zendesk brands');
|
|
1107
|
+
|
|
1108
|
+
brandsCmd
|
|
1109
|
+
.command('list')
|
|
1110
|
+
.description('List brands')
|
|
1111
|
+
.action(async () => {
|
|
1112
|
+
try {
|
|
1113
|
+
const client = getClient();
|
|
1114
|
+
const brands = await client.brands.list();
|
|
1115
|
+
print(brands, getFormat(brandsCmd));
|
|
1116
|
+
} catch (err) {
|
|
1117
|
+
error(String(err));
|
|
1118
|
+
process.exit(1);
|
|
1119
|
+
}
|
|
1120
|
+
});
|
|
1121
|
+
|
|
1122
|
+
brandsCmd
|
|
1123
|
+
.command('get <id>')
|
|
1124
|
+
.description('Get brand by ID')
|
|
1125
|
+
.action(async (id: string) => {
|
|
1126
|
+
try {
|
|
1127
|
+
const client = getClient();
|
|
1128
|
+
const brand = await client.brands.get(parseInt(id));
|
|
1129
|
+
print(brand, getFormat(brandsCmd));
|
|
1130
|
+
} catch (err) {
|
|
1131
|
+
error(String(err));
|
|
1132
|
+
process.exit(1);
|
|
1133
|
+
}
|
|
1134
|
+
});
|
|
1135
|
+
|
|
1136
|
+
brandsCmd
|
|
1137
|
+
.command('export')
|
|
1138
|
+
.description('Export brands to CSV or JSON')
|
|
1139
|
+
.option('-f, --format <format>', 'Export format (csv, json)', 'csv')
|
|
1140
|
+
.option('-o, --output <filename>', 'Output filename', 'brands')
|
|
1141
|
+
.action(async (opts) => {
|
|
1142
|
+
try {
|
|
1143
|
+
const client = getClient();
|
|
1144
|
+
logger.command('brands export', { format: opts.format, output: opts.output });
|
|
1145
|
+
info('Fetching brands...');
|
|
1146
|
+
|
|
1147
|
+
const response = await client.brands.list();
|
|
1148
|
+
const filepath = exportData(response.brands, opts.output, opts.format);
|
|
1149
|
+
logger.export('brands', opts.format, filepath, response.brands.length);
|
|
1150
|
+
success(`Exported ${response.brands.length} brands to ${filepath}`);
|
|
1151
|
+
} catch (err) {
|
|
1152
|
+
error(String(err));
|
|
1153
|
+
logger.error('Brands export failed', { error: String(err) });
|
|
1154
|
+
process.exit(1);
|
|
1155
|
+
}
|
|
1156
|
+
});
|
|
1157
|
+
|
|
1158
|
+
// ============================================
|
|
1159
|
+
// Bulk Operations Commands
|
|
1160
|
+
// ============================================
|
|
1161
|
+
const bulkCmd = program
|
|
1162
|
+
.command('bulk')
|
|
1163
|
+
.description('Bulk operations for tickets and users');
|
|
1164
|
+
|
|
1165
|
+
bulkCmd
|
|
1166
|
+
.command('update <resource>')
|
|
1167
|
+
.description('Bulk update tickets or users')
|
|
1168
|
+
.requiredOption('-w, --where <filter>', 'Filter expression (e.g., "status=open", "priority=high")')
|
|
1169
|
+
.requiredOption('-s, --set <updates...>', 'Updates to apply (e.g., "status=solved" "priority=low")')
|
|
1170
|
+
.option('--ids <ids>', 'Comma-separated IDs to update (alternative to --where)')
|
|
1171
|
+
.option('--dry-run', 'Preview changes without applying them')
|
|
1172
|
+
.option('--concurrency <number>', 'Number of concurrent operations', '3')
|
|
1173
|
+
.option('--wait', 'Wait for bulk job to complete and show results')
|
|
1174
|
+
.action(async (resource: string, opts) => {
|
|
1175
|
+
try {
|
|
1176
|
+
const client = getClient();
|
|
1177
|
+
const resourceType = resource.toLowerCase() as 'tickets' | 'users';
|
|
1178
|
+
|
|
1179
|
+
if (!['tickets', 'users'].includes(resourceType)) {
|
|
1180
|
+
error(`Invalid resource type: ${resource}. Must be "tickets" or "users".`);
|
|
1181
|
+
process.exit(1);
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
// Parse IDs if provided
|
|
1185
|
+
const ids = opts.ids ? opts.ids.split(',').map((id: string) => parseInt(id.trim(), 10)) : undefined;
|
|
1186
|
+
|
|
1187
|
+
// Parse updates
|
|
1188
|
+
const { FilterParser } = await import('../api/bulk');
|
|
1189
|
+
const updates = (opts.set as string[]).map(s => FilterParser.parseUpdate(s));
|
|
1190
|
+
|
|
1191
|
+
logger.command('bulk update', {
|
|
1192
|
+
resource: resourceType,
|
|
1193
|
+
where: opts.where,
|
|
1194
|
+
ids,
|
|
1195
|
+
updates,
|
|
1196
|
+
dryRun: opts.dryRun,
|
|
1197
|
+
});
|
|
1198
|
+
|
|
1199
|
+
if (opts.dryRun) {
|
|
1200
|
+
info(`[DRY RUN] Would update ${resourceType} matching: ${opts.where || `IDs: ${ids?.join(', ')}`}`);
|
|
1201
|
+
info('Updates to apply:');
|
|
1202
|
+
updates.forEach(u => info(` ${u.field} = ${u.value}`));
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
info(`Searching for ${resourceType}...`);
|
|
1206
|
+
|
|
1207
|
+
const result = await client.bulk.update({
|
|
1208
|
+
resourceType,
|
|
1209
|
+
where: opts.where,
|
|
1210
|
+
ids,
|
|
1211
|
+
updates,
|
|
1212
|
+
dryRun: opts.dryRun,
|
|
1213
|
+
concurrency: parseInt(opts.concurrency, 10),
|
|
1214
|
+
onProgress: (current, total) => {
|
|
1215
|
+
process.stdout.write(`\rProgress: ${current}/${total}`);
|
|
1216
|
+
},
|
|
1217
|
+
});
|
|
1218
|
+
|
|
1219
|
+
console.log(''); // New line after progress
|
|
1220
|
+
|
|
1221
|
+
if (opts.dryRun) {
|
|
1222
|
+
success(`[DRY RUN] Would update ${result.total} ${resourceType}`);
|
|
1223
|
+
if (result.updatedItems.length > 0) {
|
|
1224
|
+
info('\nSample items that would be updated:');
|
|
1225
|
+
result.updatedItems.slice(0, 5).forEach(item => {
|
|
1226
|
+
const title = resourceType === 'tickets'
|
|
1227
|
+
? (item as any).subject || `Ticket #${item.id}`
|
|
1228
|
+
: (item as any).name || `User #${item.id}`;
|
|
1229
|
+
info(` - ${title} (ID: ${item.id})`);
|
|
1230
|
+
});
|
|
1231
|
+
if (result.updatedItems.length > 5) {
|
|
1232
|
+
info(` ... and ${result.updatedItems.length - 5} more`);
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
} else {
|
|
1236
|
+
success(`Bulk update completed:`);
|
|
1237
|
+
info(` Total: ${result.total}`);
|
|
1238
|
+
info(` Success: ${chalk.green(result.success)}`);
|
|
1239
|
+
info(` Failed: ${result.failed > 0 ? chalk.red(result.failed) : result.failed}`);
|
|
1240
|
+
|
|
1241
|
+
if (result.jobStatus) {
|
|
1242
|
+
info(`\nJob Status:`);
|
|
1243
|
+
info(` ID: ${result.jobStatus.id}`);
|
|
1244
|
+
info(` Status: ${result.jobStatus.status}`);
|
|
1245
|
+
if (result.jobStatus.message) {
|
|
1246
|
+
info(` Message: ${result.jobStatus.message}`);
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
// Wait for job completion if requested
|
|
1250
|
+
if (opts.wait && result.jobStatus.status !== 'completed') {
|
|
1251
|
+
info('\nWaiting for job to complete...');
|
|
1252
|
+
const finalStatus = await client.bulk.waitForJob(result.jobStatus.id, {
|
|
1253
|
+
onProgress: (progress, total) => {
|
|
1254
|
+
process.stdout.write(`\rJob progress: ${progress}/${total}`);
|
|
1255
|
+
},
|
|
1256
|
+
});
|
|
1257
|
+
console.log(''); // New line after progress
|
|
1258
|
+
info(`Final status: ${finalStatus.status}`);
|
|
1259
|
+
if (finalStatus.results) {
|
|
1260
|
+
const successes = finalStatus.results.filter(r => r.success).length;
|
|
1261
|
+
const failures = finalStatus.results.filter(r => !r.success).length;
|
|
1262
|
+
info(` Successes: ${chalk.green(successes)}`);
|
|
1263
|
+
info(` Failures: ${failures > 0 ? chalk.red(failures) : failures}`);
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
if (result.errors.length > 0) {
|
|
1269
|
+
error('\nErrors:');
|
|
1270
|
+
result.errors.slice(0, 10).forEach(e => {
|
|
1271
|
+
error(` - ID ${e.id}: ${e.error}`);
|
|
1272
|
+
});
|
|
1273
|
+
if (result.errors.length > 10) {
|
|
1274
|
+
error(` ... and ${result.errors.length - 10} more errors`);
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
} catch (err) {
|
|
1279
|
+
error(String(err));
|
|
1280
|
+
logger.error('Bulk update failed', { error: String(err) });
|
|
1281
|
+
process.exit(1);
|
|
1282
|
+
}
|
|
1283
|
+
});
|
|
1284
|
+
|
|
1285
|
+
bulkCmd
|
|
1286
|
+
.command('preview <resource>')
|
|
1287
|
+
.description('Preview items that would be affected by a bulk operation')
|
|
1288
|
+
.requiredOption('-w, --where <filter>', 'Filter expression (e.g., "status=open", "priority=high")')
|
|
1289
|
+
.option('-s, --set <updates...>', 'Updates to preview (shows current values for these fields)')
|
|
1290
|
+
.option('--ids <ids>', 'Comma-separated IDs to preview (alternative to --where)')
|
|
1291
|
+
.option('-l, --limit <limit>', 'Maximum number of items to show', '20')
|
|
1292
|
+
.action(async (resource: string, opts) => {
|
|
1293
|
+
try {
|
|
1294
|
+
const client = getClient();
|
|
1295
|
+
const resourceType = resource.toLowerCase() as 'tickets' | 'users';
|
|
1296
|
+
|
|
1297
|
+
if (!['tickets', 'users'].includes(resourceType)) {
|
|
1298
|
+
error(`Invalid resource type: ${resource}. Must be "tickets" or "users".`);
|
|
1299
|
+
process.exit(1);
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
// Parse IDs if provided
|
|
1303
|
+
const ids = opts.ids ? opts.ids.split(',').map((id: string) => parseInt(id.trim(), 10)) : undefined;
|
|
1304
|
+
|
|
1305
|
+
// Parse updates if provided
|
|
1306
|
+
const { FilterParser } = await import('../api/bulk');
|
|
1307
|
+
const updates = opts.set ? (opts.set as string[]).map(s => FilterParser.parseUpdate(s)) : [];
|
|
1308
|
+
|
|
1309
|
+
logger.command('bulk preview', { resource: resourceType, where: opts.where, ids });
|
|
1310
|
+
|
|
1311
|
+
info(`Searching for ${resourceType} matching: ${opts.where || `IDs: ${ids?.join(', ')}`}`);
|
|
1312
|
+
|
|
1313
|
+
const result = await client.bulk.preview({
|
|
1314
|
+
resourceType,
|
|
1315
|
+
where: opts.where,
|
|
1316
|
+
ids,
|
|
1317
|
+
updates,
|
|
1318
|
+
});
|
|
1319
|
+
|
|
1320
|
+
success(`Found ${result.count} ${resourceType}`);
|
|
1321
|
+
|
|
1322
|
+
if (result.items.length === 0) {
|
|
1323
|
+
info('No items match the filter.');
|
|
1324
|
+
return;
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
info('\nItems:');
|
|
1328
|
+
const limit = parseInt(opts.limit, 10);
|
|
1329
|
+
result.items.slice(0, limit).forEach(item => {
|
|
1330
|
+
info(`\n ${chalk.cyan(item.title)} (ID: ${item.id})`);
|
|
1331
|
+
if (Object.keys(item.currentValues).length > 0) {
|
|
1332
|
+
info(' Current values:');
|
|
1333
|
+
Object.entries(item.currentValues).forEach(([key, value]) => {
|
|
1334
|
+
info(` ${key}: ${chalk.yellow(String(value ?? 'null'))}`);
|
|
1335
|
+
});
|
|
1336
|
+
}
|
|
1337
|
+
});
|
|
1338
|
+
|
|
1339
|
+
if (result.items.length > limit) {
|
|
1340
|
+
info(`\n ... and ${result.items.length - limit} more`);
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
if (updates.length > 0) {
|
|
1344
|
+
info('\nProposed updates:');
|
|
1345
|
+
updates.forEach(u => {
|
|
1346
|
+
info(` ${u.field} -> ${chalk.green(u.value)}`);
|
|
1347
|
+
});
|
|
1348
|
+
}
|
|
1349
|
+
} catch (err) {
|
|
1350
|
+
error(String(err));
|
|
1351
|
+
logger.error('Bulk preview failed', { error: String(err) });
|
|
1352
|
+
process.exit(1);
|
|
1353
|
+
}
|
|
1354
|
+
});
|
|
1355
|
+
|
|
1356
|
+
bulkCmd
|
|
1357
|
+
.command('schema [resource]')
|
|
1358
|
+
.description('Show available fields and values for bulk operations')
|
|
1359
|
+
.option('--field <field>', 'Show details for a specific field')
|
|
1360
|
+
.action(async (resource: string | undefined, opts) => {
|
|
1361
|
+
try {
|
|
1362
|
+
const client = getClient();
|
|
1363
|
+
logger.command('bulk schema', { resource, field: opts.field });
|
|
1364
|
+
|
|
1365
|
+
info('Fetching schema...');
|
|
1366
|
+
const schema = await client.bulk.getSchema();
|
|
1367
|
+
|
|
1368
|
+
if (resource === 'tickets' || !resource) {
|
|
1369
|
+
info(chalk.bold('\nTickets Schema'));
|
|
1370
|
+
info(chalk.bold('=============='));
|
|
1371
|
+
|
|
1372
|
+
info('\nStatuses:');
|
|
1373
|
+
schema.tickets.statuses.forEach(s => info(` - ${s}`));
|
|
1374
|
+
|
|
1375
|
+
info('\nPriorities:');
|
|
1376
|
+
schema.tickets.priorities.forEach(p => info(` - ${p}`));
|
|
1377
|
+
|
|
1378
|
+
info('\nTypes:');
|
|
1379
|
+
schema.tickets.types.forEach(t => info(` - ${t}`));
|
|
1380
|
+
|
|
1381
|
+
info('\nFields:');
|
|
1382
|
+
schema.tickets.fields.forEach(field => {
|
|
1383
|
+
if (opts.field && field.name !== opts.field) return;
|
|
1384
|
+
|
|
1385
|
+
info(`\n ${chalk.cyan(field.name)} (${field.type})`);
|
|
1386
|
+
if (field.description) {
|
|
1387
|
+
info(` ${chalk.gray(field.description)}`);
|
|
1388
|
+
}
|
|
1389
|
+
if (field.options && field.options.length > 0) {
|
|
1390
|
+
info(' Options:');
|
|
1391
|
+
field.options.forEach(opt => {
|
|
1392
|
+
info(` - ${opt.name}: ${chalk.yellow(opt.value)}`);
|
|
1393
|
+
});
|
|
1394
|
+
}
|
|
1395
|
+
});
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
if (resource === 'users' || !resource) {
|
|
1399
|
+
info(chalk.bold('\nUsers Schema'));
|
|
1400
|
+
info(chalk.bold('============'));
|
|
1401
|
+
|
|
1402
|
+
info('\nRoles:');
|
|
1403
|
+
schema.users.roles.forEach(r => info(` - ${r}`));
|
|
1404
|
+
|
|
1405
|
+
info('\nFields:');
|
|
1406
|
+
schema.users.fields.forEach(field => {
|
|
1407
|
+
if (opts.field && field.name !== opts.field) return;
|
|
1408
|
+
|
|
1409
|
+
info(`\n ${chalk.cyan(field.name)} (${field.type})`);
|
|
1410
|
+
if (field.description) {
|
|
1411
|
+
info(` ${chalk.gray(field.description)}`);
|
|
1412
|
+
}
|
|
1413
|
+
if (field.options && field.options.length > 0) {
|
|
1414
|
+
info(' Options:');
|
|
1415
|
+
field.options.forEach(opt => {
|
|
1416
|
+
info(` - ${opt.name}: ${chalk.yellow(opt.value)}`);
|
|
1417
|
+
});
|
|
1418
|
+
}
|
|
1419
|
+
});
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
info('\n' + chalk.bold('Usage Examples:'));
|
|
1423
|
+
info(' # Update all open tickets to pending');
|
|
1424
|
+
info(' connect-zendesk bulk update tickets --where "status=open" --set "status=pending"');
|
|
1425
|
+
info('');
|
|
1426
|
+
info(' # Update priority for high-priority open tickets');
|
|
1427
|
+
info(' connect-zendesk bulk update tickets --where "status=open&priority=high" --set "priority=urgent"');
|
|
1428
|
+
info('');
|
|
1429
|
+
info(' # Update multiple fields at once');
|
|
1430
|
+
info(' connect-zendesk bulk update tickets --where "status=new" --set "status=open" "priority=normal"');
|
|
1431
|
+
info('');
|
|
1432
|
+
info(' # Preview changes before applying');
|
|
1433
|
+
info(' connect-zendesk bulk update tickets --where "status=pending" --set "status=solved" --dry-run');
|
|
1434
|
+
info('');
|
|
1435
|
+
info(' # Update specific tickets by ID');
|
|
1436
|
+
info(' connect-zendesk bulk update tickets --ids "123,456,789" --set "status=closed"');
|
|
1437
|
+
info('');
|
|
1438
|
+
info(' # Suspend users matching a filter');
|
|
1439
|
+
info(' connect-zendesk bulk update users --where "suspended=false" --set "suspended=true"');
|
|
1440
|
+
|
|
1441
|
+
} catch (err) {
|
|
1442
|
+
error(String(err));
|
|
1443
|
+
logger.error('Bulk schema failed', { error: String(err) });
|
|
1444
|
+
process.exit(1);
|
|
1445
|
+
}
|
|
1446
|
+
});
|
|
1447
|
+
|
|
1448
|
+
bulkCmd
|
|
1449
|
+
.command('job <jobId>')
|
|
1450
|
+
.description('Check the status of a bulk operation job')
|
|
1451
|
+
.option('--wait', 'Wait for job to complete')
|
|
1452
|
+
.action(async (jobId: string, opts) => {
|
|
1453
|
+
try {
|
|
1454
|
+
const client = getClient();
|
|
1455
|
+
logger.command('bulk job', { jobId, wait: opts.wait });
|
|
1456
|
+
|
|
1457
|
+
if (opts.wait) {
|
|
1458
|
+
info(`Waiting for job ${jobId} to complete...`);
|
|
1459
|
+
const status = await client.bulk.waitForJob(jobId, {
|
|
1460
|
+
onProgress: (progress, total) => {
|
|
1461
|
+
process.stdout.write(`\rProgress: ${progress}/${total}`);
|
|
1462
|
+
},
|
|
1463
|
+
});
|
|
1464
|
+
console.log(''); // New line after progress
|
|
1465
|
+
print(status, getFormat(bulkCmd));
|
|
1466
|
+
} else {
|
|
1467
|
+
const status = await client.bulk.getJobStatus(jobId);
|
|
1468
|
+
print(status, getFormat(bulkCmd));
|
|
1469
|
+
}
|
|
1470
|
+
} catch (err) {
|
|
1471
|
+
error(String(err));
|
|
1472
|
+
logger.error('Bulk job check failed', { error: String(err) });
|
|
1473
|
+
process.exit(1);
|
|
1474
|
+
}
|
|
1475
|
+
});
|
|
1476
|
+
|
|
1477
|
+
// Parse and execute
|
|
1478
|
+
program.parse();
|