From 6b9e3d0709df8ed3ba1a736c4145b346fbed04de Mon Sep 17 00:00:00 2001 From: Chaker Atallah <74781393+MrChaker@users.noreply.github.com> Date: Wed, 2 Sep 2026 09:47:04 +0100 Subject: [PATCH 1/3] fix(worker): tie the health endpoint to socket connectivity and warmed cache (#15203) Co-authored-by: Mohammad AbuAboud --- packages/server/worker/src/lib/worker.ts | 51 ++++++++++++++----- .../server/worker/test/lib/worker.test.ts | 25 +++++++-- packages/server/worker/vitest.config.ts | 1 + 3 files changed, 60 insertions(+), 17 deletions(-) diff --git a/packages/server/worker/src/lib/worker.ts b/packages/server/worker/src/lib/worker.ts index a587298eb5fc..46d07511d5cd 100644 --- a/packages/server/worker/src/lib/worker.ts +++ b/packages/server/worker/src/lib/worker.ts @@ -59,6 +59,8 @@ const workerHostname = os.hostname() let healthServerInstance: ReturnType | null = null +let shouldStartHealthServer = false + let runtime: Runtime | null = null // Jobs executing across all poll loops. stop() waits for these to finish + report before tearing @@ -77,7 +79,7 @@ let sandboxInfoInterval: NodeJS.Timeout | null = null const SANDBOX_INFO_REFRESH_MS = 15_000 const SERVER_PING_TIMEOUT_MS = 5_000 const MACHINE_INFO_TIMEOUT_MS = 15_000 -const POLL_LIVENESS_TIMEOUT_MS = 180_000 +const POLL_LIVENESS_TIMEOUT_MS = 600_000 const POLL_WATCHDOG_INTERVAL_MS = 30_000 const RPC_TIMEOUT_MS = 60_000 const LONG_RUNNING_RPC_MARGIN_MS = 120_000 @@ -105,7 +107,7 @@ export const worker = { socket.on('connect', async () => { logger.info('Connected to API server via Socket.IO') - resetPollLoopLiveness({ loopCount: 1 }) + resetPollLoopLiveness({ loopCount: 0 }) await fetchAndStoreSettings(socket!) void startPollingWorkers(apiClient).catch((err) => { logger.error({ error: err }, 'Polling workers crashed unexpectedly') @@ -120,8 +122,11 @@ export const worker = { // For any other reason the socket dropped while a job may still be running locally; the app // reclaims that job on disconnect, so kill the runtime now or the original keeps executing // to completion and double-runs the requeued copy. (The reconnect path recreates it.) + // Also close the health server so orchestrators stop routing/keeping traffic on a worker + // that can't consume jobs; the reconnect path brings it back up after prewarm completes. if (reason !== 'io client disconnect') { abortInFlightRuntime() + stopHealthServer() } // Socket.IO does NOT auto-reconnect when the server initiates the disconnect // (reason 'io server disconnect' — e.g. the API process restarts/hot-reloads). @@ -143,9 +148,7 @@ export const worker = { log: logger, }), logger) - if (withHealthServer) { - healthServerInstance = startHealthServer() - } + shouldStartHealthServer = withHealthServer startSandboxInfoSampling() startPollWatchdog() startCacheSweeper() @@ -165,8 +168,7 @@ export const worker = { } socket?.disconnect() socket = null - healthServerInstance?.close() - healthServerInstance = null + stopHealthServer() logger.info('Worker stopped') }, } @@ -196,29 +198,40 @@ async function startPollingWorkers(apiClient: WorkerToApiContract): Promise sandboxConfig.getSandboxSettings(), }) + runtime = createdRuntime - // Fire-and-forget: warm the piece cache for this platform's flows without blocking the poll loop. // Opt-in via AP_PREWARM_CACHE_ON_STARTUP: the warm-up resolves and compiles every enabled flow, // so its startup memory/CPU spike grows with flow count and can OOM small workers on large instances. + // When enabled it is awaited so the health server only comes up once the cache is warm and + // orchestrators don't route/keep traffic on a cold worker; when disabled it is skipped entirely. if (system.getBoolean(WorkerSystemProp.PREWARM_CACHE_ON_STARTUP) ?? false) { - void runtime.prewarm({ + const { error: prewarmError } = await tryCatch(() => createdRuntime.prewarm({ log: logger, apiClient, publicApiUrl: ensurePublicApiUrl(workerSettings.getSettings().PUBLIC_URL), - }) + })) + if (prewarmError) { + logger.error({ error: prewarmError }, 'Prewarm failed, continuing without a warm cache') + } + } + + // The generation check keeps a disconnect that landed mid-prewarm from re-opening the health + // server for a connection that no longer exists — the reconnect's own run brings it back up. + const stillCurrentConnection = polling && connectionGeneration === generation + if (shouldStartHealthServer && stillCurrentConnection && isNil(healthServerInstance)) { + healthServerInstance = startHealthServer() } logger.info({ concurrency }, 'Starting poll loops') resetPollLoopLiveness({ loopCount: concurrency }) - const activeRuntime = runtime await Promise.all(Array.from({ length: concurrency }, (_, workerIndex) => - pollAndExecute(apiClient, activeRuntime, workerIndex, generation), + pollAndExecute(apiClient, createdRuntime, workerIndex, generation), )) } @@ -695,6 +708,18 @@ function startHealthServer(): ReturnType { return server } +// closeAllConnections drops kubelet keep-alive sockets too, so the next probe is refused +// immediately instead of riding an already-open connection until it happens to close. +function stopHealthServer(): void { + if (isNil(healthServerInstance)) { + return + } + healthServerInstance.closeAllConnections() + healthServerInstance.close() + healthServerInstance = null + logger.info('Health server stopped, probes will fail until reconnect and prewarm complete') +} + type WorkerStartParams = { apiUrl: string socketUrl: { url: string, path: string } diff --git a/packages/server/worker/test/lib/worker.test.ts b/packages/server/worker/test/lib/worker.test.ts index 5eac046d3bc8..62c2f63961f1 100644 --- a/packages/server/worker/test/lib/worker.test.ts +++ b/packages/server/worker/test/lib/worker.test.ts @@ -584,6 +584,7 @@ describe('worker integration', () => { }) async function startWithHealthServer(): Promise { + registerRpcServer({}) worker.start({ apiUrl: `http://127.0.0.1:${port}/api/`, socketUrl: { url: `http://127.0.0.1:${port}`, path: '/api/socket.io' }, @@ -608,27 +609,43 @@ describe('worker integration', () => { const res = await fetch(`http://127.0.0.1:${healthPort}/v1/health`) expect(res.status).toBe(200) expect(await res.json()).toEqual({ status: 'ok' }) - }, 5_000) + }, 15_000) it('responds 200 with status ok on /worker/health', async () => { await startWithHealthServer() const res = await fetch(`http://127.0.0.1:${healthPort}/worker/health`) expect(res.status).toBe(200) expect(await res.json()).toEqual({ status: 'ok' }) - }, 5_000) + }, 15_000) it('responds 200 with status ok on /api/v1/health', async () => { await startWithHealthServer() const res = await fetch(`http://127.0.0.1:${healthPort}/api/v1/health`) expect(res.status).toBe(200) expect(await res.json()).toEqual({ status: 'ok' }) - }, 5_000) + }, 15_000) it('responds 404 on unknown paths', async () => { await startWithHealthServer() const res = await fetch(`http://127.0.0.1:${healthPort}/unknown`) expect(res.status).toBe(404) - }, 5_000) + }, 15_000) + + it('closes the health server when the socket disconnects', async () => { + await startWithHealthServer() + await new Promise((resolve) => ioServer.close(() => resolve())) + for (let i = 0; i < 50; i++) { + try { + const res = await fetch(`http://127.0.0.1:${healthPort}/v1/health`) + void res.body?.cancel() + } + catch { + return + } + await new Promise((resolve) => setTimeout(resolve, 100)) + } + throw new Error('Health server still reachable after disconnect') + }, 15_000) }) }) diff --git a/packages/server/worker/vitest.config.ts b/packages/server/worker/vitest.config.ts index bf624805aa44..788685102319 100644 --- a/packages/server/worker/vitest.config.ts +++ b/packages/server/worker/vitest.config.ts @@ -11,6 +11,7 @@ export default defineConfig({ }, resolve: { alias: { + '@activepieces/ai-providers': path.resolve(__dirname, '../../../packages/core/ai-providers/src/index.ts'), '@activepieces/shared': path.resolve(__dirname, '../../../packages/core/shared/src/index.ts'), '@activepieces/pieces-framework': path.resolve(__dirname, '../../../packages/pieces/framework/src/index.ts'), '@activepieces/server-utils': path.resolve(__dirname, '../../../packages/server/utils/src/index.ts'), From ddb0c9907322ff993324159e347684304ba8f21a Mon Sep 17 00:00:00 2001 From: Kishan Parmar <135701940+kishanprmr@users.noreply.github.com> Date: Wed, 2 Sep 2026 14:53:28 +0530 Subject: [PATCH 2/3] feat(pieces): add Clay piece (#15176) --- packages/pieces/community/clay/.eslintrc.json | 9 + packages/pieces/community/clay/package.json | 16 + packages/pieces/community/clay/src/index.ts | 28 + .../clay/src/lib/actions/search-companies.ts | 154 ++++ .../clay/src/lib/actions/search-people.ts | 216 ++++++ .../pieces/community/clay/src/lib/auth.ts | 22 + .../src/lib/common/company-search-options.ts | 718 ++++++++++++++++++ .../community/clay/src/lib/common/index.ts | 93 +++ .../src/lib/common/people-search-options.ts | 273 +++++++ packages/pieces/community/clay/tsconfig.json | 15 + .../pieces/community/clay/tsconfig.lib.json | 13 + tsconfig.base.json | 3 + 12 files changed, 1560 insertions(+) create mode 100644 packages/pieces/community/clay/.eslintrc.json create mode 100644 packages/pieces/community/clay/package.json create mode 100644 packages/pieces/community/clay/src/index.ts create mode 100644 packages/pieces/community/clay/src/lib/actions/search-companies.ts create mode 100644 packages/pieces/community/clay/src/lib/actions/search-people.ts create mode 100644 packages/pieces/community/clay/src/lib/auth.ts create mode 100644 packages/pieces/community/clay/src/lib/common/company-search-options.ts create mode 100644 packages/pieces/community/clay/src/lib/common/index.ts create mode 100644 packages/pieces/community/clay/src/lib/common/people-search-options.ts create mode 100644 packages/pieces/community/clay/tsconfig.json create mode 100644 packages/pieces/community/clay/tsconfig.lib.json diff --git a/packages/pieces/community/clay/.eslintrc.json b/packages/pieces/community/clay/.eslintrc.json new file mode 100644 index 000000000000..a86bd8287d5a --- /dev/null +++ b/packages/pieces/community/clay/.eslintrc.json @@ -0,0 +1,9 @@ +{ + "extends": ["../../../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], "rules": {} }, + { "files": ["*.ts", "*.tsx"], "rules": {} }, + { "files": ["*.js", "*.jsx"], "rules": {} } + ] +} diff --git a/packages/pieces/community/clay/package.json b/packages/pieces/community/clay/package.json new file mode 100644 index 000000000000..29681602bd19 --- /dev/null +++ b/packages/pieces/community/clay/package.json @@ -0,0 +1,16 @@ +{ + "name": "@activepieces/piece-clay", + "version": "0.0.1", + "main": "./dist/src/index.js", + "types": "./dist/src/index.d.ts", + "scripts": { + "build": "tsc -p tsconfig.lib.json && cp package.json dist/", + "lint": "eslint 'src/**/*.ts'" + }, + "dependencies": { + "@activepieces/pieces-common": "workspace:*", + "@activepieces/pieces-framework": "workspace:*", + "@activepieces/shared": "workspace:*", + "tslib": "2.6.2" + } +} diff --git a/packages/pieces/community/clay/src/index.ts b/packages/pieces/community/clay/src/index.ts new file mode 100644 index 000000000000..1b3c50b79ebc --- /dev/null +++ b/packages/pieces/community/clay/src/index.ts @@ -0,0 +1,28 @@ +import { createPiece } from '@activepieces/pieces-framework'; +import { createCustomApiCallAction } from '@activepieces/pieces-common'; +import { PieceCategory } from '@activepieces/shared'; +import { clayAuth } from './lib/auth'; +import { searchCompaniesAction } from './lib/actions/search-companies'; +import { searchPeopleAction } from './lib/actions/search-people'; + +export const clay = createPiece({ + displayName: 'Clay', + description: 'Search Clay\'s GTM database for people and companies.', + minimumSupportedRelease: '0.36.1', + logoUrl: 'https://cdn.activepieces.com/pieces/clay.png', + categories: [PieceCategory.SALES_AND_CRM], + auth: clayAuth, + authors: ['kishanprmr'], + actions: [ + searchCompaniesAction, + searchPeopleAction, + createCustomApiCallAction({ + baseUrl: () => 'https://api.clay.com/public/v0', + auth: clayAuth, + authMapping: async (auth) => ({ + 'clay-api-key': auth.secret_text, + }), + }), + ], + triggers: [], +}); diff --git a/packages/pieces/community/clay/src/lib/actions/search-companies.ts b/packages/pieces/community/clay/src/lib/actions/search-companies.ts new file mode 100644 index 000000000000..0c70e0bfcc8c --- /dev/null +++ b/packages/pieces/community/clay/src/lib/actions/search-companies.ts @@ -0,0 +1,154 @@ +import { createAction, Property } from '@activepieces/pieces-framework'; +import { clayAuth } from '../auth'; +import { buildClayInClause, escapeClayQueryValue, runClayQueryModeSearch } from '../common'; +import { clayCompanySearchOptions } from '../common/company-search-options'; + +export const searchCompaniesAction = createAction({ + auth: clayAuth, + name: 'search_companies', + classification: 'SEARCH', + displayName: 'Search Companies', + description: 'Searches Clay\'s company database using structured filters.', + audience: 'both', + aiMetadata: { + description: + 'Search Clay\'s proprietary GTM database for companies matching structured filters (identifiers, industry, size, revenue, type, headquarters country, keyword). Use Search People instead when looking up individuals. Safe to retry; results may change between calls.', + idempotent: true, + }, + props: { + company_identifiers: Property.Array({ + displayName: 'Company Identifiers', + description: 'Domains or LinkedIn company URLs to match exactly, e.g. "stripe.com".', + required: false, + }), + industries: Property.StaticMultiSelectDropdown({ + displayName: 'Industry', + required: false, + options: { options: clayCompanySearchOptions.industry }, + }), + company_sizes: Property.StaticMultiSelectDropdown({ + displayName: 'Company Size', + required: false, + options: { options: clayCompanySearchOptions.companySize }, + }), + annual_revenues: Property.StaticMultiSelectDropdown({ + displayName: 'Annual Revenue', + required: false, + options: { options: clayCompanySearchOptions.annualRevenue }, + }), + company_types: Property.StaticMultiSelectDropdown({ + displayName: 'Company Type', + required: false, + options: { options: clayCompanySearchOptions.companyType }, + }), + headquarters_countries: Property.StaticMultiSelectDropdown({ + displayName: 'Headquarters Country', + required: false, + options: { options: clayCompanySearchOptions.locationCountry }, + }), + headquarters_only: Property.Checkbox({ + displayName: 'Match headquarters location only', + description: 'Only match the office marked as the company headquarters, not any office.', + required: false, + defaultValue: false, + }), + keyword: Property.ShortText({ + displayName: 'Description Keyword', + description: 'Matches companies whose description contains this word or phrase.', + required: false, + }), + advanced_filter: Property.LongText({ + displayName: 'Advanced Filter (Clay query syntax)', + description: + 'Optional raw filter, ANDed onto the filters above. See Clay\'s advanced search query syntax: https://developers.clay.com/searches/advanced', + required: false, + }), + limit: Property.Number({ + displayName: 'Max results', + required: false, + defaultValue: 20, + display: 'stepper', + min: 1, + max: 500, + }), + }, + async run(context) { + const { + company_identifiers, + industries, + company_sizes, + annual_revenues, + company_types, + headquarters_countries, + headquarters_only, + keyword, + advanced_filter, + limit, + } = context.propsValue; + + const clauses = buildCompanyFilterClauses({ + companyIdentifiers: (company_identifiers as string[] | undefined) ?? [], + industries: industries ?? [], + companySizes: company_sizes ?? [], + annualRevenues: annual_revenues ?? [], + companyTypes: company_types ?? [], + headquartersCountries: headquarters_countries ?? [], + headquartersOnly: headquarters_only ?? false, + keyword, + advancedFilter: advanced_filter, + }); + + if (clauses.length === 0) { + throw new Error('Provide at least one filter to search companies.'); + } + + return await runClayQueryModeSearch({ + apiKey: context.auth.secret_text, + sourceType: 'companies', + query: `select from companies where ${clauses.join(' and ')}`, + limit: limit ?? 20, + }); + }, +}); + +function buildCompanyFilterClauses({ + companyIdentifiers, + industries, + companySizes, + annualRevenues, + companyTypes, + headquartersCountries, + headquartersOnly, + keyword, + advancedFilter, +}: { + companyIdentifiers: string[]; + industries: string[]; + companySizes: string[]; + annualRevenues: string[]; + companyTypes: string[]; + headquartersCountries: string[]; + headquartersOnly: boolean; + keyword: string | undefined; + advancedFilter: string | undefined; +}): string[] { + const locationParts = [ + buildClayInClause({ field: 'country_name', values: headquartersCountries }), + headquartersOnly ? 'is_headquarters = true' : undefined, + ].filter((part): part is string => part !== undefined); + + return [ + companyIdentifiers.length > 0 + ? `clay.include_company_identifiers((${companyIdentifiers + .map((identifier) => `"${escapeClayQueryValue(identifier)}"`) + .join(', ')}))` + : undefined, + buildClayInClause({ field: 'industry', values: industries }), + buildClayInClause({ field: 'company_size', values: companySizes }), + buildClayInClause({ field: 'annual_revenue', values: annualRevenues }), + buildClayInClause({ field: 'company_type', values: companyTypes }), + locationParts.length > 0 ? `locations.any(${locationParts.join(' and ')})` : undefined, + keyword ? `description contains "${escapeClayQueryValue(keyword)}"` : undefined, + advancedFilter ? `(${advancedFilter})` : undefined, + ].filter((clause): clause is string => clause !== undefined); +} diff --git a/packages/pieces/community/clay/src/lib/actions/search-people.ts b/packages/pieces/community/clay/src/lib/actions/search-people.ts new file mode 100644 index 000000000000..9ee9cc501d1c --- /dev/null +++ b/packages/pieces/community/clay/src/lib/actions/search-people.ts @@ -0,0 +1,216 @@ +import { createAction, Property } from '@activepieces/pieces-framework'; +import { clayAuth } from '../auth'; +import { buildClayInClause, escapeClayQueryValue, runClayQueryModeSearch } from '../common'; +import { clayPeopleSearchOptions } from '../common/people-search-options'; + +export const searchPeopleAction = createAction({ + auth: clayAuth, + name: 'search_people', + classification: 'SEARCH', + displayName: 'Search People', + description: 'Searches Clay\'s people database using structured filters.', + audience: 'both', + aiMetadata: { + description: + 'Search Clay\'s proprietary GTM database for people matching structured filters (job title, seniority, employer, location, keyword). Use Search Companies instead when looking up companies rather than individuals. Safe to retry; results may change between calls.', + idempotent: true, + }, + props: { + full_name_contains: Property.ShortText({ + displayName: 'Full Name Contains', + required: false, + }), + job_titles: Property.Array({ + displayName: 'Job Title', + description: 'Matches similar titles too (e.g. "VP of Sales" also matches "Head of Sales").', + required: false, + }), + seniorities: Property.StaticMultiSelectDropdown({ + displayName: 'Seniority', + required: false, + options: { options: clayPeopleSearchOptions.experienceSeniority }, + }), + tenure: Property.StaticDropdown({ + displayName: 'Employment Tenure', + required: false, + defaultValue: 'current', + options: { + options: [ + { label: 'Current role', value: 'current' }, + { label: 'Past role', value: 'past' }, + { label: 'Any role (current or past)', value: 'any' }, + ], + }, + }), + company_identifiers: Property.Array({ + displayName: 'Employer (Domains or LinkedIn URLs)', + description: 'Matches people at these exact companies. Scoped by Employment Tenure above.', + required: false, + }), + company_name_contains: Property.ShortText({ + displayName: 'Employer Name Contains', + description: 'Fuzzy employer name match, use when you don\'t have a domain. Scoped by Employment Tenure above.', + required: false, + }), + location_cities: Property.Array({ + displayName: 'City', + required: false, + }), + location_states: Property.Array({ + displayName: 'State / Province', + required: false, + }), + location_countries: Property.StaticMultiSelectDropdown({ + displayName: 'Country', + required: false, + options: { options: clayPeopleSearchOptions.locationCountry }, + }), + location_regions: Property.StaticMultiSelectDropdown({ + displayName: 'Region', + required: false, + options: { options: clayPeopleSearchOptions.locationRegion }, + }), + languages: Property.Array({ + displayName: 'Languages', + required: false, + }), + headline_contains: Property.ShortText({ + displayName: 'Headline Contains', + required: false, + }), + about_contains: Property.ShortText({ + displayName: 'About Contains', + required: false, + }), + advanced_filter: Property.LongText({ + displayName: 'Advanced Filter (Clay query syntax)', + description: + 'Optional raw filter, ANDed onto the filters above. See Clay\'s advanced search query syntax: https://developers.clay.com/searches/advanced', + required: false, + }), + limit: Property.Number({ + displayName: 'Max results', + required: false, + defaultValue: 20, + display: 'stepper', + min: 1, + max: 500, + }), + }, + async run(context) { + const { + full_name_contains, + job_titles, + seniorities, + tenure, + company_identifiers, + company_name_contains, + location_cities, + location_states, + location_countries, + location_regions, + languages, + headline_contains, + about_contains, + advanced_filter, + limit, + } = context.propsValue; + + const clauses = buildPeopleFilterClauses({ + fullNameContains: full_name_contains, + jobTitles: (job_titles as string[] | undefined) ?? [], + seniorities: seniorities ?? [], + tenure: tenure ?? 'current', + companyIdentifiers: (company_identifiers as string[] | undefined) ?? [], + companyNameContains: company_name_contains, + locationCities: (location_cities as string[] | undefined) ?? [], + locationStates: (location_states as string[] | undefined) ?? [], + locationCountries: location_countries ?? [], + locationRegions: location_regions ?? [], + languages: (languages as string[] | undefined) ?? [], + headlineContains: headline_contains, + aboutContains: about_contains, + advancedFilter: advanced_filter, + }); + + if (clauses.length === 0) { + throw new Error('Provide at least one filter to search people.'); + } + + return await runClayQueryModeSearch({ + apiKey: context.auth.secret_text, + sourceType: 'people', + query: `select from people where ${clauses.join(' and ')}`, + limit: limit ?? 20, + }); + }, +}); + +function buildPeopleFilterClauses({ + fullNameContains, + jobTitles, + seniorities, + tenure, + companyIdentifiers, + companyNameContains, + locationCities, + locationStates, + locationCountries, + locationRegions, + languages, + headlineContains, + aboutContains, + advancedFilter, +}: { + fullNameContains: string | undefined; + jobTitles: string[]; + seniorities: string[]; + tenure: string; + companyIdentifiers: string[]; + companyNameContains: string | undefined; + locationCities: string[]; + locationStates: string[]; + locationCountries: string[]; + locationRegions: string[]; + languages: string[]; + headlineContains: string | undefined; + aboutContains: string | undefined; + advancedFilter: string | undefined; +}): string[] { + const experienceContentParts = [ + jobTitles.length > 0 + ? `job_title is_similar_to (${jobTitles.map((title) => `"${escapeClayQueryValue(title)}"`).join(', ')})` + : undefined, + buildClayInClause({ field: 'seniority', values: seniorities }), + companyNameContains ? `company_name contains "${escapeClayQueryValue(companyNameContains)}"` : undefined, + tenure !== 'current' ? buildClayInClause({ field: 'company.domain', values: companyIdentifiers }) : undefined, + ].filter((part): part is string => part !== undefined); + + const experiencesClause = + experienceContentParts.length > 0 + ? `experiences.any(${[ + tenure === 'current' ? 'is_current = true' : tenure === 'past' ? 'is_current = false' : undefined, + ...experienceContentParts, + ] + .filter((part): part is string => part !== undefined) + .join(' and ')})` + : undefined; + + return [ + fullNameContains ? `full_name contains "${escapeClayQueryValue(fullNameContains)}"` : undefined, + tenure === 'current' && companyIdentifiers.length > 0 + ? `clay.filter_to_companies((${companyIdentifiers + .map((identifier) => `"${escapeClayQueryValue(identifier)}"`) + .join(', ')}))` + : undefined, + buildClayInClause({ field: 'location_city', values: locationCities }), + buildClayInClause({ field: 'location_state', values: locationStates }), + buildClayInClause({ field: 'location_country', values: locationCountries }), + buildClayInClause({ field: 'location_region', values: locationRegions }), + buildClayInClause({ field: 'languages', values: languages }), + headlineContains ? `headline contains "${escapeClayQueryValue(headlineContains)}"` : undefined, + aboutContains ? `about contains "${escapeClayQueryValue(aboutContains)}"` : undefined, + experiencesClause, + advancedFilter ? `(${advancedFilter})` : undefined, + ].filter((clause): clause is string => clause !== undefined); +} diff --git a/packages/pieces/community/clay/src/lib/auth.ts b/packages/pieces/community/clay/src/lib/auth.ts new file mode 100644 index 000000000000..fb0ca767478d --- /dev/null +++ b/packages/pieces/community/clay/src/lib/auth.ts @@ -0,0 +1,22 @@ +import { PieceAuth } from '@activepieces/pieces-framework'; +import { HttpMethod } from '@activepieces/pieces-common'; +import { clayApiCall } from './common'; + +export const clayAuth = PieceAuth.SecretText({ + displayName: 'API Key', + description: + 'Create a key from [Settings > Account > API keys (beta)](https://app.clay.com/workspaces/~/settings/account?accountTab=api-keys-beta), then paste it here.', + required: true, + validate: async ({ auth }) => { + try { + await clayApiCall({ + apiKey: auth, + method: HttpMethod.GET, + path: '/me', + }); + return { valid: true }; + } catch (e) { + return { valid: false, error: 'Invalid API key' }; + } + }, +}); diff --git a/packages/pieces/community/clay/src/lib/common/company-search-options.ts b/packages/pieces/community/clay/src/lib/common/company-search-options.ts new file mode 100644 index 000000000000..084d658b5a1a --- /dev/null +++ b/packages/pieces/community/clay/src/lib/common/company-search-options.ts @@ -0,0 +1,718 @@ +export const clayCompanySearchOptions = { + companyType: [ + { label: "Privately held", value: "Privately Held" }, + { label: "Public company", value: "Public Company" }, + { label: "Partnership", value: "Partnership" }, + { label: "Self-employed", value: "Self Employed" }, + { label: "Nonprofit", value: "Non Profit" }, + { label: "Educational", value: "Educational" }, + { label: "Self-owned", value: "Self Owned" }, + { label: "Government agency", value: "Government Agency" }, + ], + companySize: [ + { label: "1 employee", value: "1" }, + { label: "2–10 employees", value: "2-10" }, + { label: "11–50 employees", value: "11-50" }, + { label: "51–200 employees", value: "51-200" }, + { label: "201–500 employees", value: "201-500" }, + { label: "501–1,000 employees", value: "501-1,000" }, + { label: "1,001–5,000 employees", value: "1,001-5,000" }, + { label: "5,001–10,000 employees", value: "5,001-10,000" }, + { label: "10,001+ employees", value: "10,001+" }, + ], + annualRevenue: [ + { label: "$0–$500K", value: "0-500K" }, + { label: "$500K–$1M", value: "500K-1M" }, + { label: "$1M–$5M", value: "1M-5M" }, + { label: "$5M–$10M", value: "5M-10M" }, + { label: "$10M–$25M", value: "10M-25M" }, + { label: "$25M–$75M", value: "25M-75M" }, + { label: "$75M–$200M", value: "75M-200M" }, + { label: "$200M–$500M", value: "200M-500M" }, + { label: "$500M–$1B", value: "500M-1B" }, + { label: "$1B–$10B", value: "1B-10B" }, + { label: "$10B–$100B", value: "10B-100B" }, + { label: "$100B+", value: "100B-1T" }, + ], + industry: [ + { label: "Abrasives and Nonmetallic Minerals Manufacturing", value: "Abrasives and Nonmetallic Minerals Manufacturing" }, + { label: "Accessible Architecture and Design", value: "Accessible Architecture and Design" }, + { label: "Accommodation Services", value: "Accommodation Services" }, + { label: "Accounting", value: "Accounting" }, + { label: "Administration of Justice", value: "Administration of Justice" }, + { label: "Administrative and Support Services", value: "Administrative and Support Services" }, + { label: "Advertising Services", value: "Advertising Services" }, + { label: "Agricultural Chemical Manufacturing", value: "Agricultural Chemical Manufacturing" }, + { label: "Agriculture, Construction, Mining Machinery Manufacturing", value: "Agriculture, Construction, Mining Machinery Manufacturing" }, + { label: "Air, Water, and Waste Program Management", value: "Air, Water, and Waste Program Management" }, + { label: "Airlines and Aviation", value: "Airlines and Aviation" }, + { label: "Alternative Dispute Resolution", value: "Alternative Dispute Resolution" }, + { label: "Alternative Medicine", value: "Alternative Medicine" }, + { label: "Ambulance Services", value: "Ambulance Services" }, + { label: "Amusement Parks and Arcades", value: "Amusement Parks and Arcades" }, + { label: "Animal Feed Manufacturing", value: "Animal Feed Manufacturing" }, + { label: "Animation", value: "Animation" }, + { label: "Animation and Post-production", value: "Animation and Post-production" }, + { label: "Apparel Manufacturing", value: "Apparel Manufacturing" }, + { label: "Apparel and Fashion", value: "Apparel and Fashion" }, + { label: "Appliances, Electrical, and Electronics Manufacturing", value: "Appliances, Electrical, and Electronics Manufacturing" }, + { label: "Architectural and Structural Metal Manufacturing", value: "Architectural and Structural Metal Manufacturing" }, + { label: "Architecture and Planning", value: "Architecture and Planning" }, + { label: "Armed Forces", value: "Armed Forces" }, + { label: "Artists and Writers", value: "Artists and Writers" }, + { label: "Arts and Crafts", value: "Arts and Crafts" }, + { label: "Audio and Video Equipment Manufacturing", value: "Audio and Video Equipment Manufacturing" }, + { label: "Automation Machinery Manufacturing", value: "Automation Machinery Manufacturing" }, + { label: "Automotive", value: "Automotive" }, + { label: "Aviation & Aerospace", value: "Aviation & Aerospace" }, + { label: "Aviation and Aerospace Component Manufacturing", value: "Aviation and Aerospace Component Manufacturing" }, + { label: "Baked Goods Manufacturing", value: "Baked Goods Manufacturing" }, + { label: "Banking", value: "Banking" }, + { label: "Bars, Taverns, and Nightclubs", value: "Bars, Taverns, and Nightclubs" }, + { label: "Bed-and-Breakfasts, Hostels, Homestays", value: "Bed-and-Breakfasts, Hostels, Homestays" }, + { label: "Beverage Manufacturing", value: "Beverage Manufacturing" }, + { label: "Biomass Electric Power Generation", value: "Biomass Electric Power Generation" }, + { label: "Biotechnology", value: "Biotechnology" }, + { label: "Biotechnology Research", value: "Biotechnology Research" }, + { label: "Blockchain Services", value: "Blockchain Services" }, + { label: "Blogs", value: "Blogs" }, + { label: "Boilers, Tanks, and Shipping Container Manufacturing", value: "Boilers, Tanks, and Shipping Container Manufacturing" }, + { label: "Book Publishing", value: "Book Publishing" }, + { label: "Book and Periodical Publishing", value: "Book and Periodical Publishing" }, + { label: "Breweries", value: "Breweries" }, + { label: "Broadcast Media Production and Distribution", value: "Broadcast Media Production and Distribution" }, + { label: "Building Construction", value: "Building Construction" }, + { label: "Building Equipment Contractors", value: "Building Equipment Contractors" }, + { label: "Building Finishing Contractors", value: "Building Finishing Contractors" }, + { label: "Building Materials", value: "Building Materials" }, + { label: "Building Structure and Exterior Contractors", value: "Building Structure and Exterior Contractors" }, + { label: "Business Consulting and Services", value: "Business Consulting and Services" }, + { label: "Business Content", value: "Business Content" }, + { label: "Business Intelligence Platforms", value: "Business Intelligence Platforms" }, + { label: "Business Supplies and Equipment", value: "Business Supplies and Equipment" }, + { label: "Capital Markets", value: "Capital Markets" }, + { label: "Caterers", value: "Caterers" }, + { label: "Chemical Manufacturing", value: "Chemical Manufacturing" }, + { label: "Chemical Raw Materials Manufacturing", value: "Chemical Raw Materials Manufacturing" }, + { label: "Child Day Care Services", value: "Child Day Care Services" }, + { label: "Chiropractors", value: "Chiropractors" }, + { label: "Civic and Social Organizations", value: "Civic and Social Organizations" }, + { label: "Civil Engineering", value: "Civil Engineering" }, + { label: "Claims Adjusting, Actuarial Services", value: "Claims Adjusting, Actuarial Services" }, + { label: "Clay and Refractory Products Manufacturing", value: "Clay and Refractory Products Manufacturing" }, + { label: "Climate Data and Analytics", value: "Climate Data and Analytics" }, + { label: "Climate Technology Product Manufacturing", value: "Climate Technology Product Manufacturing" }, + { label: "Coal Mining", value: "Coal Mining" }, + { label: "Collection Agencies", value: "Collection Agencies" }, + { label: "Commercial Real Estate", value: "Commercial Real Estate" }, + { label: "Commercial and Industrial Equipment Rental", value: "Commercial and Industrial Equipment Rental" }, + { label: "Commercial and Industrial Machinery Maintenance", value: "Commercial and Industrial Machinery Maintenance" }, + { label: "Commercial and Service Industry Machinery Manufacturing", value: "Commercial and Service Industry Machinery Manufacturing" }, + { label: "Communications Equipment Manufacturing", value: "Communications Equipment Manufacturing" }, + { label: "Community Development and Urban Planning", value: "Community Development and Urban Planning" }, + { label: "Community Services", value: "Community Services" }, + { label: "Computer Games", value: "Computer Games" }, + { label: "Computer Hardware", value: "Computer Hardware" }, + { label: "Computer Hardware Manufacturing", value: "Computer Hardware Manufacturing" }, + { label: "Computer Networking", value: "Computer Networking" }, + { label: "Computer Networking Products", value: "Computer Networking Products" }, + { label: "Computer and Network Security", value: "Computer and Network Security" }, + { label: "Computers and Electronics Manufacturing", value: "Computers and Electronics Manufacturing" }, + { label: "Conservation Programs", value: "Conservation Programs" }, + { label: "Construction", value: "Construction" }, + { label: "Construction Hardware Manufacturing", value: "Construction Hardware Manufacturing" }, + { label: "Consumer Electronics", value: "Consumer Electronics" }, + { label: "Consumer Goods", value: "Consumer Goods" }, + { label: "Consumer Goods Rental", value: "Consumer Goods Rental" }, + { label: "Consumer Services", value: "Consumer Services" }, + { label: "Cosmetics", value: "Cosmetics" }, + { label: "Cosmetology and Barber Schools", value: "Cosmetology and Barber Schools" }, + { label: "Courts of Law", value: "Courts of Law" }, + { label: "Credit Intermediation", value: "Credit Intermediation" }, + { label: "Dairy", value: "Dairy" }, + { label: "Dairy Product Manufacturing", value: "Dairy Product Manufacturing" }, + { label: "Dance Companies", value: "Dance Companies" }, + { label: "Data Infrastructure and Analytics", value: "Data Infrastructure and Analytics" }, + { label: "Data Security Software Products", value: "Data Security Software Products" }, + { label: "Defense & Space", value: "Defense & Space" }, + { label: "Defense and Space Manufacturing", value: "Defense and Space Manufacturing" }, + { label: "Dentists", value: "Dentists" }, + { label: "Design", value: "Design" }, + { label: "Design Services", value: "Design Services" }, + { label: "Desktop Computing Software Products", value: "Desktop Computing Software Products" }, + { label: "Digital Accessibility Services", value: "Digital Accessibility Services" }, + { label: "Distilleries", value: "Distilleries" }, + { label: "E-Learning", value: "E-Learning" }, + { label: "E-Learning Providers", value: "E-Learning Providers" }, + { label: "Economic Programs", value: "Economic Programs" }, + { label: "Education", value: "Education" }, + { label: "Education Administration Programs", value: "Education Administration Programs" }, + { label: "Education Management", value: "Education Management" }, + { label: "Electric Lighting Equipment Manufacturing", value: "Electric Lighting Equipment Manufacturing" }, + { label: "Electric Power Generation", value: "Electric Power Generation" }, + { label: "Electric Power Transmission, Control, and Distribution", value: "Electric Power Transmission, Control, and Distribution" }, + { label: "Electrical Equipment Manufacturing", value: "Electrical Equipment Manufacturing" }, + { label: "Electronic and Precision Equipment Maintenance", value: "Electronic and Precision Equipment Maintenance" }, + { label: "Embedded Software Products", value: "Embedded Software Products" }, + { label: "Emergency and Relief Services", value: "Emergency and Relief Services" }, + { label: "Engineering Services", value: "Engineering Services" }, + { label: "Engines and Power Transmission Equipment Manufacturing", value: "Engines and Power Transmission Equipment Manufacturing" }, + { label: "Entertainment", value: "Entertainment" }, + { label: "Entertainment Providers", value: "Entertainment Providers" }, + { label: "Environmental Quality Programs", value: "Environmental Quality Programs" }, + { label: "Environmental Services", value: "Environmental Services" }, + { label: "Equipment Rental Services", value: "Equipment Rental Services" }, + { label: "Events Services", value: "Events Services" }, + { label: "Executive Offices", value: "Executive Offices" }, + { label: "Executive Search Services", value: "Executive Search Services" }, + { label: "Fabricated Metal Products", value: "Fabricated Metal Products" }, + { label: "Facilities Services", value: "Facilities Services" }, + { label: "Farming, Ranching, Forestry", value: "Farming, Ranching, Forestry" }, + { label: "Farming", value: "Farming" }, + { label: "Fashion Accessories Manufacturing", value: "Fashion Accessories Manufacturing" }, + { label: "Financial Services", value: "Financial Services" }, + { label: "Fine Art", value: "Fine Art" }, + { label: "Fine Arts Schools", value: "Fine Arts Schools" }, + { label: "Fire Protection", value: "Fire Protection" }, + { label: "Fisheries", value: "Fisheries" }, + { label: "Flight Training", value: "Flight Training" }, + { label: "Food & Beverages", value: "Food & Beverages" }, + { label: "Food and Beverage Manufacturing", value: "Food and Beverage Manufacturing" }, + { label: "Food and Beverage Retail", value: "Food and Beverage Retail" }, + { label: "Food and Beverage Services", value: "Food and Beverage Services" }, + { label: "Food Production", value: "Food Production" }, + { label: "Footwear Manufacturing", value: "Footwear Manufacturing" }, + { label: "Forestry and Logging", value: "Forestry and Logging" }, + { label: "Freight and Package Transportation", value: "Freight and Package Transportation" }, + { label: "Fruit and Vegetable Preserves Manufacturing", value: "Fruit and Vegetable Preserves Manufacturing" }, + { label: "Fundraising", value: "Fundraising" }, + { label: "Funds and Trusts", value: "Funds and Trusts" }, + { label: "Furniture", value: "Furniture" }, + { label: "Furniture and Home Furnishings Manufacturing", value: "Furniture and Home Furnishings Manufacturing" }, + { label: "Gambling Facilities and Casinos", value: "Gambling Facilities and Casinos" }, + { label: "Geothermal Electric Power Generation", value: "Geothermal Electric Power Generation" }, + { label: "Glass Product Manufacturing", value: "Glass Product Manufacturing" }, + { label: "Glass, Ceramics and Concrete Manufacturing", value: "Glass, Ceramics and Concrete Manufacturing" }, + { label: "Golf Courses and Country Clubs", value: "Golf Courses and Country Clubs" }, + { label: "Government Administration", value: "Government Administration" }, + { label: "Government Relations", value: "Government Relations" }, + { label: "Government Relations Services", value: "Government Relations Services" }, + { label: "Graphic Design", value: "Graphic Design" }, + { label: "Ground Passenger Transportation", value: "Ground Passenger Transportation" }, + { label: "HVAC and Refrigeration Equipment Manufacturing", value: "HVAC and Refrigeration Equipment Manufacturing" }, + { label: "Health and Human Services", value: "Health and Human Services" }, + { label: "Health, Wellness and Fitness", value: "Health, Wellness and Fitness" }, + { label: "Higher Education", value: "Higher Education" }, + { label: "Highway, Street, and Bridge Construction", value: "Highway, Street, and Bridge Construction" }, + { label: "Historical Sites", value: "Historical Sites" }, + { label: "Holding Companies", value: "Holding Companies" }, + { label: "Home Health Care Services", value: "Home Health Care Services" }, + { label: "Horticulture", value: "Horticulture" }, + { label: "Hospitality", value: "Hospitality" }, + { label: "Hospitals", value: "Hospitals" }, + { label: "Hospitals and Health Care", value: "Hospitals and Health Care" }, + { label: "Hotels and Motels", value: "Hotels and Motels" }, + { label: "Household Appliance Manufacturing", value: "Household Appliance Manufacturing" }, + { label: "Household Services", value: "Household Services" }, + { label: "Household and Institutional Furniture Manufacturing", value: "Household and Institutional Furniture Manufacturing" }, + { label: "Housing Programs", value: "Housing Programs" }, + { label: "Housing and Community Development", value: "Housing and Community Development" }, + { label: "Human Resources", value: "Human Resources" }, + { label: "Human Resources Services", value: "Human Resources Services" }, + { label: "Hydroelectric Power Generation", value: "Hydroelectric Power Generation" }, + { label: "IT Services and IT Consulting", value: "IT Services and IT Consulting" }, + { label: "IT System Custom Software Development", value: "IT System Custom Software Development" }, + { label: "IT System Data Services", value: "IT System Data Services" }, + { label: "IT System Design Services", value: "IT System Design Services" }, + { label: "IT System Installation and Disposal", value: "IT System Installation and Disposal" }, + { label: "IT System Operations and Maintenance", value: "IT System Operations and Maintenance" }, + { label: "IT System Testing and Evaluation", value: "IT System Testing and Evaluation" }, + { label: "IT System Training and Support", value: "IT System Training and Support" }, + { label: "Import and Export", value: "Import and Export" }, + { label: "Individual and Family Services", value: "Individual and Family Services" }, + { label: "Industrial Automation", value: "Industrial Automation" }, + { label: "Industrial Machinery Manufacturing", value: "Industrial Machinery Manufacturing" }, + { label: "Industry Associations", value: "Industry Associations" }, + { label: "Information Services", value: "Information Services" }, + { label: "Information Technology and Services", value: "Information Technology and Services" }, + { label: "Insurance", value: "Insurance" }, + { label: "Insurance Agencies and Brokerages", value: "Insurance Agencies and Brokerages" }, + { label: "Insurance Carriers", value: "Insurance Carriers" }, + { label: "Insurance and Employee Benefit Funds", value: "Insurance and Employee Benefit Funds" }, + { label: "Interior Design", value: "Interior Design" }, + { label: "International Affairs", value: "International Affairs" }, + { label: "International Trade and Development", value: "International Trade and Development" }, + { label: "Internet Marketplace Platforms", value: "Internet Marketplace Platforms" }, + { label: "Internet News", value: "Internet News" }, + { label: "Internet Publishing", value: "Internet Publishing" }, + { label: "Investment Advice", value: "Investment Advice" }, + { label: "Investment Banking", value: "Investment Banking" }, + { label: "Investment Management", value: "Investment Management" }, + { label: "Janitorial Services", value: "Janitorial Services" }, + { label: "Landscaping Services", value: "Landscaping Services" }, + { label: "Language Schools", value: "Language Schools" }, + { label: "Laundry and Drycleaning Services", value: "Laundry and Drycleaning Services" }, + { label: "Law Enforcement", value: "Law Enforcement" }, + { label: "Law Practice", value: "Law Practice" }, + { label: "Leasing Non-residential Real Estate", value: "Leasing Non-residential Real Estate" }, + { label: "Leasing Residential Real Estate", value: "Leasing Residential Real Estate" }, + { label: "Leather Product Manufacturing", value: "Leather Product Manufacturing" }, + { label: "Legal Services", value: "Legal Services" }, + { label: "Legislative Offices", value: "Legislative Offices" }, + { label: "Leisure, Travel & Tourism", value: "Leisure, Travel & Tourism" }, + { label: "Libraries", value: "Libraries" }, + { label: "Loan Brokers", value: "Loan Brokers" }, + { label: "Luxury Goods and Jewelry", value: "Luxury Goods and Jewelry" }, + { label: "Machinery Manufacturing", value: "Machinery Manufacturing" }, + { label: "Manufacturing", value: "Manufacturing" }, + { label: "Maritime", value: "Maritime" }, + { label: "Maritime Transportation", value: "Maritime Transportation" }, + { label: "Market Research", value: "Market Research" }, + { label: "Marketing Services", value: "Marketing Services" }, + { label: "Mattress and Blinds Manufacturing", value: "Mattress and Blinds Manufacturing" }, + { label: "Measuring and Control Instrument Manufacturing", value: "Measuring and Control Instrument Manufacturing" }, + { label: "Meat Products Manufacturing", value: "Meat Products Manufacturing" }, + { label: "Mechanical or Industrial Engineering", value: "Mechanical or Industrial Engineering" }, + { label: "Media & Telecommunications", value: "Media & Telecommunications" }, + { label: "Media Production", value: "Media Production" }, + { label: "Medical Devices", value: "Medical Devices" }, + { label: "Medical Equipment Manufacturing", value: "Medical Equipment Manufacturing" }, + { label: "Medical Practices", value: "Medical Practices" }, + { label: "Medical and Diagnostic Laboratories", value: "Medical and Diagnostic Laboratories" }, + { label: "Mental Health Care", value: "Mental Health Care" }, + { label: "Metal Ore Mining", value: "Metal Ore Mining" }, + { label: "Metal Treatments", value: "Metal Treatments" }, + { label: "Metal Valve, Ball, and Roller Manufacturing", value: "Metal Valve, Ball, and Roller Manufacturing" }, + { label: "Metalworking Machinery Manufacturing", value: "Metalworking Machinery Manufacturing" }, + { label: "Military and International Affairs", value: "Military and International Affairs" }, + { label: "Mining", value: "Mining" }, + { label: "Mobile Computing Software Products", value: "Mobile Computing Software Products" }, + { label: "Mobile Food Services", value: "Mobile Food Services" }, + { label: "Mobile Gaming Apps", value: "Mobile Gaming Apps" }, + { label: "Motor Vehicle Manufacturing", value: "Motor Vehicle Manufacturing" }, + { label: "Motor Vehicle Parts Manufacturing", value: "Motor Vehicle Parts Manufacturing" }, + { label: "Movies and Sound Recording", value: "Movies and Sound Recording" }, + { label: "Movies, Videos and Sound", value: "Movies, Videos and Sound" }, + { label: "Museums", value: "Museums" }, + { label: "Museums, Historical Sites, and Zoos", value: "Museums, Historical Sites, and Zoos" }, + { label: "Music", value: "Music" }, + { label: "Musicians", value: "Musicians" }, + { label: "Nanotechnology Research", value: "Nanotechnology Research" }, + { label: "Natural Gas Distribution", value: "Natural Gas Distribution" }, + { label: "Newspaper Publishing", value: "Newspaper Publishing" }, + { label: "Non-profit Organization Management", value: "Non-profit Organization Management" }, + { label: "Non-profit Organizations", value: "Non-profit Organizations" }, + { label: "Nonmetallic Mineral Mining", value: "Nonmetallic Mineral Mining" }, + { label: "Nonresidential Building Construction", value: "Nonresidential Building Construction" }, + { label: "Nuclear Electric Power Generation", value: "Nuclear Electric Power Generation" }, + { label: "Nursing Homes and Residential Care Facilities", value: "Nursing Homes and Residential Care Facilities" }, + { label: "Office Administration", value: "Office Administration" }, + { label: "Office Furniture and Fixtures Manufacturing", value: "Office Furniture and Fixtures Manufacturing" }, + { label: "Oil and Gas", value: "Oil and Gas" }, + { label: "Oil, Gas, and Mining", value: "Oil, Gas, and Mining" }, + { label: "Online Audio and Video Media", value: "Online Audio and Video Media" }, + { label: "Online Media", value: "Online Media" }, + { label: "Online and Mail Order Retail", value: "Online and Mail Order Retail" }, + { label: "Operations Consulting", value: "Operations Consulting" }, + { label: "Optometrists", value: "Optometrists" }, + { label: "Outpatient Care Centers", value: "Outpatient Care Centers" }, + { label: "Outsourcing and Offshoring Consulting", value: "Outsourcing and Offshoring Consulting" }, + { label: "Outsourcing/Offshoring", value: "Outsourcing/Offshoring" }, + { label: "Packaging and Containers", value: "Packaging and Containers" }, + { label: "Packaging and Containers Manufacturing", value: "Packaging and Containers Manufacturing" }, + { label: "Paint, Coating, and Adhesive Manufacturing", value: "Paint, Coating, and Adhesive Manufacturing" }, + { label: "Paper and Forest Product Manufacturing", value: "Paper and Forest Product Manufacturing" }, + { label: "Paper and Forest Products", value: "Paper and Forest Products" }, + { label: "Performing Arts", value: "Performing Arts" }, + { label: "Performing Arts and Spectator Sports", value: "Performing Arts and Spectator Sports" }, + { label: "Periodical Publishing", value: "Periodical Publishing" }, + { label: "Personal Care Product Manufacturing", value: "Personal Care Product Manufacturing" }, + { label: "Personal Care Services", value: "Personal Care Services" }, + { label: "Personal and Laundry Services", value: "Personal and Laundry Services" }, + { label: "Pet Services", value: "Pet Services" }, + { label: "Pharmaceutical Manufacturing", value: "Pharmaceutical Manufacturing" }, + { label: "Philanthropic Fundraising Services", value: "Philanthropic Fundraising Services" }, + { label: "Philanthropy", value: "Philanthropy" }, + { label: "Photography", value: "Photography" }, + { label: "Physical, Occupational and Speech Therapists", value: "Physical, Occupational and Speech Therapists" }, + { label: "Physicians", value: "Physicians" }, + { label: "Plastics Manufacturing", value: "Plastics Manufacturing" }, + { label: "Plastics and Rubber Product Manufacturing", value: "Plastics and Rubber Product Manufacturing" }, + { label: "Political Organizations", value: "Political Organizations" }, + { label: "Primary Metal Manufacturing", value: "Primary Metal Manufacturing" }, + { label: "Primary and Secondary Education", value: "Primary and Secondary Education" }, + { label: "Printing Services", value: "Printing Services" }, + { label: "Professional Organizations", value: "Professional Organizations" }, + { label: "Professional Services", value: "Professional Services" }, + { label: "Professional Training and Coaching", value: "Professional Training and Coaching" }, + { label: "Program Development", value: "Program Development" }, + { label: "Public Assistance Programs", value: "Public Assistance Programs" }, + { label: "Public Health", value: "Public Health" }, + { label: "Public Policy", value: "Public Policy" }, + { label: "Public Policy Offices", value: "Public Policy Offices" }, + { label: "Public Relations and Communications Services", value: "Public Relations and Communications Services" }, + { label: "Public Safety", value: "Public Safety" }, + { label: "Radio and Television Broadcasting", value: "Radio and Television Broadcasting" }, + { label: "Rail Transportation", value: "Rail Transportation" }, + { label: "Railroad Equipment Manufacturing", value: "Railroad Equipment Manufacturing" }, + { label: "Ranching", value: "Ranching" }, + { label: "Real Estate", value: "Real Estate" }, + { label: "Real Estate Agents and Brokers", value: "Real Estate Agents and Brokers" }, + { label: "Real Estate and Equipment Rental Services", value: "Real Estate and Equipment Rental Services" }, + { label: "Recreational Facilities", value: "Recreational Facilities" }, + { label: "Religious Institutions", value: "Religious Institutions" }, + { label: "Renewable Energy Equipment Manufacturing", value: "Renewable Energy Equipment Manufacturing" }, + { label: "Renewable Energy Power Generation", value: "Renewable Energy Power Generation" }, + { label: "Renewable Energy Semiconductor Manufacturing", value: "Renewable Energy Semiconductor Manufacturing" }, + { label: "Renewables & Environment", value: "Renewables & Environment" }, + { label: "Repair and Maintenance", value: "Repair and Maintenance" }, + { label: "Research", value: "Research" }, + { label: "Research Services", value: "Research Services" }, + { label: "Residential Building Construction", value: "Residential Building Construction" }, + { label: "Restaurants", value: "Restaurants" }, + { label: "Retail", value: "Retail" }, + { label: "Retail Apparel and Fashion", value: "Retail Apparel and Fashion" }, + { label: "Retail Appliances, Electrical, and Electronic Equipment", value: "Retail Appliances, Electrical, and Electronic Equipment" }, + { label: "Retail Art Dealers", value: "Retail Art Dealers" }, + { label: "Retail Art Supplies", value: "Retail Art Supplies" }, + { label: "Retail Books and Printed News", value: "Retail Books and Printed News" }, + { label: "Retail Building Materials and Garden Equipment", value: "Retail Building Materials and Garden Equipment" }, + { label: "Retail Florists", value: "Retail Florists" }, + { label: "Retail Furniture and Home Furnishings", value: "Retail Furniture and Home Furnishings" }, + { label: "Retail Gasoline", value: "Retail Gasoline" }, + { label: "Retail Groceries", value: "Retail Groceries" }, + { label: "Retail Health and Personal Care Products", value: "Retail Health and Personal Care Products" }, + { label: "Retail Luxury Goods and Jewelry", value: "Retail Luxury Goods and Jewelry" }, + { label: "Retail Motor Vehicles", value: "Retail Motor Vehicles" }, + { label: "Retail Musical Instruments", value: "Retail Musical Instruments" }, + { label: "Retail Office Equipment", value: "Retail Office Equipment" }, + { label: "Retail Office Supplies and Gifts", value: "Retail Office Supplies and Gifts" }, + { label: "Retail Pharmacies", value: "Retail Pharmacies" }, + { label: "Retail Recyclable Materials & Used Merchandise", value: "Retail Recyclable Materials & Used Merchandise" }, + { label: "Reupholstery and Furniture Repair", value: "Reupholstery and Furniture Repair" }, + { label: "Robotics Engineering", value: "Robotics Engineering" }, + { label: "Rubber Products Manufacturing", value: "Rubber Products Manufacturing" }, + { label: "Satellite Telecommunications", value: "Satellite Telecommunications" }, + { label: "School and Employee Bus Services", value: "School and Employee Bus Services" }, + { label: "Seafood Product Manufacturing", value: "Seafood Product Manufacturing" }, + { label: "Securities and Commodity Exchanges", value: "Securities and Commodity Exchanges" }, + { label: "Security Guards and Patrol Services", value: "Security Guards and Patrol Services" }, + { label: "Security Systems Services", value: "Security Systems Services" }, + { label: "Security and Investigations", value: "Security and Investigations" }, + { label: "Semiconductor Manufacturing", value: "Semiconductor Manufacturing" }, + { label: "Semiconductors", value: "Semiconductors" }, + { label: "Services for Renewable Energy", value: "Services for Renewable Energy" }, + { label: "Services for the Elderly and Disabled", value: "Services for the Elderly and Disabled" }, + { label: "Sheet Music Publishing", value: "Sheet Music Publishing" }, + { label: "Shipbuilding", value: "Shipbuilding" }, + { label: "Shuttles and Special Needs Transportation Services", value: "Shuttles and Special Needs Transportation Services" }, + { label: "Sightseeing Transportation", value: "Sightseeing Transportation" }, + { label: "Soap and Cleaning Product Manufacturing", value: "Soap and Cleaning Product Manufacturing" }, + { label: "Social Networking Platforms", value: "Social Networking Platforms" }, + { label: "Software Development", value: "Software Development" }, + { label: "Solar Electric Power Generation", value: "Solar Electric Power Generation" }, + { label: "Sound Recording", value: "Sound Recording" }, + { label: "Space Research and Technology", value: "Space Research and Technology" }, + { label: "Specialty Trade Contractors", value: "Specialty Trade Contractors" }, + { label: "Spectator Sports", value: "Spectator Sports" }, + { label: "Sporting Goods", value: "Sporting Goods" }, + { label: "Sporting Goods Manufacturing", value: "Sporting Goods Manufacturing" }, + { label: "Sports Teams and Clubs", value: "Sports Teams and Clubs" }, + { label: "Sports and Recreation Instruction", value: "Sports and Recreation Instruction" }, + { label: "Spring and Wire Product Manufacturing", value: "Spring and Wire Product Manufacturing" }, + { label: "Staffing and Recruiting", value: "Staffing and Recruiting" }, + { label: "Steam and Air-Conditioning Supply", value: "Steam and Air-Conditioning Supply" }, + { label: "Strategic Management Services", value: "Strategic Management Services" }, + { label: "Subdivision of Land", value: "Subdivision of Land" }, + { label: "Sugar and Confectionery Product Manufacturing", value: "Sugar and Confectionery Product Manufacturing" }, + { label: "Surveying and Mapping Services", value: "Surveying and Mapping Services" }, + { label: "Taxi and Limousine Services", value: "Taxi and Limousine Services" }, + { label: "Technical and Vocational Training", value: "Technical and Vocational Training" }, + { label: "Technology, Information and Internet", value: "Technology, Information and Internet" }, + { label: "Technology, Information and Media", value: "Technology, Information and Media" }, + { label: "Telecommunications", value: "Telecommunications" }, + { label: "Telecommunications Carriers", value: "Telecommunications Carriers" }, + { label: "Telephone Call Centers", value: "Telephone Call Centers" }, + { label: "Temporary Help Services", value: "Temporary Help Services" }, + { label: "Textile Manufacturing", value: "Textile Manufacturing" }, + { label: "Theater Companies", value: "Theater Companies" }, + { label: "Think Tanks", value: "Think Tanks" }, + { label: "Tobacco", value: "Tobacco" }, + { label: "Tobacco Manufacturing", value: "Tobacco Manufacturing" }, + { label: "Translation and Localization", value: "Translation and Localization" }, + { label: "Transportation Equipment Manufacturing", value: "Transportation Equipment Manufacturing" }, + { label: "Transportation Programs", value: "Transportation Programs" }, + { label: "Transportation, Logistics, Supply Chain and Storage", value: "Transportation, Logistics, Supply Chain and Storage" }, + { label: "Transportation/Trucking/Railroad", value: "Transportation/Trucking/Railroad" }, + { label: "Travel Arrangements", value: "Travel Arrangements" }, + { label: "Truck Transportation", value: "Truck Transportation" }, + { label: "Trusts and Estates", value: "Trusts and Estates" }, + { label: "Turned Products and Fastener Manufacturing", value: "Turned Products and Fastener Manufacturing" }, + { label: "Urban Transit Services", value: "Urban Transit Services" }, + { label: "Utilities", value: "Utilities" }, + { label: "Utilities Administration", value: "Utilities Administration" }, + { label: "Utility System Construction", value: "Utility System Construction" }, + { label: "Vehicle Repair and Maintenance", value: "Vehicle Repair and Maintenance" }, + { label: "Venture Capital and Private Equity Principals", value: "Venture Capital and Private Equity Principals" }, + { label: "Veterinary", value: "Veterinary" }, + { label: "Veterinary Services", value: "Veterinary Services" }, + { label: "Vocational Rehabilitation Services", value: "Vocational Rehabilitation Services" }, + { label: "Warehousing", value: "Warehousing" }, + { label: "Warehousing and Storage", value: "Warehousing and Storage" }, + { label: "Waste Collection", value: "Waste Collection" }, + { label: "Waste Treatment and Disposal", value: "Waste Treatment and Disposal" }, + { label: "Water Supply and Irrigation Systems", value: "Water Supply and Irrigation Systems" }, + { label: "Water, Waste, Steam, and Air Conditioning Services", value: "Water, Waste, Steam, and Air Conditioning Services" }, + { label: "Wellness and Fitness Services", value: "Wellness and Fitness Services" }, + { label: "Wholesale", value: "Wholesale" }, + { label: "Wholesale Alcoholic Beverages", value: "Wholesale Alcoholic Beverages" }, + { label: "Wholesale Apparel and Sewing Supplies", value: "Wholesale Apparel and Sewing Supplies" }, + { label: "Wholesale Appliances, Electrical, and Electronics", value: "Wholesale Appliances, Electrical, and Electronics" }, + { label: "Wholesale Building Materials", value: "Wholesale Building Materials" }, + { label: "Wholesale Chemical and Allied Products", value: "Wholesale Chemical and Allied Products" }, + { label: "Wholesale Computer Equipment", value: "Wholesale Computer Equipment" }, + { label: "Wholesale Drugs and Sundries", value: "Wholesale Drugs and Sundries" }, + { label: "Wholesale Food and Beverage", value: "Wholesale Food and Beverage" }, + { label: "Wholesale Footwear", value: "Wholesale Footwear" }, + { label: "Wholesale Furniture and Home Furnishings", value: "Wholesale Furniture and Home Furnishings" }, + { label: "Wholesale Hardware, Plumbing, Heating Equipment", value: "Wholesale Hardware, Plumbing, Heating Equipment" }, + { label: "Wholesale Import and Export", value: "Wholesale Import and Export" }, + { label: "Wholesale Luxury Goods and Jewelry", value: "Wholesale Luxury Goods and Jewelry" }, + { label: "Wholesale Machinery", value: "Wholesale Machinery" }, + { label: "Wholesale Metals and Minerals", value: "Wholesale Metals and Minerals" }, + { label: "Wholesale Motor Vehicles and Parts", value: "Wholesale Motor Vehicles and Parts" }, + { label: "Wholesale Paper Products", value: "Wholesale Paper Products" }, + { label: "Wholesale Petroleum and Petroleum Products", value: "Wholesale Petroleum and Petroleum Products" }, + { label: "Wholesale Raw Farm Products", value: "Wholesale Raw Farm Products" }, + { label: "Wholesale Recyclable Materials", value: "Wholesale Recyclable Materials" }, + { label: "Wind Electric Power Generation", value: "Wind Electric Power Generation" }, + { label: "Wine and Spirits", value: "Wine and Spirits" }, + { label: "Wineries", value: "Wineries" }, + { label: "Wireless Services", value: "Wireless Services" }, + { label: "Wood Product Manufacturing", value: "Wood Product Manufacturing" }, + { label: "Writing and Editing", value: "Writing and Editing" }, + { label: "Zoos and Botanical Gardens", value: "Zoos and Botanical Gardens" }, + ], + locationCountry: [ + { label: "Afghanistan", value: "Afghanistan" }, + { label: "Albania", value: "Albania" }, + { label: "Algeria", value: "Algeria" }, + { label: "Andorra", value: "Andorra" }, + { label: "Angola", value: "Angola" }, + { label: "Anguilla", value: "Anguilla" }, + { label: "Antarctica", value: "Antarctica" }, + { label: "Antigua and Barbuda", value: "Antigua and Barbuda" }, + { label: "Argentina", value: "Argentina" }, + { label: "Armenia", value: "Armenia" }, + { label: "Aruba", value: "Aruba" }, + { label: "Australia", value: "Australia" }, + { label: "Austria", value: "Austria" }, + { label: "Azerbaijan", value: "Azerbaijan" }, + { label: "Bahamas", value: "Bahamas" }, + { label: "Bahrain", value: "Bahrain" }, + { label: "Bangladesh", value: "Bangladesh" }, + { label: "Barbados", value: "Barbados" }, + { label: "Belarus", value: "Belarus" }, + { label: "Belgium", value: "Belgium" }, + { label: "Belize", value: "Belize" }, + { label: "Benin", value: "Benin" }, + { label: "Bermuda", value: "Bermuda" }, + { label: "Bhutan", value: "Bhutan" }, + { label: "Bolivia", value: "Bolivia" }, + { label: "Bonaire, Saint Eustatius and Saba ", value: "Bonaire, Saint Eustatius and Saba " }, + { label: "Bosnia and Herzegovina", value: "Bosnia and Herzegovina" }, + { label: "Botswana", value: "Botswana" }, + { label: "Brazil", value: "Brazil" }, + { label: "British Virgin Islands", value: "British Virgin Islands" }, + { label: "Brunei", value: "Brunei" }, + { label: "Bulgaria", value: "Bulgaria" }, + { label: "Burkina Faso", value: "Burkina Faso" }, + { label: "Burundi", value: "Burundi" }, + { label: "Cambodia", value: "Cambodia" }, + { label: "Cameroon", value: "Cameroon" }, + { label: "Canada", value: "Canada" }, + { label: "Cape Verde", value: "Cape Verde" }, + { label: "Cayman Islands", value: "Cayman Islands" }, + { label: "Central African Republic", value: "Central African Republic" }, + { label: "Chad", value: "Chad" }, + { label: "Chile", value: "Chile" }, + { label: "China", value: "China" }, + { label: "Colombia", value: "Colombia" }, + { label: "Comoros", value: "Comoros" }, + { label: "Costa Rica", value: "Costa Rica" }, + { label: "Croatia", value: "Croatia" }, + { label: "Cuba", value: "Cuba" }, + { label: "Curacao", value: "Curacao" }, + { label: "Cyprus", value: "Cyprus" }, + { label: "Czechia", value: "Czechia" }, + { label: "Democratic Republic of the Congo", value: "Democratic Republic of the Congo" }, + { label: "Denmark", value: "Denmark" }, + { label: "Djibouti", value: "Djibouti" }, + { label: "Dominican Republic", value: "Dominican Republic" }, + { label: "East Timor", value: "East Timor" }, + { label: "Ecuador", value: "Ecuador" }, + { label: "Egypt", value: "Egypt" }, + { label: "El Salvador", value: "El Salvador" }, + { label: "Equatorial Guinea", value: "Equatorial Guinea" }, + { label: "Estonia", value: "Estonia" }, + { label: "Ethiopia", value: "Ethiopia" }, + { label: "Faroe Islands", value: "Faroe Islands" }, + { label: "Fiji", value: "Fiji" }, + { label: "Finland", value: "Finland" }, + { label: "France", value: "France" }, + { label: "French Guiana", value: "French Guiana" }, + { label: "French Polynesia", value: "French Polynesia" }, + { label: "Gabon", value: "Gabon" }, + { label: "Gambia", value: "Gambia" }, + { label: "Georgia", value: "Georgia" }, + { label: "Germany", value: "Germany" }, + { label: "Ghana", value: "Ghana" }, + { label: "Gibraltar", value: "Gibraltar" }, + { label: "Greece", value: "Greece" }, + { label: "Greenland", value: "Greenland" }, + { label: "Grenada", value: "Grenada" }, + { label: "Guadeloupe", value: "Guadeloupe" }, + { label: "Guam", value: "Guam" }, + { label: "Guatemala", value: "Guatemala" }, + { label: "Guernsey", value: "Guernsey" }, + { label: "Guinea", value: "Guinea" }, + { label: "Guyana", value: "Guyana" }, + { label: "Haiti", value: "Haiti" }, + { label: "Honduras", value: "Honduras" }, + { label: "Hong Kong", value: "Hong Kong" }, + { label: "Hungary", value: "Hungary" }, + { label: "Iceland", value: "Iceland" }, + { label: "India", value: "India" }, + { label: "Indonesia", value: "Indonesia" }, + { label: "Iran", value: "Iran" }, + { label: "Iraq", value: "Iraq" }, + { label: "Ireland", value: "Ireland" }, + { label: "Isle of Man", value: "Isle of Man" }, + { label: "Israel", value: "Israel" }, + { label: "Italy", value: "Italy" }, + { label: "Ivory Coast", value: "Ivory Coast" }, + { label: "Jamaica", value: "Jamaica" }, + { label: "Japan", value: "Japan" }, + { label: "Jersey", value: "Jersey" }, + { label: "Jordan", value: "Jordan" }, + { label: "Kazakhstan", value: "Kazakhstan" }, + { label: "Kenya", value: "Kenya" }, + { label: "Kosovo", value: "Kosovo" }, + { label: "Kuwait", value: "Kuwait" }, + { label: "Kyrgyzstan", value: "Kyrgyzstan" }, + { label: "Laos", value: "Laos" }, + { label: "Latvia", value: "Latvia" }, + { label: "Lebanon", value: "Lebanon" }, + { label: "Lesotho", value: "Lesotho" }, + { label: "Liberia", value: "Liberia" }, + { label: "Libya", value: "Libya" }, + { label: "Liechtenstein", value: "Liechtenstein" }, + { label: "Lithuania", value: "Lithuania" }, + { label: "Luxembourg", value: "Luxembourg" }, + { label: "Macao", value: "Macao" }, + { label: "Macedonia", value: "Macedonia" }, + { label: "Madagascar", value: "Madagascar" }, + { label: "Malawi", value: "Malawi" }, + { label: "Malaysia", value: "Malaysia" }, + { label: "Maldives", value: "Maldives" }, + { label: "Mali", value: "Mali" }, + { label: "Malta", value: "Malta" }, + { label: "Marshall Islands", value: "Marshall Islands" }, + { label: "Martinique", value: "Martinique" }, + { label: "Mauritania", value: "Mauritania" }, + { label: "Mauritius", value: "Mauritius" }, + { label: "Mayotte", value: "Mayotte" }, + { label: "Mexico", value: "Mexico" }, + { label: "Moldova", value: "Moldova" }, + { label: "Monaco", value: "Monaco" }, + { label: "Mongolia", value: "Mongolia" }, + { label: "Montenegro", value: "Montenegro" }, + { label: "Morocco", value: "Morocco" }, + { label: "Mozambique", value: "Mozambique" }, + { label: "Myanmar", value: "Myanmar" }, + { label: "Namibia", value: "Namibia" }, + { label: "Nepal", value: "Nepal" }, + { label: "Netherlands", value: "Netherlands" }, + { label: "Netherlands Antilles", value: "Netherlands Antilles" }, + { label: "New Caledonia", value: "New Caledonia" }, + { label: "New Zealand", value: "New Zealand" }, + { label: "Nicaragua", value: "Nicaragua" }, + { label: "Niger", value: "Niger" }, + { label: "Nigeria", value: "Nigeria" }, + { label: "North Korea", value: "North Korea" }, + { label: "Northern Mariana Islands", value: "Northern Mariana Islands" }, + { label: "Norway", value: "Norway" }, + { label: "Oman", value: "Oman" }, + { label: "Pakistan", value: "Pakistan" }, + { label: "Palestinian Territory", value: "Palestinian Territory" }, + { label: "Panama", value: "Panama" }, + { label: "Papua New Guinea", value: "Papua New Guinea" }, + { label: "Paraguay", value: "Paraguay" }, + { label: "Peru", value: "Peru" }, + { label: "Philippines", value: "Philippines" }, + { label: "Poland", value: "Poland" }, + { label: "Portugal", value: "Portugal" }, + { label: "Puerto Rico", value: "Puerto Rico" }, + { label: "Qatar", value: "Qatar" }, + { label: "Republic of the Congo", value: "Republic of the Congo" }, + { label: "Reunion", value: "Reunion" }, + { label: "Romania", value: "Romania" }, + { label: "Russia", value: "Russia" }, + { label: "Rwanda", value: "Rwanda" }, + { label: "Saint Barthelemy", value: "Saint Barthelemy" }, + { label: "Saint Kitts and Nevis", value: "Saint Kitts and Nevis" }, + { label: "Saint Lucia", value: "Saint Lucia" }, + { label: "Saint Vincent and the Grenadines", value: "Saint Vincent and the Grenadines" }, + { label: "Samoa", value: "Samoa" }, + { label: "San Marino", value: "San Marino" }, + { label: "Sao Tome and Principe", value: "Sao Tome and Principe" }, + { label: "Saudi Arabia", value: "Saudi Arabia" }, + { label: "Senegal", value: "Senegal" }, + { label: "Serbia", value: "Serbia" }, + { label: "Serbia and Montenegro", value: "Serbia and Montenegro" }, + { label: "Seychelles", value: "Seychelles" }, + { label: "Sierra Leone", value: "Sierra Leone" }, + { label: "Singapore", value: "Singapore" }, + { label: "Sint Maarten", value: "Sint Maarten" }, + { label: "Slovakia", value: "Slovakia" }, + { label: "Slovenia", value: "Slovenia" }, + { label: "Somalia", value: "Somalia" }, + { label: "South Africa", value: "South Africa" }, + { label: "South Korea", value: "South Korea" }, + { label: "South Sudan", value: "South Sudan" }, + { label: "Spain", value: "Spain" }, + { label: "Sri Lanka", value: "Sri Lanka" }, + { label: "Sudan", value: "Sudan" }, + { label: "Suriname", value: "Suriname" }, + { label: "Svalbard and Jan Mayen", value: "Svalbard and Jan Mayen" }, + { label: "Swaziland", value: "Swaziland" }, + { label: "Sweden", value: "Sweden" }, + { label: "Switzerland", value: "Switzerland" }, + { label: "Syria", value: "Syria" }, + { label: "Taiwan", value: "Taiwan" }, + { label: "Tajikistan", value: "Tajikistan" }, + { label: "Tanzania", value: "Tanzania" }, + { label: "Thailand", value: "Thailand" }, + { label: "Togo", value: "Togo" }, + { label: "Tonga", value: "Tonga" }, + { label: "Trinidad and Tobago", value: "Trinidad and Tobago" }, + { label: "Tunisia", value: "Tunisia" }, + { label: "Turkey", value: "Turkey" }, + { label: "Turkmenistan", value: "Turkmenistan" }, + { label: "Turks and Caicos Islands", value: "Turks and Caicos Islands" }, + { label: "U.S. Virgin Islands", value: "U.S. Virgin Islands" }, + { label: "Uganda", value: "Uganda" }, + { label: "Ukraine", value: "Ukraine" }, + { label: "United Arab Emirates", value: "United Arab Emirates" }, + { label: "United Kingdom", value: "United Kingdom" }, + { label: "United States", value: "United States" }, + { label: "Uruguay", value: "Uruguay" }, + { label: "Uzbekistan", value: "Uzbekistan" }, + { label: "Vanuatu", value: "Vanuatu" }, + { label: "Venezuela", value: "Venezuela" }, + { label: "Vietnam", value: "Vietnam" }, + { label: "Yemen", value: "Yemen" }, + { label: "Zambia", value: "Zambia" }, + { label: "Zimbabwe", value: "Zimbabwe" }, + ], +}; diff --git a/packages/pieces/community/clay/src/lib/common/index.ts b/packages/pieces/community/clay/src/lib/common/index.ts new file mode 100644 index 000000000000..a36ff144f2e9 --- /dev/null +++ b/packages/pieces/community/clay/src/lib/common/index.ts @@ -0,0 +1,93 @@ +import { httpClient, HttpMethod, HttpMessageBody, HttpResponse } from '@activepieces/pieces-common'; + +export async function clayApiCall({ + apiKey, + method, + path, + body, + queryParams, +}: { + apiKey: string; + method: HttpMethod; + path: string; + body?: unknown; + queryParams?: Record; +}): Promise> { + return await httpClient.sendRequest({ + method, + url: `${BASE_URL}${path}`, + headers: { + 'clay-api-key': apiKey, + }, + queryParams, + body, + }); +} + +export async function runClayQueryModeSearch({ + apiKey, + sourceType, + query, + limit, +}: { + apiKey: string; + sourceType: 'people' | 'companies'; + query: string; + limit: number; +}): Promise<{ + search_id: string; + records: unknown[]; + has_more: boolean; + period_quota: { limit: number; used: number; remaining: number; resets_at: string }; +}> { + const created = await clayApiCall<{ search_id: string; source_type: 'people' | 'companies' }>({ + apiKey, + method: HttpMethod.POST, + path: '/search/query-mode', + body: { query }, + }); + + if (created.body.source_type !== sourceType) { + throw new Error( + `Query resolved to a "${created.body.source_type}" search, but this action searches "${sourceType}". Rephrase the query to describe ${sourceType} instead.`, + ); + } + + const results = await clayApiCall<{ + data: unknown[]; + has_more: boolean; + period_quota: { limit: number; used: number; remaining: number; resets_at: string }; + }>({ + apiKey, + method: HttpMethod.POST, + path: `/search/query-mode/${created.body.search_id}/run`, + body: { limit }, + }); + + return { + search_id: created.body.search_id, + records: results.body.data, + has_more: results.body.has_more, + period_quota: results.body.period_quota, + }; +} + +export function escapeClayQueryValue(value: string): string { + return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"'); +} + +export function buildClayInClause({ + field, + values, +}: { + field: string; + values: string[]; +}): string | undefined { + if (values.length === 0) { + return undefined; + } + const list = values.map((value) => `"${escapeClayQueryValue(value)}"`).join(', '); + return `${field} in (${list})`; +} + +const BASE_URL = 'https://api.clay.com/public/v0'; diff --git a/packages/pieces/community/clay/src/lib/common/people-search-options.ts b/packages/pieces/community/clay/src/lib/common/people-search-options.ts new file mode 100644 index 000000000000..ac34b2fb3600 --- /dev/null +++ b/packages/pieces/community/clay/src/lib/common/people-search-options.ts @@ -0,0 +1,273 @@ +export const clayPeopleSearchOptions = { + locationCountry: [ + { label: "Afghanistan", value: "Afghanistan" }, + { label: "Åland Islands", value: "Åland Islands" }, + { label: "Albania", value: "Albania" }, + { label: "Algeria", value: "Algeria" }, + { label: "American Samoa", value: "American Samoa" }, + { label: "Andorra", value: "Andorra" }, + { label: "Angola", value: "Angola" }, + { label: "Anguilla", value: "Anguilla" }, + { label: "Antarctica", value: "Antarctica" }, + { label: "Antigua and Barbuda", value: "Antigua and Barbuda" }, + { label: "Argentina", value: "Argentina" }, + { label: "Armenia", value: "Armenia" }, + { label: "Aruba", value: "Aruba" }, + { label: "Australia", value: "Australia" }, + { label: "Austria", value: "Austria" }, + { label: "Azerbaijan", value: "Azerbaijan" }, + { label: "Bahamas", value: "Bahamas" }, + { label: "Bahrain", value: "Bahrain" }, + { label: "Bangladesh", value: "Bangladesh" }, + { label: "Barbados", value: "Barbados" }, + { label: "Belarus", value: "Belarus" }, + { label: "Belgium", value: "Belgium" }, + { label: "Belize", value: "Belize" }, + { label: "Benin", value: "Benin" }, + { label: "Bermuda", value: "Bermuda" }, + { label: "Bhutan", value: "Bhutan" }, + { label: "Bolivia", value: "Bolivia" }, + { label: "Bosnia and Herzegovina", value: "Bosnia and Herzegovina" }, + { label: "Botswana", value: "Botswana" }, + { label: "Bouvet Island", value: "Bouvet Island" }, + { label: "Brazil", value: "Brazil" }, + { label: "British Indian Ocean Territory", value: "British Indian Ocean Territory" }, + { label: "Brunei Darussalam", value: "Brunei Darussalam" }, + { label: "Bulgaria", value: "Bulgaria" }, + { label: "Burkina Faso", value: "Burkina Faso" }, + { label: "Burundi", value: "Burundi" }, + { label: "Cambodia", value: "Cambodia" }, + { label: "Cameroon", value: "Cameroon" }, + { label: "Canada", value: "Canada" }, + { label: "Cape Verde", value: "Cape Verde" }, + { label: "Cayman Islands", value: "Cayman Islands" }, + { label: "Central African Republic", value: "Central African Republic" }, + { label: "Chad", value: "Chad" }, + { label: "Chile", value: "Chile" }, + { label: "China", value: "China" }, + { label: "Christmas Island", value: "Christmas Island" }, + { label: "Cocos (Keeling) Islands", value: "Cocos (Keeling) Islands" }, + { label: "Collectivity of Saint Martin", value: "Collectivity of Saint Martin" }, + { label: "Colombia", value: "Colombia" }, + { label: "Comoros", value: "Comoros" }, + { label: "Cook Islands", value: "Cook Islands" }, + { label: "Costa Rica", value: "Costa Rica" }, + { label: "Côte d'Ivoire", value: "Côte d'Ivoire" }, + { label: "Croatia", value: "Croatia" }, + { label: "Cuba", value: "Cuba" }, + { label: "Curaçao", value: "Curaçao" }, + { label: "Cyprus", value: "Cyprus" }, + { label: "Czech Republic", value: "Czech Republic" }, + { label: "Democratic Republic of the Congo", value: "Democratic Republic of the Congo" }, + { label: "Denmark", value: "Denmark" }, + { label: "Djibouti", value: "Djibouti" }, + { label: "Dominica", value: "Dominica" }, + { label: "Dominican Republic", value: "Dominican Republic" }, + { label: "Ecuador", value: "Ecuador" }, + { label: "Egypt", value: "Egypt" }, + { label: "El Salvador", value: "El Salvador" }, + { label: "Equatorial Guinea", value: "Equatorial Guinea" }, + { label: "Eritrea", value: "Eritrea" }, + { label: "Estonia", value: "Estonia" }, + { label: "Ethiopia", value: "Ethiopia" }, + { label: "Falkland Islands (Malvinas)", value: "Falkland Islands (Malvinas)" }, + { label: "Faroe Islands", value: "Faroe Islands" }, + { label: "Fiji", value: "Fiji" }, + { label: "Finland", value: "Finland" }, + { label: "France", value: "France" }, + { label: "French Guiana", value: "French Guiana" }, + { label: "French Polynesia", value: "French Polynesia" }, + { label: "French Southern Territories", value: "French Southern Territories" }, + { label: "Gabon", value: "Gabon" }, + { label: "Gambia", value: "Gambia" }, + { label: "Georgia", value: "Georgia" }, + { label: "Germany", value: "Germany" }, + { label: "Ghana", value: "Ghana" }, + { label: "Gibralta", value: "Gibralta" }, + { label: "Greece", value: "Greece" }, + { label: "Greenland", value: "Greenland" }, + { label: "Grenada", value: "Grenada" }, + { label: "Guadeloupe", value: "Guadeloupe" }, + { label: "Guam", value: "Guam" }, + { label: "Guatemala", value: "Guatemala" }, + { label: "Guernsey", value: "Guernsey" }, + { label: "Guinea-Bissau", value: "Guinea-Bissau" }, + { label: "Guinea", value: "Guinea" }, + { label: "Guyana", value: "Guyana" }, + { label: "Haiti", value: "Haiti" }, + { label: "Heard Island and McDonald Islands", value: "Heard Island and McDonald Islands" }, + { label: "Holy See", value: "Holy See" }, + { label: "Honduras", value: "Honduras" }, + { label: "Hong Kong", value: "Hong Kong" }, + { label: "Hungary", value: "Hungary" }, + { label: "Iceland", value: "Iceland" }, + { label: "India", value: "India" }, + { label: "Indonesia", value: "Indonesia" }, + { label: "Iran", value: "Iran" }, + { label: "Iraq", value: "Iraq" }, + { label: "Ireland", value: "Ireland" }, + { label: "Isle of Man", value: "Isle of Man" }, + { label: "Israel", value: "Israel" }, + { label: "Italy", value: "Italy" }, + { label: "Jamaica", value: "Jamaica" }, + { label: "Japan", value: "Japan" }, + { label: "Jersey", value: "Jersey" }, + { label: "Jordan", value: "Jordan" }, + { label: "Kazakhstan", value: "Kazakhstan" }, + { label: "Kenya", value: "Kenya" }, + { label: "Kiribati", value: "Kiribati" }, + { label: "Kuwait", value: "Kuwait" }, + { label: "Kyrgyzstan", value: "Kyrgyzstan" }, + { label: "Laos", value: "Laos" }, + { label: "Latvia", value: "Latvia" }, + { label: "Lebanon", value: "Lebanon" }, + { label: "Lesotho", value: "Lesotho" }, + { label: "Liberia", value: "Liberia" }, + { label: "Libya", value: "Libya" }, + { label: "Liechtenstein", value: "Liechtenstein" }, + { label: "Lithuania", value: "Lithuania" }, + { label: "Luxembourg", value: "Luxembourg" }, + { label: "Macao", value: "Macao" }, + { label: "Madagascar", value: "Madagascar" }, + { label: "Malawi", value: "Malawi" }, + { label: "Malaysia", value: "Malaysia" }, + { label: "Maldives", value: "Maldives" }, + { label: "Mali", value: "Mali" }, + { label: "Malta", value: "Malta" }, + { label: "Marshall Islands", value: "Marshall Islands" }, + { label: "Martinique", value: "Martinique" }, + { label: "Mauritania", value: "Mauritania" }, + { label: "Mauritius", value: "Mauritius" }, + { label: "Mayotte", value: "Mayotte" }, + { label: "Mexico", value: "Mexico" }, + { label: "Micronesia", value: "Micronesia" }, + { label: "Moldova", value: "Moldova" }, + { label: "Monaco", value: "Monaco" }, + { label: "Mongolia", value: "Mongolia" }, + { label: "Montenegro", value: "Montenegro" }, + { label: "Montserrat", value: "Montserrat" }, + { label: "Morocco", value: "Morocco" }, + { label: "Mozambique", value: "Mozambique" }, + { label: "Myanmar", value: "Myanmar" }, + { label: "Namibia", value: "Namibia" }, + { label: "Nauru", value: "Nauru" }, + { label: "Nepal", value: "Nepal" }, + { label: "Netherlands", value: "Netherlands" }, + { label: "New Caledonia", value: "New Caledonia" }, + { label: "New Zealand", value: "New Zealand" }, + { label: "Nicaragua", value: "Nicaragua" }, + { label: "Niger", value: "Niger" }, + { label: "Nigeria", value: "Nigeria" }, + { label: "Niue", value: "Niue" }, + { label: "Norfolk Island", value: "Norfolk Island" }, + { label: "North Korea", value: "North Korea" }, + { label: "North Macedonia", value: "North Macedonia" }, + { label: "Northern Mariana Islands", value: "Northern Mariana Islands" }, + { label: "Norway", value: "Norway" }, + { label: "Oman", value: "Oman" }, + { label: "Pakistan", value: "Pakistan" }, + { label: "Palau", value: "Palau" }, + { label: "Palestine", value: "Palestine" }, + { label: "Panama", value: "Panama" }, + { label: "Papua New Guinea", value: "Papua New Guinea" }, + { label: "Paraguay", value: "Paraguay" }, + { label: "Peru", value: "Peru" }, + { label: "Philippines", value: "Philippines" }, + { label: "Pitcairn", value: "Pitcairn" }, + { label: "Poland", value: "Poland" }, + { label: "Portugal", value: "Portugal" }, + { label: "Puerto Rico", value: "Puerto Rico" }, + { label: "Qatar", value: "Qatar" }, + { label: "Republic of the Congo", value: "Republic of the Congo" }, + { label: "Réunion", value: "Réunion" }, + { label: "Romania", value: "Romania" }, + { label: "Russia", value: "Russia" }, + { label: "Rwanda", value: "Rwanda" }, + { label: "Saint Barthélemy", value: "Saint Barthélemy" }, + { label: "Saint Helena, Ascension and Tristan da Cunha", value: "Saint Helena, Ascension and Tristan da Cunha" }, + { label: "Saint Kitts and Nevis", value: "Saint Kitts and Nevis" }, + { label: "Saint Lucia", value: "Saint Lucia" }, + { label: "Saint Pierre and Miquelon", value: "Saint Pierre and Miquelon" }, + { label: "Saint Vincent and the Grenadines", value: "Saint Vincent and the Grenadines" }, + { label: "Samoa", value: "Samoa" }, + { label: "San Marino", value: "San Marino" }, + { label: "Sao Tome and Principe", value: "Sao Tome and Principe" }, + { label: "Saudi Arabia", value: "Saudi Arabia" }, + { label: "Senegal", value: "Senegal" }, + { label: "Serbia", value: "Serbia" }, + { label: "Seychelles", value: "Seychelles" }, + { label: "Sierra Leone", value: "Sierra Leone" }, + { label: "Singapore", value: "Singapore" }, + { label: "Sint Maarten", value: "Sint Maarten" }, + { label: "Slovakia", value: "Slovakia" }, + { label: "Slovenia", value: "Slovenia" }, + { label: "Solomon Islands", value: "Solomon Islands" }, + { label: "Somalia", value: "Somalia" }, + { label: "South Africa", value: "South Africa" }, + { label: "South Georgia and the South Sandwich Islands", value: "South Georgia and the South Sandwich Islands" }, + { label: "South Korea", value: "South Korea" }, + { label: "South Sudan", value: "South Sudan" }, + { label: "Spain", value: "Spain" }, + { label: "Sri Lanka", value: "Sri Lanka" }, + { label: "Sudan", value: "Sudan" }, + { label: "Suriname", value: "Suriname" }, + { label: "Swaziland", value: "Swaziland" }, + { label: "Sweden", value: "Sweden" }, + { label: "Switzerland", value: "Switzerland" }, + { label: "Syria", value: "Syria" }, + { label: "Taiwan", value: "Taiwan" }, + { label: "Tajikistan", value: "Tajikistan" }, + { label: "Tanzania", value: "Tanzania" }, + { label: "Thailand", value: "Thailand" }, + { label: "Timor-Leste", value: "Timor-Leste" }, + { label: "Togo", value: "Togo" }, + { label: "Tokelau", value: "Tokelau" }, + { label: "Tonga", value: "Tonga" }, + { label: "Trinidad and Tobago", value: "Trinidad and Tobago" }, + { label: "Tunisia", value: "Tunisia" }, + { label: "Turkey", value: "Turkey" }, + { label: "Turkmenistan", value: "Turkmenistan" }, + { label: "Turks and Caicos Islands", value: "Turks and Caicos Islands" }, + { label: "Tuvalu", value: "Tuvalu" }, + { label: "Uganda", value: "Uganda" }, + { label: "Ukraine", value: "Ukraine" }, + { label: "United Arab Emirates", value: "United Arab Emirates" }, + { label: "United Kingdom", value: "United Kingdom" }, + { label: "United States Minor Outlying Islands", value: "United States Minor Outlying Islands" }, + { label: "United States", value: "United States" }, + { label: "Uruguay", value: "Uruguay" }, + { label: "Uzbekistan", value: "Uzbekistan" }, + { label: "Vanuatu", value: "Vanuatu" }, + { label: "Venezuela", value: "Venezuela" }, + { label: "Vietnam", value: "Vietnam" }, + { label: "Virgin Islands, British", value: "Virgin Islands, British" }, + { label: "Virgin Islands, U.S.", value: "Virgin Islands, U.S." }, + { label: "Wallis and Futuna", value: "Wallis and Futuna" }, + { label: "Western Sahara", value: "Western Sahara" }, + { label: "Yemen", value: "Yemen" }, + { label: "Zambia", value: "Zambia" }, + { label: "Zimbabwe", value: "Zimbabwe" }, + ], + locationRegion: [ + { label: "APAC", value: "APAC" }, + { label: "EMEA", value: "EMEA" }, + { label: "LATAM", value: "LATAM" }, + { label: "NAM", value: "NAM" }, + ], + experienceSeniority: [ + { label: "Founder", value: "Founder" }, + { label: "Owner", value: "Owner" }, + { label: "Board member", value: "Board Member" }, + { label: "Partner", value: "Partner" }, + { label: "C-suite", value: "C-suite" }, + { label: "VP", value: "VP" }, + { label: "Director", value: "Director" }, + { label: "Head", value: "Head" }, + { label: "Manager", value: "Manager" }, + { label: "Senior", value: "Senior" }, + { label: "Mid-level", value: "Mid-level" }, + { label: "Entry", value: "Entry" }, + { label: "Intern / in training", value: "Intern / In Training" }, + { label: "Unknown", value: "Unknown" }, + ], +}; diff --git a/packages/pieces/community/clay/tsconfig.json b/packages/pieces/community/clay/tsconfig.json new file mode 100644 index 000000000000..71bc5814f5de --- /dev/null +++ b/packages/pieces/community/clay/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "module": "commonjs", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [{ "path": "./tsconfig.lib.json" }] +} diff --git a/packages/pieces/community/clay/tsconfig.lib.json b/packages/pieces/community/clay/tsconfig.lib.json new file mode 100644 index 000000000000..a648eb45d7fa --- /dev/null +++ b/packages/pieces/community/clay/tsconfig.lib.json @@ -0,0 +1,13 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "rootDir": ".", + "baseUrl": ".", + "paths": {}, + "outDir": "./dist", + "declaration": true, + "types": ["node"] + }, + "include": ["src/**/*.ts"], + "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] +} diff --git a/tsconfig.base.json b/tsconfig.base.json index 5add412780b7..d30235243cd0 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -277,6 +277,9 @@ "@activepieces/piece-claude": [ "packages/pieces/community/claude/src/index.ts" ], + "@activepieces/piece-clay": [ + "packages/pieces/community/clay/src/index.ts" + ], "@activepieces/piece-clearout": [ "packages/pieces/community/clearout/src/index.ts" ], From c20d538337f9b3dbdd3c8b5705e0e976835f1ac3 Mon Sep 17 00:00:00 2001 From: Amr Elmohamady Date: Wed, 2 Sep 2026 12:41:53 +0300 Subject: [PATCH 3/3] fix(engine): user-caused run-callback failures no longer show as internal errors (#15198) --- .../core/utils/src/lib/activepieces-error.ts | 10 ++++++++++ .../server/api/src/app/file/files-service.ts | 7 +++++-- .../api/src/app/helper/error-handler.ts | 1 + .../engine/src/lib/api/engine-file-api.ts | 20 ++++++++++++++++++- .../engine/src/lib/handler/base-executor.ts | 2 +- .../engine/src/lib/handler/flow-executor.ts | 2 +- .../engine/src/lib/handler/piece-executor.ts | 4 ++-- .../src/lib/operations/flow.operation.ts | 2 +- 8 files changed, 40 insertions(+), 8 deletions(-) diff --git a/packages/core/utils/src/lib/activepieces-error.ts b/packages/core/utils/src/lib/activepieces-error.ts index 67533a671e98..f06a442c8281 100644 --- a/packages/core/utils/src/lib/activepieces-error.ts +++ b/packages/core/utils/src/lib/activepieces-error.ts @@ -49,6 +49,7 @@ export type ApErrorParams = | TriggerUpdateStatusErrorParams | TriggerFailedErrorParams | ValidationErrorParams + | FileTooLargeErrorParams | InvitationOnlySignUpParams | UserIsInActiveErrorParams | UserNotFoundOnPlatformErrorParams @@ -316,6 +317,14 @@ ErrorCode.VALIDATION, } > +export type FileTooLargeErrorParams = BaseErrorParams< +ErrorCode.FILE_TOO_LARGE, +{ + message: string + maxBytes: number +} +> + export type TriggerUpdateStatusErrorParams = BaseErrorParams< ErrorCode.TRIGGER_UPDATE_STATUS, { @@ -567,6 +576,7 @@ export enum ErrorCode { USER_IS_INACTIVE = 'USER_IS_INACTIVE', USER_NOT_FOUND_ON_PLATFORM = 'USER_NOT_FOUND_ON_PLATFORM', VALIDATION = 'VALIDATION', + FILE_TOO_LARGE = 'FILE_TOO_LARGE', INVALID_LICENSE_KEY = 'INVALID_LICENSE_KEY', EMAIL_ALREADY_HAS_ACTIVATION_KEY = 'EMAIL_ALREADY_HAS_ACTIVATION_KEY', INVALID_SMTP_CREDENTIALS = 'INVALID_SMTP_CREDENTIALS', diff --git a/packages/server/api/src/app/file/files-service.ts b/packages/server/api/src/app/file/files-service.ts index abc392542e4b..69b45a45e3ad 100644 --- a/packages/server/api/src/app/file/files-service.ts +++ b/packages/server/api/src/app/file/files-service.ts @@ -37,8 +37,11 @@ export const filesService = { export function fileTooLargeError(maxBytes: number): ActivepiecesError { return new ActivepiecesError({ - code: ErrorCode.VALIDATION, - params: { message: `File exceeds the maximum allowed size of ${maxBytes} bytes` }, + code: ErrorCode.FILE_TOO_LARGE, + params: { + message: `File exceeds the maximum allowed size of ${maxBytes} bytes`, + maxBytes, + }, }) } diff --git a/packages/server/api/src/app/helper/error-handler.ts b/packages/server/api/src/app/helper/error-handler.ts index fdae2421f59c..04eb76cda7c0 100644 --- a/packages/server/api/src/app/helper/error-handler.ts +++ b/packages/server/api/src/app/helper/error-handler.ts @@ -103,6 +103,7 @@ const statusCodeMap: Partial> = { [ErrorCode.INVALID_GIT_CREDENTIALS]: StatusCodes.BAD_REQUEST, [ErrorCode.INVALID_OTP]: StatusCodes.GONE, [ErrorCode.VALIDATION]: StatusCodes.CONFLICT, + [ErrorCode.FILE_TOO_LARGE]: StatusCodes.REQUEST_TOO_LONG, [ErrorCode.INVITATION_ONLY_SIGN_UP]: StatusCodes.FORBIDDEN, [ErrorCode.AUTHENTICATION]: StatusCodes.UNAUTHORIZED, [ErrorCode.INVALID_LICENSE_KEY]: StatusCodes.BAD_REQUEST, diff --git a/packages/server/engine/src/lib/api/engine-file-api.ts b/packages/server/engine/src/lib/api/engine-file-api.ts index ac946bc0fbb1..feddcc28efe9 100644 --- a/packages/server/engine/src/lib/api/engine-file-api.ts +++ b/packages/server/engine/src/lib/api/engine-file-api.ts @@ -1,6 +1,6 @@ import { promisify } from 'node:util' import { zstdDecompress as zstdDecompressCallback } from 'node:zlib' -import { EngineFileNotFoundError, EngineGenericError, FileCompression, FileType, isZstdCompressed } from '@activepieces/shared' +import { EngineFileNotFoundError, EngineGenericError, ExecutionError, ExecutionErrorType, FileCompression, FileType, isZstdCompressed } from '@activepieces/shared' import { retryFetch } from './retry-fetch' const zstdDecompress = promisify(zstdDecompressCallback) @@ -83,6 +83,14 @@ export const engineFileApi = { async function resolveUploadReadUrl(fileId: string, response: Response): Promise { if (!response.ok) { + if (response.status === 413) { + const serverMessage = await readErrorMessage(response) + throw new ExecutionError( + 'EngineFileTooLarge', + JSON.stringify({ message: serverMessage ?? `File ${fileId} exceeds the server's size limit` }), + ExecutionErrorType.USER, + ) + } throw new EngineGenericError( 'EngineFileUploadError', `Failed to upload engine file ${fileId}: ${response.status} ${response.statusText}`, @@ -103,6 +111,16 @@ function toRequestBody(data: Uint8Array): BodyInit { return data.buffer instanceof ArrayBuffer ? new Uint8Array(data.buffer, data.byteOffset, data.byteLength) : new Uint8Array(data) } +async function readErrorMessage(response: Response): Promise { + try { + const body = await response.json() as { params?: { message?: unknown } } + return typeof body?.params?.message === 'string' ? body.params.message : undefined + } + catch { + return undefined + } +} + function buildPutHeaders({ type, fileName, compression, contentLength }: BuildHeadersParams): Record { const headers: Record = { 'Content-Type': 'application/octet-stream', diff --git a/packages/server/engine/src/lib/handler/base-executor.ts b/packages/server/engine/src/lib/handler/base-executor.ts index d10b969b2f8f..c67fe830db10 100644 --- a/packages/server/engine/src/lib/handler/base-executor.ts +++ b/packages/server/engine/src/lib/handler/base-executor.ts @@ -12,7 +12,7 @@ export async function failStep({ action, executionState, stepOutput, error, dura status: FlowRunStatus.FAILED, failedStep: { name: action.name, - displayName: action.displayName, + displayName: action.displayName ?? action.name, message, }, }) diff --git a/packages/server/engine/src/lib/handler/flow-executor.ts b/packages/server/engine/src/lib/handler/flow-executor.ts index ad532a8537b4..5525a464944a 100644 --- a/packages/server/engine/src/lib/handler/flow-executor.ts +++ b/packages/server/engine/src/lib/handler/flow-executor.ts @@ -181,7 +181,7 @@ const applyLogSizeLimitIfExceeded = async ( status: FlowRunStatus.LOG_SIZE_EXCEEDED, failedStep: { name: action.name, - displayName: action.displayName, + displayName: action.displayName ?? action.name, message: 'Flow run logs size exceeded', }, }) diff --git a/packages/server/engine/src/lib/handler/piece-executor.ts b/packages/server/engine/src/lib/handler/piece-executor.ts index 836b4a553059..3b8d95ea308a 100644 --- a/packages/server/engine/src/lib/handler/piece-executor.ts +++ b/packages/server/engine/src/lib/handler/piece-executor.ts @@ -1,4 +1,4 @@ -import { ActivepiecesError, ErrorCode, isNil } from '@activepieces/core-utils' +import { ActivepiecesError, ErrorCode, isNil, isObject } from '@activepieces/core-utils' import { PiecePropertyMap, StaticPropsValue } from '@activepieces/pieces-framework' import { EngineGenericError, ExecutionType, FlowActionType, FlowRunStatus, GenericStepOutput, PieceAction, RespondResponse, StepOutputStatus } from '@activepieces/shared' import { engineRunApi } from '../api/engine-run-api' @@ -100,7 +100,7 @@ const executeAction: ActionHandler = async ({ action, executionStat runResponse: { status: webhookResponse.status ?? 200, body: webhookResponse.body ?? {}, - headers: webhookResponse.headers ?? {}, + headers: isObject(webhookResponse.headers) ? webhookResponse.headers : {}, }, }, }) diff --git a/packages/server/engine/src/lib/operations/flow.operation.ts b/packages/server/engine/src/lib/operations/flow.operation.ts index 73c01e0ac217..c62023da068e 100644 --- a/packages/server/engine/src/lib/operations/flow.operation.ts +++ b/packages/server/engine/src/lib/operations/flow.operation.ts @@ -150,7 +150,7 @@ async function buildFailedTriggerContext({ input, baseContext, error }: BuildFai status: FlowRunStatus.FAILED, failedStep: { name: trigger.name, - displayName: trigger.displayName, + displayName: trigger.displayName ?? trigger.name, message, }, })