import {z} from 'zod' export type GetApiV4IntegrationsCatalogOptions = {baseUrl: string, fetch?: typeof fetch | undefined}; export const integrationType = z.enum(["postgres", "acumatica", "aircall", "amplitude", "attio", "bigquery", "cube", "custom", "ducklake", "excel", "facebookads", "facebookads_system_user", "gcs", "googleads", "googleanalytics", "googlesearchconsole", "googlesheets", "hubspot", "iceberg", "linkedinads", "linkedinpages", "mavenlink", "mysql", "omnisend", "pipedrive", "twilio", "quickbooks", "redshift", "salesforce", "salesloft", "sharepointsites", "sheets", "shopify", "slack", "snowflake", "sqlserver", "s3", "abicart", "abra", "activecampaign", "acuite", "adp", "aftership", "aha", "airtable", "amazonadvertising", "amazonassociates", "amazonsellingpartner", "anvil", "apaleo", "appstore", "applehealth", "asknicely", "atinternet", "awscloudtrail", "awscognito", "awscostexplorer", "bamboohr", "hellobaton", "bazaarvoice", "bexio", "bigmarker", "brillium", "canvas", "chorusai", "clickcast", "clickup", "clientsuccess", "closeio", "cloudwatch", "coingecko", "currencyfreaks", "dagster", "dashhudson", "datadog", "dearsystems", "dixa", "domo", "emarsys", "fastly", "fishbowl", "freshdesk", "freshcaller", "freshworks", "fullstory", "gainsightpx", "github", "gladly", "gong", "greenhouse", "holidays", "hotjar", "immuta", "instagram", "iterable", "intercom", "jira", "jotform", "judgeme", "keap", "klaviyo", "krow", "lessonly", "lightdash", "linear", "loopreturns", "maestroqa", "mailerlite", "mailjet", "marketo", "marketplacer", "netohq", "megaphone", "memberful", "mercadopago", "meshstack", "messagebird", "metronome", "mixpanel", "msgraph", "mindstamp", "miro", "mode", "monday", "mongodb", "montapacking", "moosend", "netlify", "netrivals", "netsuite", "niceincontact", "notion", "okta", "ordoro", "partnerize", "partoo", "peloton", "picqer", "plentymarkets", "getpocket", "podbean", "pulumicloud", "qls", "qualified", "readthedocs", "recruitee", "recurly", "sailthru", "segment", "sellsy", "sendinblue", "shipbob", "shiphero", "shipstation", "shoplazza", "showpad", "sleeper", "smartsheet", "square", "stamped", "stripe", "sumologic", "talkable", "thinkific", "tiktokads", "tradera", "travefy", "trustrace", "typeform", "udemyforbusiness", "unleashed", "veeqo", "webflow", "woocommerce", "zammad", "zendesk", "zohocrm"]); export const inputContextType = z.enum(["default", "ssh", "ssl", "etlConfig"]); export const selectOptionStr = z.object({label: z.string(), value: z.string(), selected: z.boolean().optional()}); export const integrationField = z.object({id: z.string(), label: z.string(), type: z.string(), context: inputContextType, placeholder: z.string().nullable().optional(), helperText: z.string().nullable().optional(), secret: z.boolean(), readonly: z.boolean().optional(), choices: z.array(selectOptionStr).nullable().optional()}); export const integrationCatalogEntry = z.object({name: z.string(), type: integrationType, fields: z.array(integrationField), category: z.string().optional(), avatar: z.string().nullable().optional(), metadata: z.record(z.string(), z.unknown()).nullable().optional()}); export const integrationCatalog = z.object({entries: z.array(integrationCatalogEntry)}); export const responseMeta = z.object({requestId: z.string().optional(), timestamp: z.string().optional(), durationMs: z.number().int().nullable().optional()}); export const successResponseIntegrationCatalog = z.object({success: z.literal(true), data: integrationCatalog, meta: responseMeta.optional()}); export const validateResponse = async ( schema: { readonly '~standard': { readonly validate: (value: unknown) => ({ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }) | Promise<{ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }> } }, value: unknown ): Promise => { const result = await schema['~standard'].validate(value) if (result.issues !== undefined) { const detail = result.issues .map(({ message, path }) => path?.length ? `${path.map((segment) => String(typeof segment === 'object' ? segment.key : segment)).join('.')}: ${message}` : message ) .join('; ') throw new Error(`Response does not match the schema: ${detail}`, { cause: { issues: result.issues } }) } return result.value }; /** * Get catalog * * GET /v4/integrations/catalog */ export const getApiV4IntegrationsCatalog = async (options: GetApiV4IntegrationsCatalogOptions) => { const {baseUrl, fetch: fetchFn = fetch} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") const url = `${baseUrl.replace(/\/+$/, '')}/v4/integrations/catalog${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "GET", headers}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(successResponseIntegrationCatalog, await res.json()) };