(dto: WorkflowGraphDto, auth?: AuthContext | null)
| 268 | } |
| 269 | |
| 270 | async create(dto: WorkflowGraphDto, auth?: AuthContext | null): Promise<ServiceWorkflowResponse> { |
| 271 | const input = this.parse(dto); |
| 272 | |
| 273 | // Validate workflow graph before saving (including port connections) |
| 274 | try { |
| 275 | compileWorkflowGraph(input); |
| 276 | } catch (error) { |
| 277 | if (error instanceof Error) { |
| 278 | throw new BadRequestException(`Workflow validation failed: ${error.message}`); |
| 279 | } |
| 280 | throw error; |
| 281 | } |
| 282 | |
| 283 | this.ensureOrganizationAdmin(auth); |
| 284 | const organizationId = this.requireOrganizationId(auth); |
| 285 | const record = await this.repository.create(input, { organizationId }); |
| 286 | let version: WorkflowVersionRecord; |
| 287 | try { |
| 288 | version = await this.versionRepository.create({ |
| 289 | workflowId: record.id, |
| 290 | graph: input, |
| 291 | organizationId, |
| 292 | }); |
| 293 | if (auth?.userId) { |
| 294 | await this.roleRepository.upsert({ |
| 295 | workflowId: record.id, |
| 296 | userId: auth.userId, |
| 297 | role: 'ADMIN', |
| 298 | organizationId, |
| 299 | }); |
| 300 | } |
| 301 | } catch (error) { |
| 302 | await this.repository.delete(record.id, { organizationId }); |
| 303 | throw error; |
| 304 | } |
| 305 | const response = this.buildWorkflowResponse(record, version); |
| 306 | this.logger.log( |
| 307 | `Created workflow ${response.id} version ${version.version} (nodes=${input.nodes.length}, edges=${input.edges.length})`, |
| 308 | ); |
| 309 | return response; |
| 310 | } |
| 311 | |
| 312 | async update( |
| 313 | id: string, |
no test coverage detected