Add Activepieces integration for workflow automation
- Add Activepieces fork with SmoothSchedule custom piece - Create integrations app with Activepieces service layer - Add embed token endpoint for iframe integration - Create Automations page with embedded workflow builder - Add sidebar visibility fix for embed mode - Add list inactive customers endpoint to Public API - Include SmoothSchedule triggers: event created/updated/cancelled - Include SmoothSchedule actions: create/update/cancel events, list resources/services/customers 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
18
activepieces-fork/packages/shared/.eslintrc.json
Normal file
18
activepieces-fork/packages/shared/.eslintrc.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"extends": [
|
||||
"../server/api/.eslintrc.json"
|
||||
],
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
"*.ts",
|
||||
"*.js"
|
||||
],
|
||||
"parserOptions": {
|
||||
"project": [
|
||||
"packages/shared/tsconfig.*?.json"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
7
activepieces-fork/packages/shared/README.md
Normal file
7
activepieces-fork/packages/shared/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# shared
|
||||
|
||||
This library was generated with [Nx](https://nx.dev).
|
||||
|
||||
## Building
|
||||
|
||||
Run `nx build shared` to build the library.
|
||||
17
activepieces-fork/packages/shared/jest.config.ts
Normal file
17
activepieces-fork/packages/shared/jest.config.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
/* eslint-disable */
|
||||
export default {
|
||||
displayName: 'shared',
|
||||
preset: '../../jest.preset.js',
|
||||
globals: {},
|
||||
testEnvironment: 'node',
|
||||
transform: {
|
||||
'^.+\\.[tj]s$': [
|
||||
'ts-jest',
|
||||
{
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json',
|
||||
},
|
||||
],
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'js', 'html'],
|
||||
coverageDirectory: '../../coverage/packages/shared',
|
||||
};
|
||||
5
activepieces-fork/packages/shared/package.json
Normal file
5
activepieces-fork/packages/shared/package.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "@activepieces/shared",
|
||||
"version": "0.30.2",
|
||||
"type": "commonjs"
|
||||
}
|
||||
39
activepieces-fork/packages/shared/project.json
Normal file
39
activepieces-fork/packages/shared/project.json
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "shared",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "packages/shared/src",
|
||||
"projectType": "library",
|
||||
"tags": [],
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@nx/js:tsc",
|
||||
"outputs": ["{options.outputPath}"],
|
||||
"options": {
|
||||
"outputPath": "dist/packages/shared",
|
||||
"main": "packages/shared/src/index.ts",
|
||||
"tsConfig": "packages/shared/tsconfig.lib.json",
|
||||
"assets": ["packages/shared/*.md"],
|
||||
"buildableProjectDepsInPackageJsonType": "dependencies",
|
||||
"updateBuildableProjectDepsInPackageJson": true
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nx/jest:jest",
|
||||
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
|
||||
"options": {
|
||||
"jestConfig": "packages/shared/jest.config.ts"
|
||||
}
|
||||
},
|
||||
"publish": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"command": "node tools/scripts/publish.mjs shared {args.ver} {args.tag}"
|
||||
},
|
||||
"dependsOn": ["build"]
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nx/eslint:lint",
|
||||
"outputs": ["{options.outputFile}"]
|
||||
}
|
||||
}
|
||||
}
|
||||
97
activepieces-fork/packages/shared/src/index.ts
Executable file
97
activepieces-fork/packages/shared/src/index.ts
Executable file
@@ -0,0 +1,97 @@
|
||||
export * from './lib/flows/actions/action'
|
||||
export * from './lib/app-connection/app-connection'
|
||||
export * from './lib/app-connection/dto/read-app-connection-request'
|
||||
export * from './lib/app-connection/dto/upsert-app-connection-request'
|
||||
export * from './lib/common'
|
||||
export * from './lib/common/activepieces-error'
|
||||
export * from './lib/common/telemetry'
|
||||
export * from './lib/engine'
|
||||
export * from './lib/workers/job-data'
|
||||
export * from './lib/workers/queue-metrics'
|
||||
export * from './lib/flag'
|
||||
export * from './lib/flow-run/dto/list-flow-runs-request'
|
||||
export * from './lib/flow-run/execution/execution-output'
|
||||
export * from './lib/flow-run/execution/step-output'
|
||||
export * from './lib/flows/operations'
|
||||
export * from './lib/flow-run/execution/execution-output'
|
||||
export * from './lib/flow-run/execution/step-output'
|
||||
export * from './lib/pieces'
|
||||
export * from './lib/store-entry/dto/store-entry-request'
|
||||
export * from './lib/webhook'
|
||||
export * from './lib/flows/dto/count-flows-request'
|
||||
export * from './lib/authentication/dto/authentication-response'
|
||||
export * from './lib/authentication/dto/sign-up-request'
|
||||
export * from './lib/authentication/dto/sign-in-request'
|
||||
export * from './lib/authentication/model/principal-type'
|
||||
export * from './lib/authentication/model/principal'
|
||||
export * from './lib/analytics'
|
||||
export * from './lib/flows/actions/action'
|
||||
export * from './lib/store-entry/store-entry'
|
||||
export * from './lib/user'
|
||||
export * from './lib/flow-run/test-flow-run-request'
|
||||
export * from './lib/flows/triggers/trigger'
|
||||
export * from './lib/flows/flow-version'
|
||||
export * from './lib/flows/flow'
|
||||
export * from './lib/file'
|
||||
export * from './lib/flow-run/flow-run'
|
||||
export * from './lib/flows/dto/create-flow-request'
|
||||
export * from './lib/common/seek-page'
|
||||
export * from './lib/common/id-generator'
|
||||
export * from './lib/flows/triggers/trigger-events/trigger-events-dto'
|
||||
export * from './lib/flows/triggers/trigger-events/trigger-event'
|
||||
export * from './lib/flows/sample-data'
|
||||
export * from './lib/common/base-model'
|
||||
export * from './lib/flows/folders/folder'
|
||||
export * from './lib/flows/folders/folder-requests'
|
||||
export * from './lib/flows/dto/flow-mcp.requests'
|
||||
export * from './lib/flows'
|
||||
export * from './lib/flows/dto/list-flows-request'
|
||||
export * from './lib/project'
|
||||
export * from './lib/forms'
|
||||
export * from './lib/platform'
|
||||
export * from './lib/flow-run/execution/flow-execution'
|
||||
export * from './lib/ai-providers'
|
||||
export * from './lib/tag'
|
||||
export * from './lib/websocket'
|
||||
export * from './lib/flow-run/execution/flow-execution'
|
||||
export * from './lib/flow-run/execution/flow-execution'
|
||||
export * from './lib/flow-run/execution/flow-execution'
|
||||
export * from './lib/flow-run/execution/flow-execution'
|
||||
export * from './lib/federated-authn'
|
||||
export * from './lib/store-entry/store-entry'
|
||||
export * from './lib/flow-run/test-flow-run-request'
|
||||
export * from './lib/support-url'
|
||||
export * from './lib/feedback-url'
|
||||
export * from './lib/license-keys'
|
||||
export * from './lib/invitations'
|
||||
export * from './lib/workers'
|
||||
export * from './lib/flows/util/flow-structure-util'
|
||||
export * from './lib/flows/operations'
|
||||
export * from './lib/flows/util/flow-piece-util'
|
||||
export * from './lib/property/markdown'
|
||||
export * from './lib/project-role/project-role'
|
||||
export * from './lib/project-role/project-role.request'
|
||||
export * from './lib/flow-run/log-serializer'
|
||||
export * from './lib/tables'
|
||||
export * from './lib/project-release/project-release'
|
||||
export * from './lib/project-release/project-release.request'
|
||||
export * from './lib/project-release/project-state'
|
||||
export * from './lib/authentication/user-identity'
|
||||
export * from './lib/flows/operations/paste-operations'
|
||||
export * from './lib/todos'
|
||||
export * from './lib/todos/todos-request'
|
||||
export * from './lib/mcp'
|
||||
export * from './lib/agents'
|
||||
export * from './lib/solutions'
|
||||
export * from './lib/flows/triggers/trigger'
|
||||
export * from './lib/trigger'
|
||||
export * from './lib/flows/triggers/trigger-run'
|
||||
export * from './lib/template'
|
||||
|
||||
// Look at https://github.com/sinclairzx81/typebox/issues/350
|
||||
import { TypeSystemPolicy } from '@sinclair/typebox/system'
|
||||
export * from './lib/license-keys'
|
||||
export * from './lib/flow-run/execution/flow-execution'
|
||||
TypeSystemPolicy.ExactOptionalPropertyTypes = false
|
||||
export * from './lib/workers/queue-metrics'
|
||||
export * from './lib/health'
|
||||
97
activepieces-fork/packages/shared/src/lib/agents/index.ts
Normal file
97
activepieces-fork/packages/shared/src/lib/agents/index.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { DiscriminatedUnion, Nullable } from '../common'
|
||||
export * from './tools'
|
||||
|
||||
export enum AgentOutputFieldType {
|
||||
TEXT = 'text',
|
||||
NUMBER = 'number',
|
||||
BOOLEAN = 'boolean',
|
||||
}
|
||||
|
||||
export enum AgentTaskStatus {
|
||||
COMPLETED = 'COMPLETED',
|
||||
FAILED = 'FAILED',
|
||||
IN_PROGRESS = 'IN_PROGRESS',
|
||||
}
|
||||
|
||||
export enum ContentBlockType {
|
||||
MARKDOWN = 'MARKDOWN',
|
||||
TOOL_CALL = 'TOOL_CALL',
|
||||
}
|
||||
|
||||
export enum ToolCallStatus {
|
||||
IN_PROGRESS = 'in-progress',
|
||||
COMPLETED = 'completed',
|
||||
}
|
||||
|
||||
export enum ExecutionToolStatus {
|
||||
SUCCESS = 'SUCCESS',
|
||||
FAILED = 'FAILED',
|
||||
}
|
||||
|
||||
export enum ToolCallType {
|
||||
PIECE = 'PIECE',
|
||||
FLOW = 'FLOW',
|
||||
}
|
||||
|
||||
export const AgentOutputField = Type.Object({
|
||||
displayName: Type.String(),
|
||||
description: Type.Optional(Type.String()),
|
||||
type: Type.Enum(AgentOutputFieldType),
|
||||
})
|
||||
export type AgentOutputField = Static<typeof AgentOutputField>
|
||||
|
||||
export type AgentResult = {
|
||||
prompt: string
|
||||
steps: AgentStepBlock[]
|
||||
status: AgentTaskStatus
|
||||
structuredOutput?: unknown
|
||||
}
|
||||
|
||||
export enum AgentPieceProps {
|
||||
AGENT_TOOLS = 'agentTools',
|
||||
STRUCTURED_OUTPUT = 'structuredOutput',
|
||||
PROMPT = 'prompt',
|
||||
MAX_STEPS = 'maxSteps',
|
||||
AI_PROVIDER = 'provider',
|
||||
AI_MODEL = 'model',
|
||||
}
|
||||
|
||||
export const MarkdownContentBlock = Type.Object({
|
||||
type: Type.Literal(ContentBlockType.MARKDOWN),
|
||||
markdown: Type.String(),
|
||||
})
|
||||
export type MarkdownContentBlock = Static<typeof MarkdownContentBlock>
|
||||
|
||||
const ToolCallBaseSchema = Type.Object({
|
||||
type: Type.Literal(ContentBlockType.TOOL_CALL),
|
||||
input: Nullable(Type.Record(Type.String(), Type.Unknown())),
|
||||
output: Type.Optional(Type.Unknown()),
|
||||
toolName: Type.String(),
|
||||
status: Type.Enum(ToolCallStatus),
|
||||
toolCallId: Type.String(),
|
||||
startTime: Type.String(),
|
||||
endTime: Type.Optional(Type.String()),
|
||||
})
|
||||
export type ToolCallBase = Static<typeof ToolCallBaseSchema>
|
||||
|
||||
export const ToolCallContentBlock = DiscriminatedUnion('toolCallType', [
|
||||
Type.Object({
|
||||
...ToolCallBaseSchema.properties,
|
||||
toolCallType: Type.Literal(ToolCallType.PIECE),
|
||||
pieceName: Type.String(),
|
||||
pieceVersion: Type.String(),
|
||||
actionName: Type.String(),
|
||||
}),
|
||||
Type.Object({
|
||||
...ToolCallBaseSchema.properties,
|
||||
toolCallType: Type.Literal(ToolCallType.FLOW),
|
||||
displayName: Type.String(),
|
||||
flowId: Type.String(),
|
||||
}),
|
||||
])
|
||||
|
||||
export type ToolCallContentBlock = Static<typeof ToolCallContentBlock>
|
||||
|
||||
export const AgentStepBlock = Type.Union([MarkdownContentBlock, ToolCallContentBlock])
|
||||
export type AgentStepBlock = Static<typeof AgentStepBlock>
|
||||
42
activepieces-fork/packages/shared/src/lib/agents/tools.ts
Normal file
42
activepieces-fork/packages/shared/src/lib/agents/tools.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { DiscriminatedUnion } from '../common'
|
||||
import { ApId } from '../common/id-generator'
|
||||
|
||||
export const TASK_COMPLETION_TOOL_NAME = 'updateTaskStatus'
|
||||
|
||||
export enum AgentToolType {
|
||||
PIECE = 'PIECE',
|
||||
FLOW = 'FLOW',
|
||||
}
|
||||
|
||||
const AgentToolBase = {
|
||||
toolName: Type.String(),
|
||||
}
|
||||
|
||||
export const AgentPieceToolMetadata = Type.Object({
|
||||
pieceName: Type.String(),
|
||||
pieceVersion: Type.String(),
|
||||
actionName: Type.String(),
|
||||
predefinedInput: Type.Record(Type.String(), Type.Unknown()),
|
||||
})
|
||||
export type AgentPieceToolMetadata = Static<typeof AgentPieceToolMetadata>
|
||||
|
||||
export const AgentPieceTool = Type.Object({
|
||||
type: Type.Literal(AgentToolType.PIECE),
|
||||
...AgentToolBase,
|
||||
pieceMetadata: AgentPieceToolMetadata,
|
||||
})
|
||||
export type AgentPieceTool = Static<typeof AgentPieceTool>
|
||||
|
||||
export const AgentFlowTool = Type.Object({
|
||||
type: Type.Literal(AgentToolType.FLOW),
|
||||
...AgentToolBase,
|
||||
flowId: ApId,
|
||||
})
|
||||
export type AgentFlowTool = Static<typeof AgentFlowTool>
|
||||
|
||||
export const AgentTool = DiscriminatedUnion('type', [
|
||||
AgentPieceTool,
|
||||
AgentFlowTool,
|
||||
])
|
||||
export type AgentTool = Static<typeof AgentTool>
|
||||
119
activepieces-fork/packages/shared/src/lib/ai-providers/index.ts
Normal file
119
activepieces-fork/packages/shared/src/lib/ai-providers/index.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { BaseModelSchema, DiscriminatedUnion } from '../common/base-model'
|
||||
|
||||
export const AnthropicProviderConfig = Type.Object({
|
||||
apiKey: Type.String(),
|
||||
})
|
||||
export type AnthropicProviderConfig = Static<typeof AnthropicProviderConfig>
|
||||
|
||||
export const AzureProviderConfig = Type.Object({
|
||||
apiKey: Type.String(),
|
||||
resourceName: Type.String(),
|
||||
})
|
||||
export type AzureProviderConfig = Static<typeof AzureProviderConfig>
|
||||
|
||||
export const GoogleProviderConfig = Type.Object({
|
||||
apiKey: Type.String(),
|
||||
})
|
||||
export type GoogleProviderConfig = Static<typeof GoogleProviderConfig>
|
||||
|
||||
export const OpenAIProviderConfig = Type.Object({
|
||||
apiKey: Type.String(),
|
||||
})
|
||||
export type OpenAIProviderConfig = Static<typeof OpenAIProviderConfig>
|
||||
|
||||
export const OpenRouterProviderConfig = Type.Object({
|
||||
apiKey: Type.String(),
|
||||
})
|
||||
export type OpenRouterProviderConfig = Static<typeof OpenRouterProviderConfig>
|
||||
|
||||
export const AIProviderConfig = Type.Union([
|
||||
AnthropicProviderConfig,
|
||||
AzureProviderConfig,
|
||||
GoogleProviderConfig,
|
||||
OpenAIProviderConfig,
|
||||
OpenRouterProviderConfig,
|
||||
])
|
||||
export type AIProviderConfig = Static<typeof AIProviderConfig>
|
||||
|
||||
export enum
|
||||
AIProviderName {
|
||||
OPENAI = 'openai',
|
||||
OPENROUTER = 'openrouter',
|
||||
ANTHROPIC = 'anthropic',
|
||||
AZURE = 'azure',
|
||||
GOOGLE = 'google',
|
||||
ACTIVEPIECES = 'activepieces',
|
||||
}
|
||||
|
||||
const ProviderConfigUnion = DiscriminatedUnion('provider', [
|
||||
Type.Object({
|
||||
provider: Type.Literal(AIProviderName.OPENAI),
|
||||
config: OpenAIProviderConfig,
|
||||
}),
|
||||
Type.Object({
|
||||
provider: Type.Literal(AIProviderName.OPENROUTER),
|
||||
config: OpenRouterProviderConfig,
|
||||
}),
|
||||
Type.Object({
|
||||
provider: Type.Literal(AIProviderName.ANTHROPIC),
|
||||
config: AnthropicProviderConfig,
|
||||
}),
|
||||
Type.Object({
|
||||
provider: Type.Literal(AIProviderName.AZURE),
|
||||
config: AzureProviderConfig,
|
||||
}),
|
||||
Type.Object({
|
||||
provider: Type.Literal(AIProviderName.GOOGLE),
|
||||
config: GoogleProviderConfig,
|
||||
}),
|
||||
Type.Object({
|
||||
provider: Type.Literal(AIProviderName.ACTIVEPIECES),
|
||||
config: OpenRouterProviderConfig,
|
||||
}),
|
||||
])
|
||||
|
||||
export const AIProvider = Type.Intersect([
|
||||
Type.Object({ ...BaseModelSchema }),
|
||||
ProviderConfigUnion,
|
||||
Type.Object({
|
||||
displayName: Type.String({ minLength: 1 }),
|
||||
platformId: Type.String(),
|
||||
}),
|
||||
])
|
||||
|
||||
export type AIProvider = Static<typeof AIProvider>
|
||||
|
||||
export const AIProviderWithoutSensitiveData = Type.Object({
|
||||
id: Type.String(),
|
||||
name: Type.String(),
|
||||
configured: Type.Boolean(),
|
||||
})
|
||||
export type AIProviderWithoutSensitiveData = Static<typeof AIProviderWithoutSensitiveData>
|
||||
|
||||
export enum AIProviderModelType {
|
||||
IMAGE = 'image',
|
||||
TEXT = 'text',
|
||||
}
|
||||
|
||||
export const AIProviderModel = Type.Object({
|
||||
id: Type.String(),
|
||||
name: Type.String(),
|
||||
type: Type.Enum(AIProviderModelType),
|
||||
})
|
||||
export type AIProviderModel = Static<typeof AIProviderModel>
|
||||
|
||||
export const CreateAIProviderRequest = ProviderConfigUnion
|
||||
|
||||
export type CreateAIProviderRequest = Static<typeof CreateAIProviderRequest>
|
||||
|
||||
|
||||
export const AIErrorResponse = Type.Object({
|
||||
error: Type.Object({
|
||||
message: Type.String(),
|
||||
type: Type.String(),
|
||||
code: Type.String(),
|
||||
}),
|
||||
})
|
||||
|
||||
export type AIErrorResponse = Static<typeof AIErrorResponse>
|
||||
85
activepieces-fork/packages/shared/src/lib/analytics/index.ts
Normal file
85
activepieces-fork/packages/shared/src/lib/analytics/index.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { BaseModelSchema, Nullable } from '../common/base-model'
|
||||
|
||||
|
||||
export const DEFAULT_ESTIMATED_TIME_SAVED_PER_STEP = 2
|
||||
|
||||
export const UpdateTimeSavedPerRunRequest = Type.Object({
|
||||
flowId: Type.String(),
|
||||
timeSavedPerRun: Nullable(Type.Number()),
|
||||
})
|
||||
export type UpdateTimeSavedPerRunRequest = Static<typeof UpdateTimeSavedPerRunRequest>
|
||||
|
||||
export const UpdatePlatformReportRequest = Type.Object({
|
||||
estimatedTimeSavedPerStep: Nullable(Type.Number()),
|
||||
outdated: Type.Boolean(),
|
||||
})
|
||||
export type UpdatePlatformReportRequest = Static<typeof UpdatePlatformReportRequest>
|
||||
|
||||
export const AnalyticsPieceReportItem = Type.Object({
|
||||
name: Type.String(),
|
||||
displayName: Type.String(),
|
||||
logoUrl: Type.String(),
|
||||
usageCount: Type.Number(),
|
||||
})
|
||||
export type AnalyticsPieceReportItem = Static<typeof AnalyticsPieceReportItem>
|
||||
|
||||
export const AnalyticsPieceReport = Type.Array(AnalyticsPieceReportItem)
|
||||
export type AnalyticsPieceReport = Static<typeof AnalyticsPieceReport>
|
||||
|
||||
export const AnalyticsProjectReportItem = Type.Object({
|
||||
id: Type.String(),
|
||||
displayName: Type.String(),
|
||||
activeFlows: Type.Number(),
|
||||
totalFlows: Type.Number(),
|
||||
})
|
||||
export type AnalyticsProjectReportItem = Static<typeof AnalyticsProjectReportItem>
|
||||
|
||||
export const AnalyticsProjectReport = Type.Array(AnalyticsProjectReportItem)
|
||||
export type AnalyticsProjectReport = Static<typeof AnalyticsProjectReport>
|
||||
|
||||
export const AnalyticsRunsUsageItem = Type.Object({
|
||||
day: Type.String(),
|
||||
totalRuns: Type.Number(),
|
||||
minutesSaved: Type.Number(),
|
||||
})
|
||||
export type AnalyticsRunsUsageItem = Static<typeof AnalyticsRunsUsageItem>
|
||||
|
||||
export const AnalyticsRunsUsage = Type.Array(AnalyticsRunsUsageItem)
|
||||
export type AnalyticsRunsUsage = Static<typeof AnalyticsRunsUsage>
|
||||
|
||||
export const AnalyticsFlowReportItem = Type.Object({
|
||||
flowId: Type.String(),
|
||||
flowName: Type.String(),
|
||||
projectId: Type.String(),
|
||||
projectName: Type.String(),
|
||||
runs: Type.Number(),
|
||||
timeSavedPerRun: Type.Object({
|
||||
value: Nullable(Type.Number()),
|
||||
isEstimated: Type.Boolean(),
|
||||
}),
|
||||
minutesSaved: Type.Number(),
|
||||
})
|
||||
export type AnalyticsFlowReportItem = Static<typeof AnalyticsFlowReportItem>
|
||||
|
||||
export const AnalyticsFlowReport = Type.Array(AnalyticsFlowReportItem)
|
||||
export type AnalyticsFlowReport = Static<typeof AnalyticsFlowReport>
|
||||
|
||||
export const PlatformAnalyticsReport = Type.Object({
|
||||
...BaseModelSchema,
|
||||
estimatedTimeSavedPerStep: Nullable(Type.Number()),
|
||||
totalFlows: Type.Number(),
|
||||
activeFlows: Type.Number(),
|
||||
outdated: Type.Boolean(),
|
||||
totalUsers: Type.Number(),
|
||||
activeUsers: Type.Number(),
|
||||
totalProjects: Type.Number(),
|
||||
activeFlowsWithAI: Type.Number(),
|
||||
totalFlowRuns: Type.Number(),
|
||||
topPieces: AnalyticsPieceReport,
|
||||
topProjects: AnalyticsProjectReport,
|
||||
runsUsage: AnalyticsRunsUsage,
|
||||
flowsDetails: AnalyticsFlowReport,
|
||||
platformId: Type.String(),
|
||||
})
|
||||
export type PlatformAnalyticsReport = Static<typeof PlatformAnalyticsReport>
|
||||
153
activepieces-fork/packages/shared/src/lib/app-connection/app-connection.ts
Executable file
153
activepieces-fork/packages/shared/src/lib/app-connection/app-connection.ts
Executable file
@@ -0,0 +1,153 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { BaseModel, BaseModelSchema, Nullable } from '../common/base-model'
|
||||
import { ApId } from '../common/id-generator'
|
||||
import { Metadata } from '../common/metadata'
|
||||
import { UserWithMetaInformation } from '../user'
|
||||
import { OAuth2GrantType } from './dto/upsert-app-connection-request'
|
||||
import { OAuth2AuthorizationMethod } from './oauth2-authorization-method'
|
||||
|
||||
export type AppConnectionId = string
|
||||
|
||||
export enum AppConnectionStatus {
|
||||
ACTIVE = 'ACTIVE',
|
||||
MISSING = 'MISSING',
|
||||
ERROR = 'ERROR',
|
||||
}
|
||||
|
||||
export enum AppConnectionScope {
|
||||
PROJECT = 'PROJECT',
|
||||
PLATFORM = 'PLATFORM',
|
||||
}
|
||||
|
||||
export enum AppConnectionType {
|
||||
OAUTH2 = 'OAUTH2',
|
||||
PLATFORM_OAUTH2 = 'PLATFORM_OAUTH2',
|
||||
CLOUD_OAUTH2 = 'CLOUD_OAUTH2',
|
||||
SECRET_TEXT = 'SECRET_TEXT',
|
||||
BASIC_AUTH = 'BASIC_AUTH',
|
||||
CUSTOM_AUTH = 'CUSTOM_AUTH',
|
||||
NO_AUTH = 'NO_AUTH',
|
||||
}
|
||||
|
||||
export type SecretTextConnectionValue = {
|
||||
type: AppConnectionType.SECRET_TEXT
|
||||
secret_text: string
|
||||
}
|
||||
export type BasicAuthConnectionValue = {
|
||||
username: string
|
||||
password: string
|
||||
type: AppConnectionType.BASIC_AUTH
|
||||
}
|
||||
|
||||
export type BaseOAuth2ConnectionValue = {
|
||||
expires_in?: number
|
||||
client_id: string
|
||||
token_type: string
|
||||
access_token: string
|
||||
claimed_at: number
|
||||
refresh_token: string
|
||||
scope: string
|
||||
token_url: string
|
||||
authorization_method?: OAuth2AuthorizationMethod
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
data: Record<string, any>
|
||||
props?: Record<string, unknown>
|
||||
grant_type?: OAuth2GrantType
|
||||
}
|
||||
|
||||
export type CustomAuthConnectionValue<T extends Record<string, unknown> = Record<string, unknown>> = {
|
||||
type: AppConnectionType.CUSTOM_AUTH
|
||||
props: T
|
||||
}
|
||||
|
||||
export type CloudOAuth2ConnectionValue = {
|
||||
type: AppConnectionType.CLOUD_OAUTH2
|
||||
} & BaseOAuth2ConnectionValue
|
||||
|
||||
export type PlatformOAuth2ConnectionValue = {
|
||||
type: AppConnectionType.PLATFORM_OAUTH2
|
||||
redirect_url: string
|
||||
} & BaseOAuth2ConnectionValue
|
||||
|
||||
export type OAuth2ConnectionValueWithApp = {
|
||||
type: AppConnectionType.OAUTH2
|
||||
client_secret: string
|
||||
redirect_url: string
|
||||
} & BaseOAuth2ConnectionValue
|
||||
|
||||
export type NoAuthConnectionValue = {
|
||||
type: AppConnectionType.NO_AUTH
|
||||
}
|
||||
|
||||
export type AppConnectionValue<T extends AppConnectionType = AppConnectionType, PropsType extends Record<string, unknown> = Record<string, unknown>> =
|
||||
T extends AppConnectionType.SECRET_TEXT ? SecretTextConnectionValue :
|
||||
T extends AppConnectionType.BASIC_AUTH ? BasicAuthConnectionValue :
|
||||
T extends AppConnectionType.CLOUD_OAUTH2 ? CloudOAuth2ConnectionValue :
|
||||
T extends AppConnectionType.PLATFORM_OAUTH2 ? PlatformOAuth2ConnectionValue :
|
||||
T extends AppConnectionType.OAUTH2 ? OAuth2ConnectionValueWithApp :
|
||||
T extends AppConnectionType.CUSTOM_AUTH ? CustomAuthConnectionValue<PropsType> :
|
||||
T extends AppConnectionType.NO_AUTH ? NoAuthConnectionValue :
|
||||
never
|
||||
|
||||
export type AppConnection<Type extends AppConnectionType = AppConnectionType> = BaseModel<AppConnectionId> & {
|
||||
externalId: string
|
||||
type: Type
|
||||
scope: AppConnectionScope
|
||||
pieceName: string
|
||||
displayName: string
|
||||
projectIds: string[]
|
||||
platformId: string
|
||||
status: AppConnectionStatus
|
||||
ownerId: string
|
||||
owner: UserWithMetaInformation | null
|
||||
value: AppConnectionValue<Type>
|
||||
metadata: Metadata | null
|
||||
pieceVersion: string
|
||||
}
|
||||
|
||||
export type OAuth2AppConnection = AppConnection<AppConnectionType.OAUTH2>
|
||||
export type SecretKeyAppConnection = AppConnection<AppConnectionType.SECRET_TEXT>
|
||||
export type CloudAuth2Connection = AppConnection<AppConnectionType.CLOUD_OAUTH2>
|
||||
export type PlatformOAuth2Connection = AppConnection<AppConnectionType.PLATFORM_OAUTH2>
|
||||
export type BasicAuthConnection = AppConnection<AppConnectionType.BASIC_AUTH>
|
||||
export type CustomAuthConnection = AppConnection<AppConnectionType.CUSTOM_AUTH>
|
||||
export type NoAuthConnection = AppConnection<AppConnectionType.NO_AUTH>
|
||||
|
||||
export const AppConnectionWithoutSensitiveData = Type.Object({
|
||||
...BaseModelSchema,
|
||||
externalId: Type.String(),
|
||||
displayName: Type.String(),
|
||||
type: Type.Enum(AppConnectionType),
|
||||
pieceName: Type.String(),
|
||||
projectIds: Type.Array(ApId),
|
||||
platformId: Nullable(Type.String()),
|
||||
scope: Type.Enum(AppConnectionScope),
|
||||
status: Type.Enum(AppConnectionStatus),
|
||||
ownerId: Nullable(Type.String()),
|
||||
owner: Nullable(UserWithMetaInformation),
|
||||
metadata: Nullable(Metadata),
|
||||
flowIds: Nullable(Type.Array(ApId)),
|
||||
pieceVersion: Type.String(),
|
||||
}, {
|
||||
description: 'App connection is a connection to an external app.',
|
||||
})
|
||||
export type AppConnectionWithoutSensitiveData = Static<typeof AppConnectionWithoutSensitiveData> & { __brand: 'AppConnectionWithoutSensitiveData' }
|
||||
|
||||
export const AppConnectionOwners = Type.Object({
|
||||
firstName: Type.String(),
|
||||
lastName: Type.String(),
|
||||
email: Type.String(),
|
||||
})
|
||||
|
||||
export type AppConnectionOwners = Static<typeof AppConnectionOwners>
|
||||
/**i.e props: {projectId: "123"} and value: "{{projectId}}" will return "123" */
|
||||
export const resolveValueFromProps = (props: Record<string, unknown> | undefined, value: string)=>{
|
||||
let resolvedScope = value
|
||||
if (!props) {
|
||||
return resolvedScope
|
||||
}
|
||||
Object.entries(props).forEach(([key, value]) => {
|
||||
resolvedScope = resolvedScope.replace(`{${key}}`, String(value))
|
||||
})
|
||||
return resolvedScope
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { AppConnectionScope, AppConnectionStatus } from '../app-connection'
|
||||
|
||||
export const ListAppConnectionsRequestQuery = Type.Object({
|
||||
cursor: Type.Optional(Type.String({})),
|
||||
projectId: Type.String(),
|
||||
scope: Type.Optional(Type.Enum(AppConnectionScope)),
|
||||
pieceName: Type.Optional(Type.String({})),
|
||||
displayName: Type.Optional(Type.String({})),
|
||||
status: Type.Optional(Type.Array(Type.Enum(AppConnectionStatus))),
|
||||
limit: Type.Optional(Type.Number({})),
|
||||
})
|
||||
|
||||
export type ListAppConnectionsRequestQuery = Static<
|
||||
typeof ListAppConnectionsRequestQuery
|
||||
>
|
||||
|
||||
export const GetAppConnectionForWorkerRequestQuery = Type.Object({
|
||||
externalId: Type.String(),
|
||||
})
|
||||
export type GetAppConnectionForWorkerRequestQuery = Static<
|
||||
typeof GetAppConnectionForWorkerRequestQuery
|
||||
>
|
||||
|
||||
export const ListGlobalConnectionsRequestQuery = Type.Omit(ListAppConnectionsRequestQuery, ['projectId'])
|
||||
export type ListGlobalConnectionsRequestQuery = Static<typeof ListGlobalConnectionsRequestQuery>
|
||||
|
||||
export const ListAppConnectionOwnersRequestQuery = Type.Object({
|
||||
projectId: Type.String(),
|
||||
})
|
||||
export type ListAppConnectionOwnersRequestQuery = Static<typeof ListAppConnectionOwnersRequestQuery>
|
||||
@@ -0,0 +1,207 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { Metadata } from '../../common/metadata'
|
||||
import { AppConnectionScope, AppConnectionType } from '../app-connection'
|
||||
import { OAuth2AuthorizationMethod } from '../oauth2-authorization-method'
|
||||
|
||||
const commonAuthProps = {
|
||||
externalId: Type.String({}),
|
||||
displayName: Type.String({}),
|
||||
pieceName: Type.String({}),
|
||||
projectId: Type.String({}),
|
||||
metadata: Type.Optional(Metadata),
|
||||
pieceVersion: Type.Optional(Type.String({})),
|
||||
}
|
||||
|
||||
|
||||
export const BOTH_CLIENT_CREDENTIALS_AND_AUTHORIZATION_CODE = 'both_client_credentials_and_authorization_code'
|
||||
|
||||
export enum OAuth2GrantType {
|
||||
AUTHORIZATION_CODE = 'authorization_code',
|
||||
CLIENT_CREDENTIALS = 'client_credentials',
|
||||
}
|
||||
|
||||
const propsSchema = Type.Record(Type.String(), Type.Unknown())
|
||||
export const UpsertCustomAuthRequest = Type.Object({
|
||||
...commonAuthProps,
|
||||
type: Type.Literal(AppConnectionType.CUSTOM_AUTH),
|
||||
value: Type.Object({
|
||||
type: Type.Literal(AppConnectionType.CUSTOM_AUTH),
|
||||
props: propsSchema,
|
||||
}),
|
||||
}, {
|
||||
title: 'Custom Auth',
|
||||
description: 'Custom Auth',
|
||||
})
|
||||
|
||||
export const UpsertNoAuthRequest = Type.Object({
|
||||
...commonAuthProps,
|
||||
type: Type.Literal(AppConnectionType.NO_AUTH),
|
||||
value: Type.Object({
|
||||
type: Type.Literal(AppConnectionType.NO_AUTH),
|
||||
}),
|
||||
}, {
|
||||
title: 'No Auth',
|
||||
description: 'No Auth',
|
||||
})
|
||||
|
||||
const commonOAuth2ValueProps = {
|
||||
client_id: Type.String({
|
||||
minLength: 1,
|
||||
}),
|
||||
code: Type.String({
|
||||
minLength: 1,
|
||||
}),
|
||||
code_challenge: Type.Optional(Type.String({})),
|
||||
scope: Type.String(),
|
||||
authorization_method: Type.Optional(Type.Enum(OAuth2AuthorizationMethod)),
|
||||
}
|
||||
export const UpsertPlatformOAuth2Request = Type.Object({
|
||||
...commonAuthProps,
|
||||
type: Type.Literal(AppConnectionType.PLATFORM_OAUTH2),
|
||||
value: Type.Object({
|
||||
...commonOAuth2ValueProps,
|
||||
props: Type.Optional(propsSchema),
|
||||
type: Type.Literal(AppConnectionType.PLATFORM_OAUTH2),
|
||||
redirect_url: Type.String({
|
||||
minLength: 1,
|
||||
}),
|
||||
}),
|
||||
}, {
|
||||
title: 'Platform OAuth2',
|
||||
description: 'Platform OAuth2',
|
||||
})
|
||||
|
||||
|
||||
export const UpsertCloudOAuth2Request = Type.Object({
|
||||
...commonAuthProps,
|
||||
type: Type.Literal(AppConnectionType.CLOUD_OAUTH2),
|
||||
value: Type.Object({
|
||||
...commonOAuth2ValueProps,
|
||||
props: Type.Optional(propsSchema),
|
||||
scope: Type.String(),
|
||||
type: Type.Literal(AppConnectionType.CLOUD_OAUTH2),
|
||||
}),
|
||||
}, {
|
||||
title: 'Cloud OAuth2',
|
||||
description: 'Cloud OAuth2',
|
||||
})
|
||||
|
||||
export const UpsertSecretTextRequest = Type.Object({
|
||||
...commonAuthProps,
|
||||
type: Type.Literal(AppConnectionType.SECRET_TEXT),
|
||||
value: Type.Object({
|
||||
type: Type.Literal(AppConnectionType.SECRET_TEXT),
|
||||
secret_text: Type.String({
|
||||
minLength: 1,
|
||||
}),
|
||||
}),
|
||||
}, {
|
||||
title: 'Secret Text',
|
||||
description: 'Secret Text',
|
||||
})
|
||||
|
||||
export const UpsertOAuth2Request = Type.Object({
|
||||
...commonAuthProps,
|
||||
type: Type.Literal(AppConnectionType.OAUTH2),
|
||||
value: Type.Object({
|
||||
...commonOAuth2ValueProps,
|
||||
client_secret: Type.String({
|
||||
minLength: 1,
|
||||
}),
|
||||
grant_type: Type.Optional(Type.Enum(OAuth2GrantType)),
|
||||
props: Type.Optional(Type.Record(Type.String(), Type.Any())),
|
||||
authorization_method: Type.Optional(Type.Enum(OAuth2AuthorizationMethod)),
|
||||
redirect_url: Type.String({
|
||||
minLength: 1,
|
||||
}),
|
||||
type: Type.Literal(AppConnectionType.OAUTH2),
|
||||
}),
|
||||
}, {
|
||||
title: 'OAuth2',
|
||||
description: 'OAuth2',
|
||||
})
|
||||
|
||||
export const UpsertBasicAuthRequest = Type.Object({
|
||||
...commonAuthProps,
|
||||
type: Type.Literal(AppConnectionType.BASIC_AUTH),
|
||||
value: Type.Object({
|
||||
username: Type.String({
|
||||
minLength: 1,
|
||||
}),
|
||||
password: Type.String({
|
||||
minLength: 1,
|
||||
}),
|
||||
type: Type.Literal(AppConnectionType.BASIC_AUTH),
|
||||
}),
|
||||
}, {
|
||||
title: 'Basic Auth',
|
||||
description: 'Basic Auth',
|
||||
})
|
||||
|
||||
export const UpsertAppConnectionRequestBody = Type.Union([
|
||||
UpsertSecretTextRequest,
|
||||
UpsertOAuth2Request,
|
||||
UpsertCloudOAuth2Request,
|
||||
UpsertPlatformOAuth2Request,
|
||||
UpsertBasicAuthRequest,
|
||||
UpsertCustomAuthRequest,
|
||||
UpsertNoAuthRequest,
|
||||
])
|
||||
|
||||
export type UpsertCloudOAuth2Request = Static<typeof UpsertCloudOAuth2Request>
|
||||
export type UpsertPlatformOAuth2Request = Static<typeof UpsertPlatformOAuth2Request>
|
||||
export type UpsertOAuth2Request = Static<typeof UpsertOAuth2Request>
|
||||
export type UpsertSecretTextRequest = Static<typeof UpsertSecretTextRequest>
|
||||
export type UpsertBasicAuthRequest = Static<typeof UpsertBasicAuthRequest>
|
||||
export type UpsertCustomAuthRequest = Static<typeof UpsertCustomAuthRequest>
|
||||
export type UpsertNoAuthRequest = Static<typeof UpsertNoAuthRequest>
|
||||
export type UpsertAppConnectionRequestBody = Static<typeof UpsertAppConnectionRequestBody>
|
||||
|
||||
|
||||
export const UpdateConnectionValueRequestBody = Type.Object({
|
||||
displayName: Type.String({
|
||||
minLength: 1,
|
||||
}),
|
||||
metadata: Type.Optional(Metadata),
|
||||
})
|
||||
|
||||
export const UpdateGlobalConnectionValueRequestBody = Type.Object({
|
||||
displayName: Type.String({
|
||||
minLength: 1,
|
||||
}),
|
||||
projectIds: Type.Optional(Type.Array(Type.String())),
|
||||
metadata: Type.Optional(Metadata),
|
||||
})
|
||||
|
||||
export type UpdateConnectionValueRequestBody = Static<typeof UpdateConnectionValueRequestBody>
|
||||
export type UpdateGlobalConnectionValueRequestBody = Static<typeof UpdateGlobalConnectionValueRequestBody>
|
||||
const GlobalConnectionExtras = Type.Object({
|
||||
scope: Type.Literal(AppConnectionScope.PLATFORM),
|
||||
projectIds: Type.Array(Type.String()),
|
||||
externalId: Type.Optional(Type.String()),
|
||||
metadata: Type.Optional(Metadata),
|
||||
})
|
||||
export const UpsertGlobalConnectionRequestBody =
|
||||
Type.Union([
|
||||
Type.Composite([Type.Omit(UpsertSecretTextRequest, ['projectId', 'externalId']), GlobalConnectionExtras]),
|
||||
Type.Composite([Type.Omit(UpsertOAuth2Request, ['projectId', 'externalId']), GlobalConnectionExtras]),
|
||||
Type.Composite([Type.Omit(UpsertCloudOAuth2Request, ['projectId', 'externalId']), GlobalConnectionExtras]),
|
||||
Type.Composite([Type.Omit(UpsertPlatformOAuth2Request, ['projectId', 'externalId']), GlobalConnectionExtras]),
|
||||
Type.Composite([Type.Omit(UpsertBasicAuthRequest, ['projectId', 'externalId']), GlobalConnectionExtras]),
|
||||
Type.Composite([Type.Omit(UpsertCustomAuthRequest, ['projectId', 'externalId']), GlobalConnectionExtras]),
|
||||
Type.Composite([Type.Omit(UpsertNoAuthRequest, ['projectId', 'externalId']), GlobalConnectionExtras]),
|
||||
])
|
||||
export type UpsertGlobalConnectionRequestBody = Static<typeof UpsertGlobalConnectionRequestBody>
|
||||
|
||||
export const ReplaceAppConnectionsRequestBody = Type.Object({
|
||||
sourceAppConnectionId: Type.String(),
|
||||
targetAppConnectionId: Type.String(),
|
||||
projectId: Type.String(),
|
||||
})
|
||||
export type ReplaceAppConnectionsRequestBody = Static<typeof ReplaceAppConnectionsRequestBody>
|
||||
|
||||
export const ListFlowsFromAppConnectionRequestQuery = Type.Object({
|
||||
sourceAppConnectionIds: Type.Array(Type.String()),
|
||||
projectId: Type.String(),
|
||||
})
|
||||
export type ListFlowsFromAppConnectionRequestQuery = Static<typeof ListFlowsFromAppConnectionRequestQuery>
|
||||
@@ -0,0 +1,5 @@
|
||||
// Todo remove it's duplicated in frameworkr as well, make sure it's not exported in shared package.
|
||||
export enum OAuth2AuthorizationMethod {
|
||||
HEADER = 'HEADER',
|
||||
BODY = 'BODY',
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { User } from '../../user/user'
|
||||
import { UserIdentity } from '../user-identity'
|
||||
|
||||
|
||||
export const UserWithoutPassword = Type.Pick(User, ['id', 'platformRole', 'status', 'externalId', 'platformId'])
|
||||
export type UserWithoutPassword = Static<typeof UserWithoutPassword>
|
||||
|
||||
export const AuthenticationResponse = Type.Composite([
|
||||
UserWithoutPassword,
|
||||
Type.Pick(UserIdentity, ['verified', 'firstName', 'lastName', 'email', 'trackEvents', 'newsLetter']),
|
||||
Type.Object({
|
||||
token: Type.String(),
|
||||
projectId: Type.String(),
|
||||
}),
|
||||
])
|
||||
export type AuthenticationResponse = Static<typeof AuthenticationResponse>
|
||||
@@ -0,0 +1,9 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { EmailType, PasswordType } from '../../user/user'
|
||||
|
||||
export const SignInRequest = Type.Object({
|
||||
email: EmailType,
|
||||
password: PasswordType,
|
||||
})
|
||||
|
||||
export type SignInRequest = Static<typeof SignInRequest>
|
||||
@@ -0,0 +1,31 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { SAFE_STRING_PATTERN } from '../../common'
|
||||
import { ApId } from '../../common/id-generator'
|
||||
import { EmailType, PasswordType } from '../../user/user'
|
||||
|
||||
export const SignUpRequest = Type.Object({
|
||||
email: EmailType,
|
||||
password: PasswordType,
|
||||
firstName: Type.String({
|
||||
pattern: SAFE_STRING_PATTERN,
|
||||
}),
|
||||
lastName: Type.String({
|
||||
pattern: SAFE_STRING_PATTERN,
|
||||
}),
|
||||
trackEvents: Type.Boolean(),
|
||||
newsLetter: Type.Boolean(),
|
||||
})
|
||||
|
||||
export type SignUpRequest = Static<typeof SignUpRequest>
|
||||
|
||||
export const SwitchPlatformRequest = Type.Object({
|
||||
platformId: ApId,
|
||||
})
|
||||
|
||||
export type SwitchPlatformRequest = Static<typeof SwitchPlatformRequest>
|
||||
|
||||
export const SwitchProjectRequest = Type.Object({
|
||||
projectId: ApId,
|
||||
})
|
||||
|
||||
export type SwitchProjectRequest = Static<typeof SwitchProjectRequest>
|
||||
@@ -0,0 +1,18 @@
|
||||
export enum PrincipalType {
|
||||
USER = 'USER',
|
||||
ENGINE = 'ENGINE',
|
||||
SERVICE = 'SERVICE',
|
||||
WORKER = 'WORKER',
|
||||
UNKNOWN = 'UNKNOWN',
|
||||
}
|
||||
|
||||
export const ALL_PRINCIPAL_TYPES = Object.values(PrincipalType)
|
||||
|
||||
export const SERVICE_KEY_SECURITY_OPENAPI = {
|
||||
apiKey: [],
|
||||
}
|
||||
|
||||
export enum EndpointScope {
|
||||
PLATFORM = 'PLATFORM',
|
||||
PROJECT = 'PROJECT',
|
||||
}
|
||||
54
activepieces-fork/packages/shared/src/lib/authentication/model/principal.ts
Executable file
54
activepieces-fork/packages/shared/src/lib/authentication/model/principal.ts
Executable file
@@ -0,0 +1,54 @@
|
||||
import { ApId } from '../../common/id-generator'
|
||||
import { PlatformId } from '../../platform'
|
||||
import { ProjectId } from '../../project'
|
||||
import { PrincipalType } from './principal-type'
|
||||
|
||||
export type WorkerPrincipal = {
|
||||
id: ApId
|
||||
type: PrincipalType.WORKER
|
||||
}
|
||||
|
||||
export type AnnonymousPrincipal = {
|
||||
id: ApId
|
||||
type: PrincipalType.UNKNOWN
|
||||
}
|
||||
|
||||
export type ServicePrincipal = {
|
||||
id: ApId
|
||||
type: PrincipalType.SERVICE
|
||||
projectId: ProjectId
|
||||
platform: {
|
||||
id: ApId
|
||||
}
|
||||
}
|
||||
|
||||
export type UserPrincipal = {
|
||||
id: ApId
|
||||
type: PrincipalType.USER
|
||||
projectId: ProjectId
|
||||
platform: {
|
||||
id: ApId
|
||||
}
|
||||
tokenVersion?: string
|
||||
}
|
||||
|
||||
export type EnginePrincipal = {
|
||||
id: ApId
|
||||
type: PrincipalType.ENGINE
|
||||
projectId: ProjectId
|
||||
platform: {
|
||||
id: PlatformId
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export type PrincipalForType<T extends PrincipalType> = Extract<Principal, { type: T }>
|
||||
|
||||
export type PrincipalForTypes<R extends readonly PrincipalType[]> = PrincipalForType<R[number]>
|
||||
|
||||
export type Principal =
|
||||
| WorkerPrincipal
|
||||
| AnnonymousPrincipal
|
||||
| ServicePrincipal
|
||||
| UserPrincipal
|
||||
| EnginePrincipal
|
||||
@@ -0,0 +1,24 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { BaseModelSchema } from '../common'
|
||||
|
||||
|
||||
export enum UserIdentityProvider {
|
||||
EMAIL = 'EMAIL',
|
||||
GOOGLE = 'GOOGLE',
|
||||
SAML = 'SAML',
|
||||
JWT = 'JWT',
|
||||
}
|
||||
export const UserIdentity = Type.Object({
|
||||
...BaseModelSchema,
|
||||
firstName: Type.String(),
|
||||
lastName: Type.String(),
|
||||
email: Type.String(),
|
||||
password: Type.String(),
|
||||
trackEvents: Type.Boolean(),
|
||||
newsLetter: Type.Boolean(),
|
||||
verified: Type.Boolean(),
|
||||
tokenVersion: Type.Optional(Type.String()),
|
||||
provider: Type.Enum(UserIdentityProvider),
|
||||
})
|
||||
|
||||
export type UserIdentity = Static<typeof UserIdentity>
|
||||
572
activepieces-fork/packages/shared/src/lib/common/activepieces-error.ts
Executable file
572
activepieces-fork/packages/shared/src/lib/common/activepieces-error.ts
Executable file
@@ -0,0 +1,572 @@
|
||||
import { FileId } from '../file'
|
||||
import { FlowRunId } from '../flow-run/flow-run'
|
||||
import { FlowId } from '../flows/flow'
|
||||
import { FlowVersionId } from '../flows/flow-version'
|
||||
import { PlatformUsageMetric } from '../platform'
|
||||
import { ProjectId } from '../project'
|
||||
import { ProjectRole } from '../project-role/project-role'
|
||||
import { UserId } from '../user'
|
||||
import { ApId } from './id-generator'
|
||||
import { Permission } from './security'
|
||||
|
||||
export class ActivepiecesError extends Error {
|
||||
constructor(public error: ApErrorParams, message?: string) {
|
||||
super(error.code + (message ? `: ${message}` : ''))
|
||||
}
|
||||
|
||||
override toString(): string {
|
||||
return JSON.stringify({
|
||||
code: this.error.code,
|
||||
message: this.message,
|
||||
params: this.error.params,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export type ApErrorParams =
|
||||
| AuthenticationParams
|
||||
| AuthorizationErrorParams
|
||||
| ConfigNotFoundErrorParams
|
||||
| EmailIsNotVerifiedErrorParams
|
||||
| EngineOperationFailureParams
|
||||
| EntityNotFoundErrorParams
|
||||
| ExecutionTimeoutErrorParams
|
||||
| ExistingUserErrorParams
|
||||
| FileNotFoundErrorParams
|
||||
| FlowFormNotFoundError
|
||||
| FlowNotFoundErrorParams
|
||||
| FlowIsLockedErrorParams
|
||||
| FlowOperationErrorParams
|
||||
| FlowOperationInProgressErrorParams
|
||||
| FlowRunNotFoundErrorParams
|
||||
| InvalidApiKeyParams
|
||||
| InvalidAppConnectionParams
|
||||
| InvalidBearerTokenParams
|
||||
| InvalidClaimParams
|
||||
| InvalidCloudClaimParams
|
||||
| InvalidCredentialsErrorParams
|
||||
| InvalidJwtTokenErrorParams
|
||||
| InvalidOtpParams
|
||||
| InvalidSAMLResponseParams
|
||||
| InvitationOnlySignUpParams
|
||||
| JobRemovalFailureErrorParams
|
||||
| OpenAiFailedErrorParams
|
||||
| PauseMetadataMissingErrorParams
|
||||
| PermissionDeniedErrorParams
|
||||
| PieceNotFoundErrorParams
|
||||
| PieceTriggerNotFoundErrorParams
|
||||
| QuotaExceededParams
|
||||
| FeatureDisabledErrorParams
|
||||
| SignUpDisabledParams
|
||||
| StepNotFoundErrorParams
|
||||
| SystemInvalidErrorParams
|
||||
| SystemPropNotDefinedErrorParams
|
||||
| TestTriggerFailedErrorParams
|
||||
| TriggerUpdateStatusErrorParams
|
||||
| TriggerFailedErrorParams
|
||||
| ValidationErrorParams
|
||||
| InvitationOnlySignUpParams
|
||||
| UserIsInActiveErrorParams
|
||||
| DomainIsNotAllowedErrorParams
|
||||
| EmailAuthIsDisabledParams
|
||||
| ExistingAlertChannelErrorParams
|
||||
| EmailAlreadyHasActivationKey
|
||||
| ProviderProxyConfigNotFoundParams
|
||||
| AIProviderModelNotSupportedParams
|
||||
| AIProviderNotSupportedParams
|
||||
| AIRequestNotSupportedParams
|
||||
| AICreditLimitExceededParams
|
||||
| SessionExpiredParams
|
||||
| InvalidLicenseKeyParams
|
||||
| NoChatResponseParams
|
||||
| InvalidSmtpCredentialsErrorParams
|
||||
| InvalidGitCredentialsParams
|
||||
| InvalidReleaseTypeParams
|
||||
| ProjectExternalIdAlreadyExistsParams
|
||||
| MemoryIssueParams
|
||||
| InvalidCustomDomainErrorParams
|
||||
| McpPieceRequiresConnectionParams
|
||||
| McpPieceConnectionMismatchParams
|
||||
| ErrorUpdatingSubscriptionParams
|
||||
| TriggerExecutionFailedParams
|
||||
| SubflowFailedParams
|
||||
| MachineNotAvailableParams
|
||||
| MachineNotConnectedParams
|
||||
| DoesNotMeetBusinessRequirementsParams
|
||||
export type TriggerExecutionFailedParams = BaseErrorParams<ErrorCode.TRIGGER_EXECUTION_FAILED, {
|
||||
flowId: FlowId
|
||||
message?: string
|
||||
pieceName: string
|
||||
pieceVersion: string
|
||||
}>
|
||||
|
||||
export type BaseErrorParams<T, V> = {
|
||||
code: T
|
||||
params: V
|
||||
}
|
||||
|
||||
export type MemoryIssueParams = BaseErrorParams<ErrorCode.MEMORY_ISSUE, {
|
||||
standardOutput: string
|
||||
standardError: string
|
||||
}>
|
||||
|
||||
export type InvitationOnlySignUpParams = BaseErrorParams<
|
||||
ErrorCode.INVITATION_ONLY_SIGN_UP,
|
||||
{
|
||||
message?: string
|
||||
}
|
||||
>
|
||||
|
||||
export type InvalidClaimParams = BaseErrorParams<ErrorCode.INVALID_CLAIM, { redirectUrl: string, tokenUrl: string, clientId: string, message: string }>
|
||||
export type InvalidCloudClaimParams = BaseErrorParams<ErrorCode.INVALID_CLOUD_CLAIM, { pieceName: string }>
|
||||
|
||||
export type InvalidBearerTokenParams = BaseErrorParams<ErrorCode.INVALID_BEARER_TOKEN, {
|
||||
message?: string
|
||||
}>
|
||||
|
||||
export type SessionExpiredParams = BaseErrorParams<ErrorCode.SESSION_EXPIRED, {
|
||||
message?: string
|
||||
}>
|
||||
|
||||
export type NoChatResponseParams = BaseErrorParams<ErrorCode.NO_CHAT_RESPONSE, Record<string, never>>
|
||||
|
||||
export type FileNotFoundErrorParams = BaseErrorParams<ErrorCode.FILE_NOT_FOUND, { id: FileId }>
|
||||
|
||||
export type EmailAuthIsDisabledParams = BaseErrorParams<ErrorCode.EMAIL_AUTH_DISABLED, Record<string, never>>
|
||||
|
||||
export type AuthorizationErrorParams = BaseErrorParams<
|
||||
ErrorCode.AUTHORIZATION,
|
||||
Record<string, string> &
|
||||
{
|
||||
message?: string
|
||||
}
|
||||
>
|
||||
|
||||
export type AICreditLimitExceededParams = BaseErrorParams<ErrorCode.AI_CREDIT_LIMIT_EXCEEDED, {
|
||||
usage: number
|
||||
limit: number
|
||||
}>
|
||||
|
||||
export type PermissionDeniedErrorParams = BaseErrorParams<
|
||||
ErrorCode.PERMISSION_DENIED,
|
||||
{
|
||||
userId: UserId
|
||||
projectId: ProjectId
|
||||
projectRole: ProjectRole | null
|
||||
permission: Permission | undefined
|
||||
}
|
||||
>
|
||||
|
||||
export type SystemInvalidErrorParams = BaseErrorParams<
|
||||
ErrorCode.SYSTEM_PROP_INVALID,
|
||||
{
|
||||
prop: string
|
||||
}
|
||||
>
|
||||
|
||||
export type FlowNotFoundErrorParams = BaseErrorParams<
|
||||
ErrorCode.FLOW_NOT_FOUND,
|
||||
{
|
||||
id: FlowId
|
||||
}
|
||||
>
|
||||
|
||||
export type FlowRunNotFoundErrorParams = BaseErrorParams<
|
||||
ErrorCode.FLOW_RUN_NOT_FOUND,
|
||||
{
|
||||
id: FlowRunId
|
||||
}
|
||||
>
|
||||
|
||||
export type InvalidCredentialsErrorParams = BaseErrorParams<
|
||||
ErrorCode.INVALID_CREDENTIALS,
|
||||
null
|
||||
>
|
||||
|
||||
export type DomainIsNotAllowedErrorParams = BaseErrorParams<
|
||||
ErrorCode.DOMAIN_NOT_ALLOWED,
|
||||
{
|
||||
domain: string
|
||||
}
|
||||
>
|
||||
|
||||
export type EmailIsNotVerifiedErrorParams = BaseErrorParams<
|
||||
ErrorCode.EMAIL_IS_NOT_VERIFIED,
|
||||
{
|
||||
email: string
|
||||
}
|
||||
>
|
||||
|
||||
export type UserIsInActiveErrorParams = BaseErrorParams<
|
||||
ErrorCode.USER_IS_INACTIVE,
|
||||
{
|
||||
email: string
|
||||
}
|
||||
>
|
||||
|
||||
export type ExistingUserErrorParams = BaseErrorParams<
|
||||
ErrorCode.EXISTING_USER,
|
||||
{
|
||||
email: string
|
||||
platformId: string | null
|
||||
}
|
||||
>
|
||||
|
||||
export type StepNotFoundErrorParams = BaseErrorParams<
|
||||
ErrorCode.STEP_NOT_FOUND,
|
||||
{
|
||||
pieceName?: string
|
||||
pieceVersion?: string
|
||||
stepName: string
|
||||
}
|
||||
>
|
||||
|
||||
export type PieceNotFoundErrorParams = BaseErrorParams<
|
||||
ErrorCode.PIECE_NOT_FOUND,
|
||||
{
|
||||
pieceName: string
|
||||
pieceVersion: string | undefined
|
||||
message: string
|
||||
}
|
||||
>
|
||||
|
||||
export type PieceTriggerNotFoundErrorParams = BaseErrorParams<
|
||||
ErrorCode.PIECE_TRIGGER_NOT_FOUND,
|
||||
{
|
||||
pieceName: string
|
||||
pieceVersion: string
|
||||
triggerName: string | undefined
|
||||
}
|
||||
>
|
||||
|
||||
export type TriggerFailedErrorParams = BaseErrorParams<
|
||||
ErrorCode.TRIGGER_FAILED,
|
||||
{
|
||||
pieceName: string
|
||||
pieceVersion: string
|
||||
triggerName: string
|
||||
error: string | undefined
|
||||
}
|
||||
>
|
||||
|
||||
|
||||
export type ConfigNotFoundErrorParams = BaseErrorParams<
|
||||
ErrorCode.CONFIG_NOT_FOUND,
|
||||
{
|
||||
pieceName: string
|
||||
pieceVersion: string
|
||||
stepName: string
|
||||
configName: string
|
||||
}
|
||||
>
|
||||
|
||||
export type JobRemovalFailureErrorParams = BaseErrorParams<
|
||||
ErrorCode.JOB_REMOVAL_FAILURE,
|
||||
{
|
||||
flowVersionId: ApId
|
||||
}
|
||||
>
|
||||
|
||||
export type SystemPropNotDefinedErrorParams = BaseErrorParams<
|
||||
ErrorCode.SYSTEM_PROP_NOT_DEFINED,
|
||||
{
|
||||
prop: string
|
||||
}
|
||||
>
|
||||
|
||||
export type OpenAiFailedErrorParams = BaseErrorParams<
|
||||
ErrorCode.OPEN_AI_FAILED,
|
||||
Record<string, never>
|
||||
>
|
||||
|
||||
export type FlowOperationErrorParams = BaseErrorParams<
|
||||
ErrorCode.FLOW_OPERATION_INVALID,
|
||||
{
|
||||
message: string
|
||||
}
|
||||
>
|
||||
|
||||
export type FlowOperationInProgressErrorParams = BaseErrorParams<
|
||||
ErrorCode.FLOW_OPERATION_IN_PROGRESS, {
|
||||
message: string
|
||||
}>
|
||||
|
||||
export type FlowFormNotFoundError = BaseErrorParams<
|
||||
ErrorCode.FLOW_FORM_NOT_FOUND,
|
||||
{
|
||||
flowId: FlowVersionId
|
||||
message: string
|
||||
}>
|
||||
|
||||
export type FlowIsLockedErrorParams = BaseErrorParams<
|
||||
ErrorCode.FLOW_IN_USE,
|
||||
{
|
||||
flowVersionId: FlowVersionId
|
||||
message: string
|
||||
}>
|
||||
|
||||
export type InvalidJwtTokenErrorParams = BaseErrorParams<
|
||||
ErrorCode.INVALID_OR_EXPIRED_JWT_TOKEN,
|
||||
{
|
||||
token: string
|
||||
}
|
||||
>
|
||||
|
||||
export type TestTriggerFailedErrorParams = BaseErrorParams<
|
||||
ErrorCode.TEST_TRIGGER_FAILED,
|
||||
{
|
||||
message: string
|
||||
}
|
||||
>
|
||||
|
||||
export type EntityNotFoundErrorParams = BaseErrorParams<
|
||||
ErrorCode.ENTITY_NOT_FOUND,
|
||||
{
|
||||
message?: string
|
||||
entityType?: string
|
||||
entityId?: string
|
||||
}
|
||||
>
|
||||
|
||||
export type InvalidCustomDomainErrorParams = BaseErrorParams<
|
||||
ErrorCode.INVALID_CUSTOM_DOMAIN,
|
||||
{
|
||||
message: string
|
||||
}
|
||||
>
|
||||
|
||||
export type ExecutionTimeoutErrorParams = BaseErrorParams<
|
||||
ErrorCode.EXECUTION_TIMEOUT,
|
||||
{
|
||||
standardOutput: string
|
||||
standardError: string
|
||||
}
|
||||
>
|
||||
|
||||
export type ValidationErrorParams = BaseErrorParams<
|
||||
ErrorCode.VALIDATION,
|
||||
{
|
||||
message: string
|
||||
}
|
||||
>
|
||||
|
||||
export type TriggerUpdateStatusErrorParams = BaseErrorParams<
|
||||
ErrorCode.TRIGGER_UPDATE_STATUS,
|
||||
{
|
||||
flowId?: FlowId
|
||||
flowVersionId?: FlowVersionId
|
||||
message?: string
|
||||
standardOutput?: string
|
||||
standardError?: string
|
||||
}
|
||||
>
|
||||
|
||||
export type PauseMetadataMissingErrorParams = BaseErrorParams<
|
||||
ErrorCode.PAUSE_METADATA_MISSING,
|
||||
Record<string, never>
|
||||
>
|
||||
|
||||
export type InvalidApiKeyParams = BaseErrorParams<
|
||||
ErrorCode.INVALID_API_KEY,
|
||||
Record<string, never>
|
||||
>
|
||||
|
||||
export type EngineOperationFailureParams = BaseErrorParams<
|
||||
ErrorCode.ENGINE_OPERATION_FAILURE,
|
||||
{
|
||||
message: string
|
||||
context?: unknown
|
||||
}
|
||||
>
|
||||
|
||||
export type InvalidAppConnectionParams = BaseErrorParams<
|
||||
ErrorCode.INVALID_APP_CONNECTION,
|
||||
{
|
||||
error: string
|
||||
}
|
||||
>
|
||||
|
||||
export type QuotaExceededParams = BaseErrorParams<
|
||||
ErrorCode.QUOTA_EXCEEDED,
|
||||
{
|
||||
metric: PlatformUsageMetric
|
||||
}
|
||||
>
|
||||
|
||||
export type ErrorUpdatingSubscriptionParams = BaseErrorParams<
|
||||
ErrorCode.ERROR_UPDATING_SUBSCRIPTION,
|
||||
{
|
||||
message: string
|
||||
}>
|
||||
|
||||
export type ProviderProxyConfigNotFoundParams = BaseErrorParams<
|
||||
ErrorCode.PROVIDER_PROXY_CONFIG_NOT_FOUND_FOR_PROVIDER,
|
||||
{
|
||||
provider: string
|
||||
}>
|
||||
|
||||
export type AIProviderModelNotSupportedParams = BaseErrorParams<ErrorCode.AI_MODEL_NOT_SUPPORTED, {
|
||||
provider: string
|
||||
model: string
|
||||
}>
|
||||
|
||||
export type AIProviderNotSupportedParams = BaseErrorParams<ErrorCode.AI_PROVIDER_NOT_SUPPORTED, {
|
||||
provider: string
|
||||
}>
|
||||
|
||||
export type AIRequestNotSupportedParams = BaseErrorParams<ErrorCode.AI_REQUEST_NOT_SUPPORTED, {
|
||||
message: string
|
||||
}>
|
||||
|
||||
export type FeatureDisabledErrorParams = BaseErrorParams<
|
||||
ErrorCode.FEATURE_DISABLED,
|
||||
{
|
||||
message: string
|
||||
}>
|
||||
|
||||
export type SignUpDisabledParams = BaseErrorParams<
|
||||
ErrorCode.SIGN_UP_DISABLED,
|
||||
Record<string, never>
|
||||
>
|
||||
|
||||
export type AuthenticationParams = BaseErrorParams<
|
||||
ErrorCode.AUTHENTICATION,
|
||||
{
|
||||
message: string
|
||||
}>
|
||||
|
||||
export type InvalidSAMLResponseParams = BaseErrorParams<
|
||||
ErrorCode.INVALID_SAML_RESPONSE,
|
||||
{
|
||||
message: string
|
||||
}>
|
||||
|
||||
export type ExistingAlertChannelErrorParams = BaseErrorParams<
|
||||
ErrorCode.EXISTING_ALERT_CHANNEL,
|
||||
{
|
||||
email: string
|
||||
}>
|
||||
|
||||
export type InvalidOtpParams = BaseErrorParams<ErrorCode.INVALID_OTP, Record<string, never>>
|
||||
|
||||
export type InvalidLicenseKeyParams = BaseErrorParams<ErrorCode.INVALID_LICENSE_KEY, {
|
||||
key: string
|
||||
}>
|
||||
|
||||
export type EmailAlreadyHasActivationKey = BaseErrorParams<ErrorCode.EMAIL_ALREADY_HAS_ACTIVATION_KEY, {
|
||||
email: string
|
||||
}>
|
||||
|
||||
export type InvalidSmtpCredentialsErrorParams = BaseErrorParams<ErrorCode.INVALID_SMTP_CREDENTIALS, {
|
||||
message: string
|
||||
}>
|
||||
|
||||
export type InvalidGitCredentialsParams = BaseErrorParams<ErrorCode.INVALID_GIT_CREDENTIALS, {
|
||||
message: string
|
||||
}>
|
||||
|
||||
export type InvalidReleaseTypeParams = BaseErrorParams<ErrorCode.INVALID_RELEASE_TYPE, {
|
||||
message: string
|
||||
}>
|
||||
|
||||
export type ProjectExternalIdAlreadyExistsParams = BaseErrorParams<ErrorCode.PROJECT_EXTERNAL_ID_ALREADY_EXISTS, {
|
||||
externalId: string
|
||||
}>
|
||||
|
||||
export type McpPieceRequiresConnectionParams = BaseErrorParams<ErrorCode.MCP_PIECE_REQUIRES_CONNECTION, {
|
||||
pieceName: string
|
||||
}>
|
||||
|
||||
export type McpPieceConnectionMismatchParams = BaseErrorParams<ErrorCode.MCP_PIECE_CONNECTION_MISMATCH, {
|
||||
pieceName: string
|
||||
connectionPieceName: string
|
||||
connectionId: string
|
||||
}>
|
||||
|
||||
export type SubflowFailedParams = BaseErrorParams<ErrorCode.SUBFLOW_FAILED, {
|
||||
message: string
|
||||
}>
|
||||
|
||||
export type MachineNotAvailableParams = BaseErrorParams<ErrorCode.MACHINE_NOT_AVAILABLE, {
|
||||
resourceType: string
|
||||
}>
|
||||
|
||||
export type MachineNotConnectedParams = BaseErrorParams<ErrorCode.MACHINE_NOT_CONNECTED, {
|
||||
message: string
|
||||
}>
|
||||
export type DoesNotMeetBusinessRequirementsParams = BaseErrorParams<ErrorCode.DOES_NOT_MEET_BUSINESS_REQUIREMENTS, {
|
||||
message: string
|
||||
}>
|
||||
|
||||
export enum ErrorCode {
|
||||
MACHINE_NOT_CONNECTED = 'MACHINE_NOT_CONNECTED',
|
||||
MACHINE_NOT_AVAILABLE = 'MACHINE_NOT_AVAILABLE',
|
||||
INVALID_CUSTOM_DOMAIN = 'INVALID_CUSTOM_DOMAIN',
|
||||
NO_CHAT_RESPONSE = 'NO_CHAT_RESPONSE',
|
||||
ERROR_UPDATING_SUBSCRIPTION = 'ERROR_UPDATING_SUBSCRIPTION',
|
||||
AUTHENTICATION = 'AUTHENTICATION',
|
||||
AUTHORIZATION = 'AUTHORIZATION',
|
||||
PROVIDER_PROXY_CONFIG_NOT_FOUND_FOR_PROVIDER = 'PROVIDER_PROXY_CONFIG_NOT_FOUND_FOR_PROVIDER',
|
||||
AI_MODEL_NOT_SUPPORTED = 'AI_MODEL_NOT_SUPPORTED',
|
||||
AI_PROVIDER_NOT_SUPPORTED = 'AI_PROVIDER_NOT_SUPPORTED',
|
||||
AI_REQUEST_NOT_SUPPORTED = 'AI_REQUEST_NOT_SUPPORTED',
|
||||
CONFIG_NOT_FOUND = 'CONFIG_NOT_FOUND',
|
||||
DOMAIN_NOT_ALLOWED = 'DOMAIN_NOT_ALLOWED',
|
||||
EMAIL_IS_NOT_VERIFIED = 'EMAIL_IS_NOT_VERIFIED',
|
||||
ENGINE_OPERATION_FAILURE = 'ENGINE_OPERATION_FAILURE',
|
||||
ENTITY_NOT_FOUND = 'ENTITY_NOT_FOUND',
|
||||
EXECUTION_TIMEOUT = 'EXECUTION_TIMEOUT',
|
||||
MEMORY_ISSUE = 'MEMORY_ISSUE',
|
||||
TRIGGER_EXECUTION_FAILED = 'TRIGGER_EXECUTION_FAILED',
|
||||
EMAIL_AUTH_DISABLED = 'EMAIL_AUTH_DISABLED',
|
||||
EXISTING_USER = 'EXISTING_USER',
|
||||
EXISTING_ALERT_CHANNEL = 'EXISTING_ALERT_CHANNEL',
|
||||
PROJECT_EXTERNAL_ID_ALREADY_EXISTS = 'PROJECT_EXTERNAL_ID_ALREADY_EXISTS',
|
||||
FLOW_FORM_NOT_FOUND = 'FLOW_FORM_NOT_FOUND',
|
||||
FILE_NOT_FOUND = 'FILE_NOT_FOUND',
|
||||
FLOW_INSTANCE_NOT_FOUND = 'INSTANCE_NOT_FOUND',
|
||||
FLOW_NOT_FOUND = 'FLOW_NOT_FOUND',
|
||||
FLOW_OPERATION_INVALID = 'FLOW_OPERATION_INVALID',
|
||||
FLOW_OPERATION_IN_PROGRESS = 'FLOW_OPERATION_IN_PROGRESS',
|
||||
FLOW_IN_USE = 'FLOW_IN_USE',
|
||||
FLOW_RUN_NOT_FOUND = 'FLOW_RUN_NOT_FOUND',
|
||||
INVALID_API_KEY = 'INVALID_API_KEY',
|
||||
INVALID_APP_CONNECTION = 'INVALID_APP_CONNECTION',
|
||||
INVALID_BEARER_TOKEN = 'INVALID_BEARER_TOKEN',
|
||||
SESSION_EXPIRED = 'SESSION_EXPIRED',
|
||||
INVALID_CLAIM = 'INVALID_CLAIM',
|
||||
INVALID_CLOUD_CLAIM = 'INVALID_CLOUD_CLAIM',
|
||||
INVALID_CREDENTIALS = 'INVALID_CREDENTIALS',
|
||||
INVALID_OR_EXPIRED_JWT_TOKEN = 'INVALID_OR_EXPIRED_JWT_TOKEN',
|
||||
INVALID_OTP = 'INVALID_OTP',
|
||||
INVALID_SAML_RESPONSE = 'INVALID_SAML_RESPONSE',
|
||||
INVITATION_ONLY_SIGN_UP = 'INVITATION_ONLY_SIGN_UP',
|
||||
JOB_REMOVAL_FAILURE = 'JOB_REMOVAL_FAILURE',
|
||||
OPEN_AI_FAILED = 'OPEN_AI_FAILED',
|
||||
PAUSE_METADATA_MISSING = 'PAUSE_METADATA_MISSING',
|
||||
PERMISSION_DENIED = 'PERMISSION_DENIED',
|
||||
PIECE_NOT_FOUND = 'PIECE_NOT_FOUND',
|
||||
PIECE_TRIGGER_NOT_FOUND = 'PIECE_TRIGGER_NOT_FOUND',
|
||||
QUOTA_EXCEEDED = 'QUOTA_EXCEEDED',
|
||||
FEATURE_DISABLED = 'FEATURE_DISABLED',
|
||||
AI_CREDIT_LIMIT_EXCEEDED = 'AI_CREDIT_LIMIT_EXCEEDED',
|
||||
SIGN_UP_DISABLED = 'SIGN_UP_DISABLED',
|
||||
STEP_NOT_FOUND = 'STEP_NOT_FOUND',
|
||||
SYSTEM_PROP_INVALID = 'SYSTEM_PROP_INVALID',
|
||||
SYSTEM_PROP_NOT_DEFINED = 'SYSTEM_PROP_NOT_DEFINED',
|
||||
TEST_TRIGGER_FAILED = 'TEST_TRIGGER_FAILED',
|
||||
TRIGGER_UPDATE_STATUS = 'TRIGGER_UPDATE_STATUS',
|
||||
TRIGGER_FAILED = 'TRIGGER_FAILED',
|
||||
USER_IS_INACTIVE = 'USER_IS_INACTIVE',
|
||||
VALIDATION = 'VALIDATION',
|
||||
INVALID_LICENSE_KEY = 'INVALID_LICENSE_KEY',
|
||||
EMAIL_ALREADY_HAS_ACTIVATION_KEY = 'EMAIL_ALREADY_HAS_ACTIVATION_KEY',
|
||||
INVALID_SMTP_CREDENTIALS = 'INVALID_SMTP_CREDENTIALS',
|
||||
INVALID_GIT_CREDENTIALS = 'INVALID_GIT_CREDENTIALS',
|
||||
INVALID_RELEASE_TYPE = 'INVALID_RELEASE_TYPE',
|
||||
MCP_PIECE_REQUIRES_CONNECTION = 'MCP_PIECE_REQUIRES_CONNECTION',
|
||||
MCP_PIECE_CONNECTION_MISMATCH = 'MCP_PIECE_CONNECTION_MISMATCH',
|
||||
SUBFLOW_FAILED = 'SUBFLOW_FAILED',
|
||||
DOES_NOT_MEET_BUSINESS_REQUIREMENTS = 'DOES_NOT_MEET_BUSINESS_REQUIREMENTS',
|
||||
}
|
||||
|
||||
65
activepieces-fork/packages/shared/src/lib/common/base-model.ts
Executable file
65
activepieces-fork/packages/shared/src/lib/common/base-model.ts
Executable file
@@ -0,0 +1,65 @@
|
||||
import { CreateType, Kind, SchemaOptions, Static, TEnum, TLiteral, TObject, TSchema, TUnion, Type } from '@sinclair/typebox'
|
||||
|
||||
export type BaseModel<T> = {
|
||||
id: T
|
||||
created: string
|
||||
updated: string
|
||||
}
|
||||
|
||||
export const BaseModelSchema = {
|
||||
id: Type.String(),
|
||||
created: Type.String(),
|
||||
updated: Type.String(),
|
||||
}
|
||||
|
||||
// Used to generate valid nullable in OpenAPI Schema
|
||||
export const Nullable = <T extends TSchema>(schema: T) => Type.Optional(Type.Unsafe<Static<T> | null>({
|
||||
...schema, nullable: true,
|
||||
}))
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export function NullableEnum<T extends TEnum<any>>(schema: T) {
|
||||
const values = schema.anyOf.map(f => f.const)
|
||||
return Type.Optional(Type.Unsafe<Static<T> | null>({ type: 'string', enum: values, nullable: true }))
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// TDiscriminatedUnionObject
|
||||
//
|
||||
// Constructs a base TObject type requiring 1 discriminator property
|
||||
// ------------------------------------------------------------------
|
||||
// prettier-ignore
|
||||
type TDiscriminatedUnionProperties<Discriminator extends string> = {
|
||||
[_ in Discriminator]: TLiteral
|
||||
}
|
||||
// prettier-ignore
|
||||
type TDiscriminatedUnionObject<Discriminator extends string> = TObject<TDiscriminatedUnionProperties<Discriminator>>
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// DiscriminatedUnion
|
||||
// ------------------------------------------------------------------
|
||||
export type TDiscriminatedUnion<Types extends TObject[] = TObject[]> = {
|
||||
[Kind]: 'DiscriminatedUnion'
|
||||
static: Static<TUnion<Types>>
|
||||
anyOf: Types
|
||||
discriminator: {
|
||||
propertyName: string
|
||||
mapping?: Record<string, string>
|
||||
}
|
||||
} & TSchema
|
||||
|
||||
/** Creates a DiscriminatedUnion that works with OpenAPI. */
|
||||
export function DiscriminatedUnion<Discriminator extends string, Types extends TDiscriminatedUnionObject<Discriminator>[]>(
|
||||
discriminator: Discriminator,
|
||||
types: [...Types],
|
||||
options?: SchemaOptions,
|
||||
): TDiscriminatedUnion<Types> {
|
||||
return CreateType({
|
||||
[Kind]: 'DiscriminatedUnion',
|
||||
anyOf: types,
|
||||
discriminator: {
|
||||
propertyName: discriminator,
|
||||
},
|
||||
}, options) as never
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
|
||||
export const ColorHex = Type.String({
|
||||
pattern: '^#[0-9A-Fa-f]{6}$',
|
||||
})
|
||||
export type ColorHex = Static<typeof ColorHex>
|
||||
15
activepieces-fork/packages/shared/src/lib/common/id-generator.ts
Executable file
15
activepieces-fork/packages/shared/src/lib/common/id-generator.ts
Executable file
@@ -0,0 +1,15 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { customAlphabet } from 'nanoid'
|
||||
|
||||
const ALPHABET = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
|
||||
const ID_LENGTH = 21
|
||||
|
||||
export const ApId = Type.String({
|
||||
pattern: `^[0-9a-zA-Z]{${ID_LENGTH}}$`,
|
||||
})
|
||||
|
||||
export type ApId = Static<typeof ApId>
|
||||
|
||||
export const apId = customAlphabet(ALPHABET, ID_LENGTH)
|
||||
|
||||
export const secureApId = (length: number) => customAlphabet(ALPHABET, length)()
|
||||
@@ -0,0 +1,8 @@
|
||||
export * from './utils'
|
||||
export * from './base-model'
|
||||
export * from './locale'
|
||||
export * from './security'
|
||||
export * from './multipart-file'
|
||||
export * from './metadata'
|
||||
export * from './try-catch'
|
||||
export * from './color'
|
||||
12
activepieces-fork/packages/shared/src/lib/common/locale.ts
Normal file
12
activepieces-fork/packages/shared/src/lib/common/locale.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
export enum LocalesEnum {
|
||||
DUTCH = 'nl',
|
||||
ENGLISH = 'en',
|
||||
GERMAN = 'de',
|
||||
FRENCH = 'fr',
|
||||
SPANISH = 'es',
|
||||
JAPANESE = 'ja',
|
||||
CHINESE_SIMPLIFIED = 'zh',
|
||||
PORTUGUESE = 'pt',
|
||||
ARABIC = 'ar',
|
||||
CHINESE_TRADITIONAL = 'zh-TW',
|
||||
}
|
||||
22
activepieces-fork/packages/shared/src/lib/common/metadata.ts
Normal file
22
activepieces-fork/packages/shared/src/lib/common/metadata.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
|
||||
/**
|
||||
* Flexible key-value record type for storing arbitrary data
|
||||
*
|
||||
* The Metadata type provides a flexible way to store additional information
|
||||
* on various entities without requiring schema changes. It can be used for:
|
||||
* - Custom categorization
|
||||
* - Integration with external systems
|
||||
* - Environment-specific configurations
|
||||
* - Analytics and tracking information
|
||||
*
|
||||
* @example
|
||||
* // Example metadata for a project
|
||||
* const metadata = {
|
||||
* department: "marketing",
|
||||
* priority: 1,
|
||||
* customField: "customValue"
|
||||
* }
|
||||
*/
|
||||
export const Metadata = Type.Record(Type.String(), Type.Unknown())
|
||||
export type Metadata = Static<typeof Metadata>
|
||||
@@ -0,0 +1,17 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
|
||||
|
||||
export const ApMultipartFile = Type.Object({
|
||||
filename: Type.String(),
|
||||
data: Type.Unknown(),
|
||||
type: Type.Literal('file'),
|
||||
mimetype: Type.Optional(Type.String()),
|
||||
})
|
||||
|
||||
export type ApMultipartFile = Static<typeof ApMultipartFile> & {
|
||||
data: Buffer
|
||||
}
|
||||
|
||||
export const isMultipartFile = (value: unknown): value is ApMultipartFile => {
|
||||
return typeof value === 'object' && value !== null && 'type' in value && value.type === 'file' && 'filename' in value && 'data' in value && value.data instanceof Buffer
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './permission'
|
||||
export const SAFE_STRING_PATTERN = '^[^./]+$'
|
||||
@@ -0,0 +1,33 @@
|
||||
// Check access-control-list.ts for the list of permissions, you can add new permissions there, restart the main server to apply the changes
|
||||
export enum Permission {
|
||||
READ_APP_CONNECTION = 'READ_APP_CONNECTION',
|
||||
WRITE_APP_CONNECTION = 'WRITE_APP_CONNECTION',
|
||||
READ_FLOW = 'READ_FLOW',
|
||||
WRITE_FLOW = 'WRITE_FLOW',
|
||||
UPDATE_FLOW_STATUS = 'UPDATE_FLOW_STATUS',
|
||||
WRITE_INVITATION = 'WRITE_INVITATION',
|
||||
READ_INVITATION = 'READ_INVITATION',
|
||||
READ_PROJECT_MEMBER = 'READ_PROJECT_MEMBER',
|
||||
WRITE_PROJECT_MEMBER = 'WRITE_PROJECT_MEMBER',
|
||||
WRITE_PROJECT_RELEASE = 'WRITE_PROJECT_RELEASE',
|
||||
READ_PROJECT_RELEASE = 'READ_PROJECT_RELEASE',
|
||||
READ_RUN = 'READ_RUN',
|
||||
WRITE_RUN = 'WRITE_RUN',
|
||||
READ_FOLDER = 'READ_FOLDER',
|
||||
WRITE_FOLDER = 'WRITE_FOLDER',
|
||||
WRITE_ALERT = 'WRITE_ALERT',
|
||||
READ_ALERT = 'READ_ALERT',
|
||||
READ_MCP = 'READ_MCP',
|
||||
WRITE_MCP = 'WRITE_MCP',
|
||||
WRITE_PROJECT = 'WRITE_PROJECT',
|
||||
READ_PROJECT = 'READ_PROJECT',
|
||||
READ_TODOS = 'READ_TODOS',
|
||||
WRITE_TODOS = 'WRITE_TODOS',
|
||||
READ_TABLE = 'READ_TABLE',
|
||||
WRITE_TABLE = 'WRITE_TABLE',
|
||||
}
|
||||
|
||||
export enum RoleType {
|
||||
DEFAULT = 'DEFAULT',
|
||||
CUSTOM = 'CUSTOM',
|
||||
}
|
||||
16
activepieces-fork/packages/shared/src/lib/common/seek-page.ts
Executable file
16
activepieces-fork/packages/shared/src/lib/common/seek-page.ts
Executable file
@@ -0,0 +1,16 @@
|
||||
import { TSchema, Type } from '@sinclair/typebox'
|
||||
import { Nullable } from './base-model'
|
||||
|
||||
export type Cursor = string | null
|
||||
|
||||
export type SeekPage<T> = {
|
||||
next: Cursor
|
||||
previous: Cursor
|
||||
data: T[]
|
||||
}
|
||||
|
||||
export const SeekPage = (t: TSchema): TSchema => Type.Object({
|
||||
data: Type.Array(t),
|
||||
next: Nullable(Type.String({ description: 'Cursor to the next page' })),
|
||||
previous: Nullable(Type.String({ description: 'Cursor to the previous page' })),
|
||||
})
|
||||
253
activepieces-fork/packages/shared/src/lib/common/telemetry.ts
Normal file
253
activepieces-fork/packages/shared/src/lib/common/telemetry.ts
Normal file
@@ -0,0 +1,253 @@
|
||||
import { RunEnvironment } from '../flow-run/flow-run'
|
||||
import { FlowId } from '../flows/flow'
|
||||
import { McpId } from '../mcp/mcp'
|
||||
import { ProjectId } from '../project/project'
|
||||
import { UserId } from '../user/user'
|
||||
|
||||
type FlowCreated = {
|
||||
flowId: FlowId
|
||||
}
|
||||
type PiecesSearch = {
|
||||
target: 'steps' | 'triggers'
|
||||
search: string
|
||||
}
|
||||
|
||||
type TemplateSearch = {
|
||||
search: string
|
||||
tags: string[]
|
||||
pieces: string[]
|
||||
}
|
||||
|
||||
type RunCreated = {
|
||||
projectId: ProjectId
|
||||
flowId: FlowId
|
||||
environment: RunEnvironment
|
||||
count: number
|
||||
}
|
||||
|
||||
type FlowPublished = {
|
||||
flowId: FlowId
|
||||
}
|
||||
|
||||
type SignedUp = {
|
||||
userId: UserId
|
||||
email: string
|
||||
firstName: string
|
||||
lastName: string
|
||||
projectId: ProjectId
|
||||
}
|
||||
|
||||
type QuotaAlert = {
|
||||
percentageUsed: number
|
||||
}
|
||||
type FlowImported = {
|
||||
id: string
|
||||
name: string
|
||||
location:
|
||||
| 'import flow view'
|
||||
| 'inside the builder'
|
||||
| 'import flow by uri encoded query param'
|
||||
tab?: string
|
||||
}
|
||||
type FlowImportedUsingFile = {
|
||||
location: 'inside dashboard' | 'inside the builder'
|
||||
multiple: boolean
|
||||
}
|
||||
|
||||
type FlowIssueClicked = {
|
||||
flowId: string
|
||||
}
|
||||
|
||||
type FlowIssueResolved = {
|
||||
flowId: string
|
||||
}
|
||||
|
||||
type RequestTrialSubmitted = {
|
||||
fullName: string
|
||||
email: string
|
||||
numberOfEmployees: string
|
||||
companyName: string
|
||||
goal: string
|
||||
}
|
||||
|
||||
type RequestTrialClicked = {
|
||||
location: string
|
||||
}
|
||||
|
||||
type KeyActivated = {
|
||||
date: string
|
||||
key: string
|
||||
}
|
||||
|
||||
type UpgradeClicked = {
|
||||
limitType?: 'team'
|
||||
}
|
||||
|
||||
type UpgradePopup = {
|
||||
limitType?: 'team'
|
||||
}
|
||||
|
||||
type ReferralLinkCopied = {
|
||||
userId: UserId
|
||||
}
|
||||
|
||||
type RewardButtonClicked = {
|
||||
source: 'note' | 'rewards-button'
|
||||
}
|
||||
|
||||
type RewardInstructionsClicked = {
|
||||
type: 'share-template' | 'linkedin' | 'referral' | 'contribute-piece'
|
||||
}
|
||||
|
||||
type Referral = {
|
||||
referredUserId: UserId
|
||||
}
|
||||
|
||||
type FlowShared = {
|
||||
flowId: FlowId
|
||||
projectId: ProjectId
|
||||
}
|
||||
|
||||
type OpenedFromDashboard = {
|
||||
location: 'sidenav' | 'tasks-progress'
|
||||
}
|
||||
|
||||
type FormsViewed = {
|
||||
flowId: string
|
||||
projectId: string
|
||||
formProps: Record<string, unknown>
|
||||
}
|
||||
|
||||
type UserInvited = {
|
||||
platformId: string
|
||||
projectId?: string
|
||||
email: string
|
||||
}
|
||||
|
||||
type TriggerFailuresExceeded = {
|
||||
projectId: string
|
||||
flowId: string
|
||||
pieceName: string
|
||||
pieceVersion: string
|
||||
}
|
||||
type AiProviderConfiguredOrUsed = {
|
||||
provider: string
|
||||
projectId: string
|
||||
platformId: string
|
||||
}
|
||||
|
||||
type McpToolCalled = {
|
||||
mcpId: McpId
|
||||
toolName: string
|
||||
}
|
||||
|
||||
type PieceSelectorSearch = {
|
||||
search: string
|
||||
isTrigger: boolean
|
||||
selectedActionOrTriggerName: string | null
|
||||
}
|
||||
export enum TelemetryEventName {
|
||||
SIGNED_UP = 'signed.up',
|
||||
QUOTA_ALERT = 'quota.alert',
|
||||
REQUEST_TRIAL_CLICKED = 'request.trial.clicked',
|
||||
REQUEST_TRIAL_SUBMITTED = 'request.trial.submitted',
|
||||
KEY_ACTIVATED = 'key.activated',
|
||||
FLOW_ISSUE_CLICKED = 'flow.issue.clicked',
|
||||
FLOW_ISSUE_RESOLVED = 'flow.issue.resolved',
|
||||
USER_INVITED = 'user.invited',
|
||||
UPGRADE_POPUP = 'upgrade.popup',
|
||||
CREATED_FLOW = 'flow.created',
|
||||
DEMO_IMPORTED = 'demo.imported',
|
||||
FLOW_RUN_CREATED = 'run.created',
|
||||
FLOW_PUBLISHED = 'flow.published',
|
||||
/**used with templates dialog + import flow component + flows imported by uri query param*/
|
||||
FLOW_IMPORTED = 'flow.imported',
|
||||
/**used only with import flow dialog*/
|
||||
FLOW_IMPORTED_USING_FILE = 'flow.imported.using.file',
|
||||
PIECES_SEARCH = 'pieces.search',
|
||||
REFERRAL = 'referral',
|
||||
REFERRAL_LINK_COPIED = 'referral.link.copied',
|
||||
FLOW_SHARED = 'flow.shared',
|
||||
TEMPLATE_SEARCH = 'template.search',
|
||||
FORMS_VIEWED = 'forms.viewed',
|
||||
FORMS_SUBMITTED = 'forms.submitted',
|
||||
REWARDS_OPENED = 'rewards.opened',
|
||||
REWARDS_INSTRUCTION_CLICKED = 'rewards.instructions.clicked',
|
||||
TRIGGER_FAILURES_EXCEEDED = 'trigger.failures.exceeded',
|
||||
AI_PROVIDER_USED = 'ai.provider.used',
|
||||
AI_PROVIDER_CONFIGURED = 'ai.provider.configured',
|
||||
MCP_TOOL_CALLED = 'mcp.tool.called',
|
||||
|
||||
UPGRADE_POPUP_OPENED = 'upgrade.popup.opened',
|
||||
UPGRADE_CLICKED = 'upgrade.clicked',
|
||||
OPENED_PRICING_FROM_DASHBOARD = 'opened.pricing.from.dashboard',
|
||||
PIECE_SELECTOR_SEARCH = 'piece.selector.search',
|
||||
}
|
||||
|
||||
type BaseTelemetryEvent<T, P> = {
|
||||
name: T
|
||||
payload: P
|
||||
}
|
||||
|
||||
export type TelemetryEvent =
|
||||
| BaseTelemetryEvent<TelemetryEventName.SIGNED_UP, SignedUp>
|
||||
| BaseTelemetryEvent<TelemetryEventName.REFERRAL, Referral>
|
||||
| BaseTelemetryEvent<
|
||||
TelemetryEventName.REQUEST_TRIAL_CLICKED,
|
||||
RequestTrialClicked
|
||||
>
|
||||
| BaseTelemetryEvent<TelemetryEventName.KEY_ACTIVATED, KeyActivated>
|
||||
| BaseTelemetryEvent<
|
||||
TelemetryEventName.REQUEST_TRIAL_SUBMITTED,
|
||||
RequestTrialSubmitted
|
||||
>
|
||||
| BaseTelemetryEvent<TelemetryEventName.FLOW_ISSUE_CLICKED, FlowIssueClicked>
|
||||
| BaseTelemetryEvent<
|
||||
TelemetryEventName.FLOW_ISSUE_RESOLVED,
|
||||
FlowIssueResolved
|
||||
>
|
||||
| BaseTelemetryEvent<TelemetryEventName.UPGRADE_CLICKED, UpgradeClicked>
|
||||
| BaseTelemetryEvent<TelemetryEventName.UPGRADE_POPUP, UpgradePopup>
|
||||
| BaseTelemetryEvent<TelemetryEventName.FLOW_RUN_CREATED, RunCreated>
|
||||
| BaseTelemetryEvent<TelemetryEventName.FLOW_PUBLISHED, FlowPublished>
|
||||
| BaseTelemetryEvent<TelemetryEventName.QUOTA_ALERT, QuotaAlert>
|
||||
| BaseTelemetryEvent<TelemetryEventName.CREATED_FLOW, FlowCreated>
|
||||
| BaseTelemetryEvent<TelemetryEventName.TEMPLATE_SEARCH, TemplateSearch>
|
||||
| BaseTelemetryEvent<TelemetryEventName.PIECES_SEARCH, PiecesSearch>
|
||||
| BaseTelemetryEvent<TelemetryEventName.FLOW_IMPORTED, FlowImported>
|
||||
| BaseTelemetryEvent<
|
||||
TelemetryEventName.FLOW_IMPORTED_USING_FILE,
|
||||
FlowImportedUsingFile
|
||||
>
|
||||
| BaseTelemetryEvent<
|
||||
TelemetryEventName.REFERRAL_LINK_COPIED,
|
||||
ReferralLinkCopied
|
||||
>
|
||||
| BaseTelemetryEvent<TelemetryEventName.FLOW_SHARED, FlowShared>
|
||||
| BaseTelemetryEvent<TelemetryEventName.DEMO_IMPORTED, Record<string, never>>
|
||||
| BaseTelemetryEvent<
|
||||
TelemetryEventName.OPENED_PRICING_FROM_DASHBOARD,
|
||||
OpenedFromDashboard
|
||||
>
|
||||
| BaseTelemetryEvent<TelemetryEventName.FORMS_VIEWED, FormsViewed>
|
||||
| BaseTelemetryEvent<TelemetryEventName.USER_INVITED, UserInvited>
|
||||
| BaseTelemetryEvent<TelemetryEventName.FORMS_SUBMITTED, FormsViewed>
|
||||
| BaseTelemetryEvent<TelemetryEventName.REWARDS_OPENED, RewardButtonClicked>
|
||||
| BaseTelemetryEvent<
|
||||
TelemetryEventName.REWARDS_INSTRUCTION_CLICKED,
|
||||
RewardInstructionsClicked
|
||||
>
|
||||
| BaseTelemetryEvent<
|
||||
TelemetryEventName.TRIGGER_FAILURES_EXCEEDED,
|
||||
TriggerFailuresExceeded
|
||||
>
|
||||
| BaseTelemetryEvent<
|
||||
TelemetryEventName.AI_PROVIDER_USED,
|
||||
AiProviderConfiguredOrUsed
|
||||
>
|
||||
| BaseTelemetryEvent<
|
||||
TelemetryEventName.AI_PROVIDER_CONFIGURED,
|
||||
AiProviderConfiguredOrUsed
|
||||
>
|
||||
| BaseTelemetryEvent<TelemetryEventName.MCP_TOOL_CALLED, McpToolCalled>
|
||||
| BaseTelemetryEvent<TelemetryEventName.PIECE_SELECTOR_SEARCH, PieceSelectorSearch>
|
||||
@@ -0,0 +1,37 @@
|
||||
// Types for the result object with discriminated union
|
||||
type Success<T> = {
|
||||
data: T
|
||||
error: null
|
||||
}
|
||||
|
||||
type Failure<E> = {
|
||||
data: null
|
||||
error: E
|
||||
}
|
||||
|
||||
export type Result<T, E = Error> = Success<T> | Failure<E>
|
||||
|
||||
// Main wrapper function
|
||||
export async function tryCatch<T, E = Error>(
|
||||
fn: () => Promise<T>,
|
||||
): Promise<Result<T, E>> {
|
||||
try {
|
||||
const data = await fn()
|
||||
return { data, error: null }
|
||||
}
|
||||
catch (error) {
|
||||
return { data: null, error: error as E }
|
||||
}
|
||||
}
|
||||
|
||||
export function tryCatchSync<T, E = Error>(
|
||||
fn: () => T,
|
||||
): Result<T, E> {
|
||||
try {
|
||||
const data = fn()
|
||||
return { data, error: null }
|
||||
}
|
||||
catch (error) {
|
||||
return { data: null, error: error as E }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
export function assertEqual<T>(
|
||||
actual: T,
|
||||
expected: T,
|
||||
fieldName1: string,
|
||||
fieldName2: string,
|
||||
|
||||
): asserts actual is T {
|
||||
if (actual !== expected) {
|
||||
throw new Error(`${fieldName1} and ${fieldName2} should be equal`)
|
||||
}
|
||||
}
|
||||
|
||||
export function assertNotNullOrUndefined<T>(
|
||||
value: T | null | undefined,
|
||||
fieldName: string,
|
||||
): asserts value is T {
|
||||
if (value === null || value === undefined) {
|
||||
throw new Error(`${fieldName} is null or undefined`)
|
||||
}
|
||||
}
|
||||
|
||||
export function assertNotEqual<T>(
|
||||
value1: T,
|
||||
value2: T,
|
||||
fieldName1: string,
|
||||
fieldName2: string,
|
||||
): void {
|
||||
if (value1 === value2) {
|
||||
throw new Error(`${fieldName1} and ${fieldName2} should not be equal`)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const isNotUndefined = <T>(value: T | undefined): value is T => {
|
||||
return value !== undefined
|
||||
}
|
||||
|
||||
export function assertNull<T>(
|
||||
value: T | null,
|
||||
fieldName: string,
|
||||
): asserts value is T {
|
||||
if (value !== null) {
|
||||
throw new Error(`${fieldName} should be null`)
|
||||
}
|
||||
}
|
||||
|
||||
export function asserNotEmpty<T>(
|
||||
value: T[] | null | undefined,
|
||||
fieldName: string,
|
||||
): asserts value is T[] {
|
||||
assertNotNullOrUndefined(value, fieldName)
|
||||
if (value.length === 0) {
|
||||
throw new Error(`${fieldName} should be not empty`)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from './object-utils'
|
||||
export * from './utils'
|
||||
export * from './assertions'
|
||||
@@ -0,0 +1,125 @@
|
||||
import { isNil, isString } from './utils'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||
export function deleteProperties(obj: Record<string, unknown>, props: string[]) {
|
||||
const copy = { ...obj }
|
||||
for (const prop of props) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
delete copy[prop]
|
||||
}
|
||||
return copy
|
||||
}
|
||||
|
||||
export function omit<T extends object, K extends keyof T>(obj: T, keysToOmit: K[]): Omit<T, K> {
|
||||
return Object.fromEntries(
|
||||
Object.entries(obj).filter(([key]) => !keysToOmit.includes(key as K)),
|
||||
) as Omit<T, K>
|
||||
}
|
||||
|
||||
|
||||
export const spreadIfNotUndefined = <T>(key: string, value: T | undefined): Record<string, T> => {
|
||||
if (value === undefined) {
|
||||
return {}
|
||||
}
|
||||
return {
|
||||
[key]: value,
|
||||
}
|
||||
}
|
||||
|
||||
export const spreadIfDefined = <T>(key: string, value: T | undefined | null): Record<string, T> => {
|
||||
if (isNil(value)) {
|
||||
return {}
|
||||
}
|
||||
return {
|
||||
[key]: value,
|
||||
}
|
||||
}
|
||||
|
||||
export function deleteProps<T extends Record<string, unknown>, K extends keyof T>(
|
||||
obj: T,
|
||||
prop: K[],
|
||||
): Omit<T, K> {
|
||||
const newObj = { ...obj }
|
||||
for (const p of prop) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
delete newObj[p]
|
||||
}
|
||||
return newObj
|
||||
}
|
||||
|
||||
export function sanitizeObjectForPostgresql<T>(input: T): T {
|
||||
return applyFunctionToValuesSync<T>(input, (str) => {
|
||||
if (isString(str)) {
|
||||
// eslint-disable-next-line no-control-regex
|
||||
const controlCharsRegex = /\u0000/g
|
||||
return str.replace(controlCharsRegex, '')
|
||||
}
|
||||
return str
|
||||
})
|
||||
}
|
||||
export function applyFunctionToValuesSync<T>(obj: unknown, apply: (str: string) => unknown): T {
|
||||
if (isNil(obj)) {
|
||||
return obj as T
|
||||
}
|
||||
else if (isString(obj)) {
|
||||
return apply(obj) as T
|
||||
}
|
||||
else if (Array.isArray(obj)) {
|
||||
return obj.map(item => applyFunctionToValuesSync(item, apply)) as unknown as T
|
||||
}
|
||||
else if (isObject(obj)) {
|
||||
return Object.fromEntries(
|
||||
Object.entries(obj).map(([key, value]) => [key, applyFunctionToValuesSync(value, apply)]),
|
||||
) as T
|
||||
}
|
||||
return obj as T
|
||||
}
|
||||
|
||||
export async function applyFunctionToValues<T>(obj: unknown, apply: (str: string) => Promise<unknown>): Promise<T> {
|
||||
if (isNil(obj)) {
|
||||
return obj as T
|
||||
}
|
||||
else if (isString(obj)) {
|
||||
return (await apply(obj)) as T
|
||||
}
|
||||
else if (Array.isArray(obj)) {
|
||||
// Create a new array and map over it with Promise.all
|
||||
const newArray = await Promise.all(obj.map(item => applyFunctionToValues(item, apply)))
|
||||
return newArray as unknown as T
|
||||
}
|
||||
else if (isObject(obj)) {
|
||||
// Use Object.fromEntries and map entries asynchronously
|
||||
const newEntries = await Promise.all(
|
||||
Object.entries(obj).map(async ([key, value]) => [key, await applyFunctionToValues(value, apply)]),
|
||||
)
|
||||
return Object.fromEntries(newEntries) as T
|
||||
}
|
||||
return obj as T
|
||||
}
|
||||
|
||||
|
||||
export const isObject = (obj: unknown): obj is Record<string, unknown> => {
|
||||
return typeof obj === 'object' && obj !== null && !Array.isArray(obj)
|
||||
}
|
||||
|
||||
export type MakeKeyNonNullableAndRequired<T extends object, K extends keyof T> = T & { [P in K]-?: NonNullable<T[P]> }
|
||||
|
||||
export function groupBy<T, K extends string | number | symbol>(
|
||||
items: T[],
|
||||
keySelector: (item: T) => K,
|
||||
): Record<K, T[]> {
|
||||
const result = {} as Record<K, T[]>
|
||||
|
||||
for (const item of items) {
|
||||
const key = keySelector(item)
|
||||
|
||||
if (!result[key]) {
|
||||
result[key] = []
|
||||
}
|
||||
|
||||
result[key].push(item)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
147
activepieces-fork/packages/shared/src/lib/common/utils/utils.ts
Normal file
147
activepieces-fork/packages/shared/src/lib/common/utils/utils.ts
Normal file
@@ -0,0 +1,147 @@
|
||||
import { deepmerge } from 'deepmerge-ts'
|
||||
|
||||
export function isString(str: unknown): str is string {
|
||||
return str != null && typeof str === 'string'
|
||||
}
|
||||
|
||||
export function isNil<T>(value: T | null | undefined): value is null | undefined {
|
||||
return value === null || value === undefined
|
||||
}
|
||||
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export function setAtPath<T, K extends keyof any>(obj: T, path: K | K[], value: any): void {
|
||||
const pathArray = Array.isArray(path) ? path : (path as string).match(/([^[.\]])+/g) as unknown as K[]
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
pathArray.reduce((acc: any, key: K, i: number) => {
|
||||
if (acc[key] === undefined) acc[key] = {}
|
||||
if (i === pathArray.length - 1) acc[key] = value
|
||||
return acc[key]
|
||||
}, obj)
|
||||
}
|
||||
|
||||
|
||||
export function insertAt<T>(array: T[], index: number, item: T): T[] {
|
||||
return [...array.slice(0, index), item, ...array.slice(index)]
|
||||
}
|
||||
|
||||
export function debounce<T>(func: (...args: T[]) => void, wait: number): (key?: string, ...args: T[]) => void {
|
||||
let timeout: NodeJS.Timeout
|
||||
let currentKey: string | undefined
|
||||
return function (key?: string, ...args: T[]) {
|
||||
const later = () => {
|
||||
func(...args)
|
||||
}
|
||||
if (currentKey === key) {
|
||||
clearTimeout(timeout)
|
||||
}
|
||||
currentKey = key
|
||||
timeout = setTimeout(later, wait)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
type DeepPartial<T> = {
|
||||
[P in keyof T]?: T[P] extends Record<string, unknown> ? DeepPartial<T[P]> : T[P];
|
||||
}
|
||||
|
||||
/**
|
||||
* This function also merges arrays, x = [1, 2], y = [3, 4], z = deepMergeAndCast(x, y) -> [1, 2, 3, 4]
|
||||
**/
|
||||
export function deepMergeAndCast<T>(target: DeepPartial<T>, source: DeepPartial<T>): T {
|
||||
return deepmerge(target as Partial<T>, source as Partial<T>) as T
|
||||
}
|
||||
|
||||
|
||||
export function kebabCase(str: string): string {
|
||||
return str
|
||||
.replace(/([a-z])([A-Z])/g, '$1-$2') // Handle camelCase by adding hyphen between lowercase and uppercase letters
|
||||
.replace(/\s+/g, '-') // Replace spaces with hyphens
|
||||
.replace(/_/g, '-') // Replace underscores with hyphens
|
||||
.toLowerCase() // Convert to lowercase
|
||||
.replace(/^-+|-+$/g, '') // Remove leading and trailing hyphens
|
||||
}
|
||||
|
||||
|
||||
export function isEmpty<T>(value: T | null | undefined): boolean {
|
||||
if (value == null) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (typeof value === 'string' || Array.isArray(value)) {
|
||||
return value.length === 0
|
||||
}
|
||||
|
||||
if (typeof value === 'object') {
|
||||
return Object.keys(value).length === 0
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
export function startCase(str: string): string {
|
||||
return str
|
||||
.replace(/([a-z])([A-Z])/g, '$1 $2')
|
||||
.replace(/[_-]+/g, ' ')
|
||||
.replace(/\s+/g, ' ')
|
||||
.replace(/^[a-z]/, match => match.toUpperCase())
|
||||
.replace(/\b[a-z]/g, match => match.toUpperCase())
|
||||
}
|
||||
|
||||
export function camelCase(str: string): string {
|
||||
return str
|
||||
.replace(/([-_][a-z])/g, group => group.toUpperCase()
|
||||
.replace('-', '')
|
||||
.replace('_', ''))
|
||||
}
|
||||
|
||||
export function parseToJsonIfPossible(str: unknown): unknown {
|
||||
try {
|
||||
return JSON.parse(str as string)
|
||||
}
|
||||
catch (e) {
|
||||
return str
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
export function pickBy<T extends Record<string, unknown>>(
|
||||
object: T,
|
||||
predicate: (value: T[keyof T], key: keyof T) => boolean,
|
||||
): Partial<T> {
|
||||
return Object.keys(object).reduce((result: Partial<T>, key: keyof T) => {
|
||||
if (predicate(object[key], key)) {
|
||||
result[key] = object[key]
|
||||
}
|
||||
return result
|
||||
}, {})
|
||||
}
|
||||
|
||||
|
||||
export function chunk<T>(records: T[], size: number) {
|
||||
const chunks: T[][] = []
|
||||
for (let i = 0; i < records.length; i += size) {
|
||||
chunks.push(records.slice(i, i + size))
|
||||
}
|
||||
return chunks
|
||||
}
|
||||
|
||||
export function partition<T>(array: T[], predicate: (item: T, index: number, arr: T[]) => boolean): [T[], T[]] {
|
||||
const truthy: T[] = []
|
||||
const falsy: T[] = []
|
||||
array.forEach((item, idx) => {
|
||||
if (predicate(item, idx, array)) {
|
||||
truthy.push(item)
|
||||
}
|
||||
else {
|
||||
falsy.push(item)
|
||||
}
|
||||
})
|
||||
return [truthy, falsy]
|
||||
}
|
||||
|
||||
export function unique<T>(array: T[]): T[] {
|
||||
return array.filter((item, index, self) => index === self.findIndex(other => JSON.stringify(other) === JSON.stringify(item)))
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { FlowVersionState } from '../flows/flow-version'
|
||||
|
||||
export const DEFAULT_MCP_DATA = {
|
||||
flowId: 'mcp-flow-id',
|
||||
flowVersionId: 'mcp-flow-version-id',
|
||||
flowVersionState: FlowVersionState.LOCKED,
|
||||
flowRunId: 'mcp-flow-run-id',
|
||||
triggerPieceName: 'mcp-trigger-piece-name',
|
||||
}
|
||||
|
||||
export const ERROR_MESSAGES_TO_REDACT = [
|
||||
'HttpClient#sendRequest',
|
||||
]
|
||||
@@ -0,0 +1,255 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { ExecutionToolStatus } from '../agents'
|
||||
import { AppConnectionValue } from '../app-connection/app-connection'
|
||||
import { ExecutionState, ExecutionType, ResumePayload } from '../flow-run/execution/execution-output'
|
||||
import { FlowRunId, RunEnvironment } from '../flow-run/flow-run'
|
||||
import { FlowVersion } from '../flows/flow-version'
|
||||
import { PiecePackage } from '../pieces'
|
||||
import { PlatformId } from '../platform'
|
||||
import { ProjectId } from '../project/project'
|
||||
import { ScheduleOptions } from '../trigger'
|
||||
|
||||
export enum EngineOperationType {
|
||||
EXTRACT_PIECE_METADATA = 'EXTRACT_PIECE_METADATA',
|
||||
EXECUTE_FLOW = 'EXECUTE_FLOW',
|
||||
EXECUTE_PROPERTY = 'EXECUTE_PROPERTY',
|
||||
EXECUTE_TRIGGER_HOOK = 'EXECUTE_TRIGGER_HOOK',
|
||||
EXECUTE_VALIDATE_AUTH = 'EXECUTE_VALIDATE_AUTH',
|
||||
}
|
||||
|
||||
export enum TriggerHookType {
|
||||
ON_ENABLE = 'ON_ENABLE',
|
||||
ON_DISABLE = 'ON_DISABLE',
|
||||
HANDSHAKE = 'HANDSHAKE',
|
||||
RENEW = 'RENEW',
|
||||
RUN = 'RUN',
|
||||
TEST = 'TEST',
|
||||
}
|
||||
|
||||
export type EngineOperation =
|
||||
| ExecuteToolOperation
|
||||
| ExecuteFlowOperation
|
||||
| ExecutePropsOptions
|
||||
| ExecuteTriggerOperation<TriggerHookType>
|
||||
| ExecuteExtractPieceMetadataOperation
|
||||
| ExecuteValidateAuthOperation
|
||||
|
||||
export const enum EngineSocketEvent {
|
||||
ENGINE_RESPONSE = 'engine-response',
|
||||
ENGINE_STDOUT = 'engine-stdout',
|
||||
ENGINE_STDERR = 'engine-stderr',
|
||||
ENGINE_READY = 'engine-ready',
|
||||
ENGINE_OPERATION = 'engine-operation',
|
||||
UPDATE_RUN_PROGRESS = 'update-run-progress',
|
||||
SEND_FLOW_RESPONSE = 'send-flow-response',
|
||||
UPDATE_STEP_PROGRESS = 'update-step-progress',
|
||||
}
|
||||
|
||||
|
||||
export const EngineStdout = Type.Object({
|
||||
message: Type.String(),
|
||||
})
|
||||
|
||||
export const EngineStderr = Type.Object({
|
||||
message: Type.String(),
|
||||
})
|
||||
|
||||
|
||||
export type EngineStdout = Static<typeof EngineStdout>
|
||||
export type EngineStderr = Static<typeof EngineStderr>
|
||||
|
||||
|
||||
export type BaseEngineOperation = {
|
||||
projectId: ProjectId
|
||||
engineToken: string
|
||||
internalApiUrl: string
|
||||
publicApiUrl: string
|
||||
timeoutInSeconds: number
|
||||
platformId: PlatformId
|
||||
}
|
||||
|
||||
export type ExecuteValidateAuthOperation = Omit<BaseEngineOperation, 'projectId'> & {
|
||||
piece: PiecePackage
|
||||
auth: AppConnectionValue
|
||||
}
|
||||
|
||||
export type ExecuteExtractPieceMetadata = PiecePackage & { platformId: PlatformId }
|
||||
|
||||
export type ExecuteExtractPieceMetadataOperation = ExecuteExtractPieceMetadata & { timeoutInSeconds: number, platformId: PlatformId }
|
||||
|
||||
export type ExecuteToolOperation = BaseEngineOperation & {
|
||||
actionName: string
|
||||
pieceName: string
|
||||
pieceVersion: string
|
||||
predefinedInput: Record<string, unknown>
|
||||
instruction: string
|
||||
}
|
||||
|
||||
export type ExecutePropsOptions = BaseEngineOperation & {
|
||||
piece: PiecePackage
|
||||
propertyName: string
|
||||
actionOrTriggerName: string
|
||||
flowVersion?: FlowVersion
|
||||
input: Record<string, unknown>
|
||||
sampleData: Record<string, unknown>
|
||||
searchValue?: string
|
||||
}
|
||||
|
||||
type BaseExecuteFlowOperation<T extends ExecutionType> = BaseEngineOperation & {
|
||||
flowVersion: FlowVersion
|
||||
flowRunId: FlowRunId
|
||||
executionType: T
|
||||
runEnvironment: RunEnvironment
|
||||
executionState: ExecutionState
|
||||
serverHandlerId: string | null
|
||||
httpRequestId: string | null
|
||||
progressUpdateType: ProgressUpdateType
|
||||
stepNameToTest: string | null
|
||||
sampleData?: Record<string, unknown>
|
||||
logsUploadUrl?: string
|
||||
logsFileId?: string
|
||||
}
|
||||
|
||||
export enum ProgressUpdateType {
|
||||
WEBHOOK_RESPONSE = 'WEBHOOK_RESPONSE',
|
||||
TEST_FLOW = 'TEST_FLOW',
|
||||
NONE = 'NONE',
|
||||
}
|
||||
|
||||
export type BeginExecuteFlowOperation = BaseExecuteFlowOperation<ExecutionType.BEGIN> & {
|
||||
triggerPayload: unknown
|
||||
executeTrigger: boolean
|
||||
}
|
||||
|
||||
export type ResumeExecuteFlowOperation = BaseExecuteFlowOperation<ExecutionType.RESUME> & {
|
||||
resumePayload: ResumePayload
|
||||
}
|
||||
|
||||
export type ExecuteFlowOperation = BeginExecuteFlowOperation | ResumeExecuteFlowOperation
|
||||
|
||||
|
||||
export type ExecuteTriggerOperation<HT extends TriggerHookType> = BaseEngineOperation & {
|
||||
hookType: HT
|
||||
test: boolean
|
||||
flowVersion: FlowVersion
|
||||
webhookUrl: string
|
||||
triggerPayload?: TriggerPayload
|
||||
appWebhookUrl?: string
|
||||
webhookSecret?: string | Record<string, string>
|
||||
}
|
||||
|
||||
|
||||
export const TriggerPayload = Type.Object({
|
||||
body: Type.Unknown(),
|
||||
rawBody: Type.Optional(Type.Unknown()),
|
||||
headers: Type.Record(Type.String(), Type.String()),
|
||||
queryParams: Type.Record(Type.String(), Type.String()),
|
||||
})
|
||||
|
||||
export type TriggerPayload<T = unknown> = {
|
||||
body: T
|
||||
rawBody?: unknown
|
||||
headers: Record<string, string>
|
||||
queryParams: Record<string, string>
|
||||
}
|
||||
|
||||
export type EventPayload<B = unknown> = {
|
||||
body: B
|
||||
rawBody?: unknown
|
||||
method: string
|
||||
headers: Record<string, string>
|
||||
queryParams: Record<string, string>
|
||||
}
|
||||
|
||||
export type ParseEventResponse = {
|
||||
event?: string
|
||||
identifierValue?: string
|
||||
reply?: {
|
||||
headers: Record<string, string>
|
||||
body: unknown
|
||||
}
|
||||
}
|
||||
|
||||
export type AppEventListener = {
|
||||
events: string[]
|
||||
identifierValue: string
|
||||
}
|
||||
|
||||
|
||||
type ExecuteTestOrRunTriggerResponse = {
|
||||
success: boolean
|
||||
message?: string
|
||||
output: unknown[]
|
||||
}
|
||||
|
||||
type ExecuteHandshakeTriggerResponse = {
|
||||
success: boolean
|
||||
message?: string
|
||||
response?: {
|
||||
status: number
|
||||
body?: unknown
|
||||
headers?: Record<string, string>
|
||||
}
|
||||
}
|
||||
|
||||
type ExecuteOnEnableTriggerResponse = {
|
||||
listeners: AppEventListener[]
|
||||
scheduleOptions?: ScheduleOptions
|
||||
}
|
||||
|
||||
export const EngineHttpResponse = Type.Object({
|
||||
status: Type.Number(),
|
||||
body: Type.Unknown(),
|
||||
headers: Type.Record(Type.String(), Type.String()),
|
||||
})
|
||||
|
||||
export type EngineHttpResponse = Static<typeof EngineHttpResponse>
|
||||
|
||||
export type ExecuteTriggerResponse<H extends TriggerHookType> = H extends TriggerHookType.RUN ? ExecuteTestOrRunTriggerResponse :
|
||||
H extends TriggerHookType.HANDSHAKE ? ExecuteHandshakeTriggerResponse :
|
||||
H extends TriggerHookType.TEST ? ExecuteTestOrRunTriggerResponse :
|
||||
H extends TriggerHookType.RENEW ? Record<string, never> :
|
||||
H extends TriggerHookType.ON_DISABLE ? Record<string, never> :
|
||||
ExecuteOnEnableTriggerResponse
|
||||
|
||||
export type ExecuteToolResponse = {
|
||||
status: ExecutionToolStatus
|
||||
output?: unknown
|
||||
resolvedInput: Record<string, unknown>
|
||||
errorMessage?: unknown
|
||||
}
|
||||
|
||||
export type ExecuteActionResponse = {
|
||||
success: boolean
|
||||
input: unknown
|
||||
output: unknown
|
||||
message?: string
|
||||
}
|
||||
|
||||
type BaseExecuteValidateAuthResponseOutput<Valid extends boolean> = {
|
||||
valid: Valid
|
||||
}
|
||||
|
||||
type ValidExecuteValidateAuthResponseOutput = BaseExecuteValidateAuthResponseOutput<true>
|
||||
|
||||
type InvalidExecuteValidateAuthResponseOutput = BaseExecuteValidateAuthResponseOutput<false> & {
|
||||
error: string
|
||||
}
|
||||
export type ExecuteValidateAuthResponse =
|
||||
| ValidExecuteValidateAuthResponseOutput
|
||||
| InvalidExecuteValidateAuthResponseOutput
|
||||
|
||||
|
||||
export type EngineResponse<T = unknown> = {
|
||||
status: EngineResponseStatus
|
||||
response: T
|
||||
delayInSeconds?: number
|
||||
error?: string
|
||||
}
|
||||
|
||||
export enum EngineResponseStatus {
|
||||
OK = 'OK',
|
||||
INTERNAL_ERROR = 'INTERNAL_ERROR',
|
||||
TIMEOUT = 'TIMEOUT',
|
||||
MEMORY_ISSUE = 'MEMORY_ISSUE',
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
import { STORE_KEY_MAX_LENGTH } from '../store-entry/store-entry'
|
||||
|
||||
export enum ExecutionErrorType {
|
||||
ENGINE = 'ENGINE',
|
||||
USER = 'USER',
|
||||
}
|
||||
export class ExecutionError extends Error {
|
||||
|
||||
public type: ExecutionErrorType
|
||||
|
||||
constructor(name: string, message: string, type: ExecutionErrorType, public cause?: unknown) {
|
||||
super(message)
|
||||
this.name = name
|
||||
this.type = type
|
||||
}
|
||||
}
|
||||
|
||||
function formatMessage(message: string) {
|
||||
return JSON.stringify({
|
||||
message,
|
||||
}, null, 2)
|
||||
}
|
||||
|
||||
|
||||
|
||||
export class ConnectionNotFoundError extends ExecutionError {
|
||||
constructor(connectionName: string, cause?: unknown) {
|
||||
super('ConnectionNotFound', formatMessage(`connection (${connectionName}) not found`), ExecutionErrorType.USER, cause)
|
||||
}
|
||||
}
|
||||
|
||||
export class ConnectionLoadingError extends ExecutionError {
|
||||
constructor(connectionName: string, cause?: unknown) {
|
||||
super('ConnectionLoadingFailure', formatMessage(`Failed to load connection (${connectionName})`), ExecutionErrorType.ENGINE, cause)
|
||||
}
|
||||
}
|
||||
|
||||
export class ConnectionExpiredError extends ExecutionError {
|
||||
constructor(connectionName: string, cause?: unknown) {
|
||||
super('ConnectionExpired', formatMessage(`connection (${connectionName}) expired, reconnect again`), ExecutionErrorType.USER, cause)
|
||||
}
|
||||
}
|
||||
|
||||
export class StorageLimitError extends ExecutionError {
|
||||
|
||||
public maxStorageSizeInBytes: number
|
||||
|
||||
constructor(key: string, maxStorageSizeInBytes: number, cause?: unknown) {
|
||||
super('StorageLimitError', formatMessage(`Failed to read/write key "${key}", the value you are trying to read/write is larger than ${Math.floor(maxStorageSizeInBytes / 1024)} KB`), ExecutionErrorType.USER, cause)
|
||||
this.maxStorageSizeInBytes = maxStorageSizeInBytes
|
||||
}
|
||||
}
|
||||
|
||||
export class StorageInvalidKeyError extends ExecutionError {
|
||||
constructor(key: string, cause?: unknown) {
|
||||
super('StorageInvalidKeyError', formatMessage(`Failed to read/write key "${key}", the key is empty or longer than ${STORE_KEY_MAX_LENGTH} characters`), ExecutionErrorType.USER, cause)
|
||||
}
|
||||
}
|
||||
|
||||
export class StorageError extends ExecutionError {
|
||||
constructor(key: string, cause?: unknown) {
|
||||
super('StorageError', formatMessage(`Failed to read/write key "${key}" due to ${JSON.stringify(cause)}`), ExecutionErrorType.ENGINE, cause)
|
||||
}
|
||||
}
|
||||
|
||||
export class FileStoreError extends ExecutionError {
|
||||
constructor(cause?: unknown) {
|
||||
super('FileStoreError', formatMessage(`Failed to store file due to ${JSON.stringify(cause)}`), ExecutionErrorType.ENGINE, cause)
|
||||
}
|
||||
}
|
||||
|
||||
export class PausedFlowTimeoutError extends ExecutionError {
|
||||
constructor(cause?: unknown, maximumPauseDurationDays?: number) {
|
||||
super('PausedFlowTimeoutError', `The flow cannot be paused for more than ${maximumPauseDurationDays} days`, ExecutionErrorType.USER, cause)
|
||||
}
|
||||
}
|
||||
|
||||
export class FileSizeError extends ExecutionError {
|
||||
constructor(currentFileSize: number, maximumSupportSize: number, cause?: unknown) {
|
||||
super('FileSizeError', JSON.stringify({
|
||||
message: 'File size is larger than maximum supported size',
|
||||
currentFileSize: `${currentFileSize} MB`,
|
||||
maximumSupportSize: `${maximumSupportSize} MB`,
|
||||
}), ExecutionErrorType.USER, cause)
|
||||
}
|
||||
}
|
||||
|
||||
export class FetchError extends ExecutionError {
|
||||
constructor(url: string, cause?: unknown) {
|
||||
super('FetchError', formatMessage(`Failed to fetch from ${url}`), ExecutionErrorType.ENGINE, cause)
|
||||
}
|
||||
}
|
||||
|
||||
export class InvalidCronExpressionError extends ExecutionError {
|
||||
constructor(cronExpression: string, cause?: unknown) {
|
||||
super('InvalidCronExpressionError', formatMessage(`Invalid cron expression: ${cronExpression}`), ExecutionErrorType.USER, cause)
|
||||
}
|
||||
}
|
||||
|
||||
export class EngineGenericError extends ExecutionError {
|
||||
constructor(name: string, message: string, cause?: unknown) {
|
||||
super(name, formatMessage(message), ExecutionErrorType.ENGINE, cause)
|
||||
}
|
||||
}
|
||||
11
activepieces-fork/packages/shared/src/lib/engine/index.ts
Normal file
11
activepieces-fork/packages/shared/src/lib/engine/index.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export * from './engine-operation'
|
||||
export * from './requests'
|
||||
export * from './engine-constants'
|
||||
export * from './execution-errors'
|
||||
|
||||
export enum ExecutionMode {
|
||||
SANDBOX_PROCESS = 'SANDBOX_PROCESS',
|
||||
SANDBOX_CODE_ONLY = 'SANDBOX_CODE_ONLY',
|
||||
UNSANDBOXED = 'UNSANDBOXED',
|
||||
SANDBOX_CODE_AND_PROCESS = 'SANDBOX_CODE_AND_PROCESS',
|
||||
}
|
||||
70
activepieces-fork/packages/shared/src/lib/engine/requests.ts
Normal file
70
activepieces-fork/packages/shared/src/lib/engine/requests.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { Nullable } from '../common'
|
||||
import { FlowRunStatus, PauseMetadata } from '../flow-run/execution/flow-execution'
|
||||
import { FailedStep } from '../flow-run/flow-run'
|
||||
import { StepRunResponse } from '../flows/sample-data'
|
||||
import { ProgressUpdateType } from './engine-operation'
|
||||
|
||||
|
||||
|
||||
export const UpdateRunProgressRequest = Type.Object({
|
||||
runId: Type.String(),
|
||||
tags: Type.Optional(Type.Array(Type.String())),
|
||||
status: Type.Enum(FlowRunStatus),
|
||||
projectId: Type.String(),
|
||||
progressUpdateType: Type.Optional(Type.Enum(ProgressUpdateType)),
|
||||
workerHandlerId: Nullable(Type.String()),
|
||||
httpRequestId: Nullable(Type.String()),
|
||||
logsFileId: Type.Optional(Type.String()),
|
||||
stepNameToTest: Type.Optional(Type.String()),
|
||||
failedStep: Type.Optional(FailedStep),
|
||||
startTime: Type.Optional(Type.String()),
|
||||
finishTime: Type.Optional(Type.String()),
|
||||
stepResponse: Type.Optional(StepRunResponse),
|
||||
pauseMetadata: Type.Optional(PauseMetadata),
|
||||
stepsCount: Type.Optional(Type.Number()),
|
||||
})
|
||||
|
||||
export type UpdateRunProgressRequest = Static<typeof UpdateRunProgressRequest>
|
||||
|
||||
|
||||
export const UpdateStepProgressRequest = Type.Object({
|
||||
projectId: Type.String(),
|
||||
stepResponse: StepRunResponse,
|
||||
})
|
||||
export type UpdateStepProgressRequest = Static<typeof UpdateStepProgressRequest>
|
||||
|
||||
export const UploadLogsQueryParams = Type.Object({
|
||||
token: Type.String(),
|
||||
})
|
||||
export type UploadLogsQueryParams = Static<typeof UploadLogsQueryParams>
|
||||
|
||||
export enum UploadLogsBehavior {
|
||||
UPLOAD_DIRECTLY = 'UPLOAD_DIRECTLY',
|
||||
REDIRECT_TO_S3 = 'REDIRECT_TO_S3',
|
||||
}
|
||||
|
||||
export const UploadLogsToken = Type.Object({
|
||||
logsFileId: Type.String(),
|
||||
projectId: Type.String(),
|
||||
flowRunId: Type.String(),
|
||||
behavior: Type.Enum(UploadLogsBehavior),
|
||||
})
|
||||
|
||||
export type UploadLogsToken = Static<typeof UploadLogsToken>
|
||||
|
||||
export const SendFlowResponseRequest = Type.Object({
|
||||
workerHandlerId: Type.String(),
|
||||
httpRequestId: Type.String(),
|
||||
runResponse: Type.Object({
|
||||
status: Type.Number(),
|
||||
body: Type.Any(),
|
||||
headers: Type.Record(Type.String(), Type.String()),
|
||||
}),
|
||||
})
|
||||
export type SendFlowResponseRequest = Static<typeof SendFlowResponseRequest>
|
||||
export const GetFlowVersionForWorkerRequest = Type.Object({
|
||||
versionId: Type.String(),
|
||||
})
|
||||
|
||||
export type GetFlowVersionForWorkerRequest = Static<typeof GetFlowVersionForWorkerRequest>
|
||||
@@ -0,0 +1,8 @@
|
||||
export enum ThirdPartyAuthnProviderEnum {
|
||||
GOOGLE = 'google',
|
||||
SAML = 'saml',
|
||||
}
|
||||
|
||||
export type ThirdPartyAuthnProvidersToShowMap = {
|
||||
[k in ThirdPartyAuthnProviderEnum]: boolean;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { Nullable } from '../common'
|
||||
import { ThirdPartyAuthnProviderEnum } from './authn-provider-name'
|
||||
|
||||
export * from './authn-provider-name'
|
||||
|
||||
export const federatedAuthnLoginResponse = Type.Object({
|
||||
loginUrl: Type.String(),
|
||||
})
|
||||
export type FederatedAuthnLoginResponse = Static<typeof federatedAuthnLoginResponse>
|
||||
|
||||
|
||||
export const ClaimTokenRequest = Type.Object({
|
||||
providerName: Type.Enum(ThirdPartyAuthnProviderEnum),
|
||||
code: Type.String(),
|
||||
})
|
||||
|
||||
export type ClaimTokenRequest = Static<typeof ClaimTokenRequest>
|
||||
|
||||
export const GoogleAuthnProviderConfig = Type.Object({
|
||||
clientId: Type.String(),
|
||||
clientSecret: Type.String(),
|
||||
})
|
||||
export type GoogleAuthnProviderConfig = Static<typeof GoogleAuthnProviderConfig>
|
||||
|
||||
export const GithubAuthnProviderConfig = Type.Object({
|
||||
clientId: Type.String(),
|
||||
clientSecret: Type.String(),
|
||||
})
|
||||
export type GithubAuthnProviderConfig = Static<typeof GithubAuthnProviderConfig>
|
||||
|
||||
export const SAMLAuthnProviderConfig = Type.Object({
|
||||
idpMetadata: Type.String(),
|
||||
idpCertificate: Type.String(),
|
||||
})
|
||||
export type SAMLAuthnProviderConfig = Static<typeof SAMLAuthnProviderConfig>
|
||||
|
||||
export const FederatedAuthnProviderConfig = Type.Object({
|
||||
google: Nullable(GoogleAuthnProviderConfig),
|
||||
github: Nullable(GithubAuthnProviderConfig),
|
||||
saml: Nullable(SAMLAuthnProviderConfig),
|
||||
})
|
||||
export type FederatedAuthnProviderConfig = Static<typeof FederatedAuthnProviderConfig>
|
||||
|
||||
export const FederatedAuthnProviderConfigWithoutSensitiveData = Type.Object({
|
||||
google: Nullable(Type.Pick(GoogleAuthnProviderConfig, ['clientId'])),
|
||||
github: Nullable(Type.Pick(GithubAuthnProviderConfig, ['clientId'])),
|
||||
saml: Nullable(Type.Object({})),
|
||||
})
|
||||
|
||||
export type FederatedAuthnProviderConfigWithoutSensitiveData = Static<typeof FederatedAuthnProviderConfigWithoutSensitiveData>
|
||||
@@ -0,0 +1 @@
|
||||
export const feedbackUrl = 'https://feedback.activepieces.com'
|
||||
50
activepieces-fork/packages/shared/src/lib/file/index.ts
Normal file
50
activepieces-fork/packages/shared/src/lib/file/index.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { BaseModelSchema } from '../common/base-model'
|
||||
import { ApId } from '../common/id-generator'
|
||||
|
||||
export type FileId = ApId
|
||||
|
||||
export enum FileType {
|
||||
UNKNOWN = 'UNKNOWN',
|
||||
FLOW_RUN_LOG = 'FLOW_RUN_LOG',
|
||||
PACKAGE_ARCHIVE = 'PACKAGE_ARCHIVE',
|
||||
FLOW_STEP_FILE = 'FLOW_STEP_FILE',
|
||||
SAMPLE_DATA = 'SAMPLE_DATA',
|
||||
/*
|
||||
@deprecated activepieces no longer stores trigger payload
|
||||
*/
|
||||
TRIGGER_PAYLOAD = 'TRIGGER_PAYLOAD',
|
||||
SAMPLE_DATA_INPUT = 'SAMPLE_DATA_INPUT',
|
||||
TRIGGER_EVENT_FILE = 'TRIGGER_EVENT_FILE',
|
||||
PROJECT_RELEASE = 'PROJECT_RELEASE',
|
||||
FLOW_VERSION_BACKUP = 'FLOW_VERSION_BACKUP',
|
||||
|
||||
PLATFORM_ASSET = 'PLATFORM_ASSET',
|
||||
}
|
||||
export enum FileCompression {
|
||||
NONE = 'NONE',
|
||||
GZIP = 'GZIP',
|
||||
}
|
||||
|
||||
export enum FileLocation {
|
||||
S3 = 'S3',
|
||||
DB = 'DB',
|
||||
}
|
||||
|
||||
export const File = Type.Object({
|
||||
...BaseModelSchema,
|
||||
projectId: Type.Optional(Type.String()),
|
||||
platformId: Type.Optional(Type.String()),
|
||||
type: Type.Enum(FileType),
|
||||
compression: Type.Enum(FileCompression),
|
||||
data: Type.Optional(Type.Unknown()),
|
||||
location: Type.Enum(FileLocation),
|
||||
size: Type.Optional(Type.Number()),
|
||||
fileName: Type.Optional(Type.String()),
|
||||
s3Key: Type.Optional(Type.String()),
|
||||
metadata: Type.Optional(Type.Record(Type.String(), Type.String())),
|
||||
})
|
||||
|
||||
export type File = Static<typeof File> & {
|
||||
data: Buffer
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { TemplateCategory } from '../template/template'
|
||||
|
||||
export const UpdateTemplatesCategoriesFlagRequestBody = Type.Object({
|
||||
value: Type.Array(Type.Enum(TemplateCategory)),
|
||||
})
|
||||
export type UpdateTemplatesCategoriesFlagRequestBody = Static<typeof UpdateTemplatesCategoriesFlagRequestBody>
|
||||
62
activepieces-fork/packages/shared/src/lib/flag/flag.ts
Executable file
62
activepieces-fork/packages/shared/src/lib/flag/flag.ts
Executable file
@@ -0,0 +1,62 @@
|
||||
import { BaseModel } from '../common/base-model'
|
||||
import { ApId } from '../common/id-generator'
|
||||
|
||||
export type FlagId = ApId
|
||||
|
||||
export type Flag = {
|
||||
value: unknown
|
||||
} & BaseModel<FlagId>
|
||||
|
||||
export enum ApEnvironment {
|
||||
PRODUCTION = 'prod',
|
||||
DEVELOPMENT = 'dev',
|
||||
TESTING = 'test',
|
||||
}
|
||||
|
||||
export enum ApEdition {
|
||||
COMMUNITY = 'ce',
|
||||
ENTERPRISE = 'ee',
|
||||
CLOUD = 'cloud',
|
||||
}
|
||||
|
||||
export enum ApFlagId {
|
||||
SHOW_POWERED_BY_IN_FORM = 'SHOW_POWERED_BY_IN_FORM',
|
||||
CLOUD_AUTH_ENABLED = 'CLOUD_AUTH_ENABLED',
|
||||
CAN_CONFIGURE_AI_PROVIDER = 'CAN_CONFIGURE_AI_PROVIDER',
|
||||
AGENTS_CONFIGURED = 'AGENTS_CONFIGURED',
|
||||
CURRENT_VERSION = 'CURRENT_VERSION',
|
||||
EDITION = 'EDITION',
|
||||
EMAIL_AUTH_ENABLED = 'EMAIL_AUTH_ENABLED',
|
||||
EXECUTION_DATA_RETENTION_DAYS = 'EXECUTION_DATA_RETENTION_DAYS',
|
||||
ENVIRONMENT = 'ENVIRONMENT',
|
||||
PUBLIC_URL = 'PUBLIC_URL',
|
||||
LATEST_VERSION = 'LATEST_VERSION',
|
||||
PRIVACY_POLICY_URL = 'PRIVACY_POLICY_URL',
|
||||
PIECES_SYNC_MODE = 'PIECES_SYNC_MODE',
|
||||
PRIVATE_PIECES_ENABLED = 'PRIVATE_PIECES_ENABLED',
|
||||
FLOW_RUN_MEMORY_LIMIT_KB = 'FLOW_RUN_MEMORY_LIMIT_KB',
|
||||
FLOW_RUN_TIME_SECONDS = 'FLOW_RUN_TIME_SECONDS',
|
||||
SHOW_BILLING = 'SHOW_BILLING',
|
||||
SHOW_COMMUNITY = 'SHOW_COMMUNITY',
|
||||
SUPPORTED_APP_WEBHOOKS = 'SUPPORTED_APP_WEBHOOKS',
|
||||
TELEMETRY_ENABLED = 'TELEMETRY_ENABLED',
|
||||
TEMPLATES_PROJECT_ID = 'TEMPLATES_PROJECT_ID',
|
||||
TERMS_OF_SERVICE_URL = 'TERMS_OF_SERVICE_URL',
|
||||
THEME = 'THEME',
|
||||
THIRD_PARTY_AUTH_PROVIDER_REDIRECT_URL = 'THIRD_PARTY_AUTH_PROVIDER_REDIRECT_URL',
|
||||
THIRD_PARTY_AUTH_PROVIDERS_TO_SHOW_MAP = 'THIRD_PARTY_AUTH_PROVIDERS_TO_SHOW_MAP',
|
||||
SAML_AUTH_ACS_URL = 'SAML_AUTH_ACS_URL',
|
||||
USER_CREATED = 'USER_CREATED',
|
||||
WEBHOOK_URL_PREFIX = 'WEBHOOK_URL_PREFIX',
|
||||
ALLOW_NPM_PACKAGES_IN_CODE_STEP = 'ALLOW_NPM_PACKAGES_IN_CODE_STEP',
|
||||
PAUSED_FLOW_TIMEOUT_DAYS = 'PAUSED_FLOW_TIMEOUT_DAYS',
|
||||
WEBHOOK_TIMEOUT_SECONDS = 'WEBHOOK_TIMEOUT_SECONDS',
|
||||
MAX_RECORDS_PER_TABLE = 'MAX_RECORDS_PER_TABLE',
|
||||
MAX_FIELDS_PER_TABLE = 'MAX_FIELDS_PER_TABLE',
|
||||
MAX_FILE_SIZE_MB = 'MAX_FILE_SIZE_MB',
|
||||
MAX_MCPS_PER_PROJECT = 'MAX_MCPS_PER_PROJECT',
|
||||
ENABLE_FLOW_ON_PUBLISH = 'ENABLE_FLOW_ON_PUBLISH',
|
||||
SHOW_ALERTS = 'SHOW_ALERTS',
|
||||
SHOW_PROJECT_MEMBERS = 'SHOW_PROJECT_MEMBERS',
|
||||
TEMPLATES_CATEGORIES = 'TEMPLATES_CATEGORIES',
|
||||
}
|
||||
2
activepieces-fork/packages/shared/src/lib/flag/index.ts
Normal file
2
activepieces-fork/packages/shared/src/lib/flag/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './flag'
|
||||
export * from './flag.requests'
|
||||
@@ -0,0 +1,19 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { ApId } from '../../common/id-generator'
|
||||
import { FlowRunStatus } from '../execution/flow-execution'
|
||||
|
||||
export const ListFlowRunsRequestQuery = Type.Object({
|
||||
flowId: Type.Optional(Type.Array(ApId)),
|
||||
tags: Type.Optional(Type.Array(Type.String({}))),
|
||||
status: Type.Optional(Type.Array(Type.Enum(FlowRunStatus))),
|
||||
limit: Type.Optional(Type.Number({})),
|
||||
cursor: Type.Optional(Type.String({})),
|
||||
createdAfter: Type.Optional(Type.String({})),
|
||||
createdBefore: Type.Optional(Type.String({})),
|
||||
projectId: ApId,
|
||||
failedStepName: Type.Optional(Type.String({})),
|
||||
flowRunIds: Type.Optional(Type.Array(ApId)),
|
||||
archived: Type.Optional(Type.Boolean({})),
|
||||
})
|
||||
|
||||
export type ListFlowRunsRequestQuery = Static<typeof ListFlowRunsRequestQuery>
|
||||
@@ -0,0 +1,22 @@
|
||||
import { Type } from '@sinclair/typebox'
|
||||
import { TriggerPayload } from '../../engine'
|
||||
import { StepOutput } from './step-output'
|
||||
|
||||
export enum ExecutionType {
|
||||
BEGIN = 'BEGIN',
|
||||
RESUME = 'RESUME',
|
||||
}
|
||||
|
||||
export type ExecutionState = {
|
||||
steps: Record<string, StepOutput>
|
||||
}
|
||||
|
||||
export const ExecutionState = Type.Object({
|
||||
steps: Type.Record(Type.String(), Type.Unknown()),
|
||||
})
|
||||
|
||||
export type ExecutioOutputFile = {
|
||||
executionState: ExecutionState
|
||||
}
|
||||
|
||||
export type ResumePayload = TriggerPayload
|
||||
@@ -0,0 +1,91 @@
|
||||
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { ProgressUpdateType } from '../../engine'
|
||||
|
||||
export enum FlowRunStatus {
|
||||
FAILED = 'FAILED',
|
||||
QUOTA_EXCEEDED = 'QUOTA_EXCEEDED',
|
||||
INTERNAL_ERROR = 'INTERNAL_ERROR',
|
||||
PAUSED = 'PAUSED',
|
||||
QUEUED = 'QUEUED',
|
||||
RUNNING = 'RUNNING',
|
||||
SUCCEEDED = 'SUCCEEDED',
|
||||
MEMORY_LIMIT_EXCEEDED = 'MEMORY_LIMIT_EXCEEDED',
|
||||
TIMEOUT = 'TIMEOUT',
|
||||
CANCELED = 'CANCELED',
|
||||
}
|
||||
|
||||
export enum PauseType {
|
||||
DELAY = 'DELAY',
|
||||
WEBHOOK = 'WEBHOOK',
|
||||
}
|
||||
|
||||
export const DelayPauseMetadata = Type.Object({
|
||||
type: Type.Literal(PauseType.DELAY),
|
||||
resumeDateTime: Type.String(),
|
||||
requestIdToReply: Type.Optional(Type.String()),
|
||||
handlerId: Type.Optional(Type.String({})),
|
||||
progressUpdateType: Type.Optional(Type.Enum(ProgressUpdateType)),
|
||||
})
|
||||
|
||||
export type DelayPauseMetadata = Static<typeof DelayPauseMetadata>
|
||||
|
||||
export const RespondResponse = Type.Object({
|
||||
status: Type.Optional(Type.Number()),
|
||||
body: Type.Optional(Type.Unknown()),
|
||||
headers: Type.Optional(Type.Record(Type.String(), Type.String())),
|
||||
})
|
||||
|
||||
export type RespondResponse = Static<typeof RespondResponse>
|
||||
|
||||
export const StopResponse = Type.Object({
|
||||
status: Type.Optional(Type.Number()),
|
||||
body: Type.Optional(Type.Unknown()),
|
||||
headers: Type.Optional(Type.Record(Type.String(), Type.String())),
|
||||
})
|
||||
|
||||
export type StopResponse = Static<typeof StopResponse>
|
||||
|
||||
export const WebhookPauseMetadata = Type.Object({
|
||||
type: Type.Literal(PauseType.WEBHOOK),
|
||||
requestId: Type.String(),
|
||||
requestIdToReply: Type.Optional(Type.String()),
|
||||
response: RespondResponse,
|
||||
handlerId: Type.Optional(Type.String({})),
|
||||
progressUpdateType: Type.Optional(Type.Enum(ProgressUpdateType)),
|
||||
})
|
||||
export type WebhookPauseMetadata = Static<typeof WebhookPauseMetadata>
|
||||
|
||||
export const PauseMetadata = Type.Union([DelayPauseMetadata, WebhookPauseMetadata])
|
||||
export type PauseMetadata = Static<typeof PauseMetadata>
|
||||
|
||||
export const isFlowRunStateTerminal = ({ status, ignoreInternalError }: { status: FlowRunStatus, ignoreInternalError: boolean }): boolean => {
|
||||
switch (status) {
|
||||
case FlowRunStatus.SUCCEEDED:
|
||||
case FlowRunStatus.TIMEOUT:
|
||||
case FlowRunStatus.FAILED:
|
||||
case FlowRunStatus.QUOTA_EXCEEDED:
|
||||
case FlowRunStatus.MEMORY_LIMIT_EXCEEDED:
|
||||
case FlowRunStatus.CANCELED:
|
||||
return true
|
||||
case FlowRunStatus.INTERNAL_ERROR:
|
||||
return !ignoreInternalError
|
||||
case FlowRunStatus.QUEUED:
|
||||
case FlowRunStatus.RUNNING:
|
||||
return false
|
||||
case FlowRunStatus.PAUSED:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const FAILED_STATES = [
|
||||
FlowRunStatus.FAILED,
|
||||
FlowRunStatus.INTERNAL_ERROR,
|
||||
FlowRunStatus.QUOTA_EXCEEDED,
|
||||
FlowRunStatus.TIMEOUT,
|
||||
FlowRunStatus.MEMORY_LIMIT_EXCEEDED,
|
||||
]
|
||||
export const isFailedState = (status: FlowRunStatus): boolean => {
|
||||
return FAILED_STATES.includes(status)
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
import { isNil } from '../../common'
|
||||
import { FlowActionType } from '../../flows/actions/action'
|
||||
import { FlowTriggerType } from '../../flows/triggers/trigger'
|
||||
|
||||
export enum StepOutputStatus {
|
||||
FAILED = 'FAILED',
|
||||
PAUSED = 'PAUSED',
|
||||
RUNNING = 'RUNNING',
|
||||
STOPPED = 'STOPPED',
|
||||
SUCCEEDED = 'SUCCEEDED',
|
||||
}
|
||||
|
||||
type BaseStepOutputParams<T extends FlowActionType | FlowTriggerType, OUTPUT> = {
|
||||
type: T
|
||||
status: StepOutputStatus
|
||||
input: unknown
|
||||
output?: OUTPUT
|
||||
duration?: number
|
||||
errorMessage?: unknown
|
||||
}
|
||||
|
||||
export class GenericStepOutput<T extends FlowActionType | FlowTriggerType, OUTPUT> {
|
||||
type: T
|
||||
status: StepOutputStatus
|
||||
input: unknown
|
||||
output?: OUTPUT
|
||||
duration?: number
|
||||
errorMessage?: unknown
|
||||
|
||||
constructor(step: BaseStepOutputParams<T, OUTPUT>) {
|
||||
this.type = step.type
|
||||
this.status = step.status
|
||||
this.input = step.input
|
||||
this.output = step.output
|
||||
this.duration = step.duration
|
||||
this.errorMessage = step.errorMessage
|
||||
}
|
||||
|
||||
setOutput(output: OUTPUT): GenericStepOutput<T, OUTPUT> {
|
||||
return new GenericStepOutput<T, OUTPUT>({
|
||||
...this,
|
||||
output,
|
||||
})
|
||||
}
|
||||
|
||||
setStatus(status: StepOutputStatus): GenericStepOutput<T, OUTPUT> {
|
||||
return new GenericStepOutput<T, OUTPUT>({
|
||||
...this,
|
||||
status,
|
||||
})
|
||||
}
|
||||
|
||||
setErrorMessage(errorMessage: unknown): GenericStepOutput<T, OUTPUT> {
|
||||
return new GenericStepOutput<T, OUTPUT>({
|
||||
...this,
|
||||
errorMessage,
|
||||
})
|
||||
}
|
||||
|
||||
setDuration(duration: number): GenericStepOutput<T, OUTPUT> {
|
||||
return new GenericStepOutput<T, OUTPUT>({
|
||||
...this,
|
||||
duration,
|
||||
})
|
||||
}
|
||||
|
||||
static create<T extends FlowActionType | FlowTriggerType, OUTPUT>({
|
||||
input,
|
||||
type,
|
||||
status,
|
||||
output,
|
||||
}: {
|
||||
input: unknown
|
||||
type: T
|
||||
status: StepOutputStatus
|
||||
output?: OUTPUT
|
||||
}): GenericStepOutput<T, OUTPUT> {
|
||||
return new GenericStepOutput<T, OUTPUT>({
|
||||
input,
|
||||
type,
|
||||
status,
|
||||
output,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export type StepOutput =
|
||||
| GenericStepOutput<FlowActionType.LOOP_ON_ITEMS, LoopStepResult>
|
||||
| GenericStepOutput<FlowActionType.ROUTER, unknown>
|
||||
| GenericStepOutput<
|
||||
| Exclude<FlowActionType, FlowActionType.LOOP_ON_ITEMS | FlowActionType.ROUTER>
|
||||
| FlowTriggerType,
|
||||
unknown
|
||||
>
|
||||
|
||||
type BranchResult = {
|
||||
branchName: string
|
||||
branchIndex: number
|
||||
evaluation: boolean
|
||||
}
|
||||
|
||||
type RouterStepResult = {
|
||||
branches: BranchResult[]
|
||||
}
|
||||
|
||||
export class RouterStepOutput extends GenericStepOutput<
|
||||
FlowActionType.ROUTER,
|
||||
RouterStepResult
|
||||
> {
|
||||
static init({ input }: { input: unknown }): RouterStepOutput {
|
||||
return new RouterStepOutput({
|
||||
type: FlowActionType.ROUTER,
|
||||
input,
|
||||
status: StepOutputStatus.SUCCEEDED,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export type LoopStepResult = {
|
||||
item: unknown
|
||||
index: number
|
||||
iterations: Record<string, StepOutput>[]
|
||||
}
|
||||
|
||||
export class LoopStepOutput extends GenericStepOutput<
|
||||
FlowActionType.LOOP_ON_ITEMS,
|
||||
LoopStepResult
|
||||
> {
|
||||
constructor(
|
||||
step: BaseStepOutputParams<FlowActionType.LOOP_ON_ITEMS, LoopStepResult>,
|
||||
) {
|
||||
super(step)
|
||||
this.output = step.output ?? {
|
||||
item: undefined,
|
||||
index: 0,
|
||||
iterations: [],
|
||||
}
|
||||
}
|
||||
|
||||
static init({ input }: { input: unknown }): LoopStepOutput {
|
||||
return new LoopStepOutput({
|
||||
type: FlowActionType.LOOP_ON_ITEMS,
|
||||
input,
|
||||
status: StepOutputStatus.SUCCEEDED,
|
||||
})
|
||||
}
|
||||
|
||||
setIterations(iterations: Record<string, StepOutput>[]): LoopStepOutput {
|
||||
return new LoopStepOutput({
|
||||
...this,
|
||||
output: {
|
||||
...this.output,
|
||||
iterations,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
hasIteration(iteration: number): boolean {
|
||||
return !isNil(this.output?.iterations[iteration])
|
||||
}
|
||||
|
||||
setItemAndIndex({
|
||||
item,
|
||||
index,
|
||||
}: {
|
||||
item: unknown
|
||||
index: number
|
||||
}): LoopStepOutput {
|
||||
return new LoopStepOutput({
|
||||
...this,
|
||||
output: {
|
||||
item,
|
||||
index,
|
||||
iterations: this.output?.iterations ?? [],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
addIteration(): LoopStepOutput {
|
||||
return new LoopStepOutput({
|
||||
...this,
|
||||
output: {
|
||||
item: this.output?.item,
|
||||
index: this.output?.index,
|
||||
iterations: [...(this.output?.iterations ?? []), {}],
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
62
activepieces-fork/packages/shared/src/lib/flow-run/flow-run.ts
Executable file
62
activepieces-fork/packages/shared/src/lib/flow-run/flow-run.ts
Executable file
@@ -0,0 +1,62 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { BaseModelSchema, Nullable } from '../common/base-model'
|
||||
import { ApId } from '../common/id-generator'
|
||||
import { ExecutionState } from './execution/execution-output'
|
||||
import { FlowRunStatus, PauseMetadata } from './execution/flow-execution'
|
||||
|
||||
export const PARENT_RUN_ID_HEADER = 'ap-parent-run-id'
|
||||
export const FAIL_PARENT_ON_FAILURE_HEADER = 'ap-fail-parent-on-failure'
|
||||
|
||||
export type FlowRunId = ApId
|
||||
|
||||
export enum RunEnvironment {
|
||||
PRODUCTION = 'PRODUCTION',
|
||||
TESTING = 'TESTING',
|
||||
}
|
||||
|
||||
export enum FlowRetryStrategy {
|
||||
ON_LATEST_VERSION = 'ON_LATEST_VERSION',
|
||||
FROM_FAILED_STEP = 'FROM_FAILED_STEP',
|
||||
}
|
||||
|
||||
export type FlowRetryPayload = {
|
||||
strategy: FlowRetryStrategy
|
||||
}
|
||||
|
||||
export const FlowRun = Type.Object({
|
||||
...BaseModelSchema,
|
||||
projectId: Type.String(),
|
||||
flowId: Type.String(),
|
||||
parentRunId: Type.Optional(Type.String()),
|
||||
failParentOnFailure: Type.Boolean(),
|
||||
tags: Type.Optional(Type.Array(Type.String())),
|
||||
flowVersionId: Type.String(),
|
||||
flowVersion: Type.Optional(Type.Object({
|
||||
displayName: Type.Optional(Type.String()),
|
||||
})),
|
||||
logsFileId: Nullable(Type.String()),
|
||||
status: Type.Enum(FlowRunStatus),
|
||||
startTime: Type.Optional(Type.String()),
|
||||
finishTime: Type.Optional(Type.String()),
|
||||
environment: Type.Enum(RunEnvironment),
|
||||
pauseMetadata: Type.Optional(PauseMetadata),
|
||||
// The steps data may be missing if the flow has not started yet,
|
||||
// or if the run is older than AP_EXECUTION_DATA_RETENTION_DAYS and its execution data has been purged.
|
||||
steps: Nullable(Type.Record(Type.String(), Type.Unknown())),
|
||||
failedStep: Type.Optional(Type.Object({
|
||||
name: Type.String(),
|
||||
displayName: Type.String(),
|
||||
})),
|
||||
stepNameToTest: Type.Optional(Type.String()),
|
||||
archivedAt: Nullable(Type.String({ default: null })),
|
||||
stepsCount: Type.Optional(Type.Number()),
|
||||
})
|
||||
|
||||
export const FailedStep = Type.Object({
|
||||
name: Type.String(),
|
||||
displayName: Type.String(),
|
||||
message: Type.String(),
|
||||
})
|
||||
export type FailedStep = Static<typeof FailedStep>
|
||||
|
||||
export type FlowRun = Static<typeof FlowRun> & ExecutionState
|
||||
@@ -0,0 +1,7 @@
|
||||
import { ExecutioOutputFile } from './execution/execution-output'
|
||||
|
||||
export const logSerializer = {
|
||||
async serialize(log: ExecutioOutputFile): Promise<Buffer> {
|
||||
return Buffer.from(JSON.stringify(log, null))
|
||||
},
|
||||
}
|
||||
60
activepieces-fork/packages/shared/src/lib/flow-run/test-flow-run-request.ts
Executable file
60
activepieces-fork/packages/shared/src/lib/flow-run/test-flow-run-request.ts
Executable file
@@ -0,0 +1,60 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { ApId } from '../common/id-generator'
|
||||
import { FlowRunStatus } from './execution/flow-execution'
|
||||
import { FlowRetryStrategy } from './flow-run'
|
||||
|
||||
export const TestFlowRunRequestBody = Type.Object({
|
||||
flowVersionId: ApId,
|
||||
})
|
||||
|
||||
export type TestFlowRunRequestBody = Static<typeof TestFlowRunRequestBody>
|
||||
|
||||
export const RetryFlowRequestBody = Type.Object({
|
||||
strategy: Type.Enum(FlowRetryStrategy),
|
||||
projectId: ApId,
|
||||
})
|
||||
|
||||
export type RetryFlowRequestBody = Static<typeof RetryFlowRequestBody>
|
||||
|
||||
|
||||
export const BulkActionOnRunsRequestBody = Type.Object({
|
||||
projectId: ApId,
|
||||
flowRunIds: Type.Optional(Type.Array(ApId)),
|
||||
excludeFlowRunIds: Type.Optional(Type.Array(ApId)),
|
||||
strategy: Type.Enum(FlowRetryStrategy),
|
||||
status: Type.Optional(Type.Array(Type.Enum(FlowRunStatus))),
|
||||
flowId: Type.Optional(Type.Array(ApId)),
|
||||
createdAfter: Type.Optional(Type.String()),
|
||||
createdBefore: Type.Optional(Type.String()),
|
||||
failedStepName: Type.Optional(Type.String()),
|
||||
})
|
||||
|
||||
export type BulkActionOnRunsRequestBody = Static<typeof BulkActionOnRunsRequestBody>
|
||||
|
||||
export const BulkCancelFlowRequestBody = Type.Object({
|
||||
projectId: ApId,
|
||||
flowRunIds: Type.Optional(Type.Array(ApId)),
|
||||
excludeFlowRunIds: Type.Optional(Type.Array(ApId)),
|
||||
status: Type.Optional(Type.Array(Type.Union([
|
||||
Type.Literal(FlowRunStatus.PAUSED),
|
||||
Type.Literal(FlowRunStatus.QUEUED),
|
||||
]))),
|
||||
flowId: Type.Optional(Type.Array(ApId)),
|
||||
createdAfter: Type.Optional(Type.String()),
|
||||
createdBefore: Type.Optional(Type.String()),
|
||||
})
|
||||
|
||||
export type BulkCancelFlowRequestBody = Static<typeof BulkCancelFlowRequestBody>
|
||||
|
||||
export const BulkArchiveActionOnRunsRequestBody = Type.Object({
|
||||
projectId: ApId,
|
||||
flowRunIds: Type.Optional(Type.Array(ApId)),
|
||||
excludeFlowRunIds: Type.Optional(Type.Array(ApId)),
|
||||
status: Type.Optional(Type.Array(Type.Enum(FlowRunStatus))),
|
||||
flowId: Type.Optional(Type.Array(ApId)),
|
||||
createdAfter: Type.Optional(Type.String()),
|
||||
createdBefore: Type.Optional(Type.String()),
|
||||
failedStepName: Type.Optional(Type.String()),
|
||||
})
|
||||
|
||||
export type BulkArchiveActionOnRunsRequestBody = Static<typeof BulkArchiveActionOnRunsRequestBody>
|
||||
350
activepieces-fork/packages/shared/src/lib/flows/actions/action.ts
Executable file
350
activepieces-fork/packages/shared/src/lib/flows/actions/action.ts
Executable file
@@ -0,0 +1,350 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { VersionType } from '../../pieces'
|
||||
import { PropertySettings } from '../properties'
|
||||
import { SampleDataSetting } from '../sample-data'
|
||||
|
||||
export enum FlowActionType {
|
||||
CODE = 'CODE',
|
||||
PIECE = 'PIECE',
|
||||
LOOP_ON_ITEMS = 'LOOP_ON_ITEMS',
|
||||
ROUTER = 'ROUTER',
|
||||
}
|
||||
|
||||
export enum RouterExecutionType {
|
||||
EXECUTE_ALL_MATCH = 'EXECUTE_ALL_MATCH',
|
||||
EXECUTE_FIRST_MATCH = 'EXECUTE_FIRST_MATCH',
|
||||
}
|
||||
|
||||
export enum BranchExecutionType {
|
||||
FALLBACK = 'FALLBACK',
|
||||
CONDITION = 'CONDITION',
|
||||
}
|
||||
|
||||
const commonActionProps = {
|
||||
name: Type.String({}),
|
||||
valid: Type.Boolean({}),
|
||||
displayName: Type.String({}),
|
||||
skip: Type.Optional(Type.Boolean({})),
|
||||
}
|
||||
const commonActionSettings = {
|
||||
sampleData: Type.Optional(SampleDataSetting),
|
||||
customLogoUrl: Type.Optional(Type.String()),
|
||||
}
|
||||
|
||||
export const ActionErrorHandlingOptions = Type.Optional(
|
||||
Type.Object({
|
||||
continueOnFailure: Type.Optional(
|
||||
Type.Object({
|
||||
value: Type.Optional(Type.Boolean()),
|
||||
}),
|
||||
),
|
||||
retryOnFailure: Type.Optional(
|
||||
Type.Object({
|
||||
value: Type.Optional(Type.Boolean()),
|
||||
}),
|
||||
),
|
||||
}),
|
||||
)
|
||||
export type ActionErrorHandlingOptions = Static<
|
||||
typeof ActionErrorHandlingOptions
|
||||
>
|
||||
|
||||
export const SourceCode = Type.Object({
|
||||
packageJson: Type.String({}),
|
||||
code: Type.String({}),
|
||||
})
|
||||
|
||||
export type SourceCode = Static<typeof SourceCode>
|
||||
|
||||
export const CodeActionSettings = Type.Object({
|
||||
...commonActionSettings,
|
||||
sourceCode: SourceCode,
|
||||
input: Type.Record(Type.String({}), Type.Any()),
|
||||
errorHandlingOptions: ActionErrorHandlingOptions,
|
||||
})
|
||||
|
||||
export type CodeActionSettings = Static<typeof CodeActionSettings>
|
||||
|
||||
export const CodeActionSchema = Type.Object({
|
||||
...commonActionProps,
|
||||
type: Type.Literal(FlowActionType.CODE),
|
||||
settings: CodeActionSettings,
|
||||
})
|
||||
export const PieceActionSettings = Type.Object({
|
||||
...commonActionSettings,
|
||||
propertySettings: Type.Record(Type.String(), PropertySettings),
|
||||
pieceName: Type.String({}),
|
||||
pieceVersion: VersionType,
|
||||
actionName: Type.Optional(Type.String({})),
|
||||
input: Type.Record(Type.String({}), Type.Unknown()),
|
||||
errorHandlingOptions: ActionErrorHandlingOptions,
|
||||
})
|
||||
export type PieceActionSettings = Static<typeof PieceActionSettings>
|
||||
|
||||
export const PieceActionSchema = Type.Object({
|
||||
...commonActionProps,
|
||||
type: Type.Literal(FlowActionType.PIECE),
|
||||
settings: PieceActionSettings,
|
||||
})
|
||||
|
||||
// Loop Items
|
||||
export const LoopOnItemsActionSettings = Type.Object({
|
||||
...commonActionSettings,
|
||||
items: Type.String(),
|
||||
})
|
||||
export type LoopOnItemsActionSettings = Static<
|
||||
typeof LoopOnItemsActionSettings
|
||||
>
|
||||
|
||||
export const LoopOnItemsActionSchema = Type.Object({
|
||||
...commonActionProps,
|
||||
type: Type.Literal(FlowActionType.LOOP_ON_ITEMS),
|
||||
settings: LoopOnItemsActionSettings,
|
||||
})
|
||||
|
||||
export enum BranchOperator {
|
||||
TEXT_CONTAINS = 'TEXT_CONTAINS',
|
||||
TEXT_DOES_NOT_CONTAIN = 'TEXT_DOES_NOT_CONTAIN',
|
||||
TEXT_EXACTLY_MATCHES = 'TEXT_EXACTLY_MATCHES',
|
||||
TEXT_DOES_NOT_EXACTLY_MATCH = 'TEXT_DOES_NOT_EXACTLY_MATCH',
|
||||
TEXT_STARTS_WITH = 'TEXT_START_WITH',
|
||||
TEXT_DOES_NOT_START_WITH = 'TEXT_DOES_NOT_START_WITH',
|
||||
TEXT_ENDS_WITH = 'TEXT_ENDS_WITH',
|
||||
TEXT_DOES_NOT_END_WITH = 'TEXT_DOES_NOT_END_WITH',
|
||||
NUMBER_IS_GREATER_THAN = 'NUMBER_IS_GREATER_THAN',
|
||||
NUMBER_IS_LESS_THAN = 'NUMBER_IS_LESS_THAN',
|
||||
NUMBER_IS_EQUAL_TO = 'NUMBER_IS_EQUAL_TO',
|
||||
BOOLEAN_IS_TRUE = 'BOOLEAN_IS_TRUE',
|
||||
BOOLEAN_IS_FALSE = 'BOOLEAN_IS_FALSE',
|
||||
DATE_IS_BEFORE = 'DATE_IS_BEFORE',
|
||||
DATE_IS_EQUAL = 'DATE_IS_EQUAL',
|
||||
DATE_IS_AFTER = 'DATE_IS_AFTER',
|
||||
LIST_CONTAINS = 'LIST_CONTAINS',
|
||||
LIST_DOES_NOT_CONTAIN = 'LIST_DOES_NOT_CONTAIN',
|
||||
LIST_IS_EMPTY = 'LIST_IS_EMPTY',
|
||||
LIST_IS_NOT_EMPTY = 'LIST_IS_NOT_EMPTY',
|
||||
EXISTS = 'EXISTS',
|
||||
DOES_NOT_EXIST = 'DOES_NOT_EXIST',
|
||||
}
|
||||
|
||||
export const singleValueConditions = [
|
||||
BranchOperator.EXISTS,
|
||||
BranchOperator.DOES_NOT_EXIST,
|
||||
BranchOperator.BOOLEAN_IS_TRUE,
|
||||
BranchOperator.BOOLEAN_IS_FALSE,
|
||||
BranchOperator.LIST_IS_EMPTY,
|
||||
BranchOperator.LIST_IS_NOT_EMPTY,
|
||||
]
|
||||
|
||||
export const textConditions = [
|
||||
BranchOperator.TEXT_CONTAINS,
|
||||
BranchOperator.TEXT_DOES_NOT_CONTAIN,
|
||||
BranchOperator.TEXT_EXACTLY_MATCHES,
|
||||
BranchOperator.TEXT_DOES_NOT_EXACTLY_MATCH,
|
||||
BranchOperator.TEXT_STARTS_WITH,
|
||||
BranchOperator.TEXT_DOES_NOT_START_WITH,
|
||||
BranchOperator.TEXT_ENDS_WITH,
|
||||
BranchOperator.TEXT_DOES_NOT_END_WITH,
|
||||
BranchOperator.LIST_CONTAINS,
|
||||
BranchOperator.LIST_DOES_NOT_CONTAIN,
|
||||
]
|
||||
|
||||
const BranchOperatorTextLiterals = [
|
||||
Type.Literal(BranchOperator.TEXT_CONTAINS),
|
||||
Type.Literal(BranchOperator.TEXT_DOES_NOT_CONTAIN),
|
||||
Type.Literal(BranchOperator.TEXT_EXACTLY_MATCHES),
|
||||
Type.Literal(BranchOperator.TEXT_DOES_NOT_EXACTLY_MATCH),
|
||||
Type.Literal(BranchOperator.TEXT_STARTS_WITH),
|
||||
Type.Literal(BranchOperator.TEXT_DOES_NOT_START_WITH),
|
||||
Type.Literal(BranchOperator.TEXT_ENDS_WITH),
|
||||
Type.Literal(BranchOperator.TEXT_DOES_NOT_END_WITH),
|
||||
Type.Literal(BranchOperator.LIST_CONTAINS),
|
||||
Type.Literal(BranchOperator.LIST_DOES_NOT_CONTAIN),
|
||||
]
|
||||
|
||||
const BranchOperatorNumberLiterals = [
|
||||
Type.Literal(BranchOperator.NUMBER_IS_GREATER_THAN),
|
||||
Type.Literal(BranchOperator.NUMBER_IS_LESS_THAN),
|
||||
Type.Literal(BranchOperator.NUMBER_IS_EQUAL_TO),
|
||||
]
|
||||
|
||||
const BranchOperatorDateLiterals = [
|
||||
Type.Literal(BranchOperator.DATE_IS_BEFORE),
|
||||
Type.Literal(BranchOperator.DATE_IS_EQUAL),
|
||||
Type.Literal(BranchOperator.DATE_IS_AFTER),
|
||||
]
|
||||
|
||||
const BranchOperatorSingleValueLiterals = [
|
||||
Type.Literal(BranchOperator.EXISTS),
|
||||
Type.Literal(BranchOperator.DOES_NOT_EXIST),
|
||||
Type.Literal(BranchOperator.BOOLEAN_IS_TRUE),
|
||||
Type.Literal(BranchOperator.BOOLEAN_IS_FALSE),
|
||||
Type.Literal(BranchOperator.LIST_IS_EMPTY),
|
||||
Type.Literal(BranchOperator.LIST_IS_NOT_EMPTY),
|
||||
]
|
||||
|
||||
const BranchTextConditionValid = (addMinLength: boolean) =>
|
||||
Type.Object({
|
||||
firstValue: Type.String(addMinLength ? { minLength: 1 } : {}),
|
||||
secondValue: Type.String(addMinLength ? { minLength: 1 } : {}),
|
||||
caseSensitive: Type.Optional(Type.Boolean()),
|
||||
operator: Type.Optional(Type.Union(BranchOperatorTextLiterals)),
|
||||
})
|
||||
|
||||
const BranchNumberConditionValid = (addMinLength: boolean) =>
|
||||
Type.Object({
|
||||
firstValue: Type.String(addMinLength ? { minLength: 1 } : {}),
|
||||
secondValue: Type.String(addMinLength ? { minLength: 1 } : {}),
|
||||
operator: Type.Optional(Type.Union(BranchOperatorNumberLiterals)),
|
||||
})
|
||||
|
||||
const BranchDateConditionValid = (addMinLength: boolean) =>
|
||||
Type.Object({
|
||||
firstValue: Type.String(addMinLength ? { minLength: 1 } : {}),
|
||||
secondValue: Type.String(addMinLength ? { minLength: 1 } : {}),
|
||||
operator: Type.Optional(Type.Union(BranchOperatorDateLiterals)),
|
||||
})
|
||||
|
||||
const BranchSingleValueConditionValid = (addMinLength: boolean) =>
|
||||
Type.Object({
|
||||
firstValue: Type.String(addMinLength ? { minLength: 1 } : {}),
|
||||
operator: Type.Optional(Type.Union(BranchOperatorSingleValueLiterals)),
|
||||
})
|
||||
|
||||
const BranchConditionValid = (addMinLength: boolean) =>
|
||||
Type.Union([
|
||||
BranchTextConditionValid(addMinLength),
|
||||
BranchNumberConditionValid(addMinLength),
|
||||
BranchDateConditionValid(addMinLength),
|
||||
BranchSingleValueConditionValid(addMinLength),
|
||||
])
|
||||
|
||||
export const ValidBranchCondition = BranchConditionValid(true)
|
||||
export type ValidBranchCondition = Static<typeof ValidBranchCondition>
|
||||
|
||||
// TODO remove this and use ValidBranchCondition everywhere
|
||||
export const BranchCondition = BranchConditionValid(false)
|
||||
export type BranchCondition = Static<typeof BranchCondition>
|
||||
|
||||
export const BranchTextCondition = BranchTextConditionValid(false)
|
||||
export type BranchTextCondition = Static<typeof BranchTextCondition>
|
||||
|
||||
export const BranchNumberCondition = BranchNumberConditionValid(false)
|
||||
export type BranchNumberCondition = Static<typeof BranchNumberCondition>
|
||||
|
||||
export const BranchDateCondition = BranchDateConditionValid(false)
|
||||
export type BranchDateCondition = Static<typeof BranchDateCondition>
|
||||
|
||||
export const BranchSingleValueCondition =
|
||||
BranchSingleValueConditionValid(false)
|
||||
export type BranchSingleValueCondition = Static<
|
||||
typeof BranchSingleValueCondition
|
||||
>
|
||||
|
||||
|
||||
export const RouterBranchesSchema = (addMinLength: boolean) =>
|
||||
Type.Array(
|
||||
Type.Union([
|
||||
Type.Object({
|
||||
conditions: Type.Array(Type.Array(BranchConditionValid(addMinLength))),
|
||||
branchType: Type.Literal(BranchExecutionType.CONDITION),
|
||||
branchName: Type.String(),
|
||||
}),
|
||||
Type.Object({
|
||||
branchType: Type.Literal(BranchExecutionType.FALLBACK),
|
||||
branchName: Type.String(),
|
||||
}),
|
||||
]),
|
||||
)
|
||||
|
||||
export const RouterActionSettings = Type.Object({
|
||||
...commonActionSettings,
|
||||
branches: RouterBranchesSchema(false),
|
||||
executionType: Type.Enum(RouterExecutionType),
|
||||
})
|
||||
|
||||
export const RouterActionSettingsWithValidation = Type.Object({
|
||||
branches: RouterBranchesSchema(true),
|
||||
executionType: Type.Enum(RouterExecutionType),
|
||||
})
|
||||
|
||||
export type RouterActionSettings = Static<typeof RouterActionSettings>
|
||||
|
||||
|
||||
|
||||
// Union of all actions
|
||||
|
||||
export const FlowAction = Type.Recursive((action) =>
|
||||
Type.Union([
|
||||
Type.Intersect([
|
||||
CodeActionSchema,
|
||||
Type.Object({
|
||||
nextAction: Type.Optional(action),
|
||||
}),
|
||||
]),
|
||||
Type.Intersect([
|
||||
PieceActionSchema,
|
||||
Type.Object({
|
||||
nextAction: Type.Optional(action),
|
||||
}),
|
||||
]),
|
||||
Type.Intersect([
|
||||
LoopOnItemsActionSchema,
|
||||
Type.Object({
|
||||
nextAction: Type.Optional(action),
|
||||
firstLoopAction: Type.Optional(action),
|
||||
}),
|
||||
]),
|
||||
Type.Intersect([
|
||||
Type.Object({
|
||||
...commonActionProps,
|
||||
type: Type.Literal(FlowActionType.ROUTER),
|
||||
settings: RouterActionSettings,
|
||||
}),
|
||||
Type.Object({
|
||||
nextAction: Type.Optional(action),
|
||||
children: Type.Array(Type.Union([action, Type.Null()])),
|
||||
}),
|
||||
]),
|
||||
]),
|
||||
)
|
||||
export const RouterActionSchema = Type.Object({
|
||||
...commonActionProps,
|
||||
type: Type.Literal(FlowActionType.ROUTER),
|
||||
settings: RouterActionSettings,
|
||||
})
|
||||
|
||||
export const SingleActionSchema = Type.Union([
|
||||
CodeActionSchema,
|
||||
PieceActionSchema,
|
||||
LoopOnItemsActionSchema,
|
||||
RouterActionSchema,
|
||||
])
|
||||
export type FlowAction = Static<typeof FlowAction>
|
||||
|
||||
|
||||
export type RouterAction = Static<typeof RouterActionSchema> & {
|
||||
nextAction?: FlowAction
|
||||
children: (FlowAction | null)[]
|
||||
}
|
||||
|
||||
export type LoopOnItemsAction = Static<typeof LoopOnItemsActionSchema> & {
|
||||
nextAction?: FlowAction
|
||||
firstLoopAction?: FlowAction
|
||||
}
|
||||
|
||||
export type PieceAction = Static<typeof PieceActionSchema> & {
|
||||
nextAction?: FlowAction
|
||||
}
|
||||
|
||||
export type CodeAction = Static<typeof CodeActionSchema> & {
|
||||
nextAction?: FlowAction
|
||||
}
|
||||
|
||||
|
||||
export const emptyCondition: ValidBranchCondition = {
|
||||
firstValue: '',
|
||||
secondValue: '',
|
||||
operator: BranchOperator.TEXT_CONTAINS,
|
||||
caseSensitive: false,
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
|
||||
export const CountFlowsRequest = Type.Object({
|
||||
folderId: Type.Optional(Type.String()),
|
||||
})
|
||||
|
||||
export type CountFlowsRequest = Static<typeof CountFlowsRequest>
|
||||
13
activepieces-fork/packages/shared/src/lib/flows/dto/create-flow-request.ts
Executable file
13
activepieces-fork/packages/shared/src/lib/flows/dto/create-flow-request.ts
Executable file
@@ -0,0 +1,13 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { Metadata } from '../../common/metadata'
|
||||
|
||||
export const CreateFlowRequest = Type.Object({
|
||||
displayName: Type.String({}),
|
||||
/**If folderId is provided, folderName is ignored */
|
||||
folderId: Type.Optional(Type.String({})),
|
||||
folderName: Type.Optional(Type.String({})),
|
||||
projectId: Type.String({}),
|
||||
metadata: Type.Optional(Metadata),
|
||||
})
|
||||
|
||||
export type CreateFlowRequest = Static<typeof CreateFlowRequest>
|
||||
@@ -0,0 +1,8 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
|
||||
export const CreateMCPServerFromStepParams = Type.Object({
|
||||
flowId: Type.String(),
|
||||
flowVersionId: Type.String(),
|
||||
stepName: Type.String(),
|
||||
})
|
||||
export type CreateMCPServerFromStepParams = Static<typeof CreateMCPServerFromStepParams>
|
||||
32
activepieces-fork/packages/shared/src/lib/flows/dto/list-flows-request.ts
Executable file
32
activepieces-fork/packages/shared/src/lib/flows/dto/list-flows-request.ts
Executable file
@@ -0,0 +1,32 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { Cursor } from '../../common/seek-page'
|
||||
import { FlowStatus } from '../flow'
|
||||
import { FlowVersionState } from '../flow-version'
|
||||
|
||||
export const ListFlowsRequest = Type.Object({
|
||||
folderId: Type.Optional(Type.String()),
|
||||
limit: Type.Optional(Type.Number({})),
|
||||
cursor: Type.Optional(Type.String({})),
|
||||
status: Type.Optional(Type.Array(Type.Enum(FlowStatus))),
|
||||
projectId: Type.String({}),
|
||||
name: Type.Optional(Type.String({})),
|
||||
agentExternalIds: Type.Optional(Type.Array(Type.String({}))),
|
||||
versionState: Type.Optional(Type.Enum(FlowVersionState)),
|
||||
connectionExternalIds: Type.Optional(Type.Array(Type.String({}))),
|
||||
externalIds: Type.Optional(Type.Array(Type.String({}))),
|
||||
})
|
||||
|
||||
export type ListFlowsRequest = Omit<Static<typeof ListFlowsRequest>, 'cursor'> & { cursor: Cursor | undefined }
|
||||
|
||||
export const GetFlowQueryParamsRequest = Type.Object({
|
||||
versionId: Type.Optional(Type.String({})),
|
||||
})
|
||||
|
||||
export type GetFlowQueryParamsRequest = Static<typeof GetFlowQueryParamsRequest>
|
||||
|
||||
export const ListFlowVersionRequest = Type.Object({
|
||||
limit: Type.Optional(Type.Number({})),
|
||||
cursor: Type.Optional(Type.String({})),
|
||||
})
|
||||
|
||||
export type ListFlowVersionRequest = Omit<Static<typeof ListFlowVersionRequest>, 'cursor'> & { cursor: Cursor | undefined }
|
||||
44
activepieces-fork/packages/shared/src/lib/flows/flow-version.ts
Executable file
44
activepieces-fork/packages/shared/src/lib/flows/flow-version.ts
Executable file
@@ -0,0 +1,44 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { BaseModelSchema, Nullable } from '../common/base-model'
|
||||
import { ApId } from '../common/id-generator'
|
||||
import { UserWithMetaInformation } from '../user'
|
||||
import { FlowTrigger } from './triggers/trigger'
|
||||
|
||||
export type FlowVersionId = ApId
|
||||
|
||||
export const LATEST_FLOW_SCHEMA_VERSION = '10'
|
||||
|
||||
export enum FlowVersionState {
|
||||
LOCKED = 'LOCKED',
|
||||
DRAFT = 'DRAFT',
|
||||
}
|
||||
|
||||
export const FlowVersion = Type.Object({
|
||||
...BaseModelSchema,
|
||||
flowId: Type.String(),
|
||||
displayName: Type.String(),
|
||||
trigger: FlowTrigger,
|
||||
updatedBy: Nullable(Type.String()),
|
||||
valid: Type.Boolean(),
|
||||
schemaVersion: Nullable(Type.String()),
|
||||
agentIds: Type.Array(Type.String()),
|
||||
state: Type.Enum(FlowVersionState),
|
||||
connectionIds: Type.Array(Type.String()),
|
||||
backupFiles: Nullable(Type.Record(Type.String(), Type.String())),
|
||||
})
|
||||
|
||||
export type FlowVersion = Static<typeof FlowVersion>
|
||||
|
||||
export const FlowVersionMetadata = Type.Object({
|
||||
...BaseModelSchema,
|
||||
flowId: Type.String(),
|
||||
displayName: Type.String(),
|
||||
valid: Type.Boolean(),
|
||||
state: Type.Enum(FlowVersionState),
|
||||
updatedBy: Nullable(Type.String()),
|
||||
schemaVersion: Nullable(Type.String()),
|
||||
updatedByUser: Nullable(UserWithMetaInformation),
|
||||
})
|
||||
|
||||
export type FlowVersionMetadata = Static<typeof FlowVersionMetadata>
|
||||
|
||||
61
activepieces-fork/packages/shared/src/lib/flows/flow.ts
Executable file
61
activepieces-fork/packages/shared/src/lib/flows/flow.ts
Executable file
@@ -0,0 +1,61 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { BaseModelSchema, Nullable } from '../common/base-model'
|
||||
import { ApId } from '../common/id-generator'
|
||||
import { Metadata } from '../common/metadata'
|
||||
import { TriggerSource, WebhookHandshakeConfiguration } from '../trigger'
|
||||
import { FlowVersion } from './flow-version'
|
||||
|
||||
export type FlowId = ApId
|
||||
export enum FlowStatus {
|
||||
ENABLED = 'ENABLED',
|
||||
DISABLED = 'DISABLED',
|
||||
}
|
||||
|
||||
export enum FlowOperationStatus {
|
||||
NONE = 'NONE',
|
||||
DELETING = 'DELETING',
|
||||
ENABLING = 'ENABLING',
|
||||
DISABLING = 'DISABLING',
|
||||
}
|
||||
|
||||
export const flowExecutionStateKey = (flowId: FlowId) => `flow-execution-state:${flowId}`
|
||||
|
||||
export type FlowExecutionState = {
|
||||
exists: false
|
||||
} | {
|
||||
exists: true
|
||||
handshakeConfiguration: WebhookHandshakeConfiguration | undefined
|
||||
flow: Flow
|
||||
platformId: string
|
||||
}
|
||||
export const Flow = Type.Object({
|
||||
...BaseModelSchema,
|
||||
projectId: Type.String(),
|
||||
externalId: Type.String(),
|
||||
folderId: Nullable(Type.String()),
|
||||
status: Type.Enum(FlowStatus),
|
||||
publishedVersionId: Nullable(Type.String()),
|
||||
metadata: Nullable(Metadata),
|
||||
operationStatus: Type.Enum(FlowOperationStatus),
|
||||
timeSavedPerRun: Nullable(Type.Number()),
|
||||
})
|
||||
|
||||
export type Flow = Static<typeof Flow>
|
||||
export const PopulatedFlow = Type.Composite([
|
||||
Flow,
|
||||
Type.Object({
|
||||
version: FlowVersion,
|
||||
triggerSource: Type.Optional(Type.Pick(TriggerSource, ['schedule'])),
|
||||
}),
|
||||
])
|
||||
|
||||
export type PopulatedFlow = Static<typeof PopulatedFlow>
|
||||
|
||||
|
||||
export const PopulatedTriggerSource = Type.Composite([
|
||||
TriggerSource,
|
||||
Type.Object({
|
||||
flow: Flow,
|
||||
}),
|
||||
])
|
||||
export type PopulatedTriggerSource = Static<typeof PopulatedTriggerSource>
|
||||
@@ -0,0 +1,30 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { Cursor } from '../../common/seek-page'
|
||||
|
||||
export const CreateFolderRequest = Type.Object({
|
||||
displayName: Type.String(),
|
||||
projectId: Type.String(),
|
||||
})
|
||||
|
||||
export type CreateFolderRequest = Static<typeof CreateFolderRequest>
|
||||
|
||||
export const UpdateFolderRequest = Type.Object({
|
||||
displayName: Type.String(),
|
||||
})
|
||||
|
||||
export type UpdateFolderRequest = Static<typeof UpdateFolderRequest>
|
||||
|
||||
|
||||
export const DeleteFolderRequest = Type.Object({
|
||||
id: Type.String(),
|
||||
})
|
||||
|
||||
export type DeleteFlowRequest = Static<typeof DeleteFolderRequest>
|
||||
|
||||
export const ListFolderRequest = Type.Object({
|
||||
limit: Type.Optional(Type.Number({})),
|
||||
cursor: Type.Optional(Type.String({})),
|
||||
projectId: Type.String(),
|
||||
})
|
||||
|
||||
export type ListFolderRequest = Omit<Static<typeof ListFolderRequest>, 'cursor'> & { cursor: Cursor | undefined }
|
||||
@@ -0,0 +1,18 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { BaseModelSchema } from '../../common'
|
||||
|
||||
export type FolderId = string
|
||||
|
||||
export const Folder = Type.Object({
|
||||
...BaseModelSchema,
|
||||
id: Type.String(),
|
||||
projectId: Type.String(),
|
||||
displayName: Type.String(),
|
||||
displayOrder: Type.Number(),
|
||||
})
|
||||
|
||||
export const UncategorizedFolderId = 'NULL'
|
||||
export type Folder = Static<typeof Folder>
|
||||
|
||||
export type FolderDto = Folder & { numberOfFlows: number }
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import { Folder } from './folder'
|
||||
|
||||
export type FolderDto = Folder & { numberOfFlows: number }
|
||||
54
activepieces-fork/packages/shared/src/lib/flows/form.ts
Normal file
54
activepieces-fork/packages/shared/src/lib/flows/form.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
|
||||
export enum FormInputType {
|
||||
TEXT = 'text',
|
||||
FILE = 'file',
|
||||
TEXT_AREA = 'text_area',
|
||||
TOGGLE = 'toggle',
|
||||
}
|
||||
|
||||
export const FormInput = Type.Object({
|
||||
displayName: Type.String(),
|
||||
required: Type.Boolean(),
|
||||
description: Type.String(),
|
||||
type: Type.Enum(FormInputType),
|
||||
})
|
||||
|
||||
export type FormInput = Static<typeof FormInput>
|
||||
|
||||
|
||||
export const FormProps = Type.Object({
|
||||
inputs: Type.Array(FormInput),
|
||||
waitForResponse: Type.Boolean(),
|
||||
})
|
||||
|
||||
export type FormProps = Static<typeof FormProps>
|
||||
|
||||
export const FormResponse = Type.Object({
|
||||
id: Type.String(),
|
||||
title: Type.String(),
|
||||
props: FormProps,
|
||||
projectId: Type.String(),
|
||||
version: Type.String(),
|
||||
})
|
||||
|
||||
export type FormResponse = Static<typeof FormResponse>
|
||||
|
||||
export const ChatUIProps = Type.Object({
|
||||
botName: Type.String(),
|
||||
})
|
||||
|
||||
export type ChatUIProps = Static<typeof ChatUIProps>
|
||||
|
||||
export const ChatUIResponse = Type.Object({
|
||||
id: Type.String(),
|
||||
title: Type.String(),
|
||||
props: ChatUIProps,
|
||||
projectId: Type.String(),
|
||||
platformLogoUrl: Type.String(),
|
||||
platformName: Type.String(),
|
||||
})
|
||||
|
||||
export type ChatUIResponse = Static<typeof ChatUIResponse>
|
||||
|
||||
export const USE_DRAFT_QUERY_PARAM_NAME = 'useDraft'
|
||||
6
activepieces-fork/packages/shared/src/lib/flows/index.ts
Normal file
6
activepieces-fork/packages/shared/src/lib/flows/index.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export * from './form'
|
||||
export * from './step-file/step-file'
|
||||
export * from './sample-data'
|
||||
export * from './flow'
|
||||
export * from './test-trigger'
|
||||
export * from './properties'
|
||||
@@ -0,0 +1,82 @@
|
||||
import { applyFunctionToValuesSync, isString } from '../../common'
|
||||
import { FlowAction } from '../actions/action'
|
||||
import { FlowVersion } from '../flow-version'
|
||||
import { flowStructureUtil } from '../util/flow-structure-util'
|
||||
|
||||
|
||||
function mapToNewNames(flowVersion: FlowVersion, clonedActions: FlowAction[]): Record<string, string> {
|
||||
const existingNames = flowStructureUtil.getAllSteps(flowVersion.trigger)
|
||||
.map(step => step.name)
|
||||
|
||||
const oldStepNames = clonedActions.flatMap(clonedAction => flowStructureUtil.getAllSteps(clonedAction).map(step => step.name))
|
||||
|
||||
return oldStepNames.reduce((nameMap, oldName) => {
|
||||
const newName = flowStructureUtil.findUnusedName(existingNames)
|
||||
existingNames.push(newName)
|
||||
return { ...nameMap, [oldName]: newName }
|
||||
}, {} as Record<string, string>)
|
||||
}
|
||||
|
||||
type ReplaceOldStepNameWithNewOneProps = {
|
||||
input: string
|
||||
oldStepName: string
|
||||
newStepName: string
|
||||
}
|
||||
|
||||
function replaceOldStepNameWithNewOne({
|
||||
input,
|
||||
oldStepName,
|
||||
newStepName,
|
||||
}: ReplaceOldStepNameWithNewOneProps): string {
|
||||
const regex = /{{(.*?)}}/g // Regular expression to match strings inside {{ }}
|
||||
return input.replace(regex, (match, content) => {
|
||||
// Replace the content inside {{ }} using the provided function
|
||||
const replacedContent = content.replaceAll(
|
||||
new RegExp(`\\b${oldStepName}\\b`, 'g'),
|
||||
`${newStepName}`,
|
||||
)
|
||||
// Reconstruct the {{ }} with the replaced content
|
||||
return `{{${replacedContent}}}`
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function clone(step: FlowAction, oldNameToNewName: Record<string, string>): FlowAction {
|
||||
step.displayName = `${step.displayName} Copy`
|
||||
step.name = oldNameToNewName[step.name]
|
||||
if ('input' in step.settings) {
|
||||
Object.keys(oldNameToNewName).forEach((oldName) => {
|
||||
const settings = step.settings as { input: unknown }
|
||||
settings.input = applyFunctionToValuesSync(
|
||||
settings.input,
|
||||
(value: unknown) => {
|
||||
if (isString(value)) {
|
||||
return replaceOldStepNameWithNewOne({
|
||||
input: value,
|
||||
oldStepName: oldName,
|
||||
newStepName: oldNameToNewName[oldName],
|
||||
})
|
||||
}
|
||||
return value
|
||||
},
|
||||
)
|
||||
})
|
||||
}
|
||||
if (step.settings.sampleData) {
|
||||
step.settings = {
|
||||
...step.settings,
|
||||
sampleData: {
|
||||
...step.settings.sampleData,
|
||||
sampleDataFileId: undefined,
|
||||
sampleDataInputFileId: undefined,
|
||||
lastTestDate: undefined,
|
||||
},
|
||||
}
|
||||
}
|
||||
return step
|
||||
}
|
||||
|
||||
export const addActionUtils = {
|
||||
mapToNewNames,
|
||||
clone,
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
import { TypeCompiler } from '@sinclair/typebox/compiler'
|
||||
import { isNil } from '../../common'
|
||||
import { ActivepiecesError, ErrorCode } from '../../common/activepieces-error'
|
||||
import { FlowAction, FlowActionType, LoopOnItemsAction, RouterAction, SingleActionSchema } from '../actions/action'
|
||||
import { FlowVersion } from '../flow-version'
|
||||
import { flowStructureUtil, Step } from '../util/flow-structure-util'
|
||||
import { AddActionRequest, StepLocationRelativeToParent, UpdateActionRequest } from './index'
|
||||
|
||||
const actionSchemaValidator = TypeCompiler.Compile(SingleActionSchema)
|
||||
|
||||
type ActionCreationProps = {
|
||||
nextAction?: FlowAction
|
||||
}
|
||||
|
||||
function createAction(request: UpdateActionRequest, {
|
||||
nextAction,
|
||||
}: ActionCreationProps): FlowAction {
|
||||
const baseProperties = {
|
||||
displayName: request.displayName,
|
||||
name: request.name,
|
||||
valid: false,
|
||||
skip: request.skip,
|
||||
settings: {
|
||||
...request.settings,
|
||||
customLogoUrl: request.settings.customLogoUrl,
|
||||
},
|
||||
nextAction,
|
||||
}
|
||||
let action: FlowAction
|
||||
switch (request.type) {
|
||||
case FlowActionType.ROUTER:
|
||||
action = {
|
||||
...baseProperties,
|
||||
type: FlowActionType.ROUTER,
|
||||
settings: request.settings,
|
||||
children: request.settings.branches.map(() => null),
|
||||
}
|
||||
|
||||
break
|
||||
case FlowActionType.LOOP_ON_ITEMS:
|
||||
action = {
|
||||
...baseProperties,
|
||||
type: FlowActionType.LOOP_ON_ITEMS,
|
||||
settings: request.settings,
|
||||
}
|
||||
break
|
||||
case FlowActionType.PIECE:
|
||||
action = {
|
||||
...baseProperties,
|
||||
type: FlowActionType.PIECE,
|
||||
settings: request.settings,
|
||||
}
|
||||
break
|
||||
case FlowActionType.CODE:
|
||||
action = {
|
||||
...baseProperties,
|
||||
type: FlowActionType.CODE,
|
||||
settings: request.settings,
|
||||
}
|
||||
break
|
||||
}
|
||||
const valid = (isNil(request.valid) ? true : request.valid) && actionSchemaValidator.Check(action)
|
||||
return {
|
||||
...action,
|
||||
valid,
|
||||
}
|
||||
}
|
||||
|
||||
function handleLoopOnItems(parentStep: LoopOnItemsAction, request: AddActionRequest): Step {
|
||||
if (request.stepLocationRelativeToParent === StepLocationRelativeToParent.INSIDE_LOOP) {
|
||||
parentStep.firstLoopAction = createAction(request.action, {
|
||||
nextAction: parentStep.firstLoopAction,
|
||||
})
|
||||
}
|
||||
else if (request.stepLocationRelativeToParent === StepLocationRelativeToParent.AFTER) {
|
||||
parentStep.nextAction = createAction(request.action, {
|
||||
nextAction: parentStep.nextAction,
|
||||
})
|
||||
}
|
||||
else {
|
||||
throw new ActivepiecesError(
|
||||
{
|
||||
code: ErrorCode.FLOW_OPERATION_INVALID,
|
||||
params: {
|
||||
message: `Loop step parent ${request.stepLocationRelativeToParent} not found`,
|
||||
},
|
||||
})
|
||||
}
|
||||
return parentStep
|
||||
}
|
||||
|
||||
function handleRouter(parentStep: RouterAction, request: AddActionRequest): Step {
|
||||
if (request.stepLocationRelativeToParent === StepLocationRelativeToParent.INSIDE_BRANCH && !isNil(request.branchIndex)) {
|
||||
parentStep.children[request.branchIndex] = createAction(request.action, {
|
||||
nextAction: parentStep.children[request.branchIndex] ?? undefined,
|
||||
})
|
||||
}
|
||||
else if (request.stepLocationRelativeToParent === StepLocationRelativeToParent.AFTER) {
|
||||
parentStep.nextAction = createAction(request.action, {
|
||||
nextAction: parentStep.nextAction,
|
||||
})
|
||||
}
|
||||
else {
|
||||
throw new ActivepiecesError({
|
||||
code: ErrorCode.FLOW_OPERATION_INVALID,
|
||||
params: {
|
||||
message: `Router step parent ${request.stepLocationRelativeToParent} not found`,
|
||||
},
|
||||
})
|
||||
}
|
||||
return parentStep
|
||||
}
|
||||
|
||||
function _addAction(flowVersion: FlowVersion, request: AddActionRequest): FlowVersion {
|
||||
return flowStructureUtil.transferFlow(flowVersion, (parentStep: Step) => {
|
||||
if (parentStep.name !== request.parentStep) {
|
||||
return parentStep
|
||||
}
|
||||
switch (parentStep.type) {
|
||||
case FlowActionType.LOOP_ON_ITEMS:
|
||||
return handleLoopOnItems(parentStep, request)
|
||||
case FlowActionType.ROUTER:
|
||||
return handleRouter(parentStep, request)
|
||||
default: {
|
||||
parentStep.nextAction = createAction(request.action, {
|
||||
nextAction: parentStep.nextAction,
|
||||
})
|
||||
return parentStep
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export { _addAction }
|
||||
@@ -0,0 +1,26 @@
|
||||
import { insertAt } from '../../common'
|
||||
import { FlowActionType, RouterAction } from '../actions/action'
|
||||
import { FlowVersion } from '../flow-version'
|
||||
import { flowStructureUtil } from '../util/flow-structure-util'
|
||||
import { AddBranchRequest } from '.'
|
||||
|
||||
|
||||
function _addBranch(flowVersion: FlowVersion, request: AddBranchRequest): FlowVersion {
|
||||
return flowStructureUtil.transferFlow(flowVersion, (parentStep) => {
|
||||
if (parentStep.name !== request.stepName || parentStep.type !== FlowActionType.ROUTER) {
|
||||
return parentStep
|
||||
}
|
||||
const routerAction = parentStep as RouterAction
|
||||
return {
|
||||
...routerAction,
|
||||
settings: {
|
||||
...routerAction.settings,
|
||||
branches: insertAt(routerAction.settings.branches, request.branchIndex, flowStructureUtil.createBranch(request.branchName, request.conditions)),
|
||||
},
|
||||
children: insertAt(routerAction.children, request.branchIndex, null),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
export { _addBranch }
|
||||
@@ -0,0 +1,19 @@
|
||||
import { FlowAction } from '../actions/action'
|
||||
import { FlowVersion } from '../flow-version'
|
||||
import { flowStructureUtil } from '../util/flow-structure-util'
|
||||
import { _getImportOperations } from './import-flow'
|
||||
|
||||
export function _getActionsForCopy(selectedSteps: string[], flowVersion: FlowVersion): FlowAction[] {
|
||||
const allSteps = flowStructureUtil.getAllSteps(flowVersion.trigger)
|
||||
const actionsToCopy = selectedSteps
|
||||
.map((stepName) => flowStructureUtil.getStepOrThrow(stepName, flowVersion.trigger))
|
||||
.filter((step) => flowStructureUtil.isAction(step.type))
|
||||
return actionsToCopy
|
||||
.filter(step => !actionsToCopy.filter(parent => parent.name !== step.name).some(parent => flowStructureUtil.isChildOf(parent, step.name)))
|
||||
.map(step => {
|
||||
const clonedAction = JSON.parse(JSON.stringify(step))
|
||||
clonedAction.nextAction = undefined
|
||||
return clonedAction
|
||||
})
|
||||
.sort((a, b) => allSteps.indexOf(a) - allSteps.indexOf(b)) as FlowAction[]
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import { FlowAction, FlowActionType } from '../actions/action'
|
||||
import { FlowVersion } from '../flow-version'
|
||||
import { flowStructureUtil } from '../util/flow-structure-util'
|
||||
import { DeleteActionRequest } from './index'
|
||||
|
||||
function _deleteAction(
|
||||
flowVersion: FlowVersion,
|
||||
request: DeleteActionRequest,
|
||||
): FlowVersion {
|
||||
let clonedVersion: FlowVersion = flowVersion
|
||||
for (const name of request.names) {
|
||||
clonedVersion = flowStructureUtil.transferFlow(clonedVersion, (parentStep) => {
|
||||
if (parentStep.nextAction && parentStep.nextAction.name === name) {
|
||||
const stepToUpdate: FlowAction = parentStep.nextAction
|
||||
parentStep.nextAction = stepToUpdate.nextAction
|
||||
}
|
||||
switch (parentStep.type) {
|
||||
case FlowActionType.LOOP_ON_ITEMS: {
|
||||
if (
|
||||
parentStep.firstLoopAction &&
|
||||
parentStep.firstLoopAction.name === name
|
||||
) {
|
||||
const stepToUpdate: FlowAction = parentStep.firstLoopAction
|
||||
parentStep.firstLoopAction = stepToUpdate.nextAction
|
||||
}
|
||||
break
|
||||
}
|
||||
case FlowActionType.ROUTER: {
|
||||
parentStep.children = parentStep.children.map((child) => {
|
||||
if (child && child.name === name) {
|
||||
return child.nextAction ?? null
|
||||
}
|
||||
return child
|
||||
})
|
||||
break
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
return parentStep
|
||||
})
|
||||
}
|
||||
return clonedVersion
|
||||
}
|
||||
|
||||
export { _deleteAction }
|
||||
@@ -0,0 +1,23 @@
|
||||
import { FlowActionType, RouterAction } from '../actions/action'
|
||||
import { FlowVersion } from '../flow-version'
|
||||
import { flowStructureUtil } from '../util/flow-structure-util'
|
||||
import { DeleteBranchRequest } from '.'
|
||||
|
||||
function _deleteBranch(flowVersion: FlowVersion, request: DeleteBranchRequest): FlowVersion {
|
||||
return flowStructureUtil.transferFlow(flowVersion, (parentStep) => {
|
||||
if (parentStep.name !== request.stepName || parentStep.type !== FlowActionType.ROUTER) {
|
||||
return parentStep
|
||||
}
|
||||
const routerAction = parentStep as RouterAction
|
||||
return {
|
||||
...routerAction,
|
||||
settings: {
|
||||
...routerAction.settings,
|
||||
branches: routerAction.settings.branches.filter((_, index) => index !== request.branchIndex),
|
||||
},
|
||||
children: routerAction.children.filter((_, index) => index !== request.branchIndex),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export { _deleteBranch }
|
||||
@@ -0,0 +1,74 @@
|
||||
import { isNil } from '../../common'
|
||||
import { BranchExecutionType, FlowAction, RouterAction } from '../actions/action'
|
||||
import { FlowVersion } from '../flow-version'
|
||||
import { flowStructureUtil } from '../util/flow-structure-util'
|
||||
import { addActionUtils } from './add-action-util'
|
||||
import { _getImportOperations } from './import-flow'
|
||||
import { FlowOperationRequest, FlowOperationType, StepLocationRelativeToParent } from '.'
|
||||
|
||||
|
||||
function _duplicateStep(stepName: string, flowVersion: FlowVersion): FlowOperationRequest[] {
|
||||
const clonedAction: FlowAction = JSON.parse(JSON.stringify(flowStructureUtil.getActionOrThrow(stepName, flowVersion.trigger)))
|
||||
const clonedActionWithoutNextAction = {
|
||||
...clonedAction,
|
||||
nextAction: undefined,
|
||||
}
|
||||
const oldNameToNewName = addActionUtils.mapToNewNames(flowVersion, [clonedActionWithoutNextAction])
|
||||
const clonedSubflow = flowStructureUtil.transferStep(clonedActionWithoutNextAction, (step: FlowAction) => {
|
||||
return addActionUtils.clone(step, oldNameToNewName)
|
||||
})
|
||||
const importOperations = _getImportOperations(clonedSubflow)
|
||||
|
||||
return [
|
||||
{
|
||||
type: FlowOperationType.ADD_ACTION,
|
||||
request: {
|
||||
action: clonedSubflow as FlowAction,
|
||||
parentStep: stepName,
|
||||
stepLocationRelativeToParent: StepLocationRelativeToParent.AFTER,
|
||||
},
|
||||
},
|
||||
...importOperations,
|
||||
]
|
||||
}
|
||||
|
||||
function _duplicateBranch(
|
||||
routerName: string,
|
||||
childIndex: number,
|
||||
flowVersion: FlowVersion,
|
||||
): FlowOperationRequest[] {
|
||||
const router = flowStructureUtil.getActionOrThrow(routerName, flowVersion.trigger)
|
||||
const clonedRouter: RouterAction = JSON.parse(JSON.stringify(router))
|
||||
const operations: FlowOperationRequest[] = [{
|
||||
type: FlowOperationType.ADD_BRANCH,
|
||||
request: {
|
||||
branchName: `${clonedRouter.settings.branches[childIndex].branchName} Copy`,
|
||||
branchIndex: childIndex + 1,
|
||||
stepName: routerName,
|
||||
conditions: clonedRouter.settings.branches[childIndex].branchType === BranchExecutionType.CONDITION ? clonedRouter.settings.branches[childIndex].conditions : undefined,
|
||||
},
|
||||
}]
|
||||
|
||||
const childRouter = clonedRouter.children[childIndex]
|
||||
if (!isNil(childRouter)) {
|
||||
const oldNameToNewName = addActionUtils.mapToNewNames(flowVersion, [childRouter])
|
||||
const clonedSubflow = flowStructureUtil.transferStep(childRouter, (step: FlowAction) => {
|
||||
return addActionUtils.clone(step, oldNameToNewName)
|
||||
})
|
||||
const importOperations = _getImportOperations(clonedSubflow)
|
||||
operations.push({
|
||||
type: FlowOperationType.ADD_ACTION,
|
||||
request: {
|
||||
stepLocationRelativeToParent: StepLocationRelativeToParent.INSIDE_BRANCH,
|
||||
action: clonedSubflow as FlowAction,
|
||||
parentStep: routerName,
|
||||
branchIndex: childIndex + 1,
|
||||
},
|
||||
})
|
||||
operations.push(...importOperations)
|
||||
}
|
||||
|
||||
return operations
|
||||
}
|
||||
|
||||
export { _duplicateStep, _duplicateBranch }
|
||||
@@ -0,0 +1,130 @@
|
||||
import { isNil } from '../../common'
|
||||
import { FlowAction, FlowActionType } from '../actions/action'
|
||||
import { FlowVersion } from '../flow-version'
|
||||
import { FlowTrigger, FlowTriggerType } from '../triggers/trigger'
|
||||
import { flowStructureUtil } from '../util/flow-structure-util'
|
||||
import { FlowOperationRequest, FlowOperationType, ImportFlowRequest, StepLocationRelativeToParent } from './index'
|
||||
|
||||
function createDeleteActionOperation(actionName: string): FlowOperationRequest {
|
||||
return {
|
||||
type: FlowOperationType.DELETE_ACTION,
|
||||
request: { names: [actionName] },
|
||||
}
|
||||
}
|
||||
|
||||
function createUpdateTriggerOperation(trigger: FlowTrigger): FlowOperationRequest {
|
||||
return {
|
||||
type: FlowOperationType.UPDATE_TRIGGER,
|
||||
request: trigger,
|
||||
}
|
||||
}
|
||||
|
||||
function createChangeNameOperation(displayName: string): FlowOperationRequest {
|
||||
return {
|
||||
type: FlowOperationType.CHANGE_NAME,
|
||||
request: { displayName },
|
||||
}
|
||||
}
|
||||
|
||||
function _getImportOperations(step: FlowAction | FlowTrigger | undefined): FlowOperationRequest[] {
|
||||
const steps: FlowOperationRequest[] = []
|
||||
while (step) {
|
||||
if (step.nextAction) {
|
||||
steps.push({
|
||||
type: FlowOperationType.ADD_ACTION,
|
||||
request: {
|
||||
parentStep: step?.name ?? '',
|
||||
stepLocationRelativeToParent: StepLocationRelativeToParent.AFTER,
|
||||
action: removeAnySubsequentAction(step.nextAction),
|
||||
},
|
||||
})
|
||||
}
|
||||
switch (step.type) {
|
||||
case FlowActionType.LOOP_ON_ITEMS: {
|
||||
if (step.firstLoopAction) {
|
||||
steps.push({
|
||||
type: FlowOperationType.ADD_ACTION,
|
||||
request: {
|
||||
parentStep: step.name,
|
||||
stepLocationRelativeToParent: StepLocationRelativeToParent.INSIDE_LOOP,
|
||||
action: removeAnySubsequentAction(step.firstLoopAction),
|
||||
},
|
||||
})
|
||||
steps.push(..._getImportOperations(step.firstLoopAction))
|
||||
}
|
||||
break
|
||||
}
|
||||
case FlowActionType.ROUTER: {
|
||||
if (step.children) {
|
||||
for (const [index, child] of step.children.entries()) {
|
||||
if (!isNil(child)) {
|
||||
steps.push({
|
||||
type: FlowOperationType.ADD_ACTION,
|
||||
request: {
|
||||
parentStep: step.name,
|
||||
stepLocationRelativeToParent: StepLocationRelativeToParent.INSIDE_BRANCH,
|
||||
branchIndex: index,
|
||||
action: removeAnySubsequentAction(child),
|
||||
},
|
||||
})
|
||||
steps.push(..._getImportOperations(child))
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
case FlowActionType.CODE:
|
||||
case FlowActionType.PIECE:
|
||||
case FlowTriggerType.PIECE:
|
||||
case FlowTriggerType.EMPTY: {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
step = step.nextAction
|
||||
}
|
||||
return steps
|
||||
}
|
||||
|
||||
function removeAnySubsequentAction(action: FlowAction): FlowAction {
|
||||
const clonedAction: FlowAction = JSON.parse(JSON.stringify(action))
|
||||
switch (clonedAction.type) {
|
||||
case FlowActionType.ROUTER: {
|
||||
clonedAction.children = clonedAction.children.map((child: FlowAction | null) => {
|
||||
if (isNil(child)) {
|
||||
return null
|
||||
}
|
||||
return removeAnySubsequentAction(child)
|
||||
})
|
||||
break
|
||||
}
|
||||
case FlowActionType.LOOP_ON_ITEMS: {
|
||||
delete clonedAction.firstLoopAction
|
||||
break
|
||||
}
|
||||
case FlowActionType.PIECE:
|
||||
case FlowActionType.CODE:
|
||||
break
|
||||
}
|
||||
delete clonedAction.nextAction
|
||||
return clonedAction
|
||||
}
|
||||
|
||||
function _importFlow(flowVersion: FlowVersion, request: ImportFlowRequest): FlowOperationRequest[] {
|
||||
const existingActions = flowStructureUtil.getAllNextActionsWithoutChildren(flowVersion.trigger)
|
||||
|
||||
const deleteOperations = existingActions.map(action =>
|
||||
createDeleteActionOperation(action.name),
|
||||
)
|
||||
|
||||
const importOperations = _getImportOperations(request.trigger)
|
||||
|
||||
return [
|
||||
createChangeNameOperation(request.displayName),
|
||||
...deleteOperations,
|
||||
createUpdateTriggerOperation(request.trigger),
|
||||
...importOperations,
|
||||
]
|
||||
}
|
||||
|
||||
export { _importFlow, _getImportOperations }
|
||||
@@ -0,0 +1,462 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { Nullable } from '../../common'
|
||||
import { Metadata } from '../../common/metadata'
|
||||
import { BranchCondition, CodeActionSchema, LoopOnItemsActionSchema, PieceActionSchema, RouterActionSchema } from '../actions/action'
|
||||
import { FlowStatus } from '../flow'
|
||||
import { FlowVersion, FlowVersionState } from '../flow-version'
|
||||
import { SaveSampleDataRequest } from '../sample-data'
|
||||
import { EmptyTrigger, FlowTrigger, FlowTriggerType, PieceTrigger } from '../triggers/trigger'
|
||||
import { flowPieceUtil } from '../util/flow-piece-util'
|
||||
import { flowStructureUtil } from '../util/flow-structure-util'
|
||||
import { _addAction } from './add-action'
|
||||
import { _addBranch } from './add-branch'
|
||||
import { _getActionsForCopy } from './copy-action-operations'
|
||||
import { _deleteAction } from './delete-action'
|
||||
import { _deleteBranch } from './delete-branch'
|
||||
import { _duplicateBranch, _duplicateStep } from './duplicate-step'
|
||||
import { _importFlow } from './import-flow'
|
||||
import { _moveAction } from './move-action'
|
||||
import { _moveBranch } from './move-branch'
|
||||
import { _getOperationsForPaste } from './paste-operations'
|
||||
import { _skipAction } from './skip-action'
|
||||
import { _updateAction } from './update-action'
|
||||
import { _updateTrigger } from './update-trigger'
|
||||
|
||||
|
||||
export enum FlowOperationType {
|
||||
LOCK_AND_PUBLISH = 'LOCK_AND_PUBLISH',
|
||||
CHANGE_STATUS = 'CHANGE_STATUS',
|
||||
LOCK_FLOW = 'LOCK_FLOW',
|
||||
CHANGE_FOLDER = 'CHANGE_FOLDER',
|
||||
CHANGE_NAME = 'CHANGE_NAME',
|
||||
MOVE_ACTION = 'MOVE_ACTION',
|
||||
IMPORT_FLOW = 'IMPORT_FLOW',
|
||||
UPDATE_TRIGGER = 'UPDATE_TRIGGER',
|
||||
ADD_ACTION = 'ADD_ACTION',
|
||||
UPDATE_ACTION = 'UPDATE_ACTION',
|
||||
DELETE_ACTION = 'DELETE_ACTION',
|
||||
DUPLICATE_ACTION = 'DUPLICATE_ACTION',
|
||||
USE_AS_DRAFT = 'USE_AS_DRAFT',
|
||||
DELETE_BRANCH = 'DELETE_BRANCH',
|
||||
ADD_BRANCH = 'ADD_BRANCH',
|
||||
DUPLICATE_BRANCH = 'DUPLICATE_BRANCH',
|
||||
SET_SKIP_ACTION = 'SET_SKIP_ACTION',
|
||||
UPDATE_METADATA = 'UPDATE_METADATA',
|
||||
MOVE_BRANCH = 'MOVE_BRANCH',
|
||||
SAVE_SAMPLE_DATA = 'SAVE_SAMPLE_DATA',
|
||||
UPDATE_MINUTES_SAVED = 'UPDATE_MINUTES_SAVED',
|
||||
}
|
||||
|
||||
export const DeleteBranchRequest = Type.Object({
|
||||
branchIndex: Type.Number(),
|
||||
stepName: Type.String(),
|
||||
})
|
||||
export const AddBranchRequest = Type.Object({
|
||||
branchIndex: Type.Number(),
|
||||
stepName: Type.String(),
|
||||
conditions: Type.Optional(Type.Array(Type.Array(BranchCondition))),
|
||||
branchName: Type.String(),
|
||||
})
|
||||
export const MoveBranchRequest = Type.Object({
|
||||
sourceBranchIndex: Type.Number(),
|
||||
targetBranchIndex: Type.Number(),
|
||||
stepName: Type.String(),
|
||||
})
|
||||
export type MoveBranchRequest = Static<typeof MoveBranchRequest>
|
||||
|
||||
export const SkipActionRequest = Type.Object({
|
||||
names: Type.Array(Type.String()),
|
||||
skip: Type.Boolean(),
|
||||
})
|
||||
|
||||
export type SkipActionRequest = Static<typeof SkipActionRequest>
|
||||
|
||||
export const DuplicateBranchRequest = Type.Object({
|
||||
branchIndex: Type.Number(),
|
||||
stepName: Type.String(),
|
||||
})
|
||||
export type DeleteBranchRequest = Static<typeof DeleteBranchRequest>
|
||||
export type AddBranchRequest = Static<typeof AddBranchRequest>
|
||||
export type DuplicateBranchRequest = Static<typeof DuplicateBranchRequest>
|
||||
|
||||
export enum StepLocationRelativeToParent {
|
||||
AFTER = 'AFTER',
|
||||
INSIDE_LOOP = 'INSIDE_LOOP',
|
||||
INSIDE_BRANCH = 'INSIDE_BRANCH',
|
||||
}
|
||||
|
||||
export const UseAsDraftRequest = Type.Object({
|
||||
versionId: Type.String(),
|
||||
})
|
||||
export type UseAsDraftRequest = Static<typeof UseAsDraftRequest>
|
||||
|
||||
export const LockFlowRequest = Type.Object({})
|
||||
|
||||
export type LockFlowRequest = Static<typeof LockFlowRequest>
|
||||
|
||||
export const ImportFlowRequest = Type.Object({
|
||||
displayName: Type.String({}),
|
||||
trigger: FlowTrigger,
|
||||
schemaVersion: Nullable(Type.String()),
|
||||
})
|
||||
|
||||
export type ImportFlowRequest = Static<typeof ImportFlowRequest>
|
||||
|
||||
export const ChangeFolderRequest = Type.Object({
|
||||
folderId: Nullable(Type.String({})),
|
||||
})
|
||||
|
||||
export type ChangeFolderRequest = Static<typeof ChangeFolderRequest>
|
||||
|
||||
export const ChangeNameRequest = Type.Object({
|
||||
displayName: Type.String({}),
|
||||
})
|
||||
|
||||
export type ChangeNameRequest = Static<typeof ChangeNameRequest>
|
||||
|
||||
|
||||
export const DeleteActionRequest = Type.Object({
|
||||
names: Type.Array(Type.String()),
|
||||
})
|
||||
|
||||
export type DeleteActionRequest = Static<typeof DeleteActionRequest>
|
||||
|
||||
export const UpdateActionRequest = Type.Union([
|
||||
CodeActionSchema,
|
||||
LoopOnItemsActionSchema,
|
||||
PieceActionSchema,
|
||||
RouterActionSchema,
|
||||
])
|
||||
|
||||
export type UpdateActionRequest = Static<typeof UpdateActionRequest>
|
||||
|
||||
export const DuplicateStepRequest = Type.Object({
|
||||
stepName: Type.String(),
|
||||
})
|
||||
|
||||
export type DuplicateStepRequest = Static<typeof DuplicateStepRequest>
|
||||
|
||||
export const MoveActionRequest = Type.Object({
|
||||
name: Type.String(),
|
||||
newParentStep: Type.String(),
|
||||
stepLocationRelativeToNewParent: Type.Optional(
|
||||
Type.Enum(StepLocationRelativeToParent),
|
||||
),
|
||||
branchIndex: Type.Optional(Type.Number()),
|
||||
})
|
||||
export type MoveActionRequest = Static<typeof MoveActionRequest>
|
||||
|
||||
export const AddActionRequest = Type.Object({
|
||||
parentStep: Type.String(),
|
||||
stepLocationRelativeToParent: Type.Optional(
|
||||
Type.Enum(StepLocationRelativeToParent),
|
||||
),
|
||||
branchIndex: Type.Optional(Type.Number()),
|
||||
action: UpdateActionRequest,
|
||||
})
|
||||
export type AddActionRequest = Static<typeof AddActionRequest>
|
||||
|
||||
export const UpdateTriggerRequest = Type.Union([EmptyTrigger, PieceTrigger])
|
||||
export type UpdateTriggerRequest = Static<typeof UpdateTriggerRequest>
|
||||
|
||||
export const UpdateFlowStatusRequest = Type.Object({
|
||||
status: Type.Enum(FlowStatus),
|
||||
})
|
||||
export type UpdateFlowStatusRequest = Static<typeof UpdateFlowStatusRequest>
|
||||
|
||||
export const ChangePublishedVersionIdRequest = Type.Object({
|
||||
status: Type.Optional(Type.Enum(FlowStatus)),
|
||||
})
|
||||
export type ChangePublishedVersionIdRequest = Static<
|
||||
typeof ChangePublishedVersionIdRequest
|
||||
>
|
||||
|
||||
export const UpdateMetadataRequest = Type.Object({
|
||||
metadata: Nullable(Metadata),
|
||||
})
|
||||
export type UpdateMetadataRequest = Static<typeof UpdateMetadataRequest>
|
||||
|
||||
export const UpdateMinutesSavedRequest = Type.Object({
|
||||
timeSavedPerRun: Nullable(Type.Number()),
|
||||
})
|
||||
export type UpdateMinutesSavedRequest = Static<typeof UpdateMinutesSavedRequest>
|
||||
|
||||
export const FlowOperationRequest = Type.Union([
|
||||
Type.Object(
|
||||
{
|
||||
type: Type.Literal(FlowOperationType.MOVE_ACTION),
|
||||
request: MoveActionRequest,
|
||||
},
|
||||
{
|
||||
title: 'Move Action',
|
||||
},
|
||||
),
|
||||
Type.Object(
|
||||
{
|
||||
type: Type.Literal(FlowOperationType.CHANGE_STATUS),
|
||||
request: UpdateFlowStatusRequest,
|
||||
},
|
||||
{
|
||||
title: 'Change Status',
|
||||
},
|
||||
),
|
||||
Type.Object(
|
||||
{
|
||||
type: Type.Literal(FlowOperationType.LOCK_AND_PUBLISH),
|
||||
request: ChangePublishedVersionIdRequest,
|
||||
},
|
||||
{
|
||||
title: 'Lock and Publish',
|
||||
},
|
||||
),
|
||||
Type.Object(
|
||||
{
|
||||
type: Type.Literal(FlowOperationType.USE_AS_DRAFT),
|
||||
request: UseAsDraftRequest,
|
||||
},
|
||||
{
|
||||
title: 'Copy as Draft',
|
||||
},
|
||||
),
|
||||
Type.Object(
|
||||
{
|
||||
type: Type.Literal(FlowOperationType.LOCK_FLOW),
|
||||
request: LockFlowRequest,
|
||||
},
|
||||
{
|
||||
title: 'Lock Flow',
|
||||
},
|
||||
),
|
||||
Type.Object(
|
||||
{
|
||||
type: Type.Literal(FlowOperationType.IMPORT_FLOW),
|
||||
request: ImportFlowRequest,
|
||||
},
|
||||
{
|
||||
title: 'Import Flow',
|
||||
},
|
||||
),
|
||||
Type.Object(
|
||||
{
|
||||
type: Type.Literal(FlowOperationType.CHANGE_NAME),
|
||||
request: ChangeNameRequest,
|
||||
},
|
||||
{
|
||||
title: 'Change Name',
|
||||
},
|
||||
),
|
||||
Type.Object(
|
||||
{
|
||||
type: Type.Literal(FlowOperationType.DELETE_ACTION),
|
||||
request: DeleteActionRequest,
|
||||
},
|
||||
{
|
||||
title: 'Delete Action',
|
||||
},
|
||||
),
|
||||
Type.Object(
|
||||
{
|
||||
type: Type.Literal(FlowOperationType.UPDATE_ACTION),
|
||||
request: UpdateActionRequest,
|
||||
},
|
||||
{
|
||||
title: 'Update Action',
|
||||
},
|
||||
),
|
||||
Type.Object(
|
||||
{
|
||||
type: Type.Literal(FlowOperationType.ADD_ACTION),
|
||||
request: AddActionRequest,
|
||||
},
|
||||
{
|
||||
title: 'Add Action',
|
||||
},
|
||||
),
|
||||
Type.Object(
|
||||
{
|
||||
type: Type.Literal(FlowOperationType.UPDATE_TRIGGER),
|
||||
request: UpdateTriggerRequest,
|
||||
},
|
||||
{
|
||||
title: 'Update Trigger',
|
||||
},
|
||||
),
|
||||
Type.Object(
|
||||
{
|
||||
type: Type.Literal(FlowOperationType.CHANGE_FOLDER),
|
||||
request: ChangeFolderRequest,
|
||||
},
|
||||
{
|
||||
title: 'Change Folder',
|
||||
},
|
||||
),
|
||||
Type.Object(
|
||||
{
|
||||
type: Type.Literal(FlowOperationType.DUPLICATE_ACTION),
|
||||
request: DuplicateStepRequest,
|
||||
},
|
||||
{
|
||||
title: 'Duplicate Action',
|
||||
},
|
||||
),
|
||||
Type.Object(
|
||||
{
|
||||
type: Type.Literal(FlowOperationType.DELETE_BRANCH),
|
||||
request: DeleteBranchRequest,
|
||||
},
|
||||
{
|
||||
title: 'Delete Branch',
|
||||
},
|
||||
),
|
||||
Type.Object(
|
||||
{
|
||||
type: Type.Literal(FlowOperationType.ADD_BRANCH),
|
||||
request: AddBranchRequest,
|
||||
},
|
||||
{
|
||||
title: 'Add Branch',
|
||||
},
|
||||
),
|
||||
Type.Object(
|
||||
{
|
||||
type: Type.Literal(FlowOperationType.DUPLICATE_BRANCH),
|
||||
request: DuplicateBranchRequest,
|
||||
},
|
||||
{
|
||||
title: 'Duplicate Branch',
|
||||
},
|
||||
),
|
||||
Type.Object(
|
||||
{
|
||||
type: Type.Literal(FlowOperationType.SET_SKIP_ACTION),
|
||||
request: SkipActionRequest,
|
||||
},
|
||||
{
|
||||
title: 'Skip Action',
|
||||
},
|
||||
),
|
||||
Type.Object(
|
||||
{
|
||||
type: Type.Literal(FlowOperationType.UPDATE_METADATA),
|
||||
request: UpdateMetadataRequest,
|
||||
},
|
||||
{
|
||||
title: 'Update Metadata',
|
||||
},
|
||||
),
|
||||
Type.Object(
|
||||
{
|
||||
type: Type.Literal(FlowOperationType.MOVE_BRANCH),
|
||||
request: MoveBranchRequest,
|
||||
},
|
||||
),
|
||||
Type.Object(
|
||||
{
|
||||
type: Type.Literal(FlowOperationType.SAVE_SAMPLE_DATA),
|
||||
request: SaveSampleDataRequest,
|
||||
},
|
||||
),
|
||||
Type.Object(
|
||||
{
|
||||
type: Type.Literal(FlowOperationType.UPDATE_MINUTES_SAVED),
|
||||
request: UpdateMinutesSavedRequest,
|
||||
},
|
||||
{
|
||||
title: 'Update Minutes Saved',
|
||||
},
|
||||
),
|
||||
])
|
||||
|
||||
export type FlowOperationRequest = Static<typeof FlowOperationRequest>
|
||||
|
||||
export const flowOperations = {
|
||||
getActionsForCopy: _getActionsForCopy,
|
||||
getOperationsForPaste: _getOperationsForPaste,
|
||||
apply(flowVersion: FlowVersion, operation: FlowOperationRequest): FlowVersion {
|
||||
let clonedVersion: FlowVersion = JSON.parse(JSON.stringify(flowVersion))
|
||||
switch (operation.type) {
|
||||
case FlowOperationType.MOVE_ACTION: {
|
||||
const operations: FlowOperationRequest[] = _moveAction(clonedVersion, operation.request)
|
||||
operations.forEach((operation) => {
|
||||
clonedVersion = flowOperations.apply(clonedVersion, operation)
|
||||
})
|
||||
clonedVersion = flowPieceUtil.makeFlowAutoUpgradable(clonedVersion)
|
||||
break
|
||||
}
|
||||
case FlowOperationType.CHANGE_NAME:
|
||||
clonedVersion.displayName = operation.request.displayName
|
||||
break
|
||||
case FlowOperationType.DUPLICATE_BRANCH: {
|
||||
const operations = _duplicateBranch(operation.request.stepName, operation.request.branchIndex, clonedVersion)
|
||||
operations.forEach((operation) => {
|
||||
clonedVersion = flowOperations.apply(clonedVersion, operation)
|
||||
})
|
||||
break
|
||||
}
|
||||
case FlowOperationType.DUPLICATE_ACTION: {
|
||||
const operations = _duplicateStep(operation.request.stepName, clonedVersion)
|
||||
operations.forEach((operation) => {
|
||||
clonedVersion = flowOperations.apply(clonedVersion, operation)
|
||||
})
|
||||
break
|
||||
}
|
||||
case FlowOperationType.LOCK_FLOW:
|
||||
clonedVersion.state = FlowVersionState.LOCKED
|
||||
break
|
||||
case FlowOperationType.ADD_ACTION: {
|
||||
clonedVersion = _addAction(clonedVersion, operation.request)
|
||||
clonedVersion = flowPieceUtil.makeFlowAutoUpgradable(clonedVersion)
|
||||
break
|
||||
}
|
||||
case FlowOperationType.DELETE_ACTION: {
|
||||
clonedVersion = _deleteAction(clonedVersion, operation.request)
|
||||
clonedVersion = flowPieceUtil.makeFlowAutoUpgradable(clonedVersion)
|
||||
break
|
||||
}
|
||||
case FlowOperationType.UPDATE_TRIGGER: {
|
||||
clonedVersion = _updateTrigger(clonedVersion, operation.request)
|
||||
clonedVersion = flowPieceUtil.makeFlowAutoUpgradable(clonedVersion)
|
||||
break
|
||||
}
|
||||
case FlowOperationType.ADD_BRANCH: {
|
||||
clonedVersion = _addBranch(clonedVersion, operation.request)
|
||||
clonedVersion = flowPieceUtil.makeFlowAutoUpgradable(clonedVersion)
|
||||
break
|
||||
}
|
||||
case FlowOperationType.DELETE_BRANCH: {
|
||||
clonedVersion = _deleteBranch(clonedVersion, operation.request)
|
||||
clonedVersion = flowPieceUtil.makeFlowAutoUpgradable(clonedVersion)
|
||||
break
|
||||
}
|
||||
case FlowOperationType.UPDATE_ACTION: {
|
||||
clonedVersion = _updateAction(clonedVersion, operation.request)
|
||||
clonedVersion = flowPieceUtil.makeFlowAutoUpgradable(clonedVersion)
|
||||
break
|
||||
}
|
||||
case FlowOperationType.IMPORT_FLOW: {
|
||||
const operations = _importFlow(clonedVersion, operation.request)
|
||||
operations.forEach((operation) => {
|
||||
clonedVersion = flowOperations.apply(clonedVersion, operation)
|
||||
})
|
||||
break
|
||||
}
|
||||
case FlowOperationType.SET_SKIP_ACTION: {
|
||||
clonedVersion = _skipAction(clonedVersion, operation.request)
|
||||
clonedVersion = flowPieceUtil.makeFlowAutoUpgradable(clonedVersion)
|
||||
break
|
||||
}
|
||||
case FlowOperationType.MOVE_BRANCH: {
|
||||
clonedVersion = _moveBranch(clonedVersion, operation.request)
|
||||
clonedVersion = flowPieceUtil.makeFlowAutoUpgradable(clonedVersion)
|
||||
break
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
clonedVersion.valid = flowStructureUtil.getAllSteps(clonedVersion.trigger).every((step) => {
|
||||
const isSkipped = step.type != FlowTriggerType.EMPTY && step.type != FlowTriggerType.PIECE && step.skip
|
||||
return step.valid || isSkipped
|
||||
})
|
||||
return clonedVersion
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { FlowVersion } from '../flow-version'
|
||||
import { flowStructureUtil } from '../util/flow-structure-util'
|
||||
import { _addAction } from './add-action'
|
||||
import { _deleteAction } from './delete-action'
|
||||
import { _getImportOperations } from './import-flow'
|
||||
import { _updateAction } from './update-action'
|
||||
import { FlowOperationRequest, FlowOperationType, MoveActionRequest } from './index'
|
||||
|
||||
|
||||
export function _moveAction(flowVersion: FlowVersion, request: MoveActionRequest): FlowOperationRequest[] {
|
||||
const sourceStep = flowStructureUtil.getActionOrThrow(request.name, flowVersion.trigger)
|
||||
flowStructureUtil.getStepOrThrow(request.newParentStep, flowVersion.trigger)
|
||||
const sourceStepWithoutNextAction = {
|
||||
...sourceStep,
|
||||
nextAction: undefined,
|
||||
}
|
||||
const deleteOperations: FlowOperationRequest[] = [
|
||||
{
|
||||
type: FlowOperationType.DELETE_ACTION,
|
||||
request: {
|
||||
names: [request.name],
|
||||
},
|
||||
},
|
||||
]
|
||||
const addOperations: FlowOperationRequest[] = [
|
||||
{
|
||||
type: FlowOperationType.ADD_ACTION,
|
||||
request: {
|
||||
action: sourceStepWithoutNextAction,
|
||||
parentStep: request.newParentStep,
|
||||
stepLocationRelativeToParent: request.stepLocationRelativeToNewParent,
|
||||
branchIndex: request.branchIndex,
|
||||
},
|
||||
},
|
||||
..._getImportOperations(sourceStepWithoutNextAction),
|
||||
]
|
||||
return [
|
||||
...deleteOperations,
|
||||
...addOperations,
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { BranchExecutionType, FlowActionType } from '../actions/action'
|
||||
import { FlowVersion } from '../flow-version'
|
||||
import { flowStructureUtil } from '../util/flow-structure-util'
|
||||
import { MoveBranchRequest } from '.'
|
||||
|
||||
|
||||
const isIndexWithinBounds = (index: number, arrayLength: number) => index >= 0 && index < arrayLength
|
||||
export function _moveBranch(flowVersion: FlowVersion, request: MoveBranchRequest): FlowVersion {
|
||||
return flowStructureUtil.transferFlow(flowVersion, (stepToUpdate) => {
|
||||
if (stepToUpdate.name !== request.stepName || stepToUpdate.type !== FlowActionType.ROUTER) {
|
||||
return stepToUpdate
|
||||
}
|
||||
const routerStep = stepToUpdate
|
||||
if (!isIndexWithinBounds(request.sourceBranchIndex, routerStep.settings.branches.length) || !isIndexWithinBounds(request.targetBranchIndex, routerStep.settings.branches.length) || request.sourceBranchIndex === request.targetBranchIndex) {
|
||||
return stepToUpdate
|
||||
}
|
||||
if (routerStep.settings.branches[request.sourceBranchIndex].branchType === BranchExecutionType.FALLBACK || routerStep.settings.branches[request.targetBranchIndex].branchType === BranchExecutionType.FALLBACK) {
|
||||
return stepToUpdate
|
||||
}
|
||||
const sourceBranch = routerStep.settings.branches[request.sourceBranchIndex]
|
||||
routerStep.settings.branches.splice(request.sourceBranchIndex, 1)
|
||||
routerStep.settings.branches.splice(request.targetBranchIndex, 0, sourceBranch)
|
||||
const sourceBranchChildren = routerStep.children[request.sourceBranchIndex]
|
||||
routerStep.children.splice(request.sourceBranchIndex, 1)
|
||||
routerStep.children.splice(request.targetBranchIndex, 0, sourceBranchChildren)
|
||||
return routerStep
|
||||
})
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
import { FlowAction } from '../actions/action'
|
||||
import { FlowVersion } from '../flow-version'
|
||||
import { flowStructureUtil } from '../util/flow-structure-util'
|
||||
import { addActionUtils } from './add-action-util'
|
||||
import { _getImportOperations } from './import-flow'
|
||||
import { FlowOperationRequest, FlowOperationType, StepLocationRelativeToParent } from './index'
|
||||
|
||||
|
||||
export type InsideBranchPasteLocation = {
|
||||
branchIndex: number
|
||||
stepLocationRelativeToParent: StepLocationRelativeToParent.INSIDE_BRANCH
|
||||
parentStepName: string
|
||||
}
|
||||
|
||||
export type OutsideBranchPasteLocation = {
|
||||
parentStepName: string
|
||||
stepLocationRelativeToParent:
|
||||
| StepLocationRelativeToParent.AFTER
|
||||
| StepLocationRelativeToParent.INSIDE_LOOP
|
||||
}
|
||||
|
||||
export type PasteLocation = InsideBranchPasteLocation | OutsideBranchPasteLocation
|
||||
|
||||
export const _getOperationsForPaste = (
|
||||
actions: FlowAction[],
|
||||
flowVersion: FlowVersion,
|
||||
pastingDetails: PasteLocation,
|
||||
) => {
|
||||
const newNamesMap = addActionUtils.mapToNewNames(flowVersion, actions)
|
||||
const clonedActions: FlowAction[] = actions.map(action => flowStructureUtil.transferStep(action, (step: FlowAction) => {
|
||||
return addActionUtils.clone(step, newNamesMap)
|
||||
}) as FlowAction)
|
||||
const operations: FlowOperationRequest[] = []
|
||||
for (let i = 0; i < clonedActions.length; i++) {
|
||||
if (i === 0) {
|
||||
operations.push({
|
||||
type: FlowOperationType.ADD_ACTION,
|
||||
request: {
|
||||
action: clonedActions[i],
|
||||
parentStep: pastingDetails.parentStepName,
|
||||
stepLocationRelativeToParent: pastingDetails.stepLocationRelativeToParent,
|
||||
branchIndex: pastingDetails.stepLocationRelativeToParent === StepLocationRelativeToParent.INSIDE_BRANCH ? pastingDetails.branchIndex : undefined,
|
||||
},
|
||||
})
|
||||
}
|
||||
else {
|
||||
operations.push({
|
||||
type: FlowOperationType.ADD_ACTION,
|
||||
request: {
|
||||
action: clonedActions[i],
|
||||
parentStep: clonedActions[i - 1].name,
|
||||
stepLocationRelativeToParent: StepLocationRelativeToParent.AFTER,
|
||||
},
|
||||
})
|
||||
}
|
||||
const importOperations = _getImportOperations(clonedActions[i])
|
||||
operations.push(...importOperations)
|
||||
}
|
||||
return operations
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { FlowVersion } from '../flow-version'
|
||||
import { flowStructureUtil } from '../util/flow-structure-util'
|
||||
import { SkipActionRequest } from '.'
|
||||
|
||||
export function _skipAction(flowVersion: FlowVersion, request: SkipActionRequest): FlowVersion {
|
||||
return flowStructureUtil.transferFlow(flowVersion, (stepToUpdate) => {
|
||||
if (!request.names.includes(stepToUpdate.name)) {
|
||||
return stepToUpdate
|
||||
}
|
||||
return {
|
||||
...stepToUpdate,
|
||||
skip: request.skip,
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
import { TypeCompiler } from '@sinclair/typebox/compiler'
|
||||
import { isNil } from '../../common'
|
||||
import { FlowAction, FlowActionType, SingleActionSchema } from '../actions/action'
|
||||
import { FlowVersion } from '../flow-version'
|
||||
import { flowStructureUtil } from '../util/flow-structure-util'
|
||||
import { UpdateActionRequest } from './index'
|
||||
|
||||
const actionSchemaValidator = TypeCompiler.Compile(SingleActionSchema)
|
||||
|
||||
function _updateAction(flowVersion: FlowVersion, request: UpdateActionRequest): FlowVersion {
|
||||
return flowStructureUtil.transferFlow(flowVersion, (stepToUpdate) => {
|
||||
if (stepToUpdate.name !== request.name) {
|
||||
return stepToUpdate
|
||||
}
|
||||
|
||||
const baseProps: Omit<FlowAction, 'type'> = {
|
||||
displayName: request.displayName,
|
||||
name: request.name,
|
||||
valid: false,
|
||||
skip: request.skip,
|
||||
settings: {
|
||||
...stepToUpdate.settings,
|
||||
customLogoUrl: request.settings.customLogoUrl,
|
||||
},
|
||||
}
|
||||
|
||||
let updatedAction: FlowAction
|
||||
switch (request.type) {
|
||||
case FlowActionType.CODE: {
|
||||
updatedAction = {
|
||||
...baseProps,
|
||||
settings: request.settings,
|
||||
type: FlowActionType.CODE,
|
||||
nextAction: stepToUpdate.nextAction,
|
||||
}
|
||||
break
|
||||
}
|
||||
case FlowActionType.PIECE: {
|
||||
updatedAction = {
|
||||
...baseProps,
|
||||
settings: request.settings,
|
||||
type: FlowActionType.PIECE,
|
||||
nextAction: stepToUpdate.nextAction,
|
||||
}
|
||||
break
|
||||
}
|
||||
case FlowActionType.LOOP_ON_ITEMS: {
|
||||
updatedAction = {
|
||||
...baseProps,
|
||||
settings: request.settings,
|
||||
type: FlowActionType.LOOP_ON_ITEMS,
|
||||
firstLoopAction: 'firstLoopAction' in stepToUpdate ? stepToUpdate.firstLoopAction : undefined,
|
||||
nextAction: stepToUpdate.nextAction,
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case FlowActionType.ROUTER: {
|
||||
updatedAction = {
|
||||
...baseProps,
|
||||
settings: request.settings,
|
||||
type: FlowActionType.ROUTER,
|
||||
nextAction: stepToUpdate.nextAction,
|
||||
children: 'children' in stepToUpdate ? stepToUpdate.children : [null, null],
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
const valid = (isNil(request.valid) ? true : request.valid) && actionSchemaValidator.Check(updatedAction)
|
||||
return {
|
||||
...updatedAction,
|
||||
valid,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export { _updateAction }
|
||||
@@ -0,0 +1,53 @@
|
||||
import { TypeCompiler } from '@sinclair/typebox/compiler'
|
||||
import { isNil } from '../../common'
|
||||
import { FlowAction } from '../actions/action'
|
||||
import { FlowVersion } from '../flow-version'
|
||||
import { FlowTrigger, FlowTriggerType } from '../triggers/trigger'
|
||||
import { flowStructureUtil } from '../util/flow-structure-util'
|
||||
import { UpdateTriggerRequest } from '.'
|
||||
|
||||
const triggerSchemaValidation = TypeCompiler.Compile(FlowTrigger)
|
||||
|
||||
function createTrigger(name: string, request: UpdateTriggerRequest, nextAction: FlowAction | undefined): FlowTrigger {
|
||||
const baseProperties = {
|
||||
displayName: request.displayName,
|
||||
name,
|
||||
valid: false,
|
||||
nextAction,
|
||||
}
|
||||
let trigger: FlowTrigger
|
||||
switch (request.type) {
|
||||
case FlowTriggerType.EMPTY:
|
||||
trigger = {
|
||||
...baseProperties,
|
||||
type: FlowTriggerType.EMPTY,
|
||||
settings: request.settings,
|
||||
}
|
||||
break
|
||||
case FlowTriggerType.PIECE:
|
||||
trigger = {
|
||||
...baseProperties,
|
||||
type: FlowTriggerType.PIECE,
|
||||
settings: request.settings,
|
||||
}
|
||||
break
|
||||
}
|
||||
const valid = (isNil(request.valid) ? true : request.valid) && triggerSchemaValidation.Check(trigger)
|
||||
return {
|
||||
...trigger,
|
||||
valid,
|
||||
}
|
||||
}
|
||||
|
||||
function _updateTrigger(flowVersion: FlowVersion, request: UpdateTriggerRequest): FlowVersion {
|
||||
const trigger = flowStructureUtil.getStepOrThrow(request.name, flowVersion.trigger)
|
||||
const updatedTrigger = createTrigger(request.name, request, trigger.nextAction)
|
||||
return flowStructureUtil.transferFlow(flowVersion, (parentStep) => {
|
||||
if (parentStep.name === request.name) {
|
||||
return updatedTrigger
|
||||
}
|
||||
return parentStep
|
||||
})
|
||||
}
|
||||
|
||||
export { _updateTrigger }
|
||||
@@ -0,0 +1 @@
|
||||
export * from './property'
|
||||
@@ -0,0 +1,12 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
|
||||
export enum PropertyExecutionType {
|
||||
MANUAL = 'MANUAL',
|
||||
DYNAMIC = 'DYNAMIC',
|
||||
}
|
||||
|
||||
export const PropertySettings = Type.Object({
|
||||
type: Type.Enum(PropertyExecutionType),
|
||||
schema: Type.Optional(Type.Any()),
|
||||
})
|
||||
export type PropertySettings = Static<typeof PropertySettings>
|
||||
@@ -0,0 +1,75 @@
|
||||
import { Pick, Static, Type } from '@sinclair/typebox'
|
||||
import { File } from '../../file'
|
||||
|
||||
export enum SampleDataFileType {
|
||||
INPUT = 'INPUT',
|
||||
OUTPUT = 'OUTPUT',
|
||||
}
|
||||
|
||||
export const DATA_TYPE_KEY_IN_FILE_METADATA = 'dataType'
|
||||
|
||||
|
||||
export enum SampleDataDataType {
|
||||
JSON = 'JSON',
|
||||
STRING = 'STRING',
|
||||
}
|
||||
export const SaveSampleDataRequest = Type.Object({
|
||||
stepName: Type.String(),
|
||||
payload: Type.Unknown(),
|
||||
type: Type.Enum(SampleDataFileType),
|
||||
dataType: Type.Enum(SampleDataDataType),
|
||||
})
|
||||
export type SaveSampleDataRequest = Static<typeof SaveSampleDataRequest>
|
||||
|
||||
export const GetSampleDataRequest = Type.Object({
|
||||
flowId: Type.String(),
|
||||
flowVersionId: Type.String(),
|
||||
stepName: Type.String(),
|
||||
projectId: Type.String(),
|
||||
type: Type.Enum(SampleDataFileType),
|
||||
})
|
||||
export type GetSampleDataRequest = Static<typeof GetSampleDataRequest>
|
||||
|
||||
export const CreateStepRunRequestBody = Type.Object({
|
||||
flowVersionId: Type.String(),
|
||||
stepName: Type.String(),
|
||||
})
|
||||
|
||||
export type CreateStepRunRequestBody = Static<typeof CreateStepRunRequestBody>
|
||||
|
||||
export const StepRunResponse = Type.Object({
|
||||
runId: Type.String(),
|
||||
success: Type.Boolean(),
|
||||
input: Type.Unknown(),
|
||||
output: Type.Unknown(),
|
||||
sampleDataFileId: Type.Optional(Type.String()),
|
||||
sampleDataInputFileId: Type.Optional(Type.String()),
|
||||
standardError: Type.String(),
|
||||
standardOutput: Type.String(),
|
||||
})
|
||||
|
||||
export type StepRunResponse = Static<typeof StepRunResponse>
|
||||
|
||||
export const StepExecutionPath = Type.Array(Type.Tuple([Type.String(), Type.Number()]))
|
||||
export type StepExecutionPath = Static<typeof StepExecutionPath>
|
||||
export const SampleDataSetting = Type.Object(
|
||||
{
|
||||
sampleDataFileId: Type.Optional(Type.String()),
|
||||
sampleDataInputFileId: Type.Optional(Type.String()),
|
||||
lastTestDate: Type.Optional(Type.String()),
|
||||
},
|
||||
{
|
||||
additionalProperties: true,
|
||||
},
|
||||
)
|
||||
|
||||
export type SampleDataSettings = Static<typeof SampleDataSetting>
|
||||
|
||||
export const DEFAULT_SAMPLE_DATA_SETTINGS: SampleDataSettings = {
|
||||
sampleDataFileId: undefined,
|
||||
sampleDataInputFileId: undefined,
|
||||
}
|
||||
|
||||
export const SaveSampleDataResponse = Pick(File, ['id', 'size', 'type'])
|
||||
export type SaveSampleDataResponse = Static<typeof SaveSampleDataResponse>
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { ApMultipartFile } from '../../common'
|
||||
|
||||
export const StepFileUpsertRequest = Type.Object({
|
||||
flowId: Type.String(),
|
||||
stepName: Type.String(),
|
||||
file: Type.Optional(Type.Pick(ApMultipartFile, ['data'])),
|
||||
contentLength: Type.Number(),
|
||||
fileName: Type.String(),
|
||||
})
|
||||
|
||||
export type StepFileUpsert = Static<typeof StepFileUpsertRequest>
|
||||
|
||||
export const StepFileUpsertResponse = Type.Object({
|
||||
uploadUrl: Type.Optional(Type.String()),
|
||||
url: Type.String(),
|
||||
})
|
||||
|
||||
export type StepFileUpsertResponse = Static<typeof StepFileUpsertResponse>
|
||||
@@ -0,0 +1,22 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { ApId } from '../common/id-generator'
|
||||
|
||||
export enum TriggerTestStrategy {
|
||||
SIMULATION = 'SIMULATION',
|
||||
TEST_FUNCTION = 'TEST_FUNCTION',
|
||||
}
|
||||
|
||||
export const TestTriggerRequestBody = Type.Object({
|
||||
flowId: ApId,
|
||||
flowVersionId: ApId,
|
||||
testStrategy: Type.Enum(TriggerTestStrategy),
|
||||
})
|
||||
|
||||
export type TestTriggerRequestBody = Static<typeof TestTriggerRequestBody>
|
||||
|
||||
|
||||
export const CancelTestTriggerRequestBody = Type.Object({
|
||||
flowId: ApId,
|
||||
})
|
||||
|
||||
export type CancelTestTriggerRequestBody = Static<typeof CancelTestTriggerRequestBody>
|
||||
@@ -0,0 +1,23 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { BaseModel } from '../../../common'
|
||||
|
||||
export type TriggerEventId = string
|
||||
|
||||
export const TriggerEvent = Type.Object({
|
||||
id: Type.String(),
|
||||
projectId: Type.String(),
|
||||
flowId: Type.String(),
|
||||
sourceName: Type.String(),
|
||||
fileId: Type.String(),
|
||||
})
|
||||
export type TriggerEvent = Static<typeof TriggerEvent> & BaseModel<TriggerEventId>
|
||||
|
||||
|
||||
export const TriggerEventWithPayload = Type.Composite([
|
||||
TriggerEvent,
|
||||
Type.Object({
|
||||
payload: Type.Unknown(),
|
||||
}),
|
||||
])
|
||||
|
||||
export type TriggerEventWithPayload = Static<typeof TriggerEventWithPayload>
|
||||
@@ -0,0 +1,21 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { Cursor } from '../../../common/seek-page'
|
||||
import { FlowId } from '../../flow'
|
||||
|
||||
export const ListTriggerEventsRequest = Type.Object({
|
||||
flowId: Type.String({}),
|
||||
limit: Type.Optional(Type.Number({})),
|
||||
cursor: Type.Optional(Type.String({})),
|
||||
})
|
||||
|
||||
export type ListTriggerEventsRequest = Omit<Static<typeof ListTriggerEventsRequest>, 'flowId' | 'cursor'> & {
|
||||
flowId: FlowId
|
||||
cursor: Cursor | undefined
|
||||
}
|
||||
|
||||
export const SaveTriggerEventRequest = Type.Object({
|
||||
flowId: Type.String({}),
|
||||
mockData: Type.Unknown(),
|
||||
})
|
||||
|
||||
export type SaveTriggerEventRequest = Static<typeof SaveTriggerEventRequest>
|
||||
@@ -0,0 +1,21 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
|
||||
|
||||
export enum TriggerRunStatus {
|
||||
COMPLETED = 'COMPLETED',
|
||||
FAILED = 'FAILED',
|
||||
INTERNAL_ERROR = 'INTERNAL_ERROR',
|
||||
TIMED_OUT = 'TIMED_OUT',
|
||||
}
|
||||
|
||||
export const TriggerStatusReport = Type.Object({
|
||||
pieces: Type.Record(Type.String(), Type.Object({
|
||||
dailyStats: Type.Record(Type.String(), Type.Object({
|
||||
success: Type.Number(),
|
||||
failure: Type.Number(),
|
||||
})),
|
||||
totalRuns: Type.Number(),
|
||||
})),
|
||||
})
|
||||
|
||||
export type TriggerStatusReport = Static<typeof TriggerStatusReport>
|
||||
66
activepieces-fork/packages/shared/src/lib/flows/triggers/trigger.ts
Executable file
66
activepieces-fork/packages/shared/src/lib/flows/triggers/trigger.ts
Executable file
@@ -0,0 +1,66 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { VersionType } from '../../pieces'
|
||||
import { CodeActionSettings, LoopOnItemsActionSettings, PieceActionSettings, RouterActionSettings } from '../actions/action'
|
||||
import { PropertySettings } from '../properties'
|
||||
import { SampleDataSetting } from '../sample-data'
|
||||
|
||||
export const AUTHENTICATION_PROPERTY_NAME = 'auth'
|
||||
|
||||
|
||||
export const PieceTriggerSettings = Type.Object({
|
||||
sampleData: Type.Optional(SampleDataSetting),
|
||||
propertySettings: Type.Record(Type.String(), PropertySettings),
|
||||
customLogoUrl: Type.Optional(Type.String()),
|
||||
pieceName: Type.String({}),
|
||||
pieceVersion: VersionType,
|
||||
triggerName: Type.Optional(Type.String({})),
|
||||
input: Type.Record(Type.String({}), Type.Any()),
|
||||
})
|
||||
|
||||
export type PieceTriggerSettings = Static<typeof PieceTriggerSettings>
|
||||
|
||||
|
||||
export enum FlowTriggerType {
|
||||
EMPTY = 'EMPTY',
|
||||
PIECE = 'PIECE_TRIGGER',
|
||||
}
|
||||
|
||||
const commonProps = {
|
||||
name: Type.String({}),
|
||||
valid: Type.Boolean({}),
|
||||
displayName: Type.String({}),
|
||||
nextAction: Type.Optional(Type.Any()),
|
||||
}
|
||||
|
||||
|
||||
export const EmptyTrigger = Type.Object({
|
||||
...commonProps,
|
||||
type: Type.Literal(FlowTriggerType.EMPTY),
|
||||
settings: Type.Any(),
|
||||
})
|
||||
|
||||
export type EmptyTrigger = Static<typeof EmptyTrigger>
|
||||
|
||||
|
||||
export const PieceTrigger = Type.Object({
|
||||
...commonProps,
|
||||
type: Type.Literal(FlowTriggerType.PIECE),
|
||||
settings: PieceTriggerSettings,
|
||||
})
|
||||
|
||||
export type PieceTrigger = Static<typeof PieceTrigger>
|
||||
|
||||
export const FlowTrigger = Type.Union([
|
||||
PieceTrigger,
|
||||
EmptyTrigger,
|
||||
])
|
||||
|
||||
export type FlowTrigger = Static<typeof FlowTrigger>
|
||||
|
||||
|
||||
export type StepSettings =
|
||||
| CodeActionSettings
|
||||
| PieceActionSettings
|
||||
| PieceTriggerSettings
|
||||
| RouterActionSettings
|
||||
| LoopOnItemsActionSettings
|
||||
@@ -0,0 +1,47 @@
|
||||
import semver from 'semver'
|
||||
import { FlowActionType } from '../actions/action'
|
||||
import { FlowVersion } from '../flow-version'
|
||||
import { FlowTrigger, FlowTriggerType } from '../triggers/trigger'
|
||||
import { flowStructureUtil, Step } from '../util/flow-structure-util'
|
||||
|
||||
export const flowPieceUtil = {
|
||||
makeFlowAutoUpgradable(flowVersion: FlowVersion): FlowVersion {
|
||||
return flowStructureUtil.transferFlow(flowVersion, (step) => {
|
||||
if (step.name !== step.name) {
|
||||
return step
|
||||
}
|
||||
const clonedStep: Step = JSON.parse(JSON.stringify(step))
|
||||
switch (step.type) {
|
||||
case FlowActionType.PIECE:
|
||||
case FlowTriggerType.PIECE: {
|
||||
const { pieceVersion } = step.settings
|
||||
clonedStep.settings.pieceVersion = flowPieceUtil.getMostRecentPatchVersion(pieceVersion)
|
||||
break
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
return clonedStep
|
||||
})
|
||||
},
|
||||
getExactVersion(pieceVersion: string): string {
|
||||
if (pieceVersion.startsWith('^') || pieceVersion.startsWith('~')) {
|
||||
return pieceVersion.slice(1)
|
||||
}
|
||||
return pieceVersion
|
||||
},
|
||||
getUsedPieces(trigger: FlowTrigger): string[] {
|
||||
return flowStructureUtil.getAllSteps(trigger)
|
||||
.filter((step) => step.type === FlowActionType.PIECE || step.type === FlowTriggerType.PIECE)
|
||||
.map((step) => step.settings.pieceName)
|
||||
},
|
||||
getMostRecentPatchVersion(pieceVersion: string): string {
|
||||
if (pieceVersion.startsWith('^') || pieceVersion.startsWith('~')) {
|
||||
return pieceVersion
|
||||
}
|
||||
if (semver.valid(pieceVersion) && semver.lt(pieceVersion, '1.0.0')) {
|
||||
return `~${pieceVersion}`
|
||||
}
|
||||
return `^${pieceVersion}`
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
import { isNil } from '../../common'
|
||||
import { ActivepiecesError, ErrorCode } from '../../common/activepieces-error'
|
||||
import { BranchCondition, BranchExecutionType, emptyCondition, FlowAction, FlowActionType, LoopOnItemsAction, RouterAction } from '../actions/action'
|
||||
import { FlowVersion } from '../flow-version'
|
||||
import { FlowTrigger, FlowTriggerType } from '../triggers/trigger'
|
||||
|
||||
|
||||
export const AI_PIECE_NAME = '@activepieces/piece-ai'
|
||||
|
||||
export type Step = FlowAction | FlowTrigger
|
||||
type StepWithIndex = Step & {
|
||||
dfsIndex: number
|
||||
}
|
||||
|
||||
function isAction(type: FlowActionType | FlowTriggerType | undefined): type is FlowActionType {
|
||||
return Object.entries(FlowActionType).some(([, value]) => value === type)
|
||||
}
|
||||
|
||||
function isTrigger(type: FlowActionType | FlowTriggerType | undefined): type is FlowTriggerType {
|
||||
return Object.entries(FlowTriggerType).some(([, value]) => value === type)
|
||||
}
|
||||
|
||||
function getActionOrThrow(name: string, flowRoot: Step): FlowAction {
|
||||
const step = getStepOrThrow(name, flowRoot)
|
||||
if (!isAction(step.type)) {
|
||||
throw new ActivepiecesError({
|
||||
code: ErrorCode.STEP_NOT_FOUND,
|
||||
params: {
|
||||
stepName: name,
|
||||
},
|
||||
})
|
||||
}
|
||||
return step as FlowAction
|
||||
}
|
||||
|
||||
function getTriggerOrThrow(name: string, flowRoot: Step): FlowTrigger {
|
||||
const step = getStepOrThrow(name, flowRoot)
|
||||
if (!isTrigger(step.type)) {
|
||||
throw new ActivepiecesError({
|
||||
code: ErrorCode.STEP_NOT_FOUND,
|
||||
params: {
|
||||
stepName: name,
|
||||
},
|
||||
})
|
||||
}
|
||||
return step as FlowTrigger
|
||||
}
|
||||
|
||||
function getStep(name: string, flowRoot: Step): Step | undefined {
|
||||
return getAllSteps(flowRoot).find((step) => step.name === name)
|
||||
}
|
||||
|
||||
function getStepOrThrow(name: string, flowRoot: Step): Step {
|
||||
const step = getStep(name, flowRoot)
|
||||
if (isNil(step)) {
|
||||
throw new ActivepiecesError({
|
||||
code: ErrorCode.STEP_NOT_FOUND,
|
||||
params: {
|
||||
stepName: name,
|
||||
},
|
||||
})
|
||||
}
|
||||
return step
|
||||
}
|
||||
|
||||
function transferStep<T extends Step>(
|
||||
step: Step,
|
||||
transferFunction: (step: T) => T,
|
||||
): Step {
|
||||
const updatedStep = transferFunction(step as T)
|
||||
switch (updatedStep.type) {
|
||||
case FlowActionType.LOOP_ON_ITEMS: {
|
||||
const { firstLoopAction } = updatedStep
|
||||
if (firstLoopAction) {
|
||||
updatedStep.firstLoopAction = transferStep(
|
||||
firstLoopAction,
|
||||
transferFunction,
|
||||
) as FlowAction
|
||||
}
|
||||
break
|
||||
}
|
||||
case FlowActionType.ROUTER: {
|
||||
const { children } = updatedStep
|
||||
if (children) {
|
||||
updatedStep.children = children.map((child) =>
|
||||
child ? (transferStep(child, transferFunction) as FlowAction) : null,
|
||||
)
|
||||
}
|
||||
break
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
if (updatedStep.nextAction) {
|
||||
updatedStep.nextAction = transferStep(
|
||||
updatedStep.nextAction,
|
||||
transferFunction,
|
||||
) as FlowAction
|
||||
}
|
||||
|
||||
return updatedStep
|
||||
}
|
||||
|
||||
|
||||
function transferFlow<T extends Step>(
|
||||
flowVersion: FlowVersion,
|
||||
transferFunction: (step: T) => T,
|
||||
): FlowVersion {
|
||||
const clonedFlow = JSON.parse(JSON.stringify(flowVersion))
|
||||
clonedFlow.trigger = transferStep(
|
||||
clonedFlow.trigger,
|
||||
transferFunction,
|
||||
) as FlowTrigger
|
||||
return clonedFlow
|
||||
}
|
||||
|
||||
function getAllSteps(step: Step): Step[] {
|
||||
const steps: Step[] = []
|
||||
transferStep(step, (currentStep) => {
|
||||
steps.push(currentStep)
|
||||
return currentStep
|
||||
})
|
||||
return steps
|
||||
}
|
||||
|
||||
|
||||
const createBranch = (branchName: string, conditions: BranchCondition[][] | undefined) => {
|
||||
return {
|
||||
conditions: conditions ?? [[emptyCondition]],
|
||||
branchType: BranchExecutionType.CONDITION,
|
||||
branchName,
|
||||
}
|
||||
}
|
||||
|
||||
function findPathToStep(trigger: FlowTrigger, targetStepName: string): StepWithIndex[] {
|
||||
const steps = flowStructureUtil.getAllSteps(trigger).map((step, dfsIndex) => ({
|
||||
...step,
|
||||
dfsIndex,
|
||||
}))
|
||||
return steps
|
||||
.filter((step) => {
|
||||
const steps = flowStructureUtil.getAllSteps(step)
|
||||
return steps.some((s) => s.name === targetStepName)
|
||||
})
|
||||
.filter((step) => step.name !== targetStepName)
|
||||
}
|
||||
|
||||
|
||||
function getAllChildSteps(action: LoopOnItemsAction | RouterAction): Step[] {
|
||||
return getAllSteps({
|
||||
...action,
|
||||
nextAction: undefined,
|
||||
})
|
||||
}
|
||||
|
||||
function isChildOf(parent: Step, childStepName: string): boolean {
|
||||
switch (parent.type) {
|
||||
case FlowActionType.ROUTER:
|
||||
case FlowActionType.LOOP_ON_ITEMS: {
|
||||
const children = getAllChildSteps(parent)
|
||||
return children.findIndex((c) => c.name === childStepName) > -1
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
const findUnusedNames = (source: FlowTrigger | string[], count = 1) => {
|
||||
const names = Array.isArray(source) ? source : flowStructureUtil.getAllSteps(source).map((f) => f.name)
|
||||
const unusedNames = []
|
||||
for (let i = 1; i <= count; i++) {
|
||||
const name = findUnusedName(names)
|
||||
unusedNames.push(name)
|
||||
names.push(name)
|
||||
}
|
||||
return unusedNames
|
||||
}
|
||||
|
||||
const findUnusedName = (source: FlowTrigger | string[]) => {
|
||||
const names = Array.isArray(source) ? source : flowStructureUtil.getAllSteps(source).map((f) => f.name)
|
||||
let index = 1
|
||||
let name = 'step_1'
|
||||
while (names.includes(name)) {
|
||||
index++
|
||||
name = 'step_' + index
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
|
||||
function getAllNextActionsWithoutChildren(start: Step): Step[] {
|
||||
const actions: Step[] = []
|
||||
let currentAction = start.nextAction
|
||||
|
||||
while (!isNil(currentAction)) {
|
||||
actions.push(currentAction)
|
||||
currentAction = currentAction.nextAction
|
||||
}
|
||||
|
||||
return actions
|
||||
}
|
||||
|
||||
|
||||
function extractConnectionIdsFromAuth(auth: string): string[] {
|
||||
const match = auth.match(/{{connections\['([^']*(?:'\s*,\s*'[^']*)*)'\]}}/)
|
||||
if (!match || !match[1]) {
|
||||
return []
|
||||
}
|
||||
return match[1].split(/'\s*,\s*'/).map(id => id.trim())
|
||||
}
|
||||
|
||||
function extractAgentIds(flowVersion: FlowVersion): string[] {
|
||||
const getExternalAgentId = (action: Step) => {
|
||||
if (isAgentPiece(action) && 'agentId' in action.settings.input) {
|
||||
return action.settings.input.agentId
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
return flowStructureUtil.getAllSteps(flowVersion.trigger).map(step => getExternalAgentId(step)).filter(step => step !== null && step !== '')
|
||||
}
|
||||
|
||||
function isAgentPiece(action: Step) {
|
||||
return (
|
||||
action.type === FlowActionType.PIECE && action.settings.pieceName === AI_PIECE_NAME
|
||||
)
|
||||
}
|
||||
|
||||
function extractConnectionIds(flowVersion: FlowVersion): string[] {
|
||||
const triggerAuthIds = flowVersion.trigger.settings?.input?.auth
|
||||
? extractConnectionIdsFromAuth(flowVersion.trigger.settings.input.auth)
|
||||
: []
|
||||
|
||||
const stepAuthIds = flowStructureUtil
|
||||
.getAllSteps(flowVersion.trigger)
|
||||
.flatMap(step =>
|
||||
step.settings?.input?.auth
|
||||
? extractConnectionIdsFromAuth(step.settings.input.auth)
|
||||
: [],
|
||||
)
|
||||
|
||||
return Array.from(new Set([...triggerAuthIds, ...stepAuthIds]))
|
||||
}
|
||||
|
||||
export const flowStructureUtil = {
|
||||
isTrigger,
|
||||
isAction,
|
||||
getAllSteps,
|
||||
transferStep,
|
||||
transferFlow,
|
||||
getStepOrThrow,
|
||||
getActionOrThrow,
|
||||
getTriggerOrThrow,
|
||||
getStep,
|
||||
createBranch,
|
||||
findPathToStep,
|
||||
isChildOf,
|
||||
findUnusedName,
|
||||
findUnusedNames,
|
||||
getAllNextActionsWithoutChildren,
|
||||
getAllChildSteps,
|
||||
extractConnectionIds,
|
||||
isAgentPiece,
|
||||
extractAgentIds,
|
||||
}
|
||||
58
activepieces-fork/packages/shared/src/lib/forms/index.ts
Normal file
58
activepieces-fork/packages/shared/src/lib/forms/index.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
|
||||
const FileResponseInterfaceV1 = Type.Object({
|
||||
base64Url: Type.String(),
|
||||
fileName: Type.String(),
|
||||
extension: Type.Optional(Type.String()),
|
||||
})
|
||||
|
||||
const FileResponseInterfaceV2 = Type.Object({
|
||||
mimeType: Type.String(),
|
||||
url: Type.String(),
|
||||
fileName: Type.Optional(Type.String()),
|
||||
})
|
||||
|
||||
export const FileResponseInterface = Type.Union([FileResponseInterfaceV1, FileResponseInterfaceV2])
|
||||
|
||||
export type FileResponseInterface = Static<typeof FileResponseInterface>
|
||||
|
||||
|
||||
|
||||
export enum HumanInputFormResultTypes {
|
||||
FILE = 'file',
|
||||
MARKDOWN = 'markdown',
|
||||
}
|
||||
|
||||
export function createKeyForFormInput(displayName: string) {
|
||||
const inputKey = displayName
|
||||
.toLowerCase()
|
||||
.replace(/\s+(\w)/g, (_, letter) => letter.toUpperCase())
|
||||
.replace(/^(.)/, letter => letter.toLowerCase())
|
||||
|
||||
/**We do this because react form inputs must not contain quotes */
|
||||
return inputKey.replaceAll(/[\\"''\n\r\t]/g, '')
|
||||
}
|
||||
|
||||
|
||||
export const HumanInputFormResult = Type.Union([
|
||||
Type.Object({
|
||||
type: Type.Literal(HumanInputFormResultTypes.FILE),
|
||||
value: FileResponseInterface,
|
||||
}),
|
||||
Type.Object({
|
||||
type: Type.Literal(HumanInputFormResultTypes.MARKDOWN),
|
||||
value: Type.String(),
|
||||
files: Type.Optional(Type.Array(FileResponseInterface)),
|
||||
}),
|
||||
])
|
||||
|
||||
export type HumanInputFormResult = Static<typeof HumanInputFormResult>
|
||||
|
||||
|
||||
export const ChatFormResponse = Type.Object({
|
||||
sessionId: Type.String(),
|
||||
message: Type.String(),
|
||||
files: Type.Optional(Type.Array(Type.String())),
|
||||
})
|
||||
|
||||
export type ChatFormResponse = Static<typeof ChatFormResponse>
|
||||
@@ -0,0 +1,9 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
|
||||
export const GetSystemHealthChecksResponse = Type.Object({
|
||||
cpu: Type.Boolean(),
|
||||
disk: Type.Boolean(),
|
||||
ram: Type.Boolean(),
|
||||
})
|
||||
|
||||
export type GetSystemHealthChecksResponse = Static<typeof GetSystemHealthChecksResponse>
|
||||
@@ -0,0 +1,67 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { BaseModelSchema, Nullable, NullableEnum } from '../common'
|
||||
import { ProjectRole } from '../project-role/project-role'
|
||||
import { PlatformRole } from '../user/index'
|
||||
|
||||
export enum InvitationType {
|
||||
PLATFORM = 'PLATFORM',
|
||||
PROJECT = 'PROJECT',
|
||||
}
|
||||
|
||||
export enum InvitationStatus {
|
||||
PENDING = 'PENDING',
|
||||
ACCEPTED = 'ACCEPTED',
|
||||
}
|
||||
|
||||
export const UserInvitation = Type.Object({
|
||||
...BaseModelSchema,
|
||||
email: Type.String(),
|
||||
status: Type.Enum(InvitationStatus),
|
||||
type: Type.Enum(InvitationType),
|
||||
platformId: Type.String(),
|
||||
platformRole: NullableEnum(Type.Enum(PlatformRole)),
|
||||
projectId: Nullable(Type.String()),
|
||||
projectRoleId: Nullable(Type.String()),
|
||||
projectRole: Nullable(ProjectRole),
|
||||
})
|
||||
|
||||
export type UserInvitation = Static<typeof UserInvitation>
|
||||
|
||||
export const UserInvitationWithLink = Type.Composite([UserInvitation, Type.Object({
|
||||
link: Type.Optional(Type.String()),
|
||||
})])
|
||||
|
||||
export type UserInvitationWithLink = Static<typeof UserInvitationWithLink>
|
||||
|
||||
export const SendUserInvitationRequest = Type.Union([
|
||||
Type.Object({
|
||||
type: Type.Literal(InvitationType.PROJECT),
|
||||
email: Type.String(),
|
||||
projectId: Type.String(),
|
||||
projectRole: Type.String(),
|
||||
}),
|
||||
Type.Object({
|
||||
type: Type.Literal(InvitationType.PLATFORM),
|
||||
email: Type.String(),
|
||||
platformRole: Type.Enum(PlatformRole),
|
||||
}),
|
||||
])
|
||||
|
||||
|
||||
export type SendUserInvitationRequest = Static<typeof SendUserInvitationRequest>
|
||||
|
||||
export const AcceptUserInvitationRequest = Type.Object({
|
||||
invitationToken: Type.String(),
|
||||
})
|
||||
|
||||
export type AcceptUserInvitationRequest = Static<typeof AcceptUserInvitationRequest>
|
||||
|
||||
export const ListUserInvitationsRequest = Type.Object({
|
||||
limit: Type.Optional(Type.Number()),
|
||||
cursor: Type.Optional(Type.String()),
|
||||
type: Type.Enum(InvitationType),
|
||||
projectId: Nullable(Type.String()),
|
||||
status: Type.Optional(Type.Enum(InvitationStatus)),
|
||||
})
|
||||
|
||||
export type ListUserInvitationsRequest = Static<typeof ListUserInvitationsRequest>
|
||||
@@ -0,0 +1,49 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
|
||||
export const VerifyLicenseKeyRequestBody = Type.Object({
|
||||
licenseKey: Type.String(),
|
||||
platformId: Type.String(),
|
||||
})
|
||||
|
||||
export type VerifyLicenseKeyRequestBody = Static<typeof VerifyLicenseKeyRequestBody>
|
||||
|
||||
export const LicenseKeyEntity = Type.Object({
|
||||
id: Type.String(),
|
||||
email: Type.String(),
|
||||
expiresAt: Type.String(),
|
||||
activatedAt: Type.String(),
|
||||
createdAt: Type.String(),
|
||||
key: Type.String(),
|
||||
ssoEnabled: Type.Boolean(),
|
||||
environmentsEnabled: Type.Boolean(),
|
||||
showPoweredBy: Type.Boolean(),
|
||||
embeddingEnabled: Type.Boolean(),
|
||||
auditLogEnabled: Type.Boolean(),
|
||||
customAppearanceEnabled: Type.Boolean(),
|
||||
manageProjectsEnabled: Type.Boolean(),
|
||||
managePiecesEnabled: Type.Boolean(),
|
||||
manageTemplatesEnabled: Type.Boolean(),
|
||||
apiKeysEnabled: Type.Boolean(),
|
||||
customDomainsEnabled: Type.Boolean(),
|
||||
projectRolesEnabled: Type.Boolean(),
|
||||
analyticsEnabled: Type.Boolean(),
|
||||
globalConnectionsEnabled: Type.Boolean(),
|
||||
customRolesEnabled: Type.Boolean(),
|
||||
agentsEnabled: Type.Boolean(),
|
||||
tablesEnabled: Type.Boolean(),
|
||||
todosEnabled: Type.Boolean(),
|
||||
mcpsEnabled: Type.Boolean(),
|
||||
})
|
||||
|
||||
|
||||
export const CreateTrialLicenseKeyRequestBody = Type.Composite([Type.Object({
|
||||
email: Type.String(),
|
||||
companyName: Type.String(),
|
||||
goal: Type.String(),
|
||||
keyType: Type.Optional(Type.String()),
|
||||
}), Type.Omit(LicenseKeyEntity, ['id', 'email', 'expiresAt', 'activatedAt', 'key', 'createdAt'])])
|
||||
|
||||
export type CreateTrialLicenseKeyRequestBody = Static<typeof CreateTrialLicenseKeyRequestBody>
|
||||
|
||||
|
||||
export type LicenseKeyEntity = Static<typeof LicenseKeyEntity>
|
||||
2
activepieces-fork/packages/shared/src/lib/mcp/index.ts
Normal file
2
activepieces-fork/packages/shared/src/lib/mcp/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './mcp'
|
||||
export * from './pieces/mcp-piece'
|
||||
34
activepieces-fork/packages/shared/src/lib/mcp/mcp.ts
Normal file
34
activepieces-fork/packages/shared/src/lib/mcp/mcp.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
import { BaseModelSchema } from '../common'
|
||||
import { ApId } from '../common/id-generator'
|
||||
import { PopulatedFlow } from '../flows/flow'
|
||||
|
||||
export type McpId = ApId
|
||||
|
||||
export const MCP_TRIGGER_PIECE_NAME = '@activepieces/piece-mcp'
|
||||
|
||||
export enum McpServerStatus {
|
||||
ENABLED = 'ENABLED',
|
||||
DISABLED = 'DISABLED',
|
||||
}
|
||||
|
||||
export const McpServer = Type.Object({
|
||||
...BaseModelSchema,
|
||||
projectId: ApId,
|
||||
status: Type.Enum(McpServerStatus),
|
||||
token: ApId,
|
||||
})
|
||||
|
||||
export const PopulatedMcpServer = Type.Composite([McpServer, Type.Object({
|
||||
flows: Type.Array(PopulatedFlow),
|
||||
})])
|
||||
export type PopulatedMcpServer = Static<typeof PopulatedMcpServer>
|
||||
|
||||
export type McpServer = Static<typeof McpServer>
|
||||
|
||||
|
||||
export const UpdateMcpServerRequest = Type.Object({
|
||||
status: Type.Enum(McpServerStatus),
|
||||
})
|
||||
|
||||
export type UpdateMcpServerRequest = Static<typeof UpdateMcpServerRequest>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user