UNPKG

@prismatic-io/spectral

Version:

Utility library for building Prismatic connectors and code-native integrations

372 lines (371 loc) 21.8 kB
import type { ActionContext, ActionPerformFunction } from "./ActionPerformFunction"; import type { ActionPerformReturn } from "./ActionPerformReturn"; import type { ComponentRegistry, ConfigVarExpression, TriggerReference, ValueExpression } from "./ComponentRegistry"; import type { ConfigPages, UserLevelConfigPages } from "./ConfigPages"; import type { ConfigVars } from "./ConfigVars"; import type { FlowDefinitionFlowSchema } from "./FlowSchemas"; import type { HttpResponse } from "./HttpResponse"; import type { Inputs } from "./Inputs"; import type { PollingTriggerPerformFunction } from "./PollingTriggerDefinition"; import type { ScopedConfigVarMap } from "./ScopedConfigVars"; import type { BatchConfig } from "./TriggerDefinition"; import type { TriggerEventFunction } from "./TriggerEventFunction"; import type { TriggerPayload } from "./TriggerPayload"; import type { TriggerPerformFunction } from "./TriggerPerformFunction"; import type { TriggerResult } from "./TriggerResult"; /** * Defines attributes of a code-native integration. See * https://prismatic.io/docs/integrations/code-native/ */ export type IntegrationDefinition<TInputs extends Inputs = Inputs, TActionInputs extends Inputs = Inputs, TPayload extends TriggerPayload = TriggerPayload, TAllowsBranching extends boolean = boolean, TResult extends TriggerResult<TAllowsBranching, TPayload> = TriggerResult<TAllowsBranching, TPayload>> = { /** The unique name for this integration. */ name: string; /** Description for this integration. */ description?: string; /** Path to icon to use for this integration. Path should be relative to the built integration source. */ iconPath?: string; /** Category for this integration. */ category?: string; /** Documentation for this integration. */ documentation?: string; /** Version identifier for this integration. */ version?: string; /** Labels for this integration. */ labels?: string[]; /** * Endpoint type used by Instances of this integration. * A Preprocess Flow Config must be specified when using anything other than 'Flow Specific'. See * https://prismatic.io/docs/integrations/code-native/endpoint-config/. * * @default `EndpointType.FlowSpecific` */ endpointType?: EndpointType; /** * Preprocess Flow configuration for when the Trigger payload contains the flow routing attributes. * Cannot specify this if a Preprocess Flow is also configured. See * https://prismatic.io/docs/integrations/code-native/endpoint-config/#endpoint-configuration-in-code-native-with-preprocess-flow */ triggerPreprocessFlowConfig?: PreprocessFlowConfig; /** * Flows for this integration. See * https://prismatic.io/docs/integrations/code-native/flows/ * * The trailing `any`s for `TItem`/`TPaginationState`/`TTriggerPayload` let flows with * different resolver item and cursor types live in one array. `integration` only holds * and serializes these flows (it never invokes `onExecution`), so the precise — and * per-flow distinct — `onExecution` param type does not need to be preserved here. */ flows: Flow<TInputs, TActionInputs, TPayload, TAllowsBranching, TResult, any, any, any>[]; /** * Config wizard pages for this integration. See * https://prismatic.io/docs/integrations/code-native/config-wizard/ */ configPages?: ConfigPages; /** * User Level Config Wizard Pages for this integration. See * https://prismatic.io/docs/integrations/code-native/config-wizard/#user-level-config-wizards-in-code-native-integrations */ userLevelConfigPages?: UserLevelConfigPages; /** Scoped ConfigVars for this integration. */ scopedConfigVars?: ScopedConfigVarMap; /** Instance Profile used for this integration. * If not specified, the tenant's default Instance Profile will be used. */ instanceProfile?: string; /** * A list of components this code-native integration uses. See * https://prismatic.io/docs/integrations/code-native/existing-components/ */ componentRegistry?: ComponentRegistry; }; /** * The trigger payload as `onExecution` sees it. When a `triggerResolver` is in * play, the platform replaces `body.data` with this execution's batch slice — * a single `TItem` when `batchSize` is 1, otherwise a `TItem[]`. When no item * type is known (`TItem` defaults to `unknown`), the payload is left untouched. */ export type BatchedTriggerPayload<TPayload extends TriggerPayload, TItem> = unknown extends TItem ? TPayload : Omit<TPayload, "body"> & { body: { data: TItem | TItem[]; contentType?: string; }; }; /** * The page of records a batched trigger fire (`onTrigger`/`onDeploy`) returns. The author * returns the items plus, when paginating, the cursor for the next page. spectral wraps the * items into the wire trigger payload (`body.data`), carries the `paginationState` to the next * round, and synthesizes the resolver that reads both back. There is no separate pagination * callback to define. */ export interface BatchedTriggerReturn<TItem, TPaginationState extends Record<string, unknown> = Record<string, unknown>> { /** The records produced by this trigger fire. Chunked into batches of the flow's `batchConfig.batchSize`. */ items: TItem[]; /** * Cursor for the next page. Return it to paginate — the fire is re-invoked with this object on * `payload.paginationState`. Omit or return `null` to stop. Compute it here from the fetch * response, where the next-page token is still in scope. */ paginationState?: TPaginationState | null; /** Optional HTTP response to the request that invoked the integration. */ response?: HttpResponse; } /** * A batched trigger built by {@link batchFlowTrigger}. Bundles the normal and on-deploy trigger * fires, each returning `{ items, paginationState? }`. The two type parameters — supplied * explicitly to `batchFlowTrigger<TItem, TPaginationState>(...)` — flow through to the rest of * the flow: `TItem` types `onExecution`'s `params.onTrigger.results.body.data`, and * `TPaginationState` types both `payload.paginationState` (read on the way in) and the * `paginationState` each fire returns (the next page's cursor). */ export interface BatchTrigger<TItem, TPaginationState extends Record<string, unknown> = Record<string, unknown>> { /** * The trigger function for this flow. Fetches a page of records and returns them as `items`, * plus the next page's `paginationState` to paginate (omit/`null` to stop). Read the cursor for * the current page from `payload.paginationState`. */ onTrigger: (context: ActionContext<ConfigVars>, payload: TriggerPayload<TPaginationState>) => Promise<BatchedTriggerReturn<TItem, TPaginationState>>; /** * The on-deploy trigger fire, run once on initial instance deploy. Same shape as `onTrigger`; * return `paginationState` to paginate the backfill. */ onDeploy?: (context: ActionContext<ConfigVars>, payload: TriggerPayload<TPaginationState>) => Promise<BatchedTriggerReturn<TItem, TPaginationState>>; } export type FlowOnExecution<TTriggerPayload extends TriggerPayload, TItem = unknown> = ActionPerformFunction<{ onTrigger: { type: "data"; label: string; clean: (value: unknown) => { results: BatchedTriggerPayload<TTriggerPayload, TItem>; }; }; }, ConfigVars, { [Key in keyof ComponentRegistry]: ComponentRegistry[Key]["actions"]; }, false, ActionPerformReturn<false, unknown>>; export type FlowExecutionContext = ActionContext<ConfigVars, { [Key in keyof ComponentRegistry]: ComponentRegistry[Key]["actions"]; }>; export type FlowExecutionContextActions = FlowExecutionContext["components"]; /** * The batch-discriminated fields of a flow. A flow either batches or it does not, and * the presence of `batchConfig` is the discriminant TypeScript uses to choose a member: * * - {@link BatchFields}: `batchConfig` is present, which requires a batched `trigger` * (built with {@link batchFlowTrigger}). The flat `onTrigger`/`onDeployTrigger` are * forbidden — the trigger fires live inside the `trigger` object. * - {@link NonBatchFields}: `batchConfig`/`trigger` are absent; the flow uses the plain * `onTrigger`/`onDeployTrigger` on its variant. * * Discrimination is structural — it depends only on whether the object literal you write * has a `batchConfig` key — so it works without TypeScript having to infer any type * parameter from the value. The batched-vs-not shape of `onExecution`'s payload is handled * separately, on `FlowBase`, via `TItem`: when a `trigger` is present `TItem` is inferred * (so `onExecution` sees `TItem | TItem[]`); otherwise it stays `unknown` and the payload * is left untouched (see {@link BatchedTriggerPayload}). Keeping `onExecution` out of this * union is deliberate — a function property living in a union member loses contextual * parameter typing, which would make `onExecution`'s `context`/`params` implicitly `any`. */ interface BatchFields<TItem, TPaginationState extends Record<string, unknown>> { /** * Batch-dispatch config for this flow. Items returned by the `trigger`'s fires are chunked * into batches of `batchSize`. For a CNI flow this value is authoritative (what's written * here is what's used). Its presence requires a batched `trigger`. */ batchConfig: BatchConfig; /** * The batched trigger for this flow, built with {@link batchFlowTrigger}. Its fires * (`onTrigger`/`onDeploy`) return just `items`; spectral synthesizes the resolver that * extracts them and maps the pagination callbacks. Required when `batchConfig` is set. */ trigger: BatchTrigger<TItem, TPaginationState>; /** A batched flow's trigger fires live inside `trigger`; the flat `onTrigger` is forbidden. */ onTrigger?: never; /** A batched flow's on-deploy fire lives inside `trigger`; the flat `onDeployTrigger` is forbidden. */ onDeployTrigger?: never; } interface NonBatchFields { /** A non-batching flow may not declare batch config. */ batchConfig?: never; /** A non-batching flow may not declare a batched trigger. */ trigger?: never; } /** * The discriminated union coupling `batchConfig` and the batched `trigger`. Intersected * into each flow variant at {@link Flow}. */ type BatchDiscriminant<TItem, TPaginationState extends Record<string, unknown>> = BatchFields<TItem, TPaginationState> | NonBatchFields; /** Base properties shared by all flow types. */ interface FlowBase<TTriggerPayload extends TriggerPayload = TriggerPayload, TItem = unknown> { /** The unique name for this flow. */ name: string; /** A unique, unchanging value that is used to maintain identity for the flow even if the name changes. */ stableKey: string; /** Description for this flow. */ description?: string; /** * Preprocess flow configuration for when the result of this flow contains the flow routing attributes. * Only one flow per integration may define this. */ preprocessFlowConfig?: PreprocessFlowConfig; /** Value that specifies whether this flow is synchronous. @default `false` */ isSynchronous?: boolean; /** Value that specifies whether this flow is an AI agent flow on the integrations MCP server. @default `false` */ isAgentFlow?: boolean; /** Retry Configuration for this flow. */ retryConfig?: RetryConfig; /** Queue Configuration for this flow. */ queueConfig?: QueueConfig; /** * Security configuration to use for the endpoint of this flow. * @default `EndpointSecurityType.CustomerOptional` */ endpointSecurityType?: EndpointSecurityType; /** * List of API key(s) to use for the endpoint of this flow * when the endpoint security type is `EndpointSecurityType.Organization`. */ organizationApiKeys?: string[]; testApiKeys?: string[]; /** Error handling configuration. */ errorConfig?: StepErrorConfig; /** Optional schemas definitions for the flow. Currently only for use with AI agents. */ schemas?: Record<string, FlowDefinitionFlowSchema> & { invoke: FlowDefinitionFlowSchema; }; /** * Specifies the function to execute when an instance of this integration is deployed. See * https://prismatic.io/docs/custom-connectors/triggers/#instance-deploy-and-delete-events-for-triggers */ onInstanceDeploy?: TriggerEventFunction<Inputs, ConfigVars>; /** * Specifies the function to execute when an instance of an integration is deleted. See * https://prismatic.io/docs/custom-connectors/triggers/#instance-deploy-and-delete-events-for-triggers */ onInstanceDelete?: TriggerEventFunction<Inputs, ConfigVars>; /** * Optional webhook lifecycle handlers for create and delete operations. See * https://prismatic.io/docs/custom-connectors/triggers/#webhook-lifecycle-events */ webhookLifecycleHandlers?: { /** Function to execute to configure a webhook. */ create: TriggerEventFunction<Inputs, ConfigVars>; /** Function to execute for webhook teardown. */ delete: TriggerEventFunction<Inputs, ConfigVars>; }; /** * Specifies the main function for this flow which is run when this flow is invoked. * When the flow batches (has a `triggerResolver`/`onDeployResolver`, so `TItem` is * inferred), `params.onTrigger.results.body.data` is typed as the resolved item type * (`TItem | TItem[]`); otherwise the trigger payload is left untouched. */ onExecution: FlowOnExecution<TTriggerPayload, TItem>; } export type StandardTriggerType = "standard"; /** A standard flow with a webhook or scheduled trigger (non-polling). */ interface StandardFlow<TInputs extends Inputs = Inputs, TPayload extends TriggerPayload = TriggerPayload, TAllowsBranching extends boolean = false, TResult extends TriggerResult<TAllowsBranching, TPayload> = TriggerResult<TAllowsBranching, TPayload>, TTriggerPayload extends TriggerPayload = TriggerPayload, TItem = unknown, TPaginationState extends Record<string, unknown> = Record<string, unknown>> extends FlowBase<TTriggerPayload, TItem> { triggerType?: StandardTriggerType; /** Schedule configuration that defines the frequency with which this flow will be automatically executed. */ schedule?: (ValueExpression<string> | ConfigVarExpression) & { timezone?: string; }; /** Specifies the trigger function for this flow, which returns a payload and optional HTTP response. */ onTrigger?: TriggerReference | TriggerPerformFunction<TInputs, ConfigVars, TAllowsBranching, TResult, TPaginationState>; /** * Function to execute on initial instance deploy, in addition to (and independent of) `onTrigger`. * Typically used to backfill baseline records for systems whose webhooks only emit future events. */ onDeployTrigger?: TriggerPerformFunction<TInputs, ConfigVars, TAllowsBranching, TResult, TPaginationState>; } export type PollingTriggerType = "polling"; /** A polling flow that runs on a schedule and has access to polling context (getState/setState). */ interface PollingFlow<TInputs extends Inputs, TActionInputs extends Inputs, TPayload extends TriggerPayload = TriggerPayload, TAllowsBranching extends boolean = boolean, TResult extends TriggerResult<TAllowsBranching, TPayload> = TriggerResult<TAllowsBranching, TPayload>, TTriggerPayload extends TriggerPayload = TriggerPayload, TItem = unknown, TPaginationState extends Record<string, unknown> = Record<string, unknown>> extends FlowBase<TTriggerPayload, TItem> { /** * Type of trigger for this flow. A "polling" trigger runs on a schedule * and can use context.polling.* functions. Requires schedule to be set. */ triggerType: PollingTriggerType; /** Schedule configuration that defines the frequency with which this flow will be automatically executed. Required for polling triggers. */ schedule: (ValueExpression<string> | ConfigVarExpression) & { timezone?: string; }; /** * Specifies the trigger function for this flow. */ onTrigger: PollingTriggerPerformFunction<TInputs, TActionInputs, ConfigVars, TPayload, TAllowsBranching, TResult>; /** * Function to execute on initial instance deploy, in addition to (and independent of) `onTrigger`. * Typically used to backfill baseline records for systems whose webhooks only emit future events. */ onDeployTrigger?: TriggerPerformFunction<TInputs, ConfigVars, TAllowsBranching, TResult, TPaginationState>; } /** Defines attributes of a flow of a code-native integration. */ export type Flow<TInputs extends Inputs, TActionInputs extends Inputs, TPayload extends TriggerPayload = TriggerPayload, TAllowsBranching extends boolean = boolean, TResult extends TriggerResult<TAllowsBranching, TPayload> = TriggerResult<TAllowsBranching, TPayload>, TTriggerPayload extends TriggerPayload = TriggerPayload, TItem = unknown, TPaginationState extends Record<string, unknown> = Record<string, unknown>> = (StandardFlow<TInputs, TPayload, TAllowsBranching, TResult, TTriggerPayload, TItem, TPaginationState> & BatchDiscriminant<TItem, TPaginationState>) | (PollingFlow<TInputs, TActionInputs, TPayload, TAllowsBranching, TResult, TTriggerPayload, TItem, TPaginationState> & BatchDiscriminant<TItem, TPaginationState>); export type FlowTriggerType = PollingTriggerType | StandardTriggerType; /** Defines attributes of a Preprocess flow Configuration used by a flow of an integration. */ export type PreprocessFlowConfig = { /** Name of the field in the data payload returned by the Preprocess flow to use for a flow Name. */ flowNameField: string; /** Name of the field in the data payload returned by the Preprocess flow to use for an External Customer Id. */ externalCustomerIdField?: string; /** Name of the field in the data payload returned by the Preprocess flow to use for an External Customer User Id. */ externalCustomerUserIdField?: string; }; /** Defines attributes of a retry configuration used by a flow of an integration. */ export type RetryConfig = { /** The maximum number of retry attempts. Must be between 0 and 10. */ maxAttempts: number; /** The delay in minutes to wait between retry attempts. Must be between 0 and 60. */ delayMinutes: number; /** Specifies whether to use exponential backoff to calculate the delay between retry attempts. */ usesExponentialBackoff: boolean; /** Name of the field in the data payload returned by the flow's trigger to use as a Unique Request ID for retry request cancellation. */ uniqueRequestIdField?: string; }; /** Defines attributes of a queue configuration used by a flow of an integration. */ export type StandardQueueConfig = { /** Determines whether the flow should be executed using FIFO ordering. Not valid for synchronous or scheduled flows. */ usesFifoQueue?: boolean; /** Reference to the field in the flow's trigger return payload; used to determine whether to queue the execution. */ dedupeIdField?: string; /** Determines whether the flow should be setup for singleton executions. Only valid for scheduled/polling trigger-based flows. */ singletonExecutions?: boolean; /** The maximum number of concurrent executions for this flow. Must be between 2 and 15. */ concurrencyLimit?: number; }; export type ParallelQueueConfig = { /** No limits. All requests processed simultaneously. */ type: "parallel"; }; export type ThrottledQueueConfig = { /** Set the max concurrent executions per instance. */ type: "throttled"; /** The maximum number of concurrent executions for this flow. Must be between 2 and 15. */ concurrencyLimit?: number; /** Reference to the field in the flow's trigger return payload; used to determine whether to queue the execution. */ dedupeIdField?: string; }; export type SequentialQueueConfig = { /** Processed one at a time, in order received. */ type: "sequential"; /** Reference to the field in the flow's trigger return payload; used to determine whether to queue the execution. */ dedupeIdField?: string; }; export type QueueConfig = ParallelQueueConfig | ThrottledQueueConfig | SequentialQueueConfig | StandardQueueConfig; /** Defines attributes of a step error configuration used to determine how to handle errors during flow step execution. */ export type StepErrorConfig = { /** Defines the type of error handler. */ errorHandlerType: StepErrorHandlerType; /** The maximum number of retry attempts. Must be between 0 and 5. */ maxAttempts?: number; /** The delay in seconds to wait between retry attempts. Must be between 0 and 60. */ delaySeconds?: number; /** Specifies whether to use exponential backoff to calculate the delay between retry attempts. @default false */ usesExponentialBackoff?: boolean; /** Specifies whether to ignore the final error after the final retry attempt. @default false */ ignoreFinalError?: boolean; }; /** Choices of Endpoint Types that may be used by Instances of an integration. */ export type EndpointType = "flow_specific" | "instance_specific" | "shared_instance"; /** Choices of Endpoint Security Types that may be used by endpoints of a flow. */ export type EndpointSecurityType = "unsecured" | "customer_optional" | "customer_required" | "organization"; /** Choices of Step Error Handlers that define the behavior when a step error occurs. */ export type StepErrorHandlerType = "fail" | "ignore" | "retry"; export {};