|
1 | | -import { AuditAction, AuditResourceType, recordAudit } from '@sim/audit' |
2 | | -import { createLogger } from '@sim/logger' |
3 | | -import { getErrorMessage } from '@sim/utils/errors' |
4 | | -import type { NextRequest } from 'next/server' |
5 | | -import { NextResponse } from 'next/server' |
6 | 1 | import { |
7 | 2 | deleteCustomBlockContract, |
8 | 3 | updateCustomBlockContract, |
9 | 4 | } from '@/lib/api/contracts/custom-blocks' |
10 | | -import { parseRequest } from '@/lib/api/server' |
11 | | -import { getSession } from '@/lib/auth' |
12 | | -import { withRouteHandler } from '@/lib/core/utils/with-route-handler' |
13 | 5 | import { |
14 | | - CustomBlockValidationError, |
15 | | - deleteCustomBlock, |
16 | | - getCustomBlockUsageCounts, |
17 | | - updateCustomBlock, |
18 | | -} from '@/lib/workflows/custom-blocks/operations' |
19 | | -import { authorizeManage } from '@/app/api/custom-blocks/[id]/authorize-manage' |
20 | | - |
21 | | -const logger = createLogger('CustomBlockAPI') |
22 | | - |
23 | | -type RouteContext = { params: Promise<{ id: string }> } |
24 | | - |
25 | | -export const PATCH = withRouteHandler(async (request: NextRequest, context: RouteContext) => { |
26 | | - const session = await getSession() |
27 | | - if (!session?.user?.id) { |
28 | | - return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) |
29 | | - } |
30 | | - |
31 | | - const parsed = await parseRequest(updateCustomBlockContract, request, context) |
32 | | - if (!parsed.success) return parsed.response |
33 | | - |
34 | | - const { id } = parsed.data.params |
35 | | - const authz = await authorizeManage(session.user.id, id) |
36 | | - if (authz.error) return authz.error |
37 | | - const { ctx } = authz |
38 | | - |
39 | | - const { name, description, enabled, iconUrl, inputs, exposedOutputs, traceChildRuns } = |
40 | | - parsed.data.body |
41 | | - try { |
42 | | - await updateCustomBlock(id, { |
43 | | - name, |
44 | | - description, |
45 | | - enabled, |
46 | | - inputs, |
47 | | - iconUrl, |
48 | | - exposedOutputs, |
49 | | - traceChildRuns, |
50 | | - }) |
51 | | - recordAudit({ |
52 | | - workspaceId: ctx.sourceWorkspaceId, |
53 | | - actorId: session.user.id, |
54 | | - actorName: session.user.name, |
55 | | - actorEmail: session.user.email, |
56 | | - action: AuditAction.CUSTOM_BLOCK_UPDATED, |
57 | | - resourceType: AuditResourceType.CUSTOM_BLOCK, |
58 | | - resourceId: id, |
59 | | - resourceName: name ?? ctx.name, |
60 | | - description: `Updated custom block "${name ?? ctx.name}"`, |
61 | | - metadata: { organizationId: ctx.organizationId, type: ctx.type }, |
62 | | - request, |
63 | | - }) |
64 | | - return NextResponse.json({ success: true as const }) |
65 | | - } catch (error) { |
66 | | - if (error instanceof CustomBlockValidationError) { |
67 | | - return NextResponse.json({ error: error.message }, { status: 400 }) |
68 | | - } |
69 | | - logger.error('Failed to update custom block', { id, error: getErrorMessage(error) }) |
70 | | - throw error |
71 | | - } |
| 6 | + defineInternalJsonRoute, |
| 7 | + internalRateLimits, |
| 8 | + internalSessionAuth, |
| 9 | +} from '@/lib/api/server/routes' |
| 10 | +import { |
| 11 | + customBlockSettingsOperations, |
| 12 | + deleteCustomBlockSettings, |
| 13 | + updateCustomBlockSettings, |
| 14 | +} from '@/lib/workflows/custom-blocks/application/settings' |
| 15 | +import { customBlockError } from '@/app/api/custom-blocks/errors' |
| 16 | + |
| 17 | +export const PATCH = defineInternalJsonRoute({ |
| 18 | + contract: updateCustomBlockContract, |
| 19 | + auth: internalSessionAuth, |
| 20 | + operation: customBlockSettingsOperations.update, |
| 21 | + rateLimit: internalRateLimits.none({ reason: 'Preserve existing custom block update policy.' }), |
| 22 | + errorPolicy: { project: customBlockError }, |
| 23 | + mapInput: ({ params, body }) => ({ id: params.id, patch: body }), |
| 24 | + useCase: updateCustomBlockSettings, |
72 | 25 | }) |
73 | 26 |
|
74 | | -export const DELETE = withRouteHandler(async (request: NextRequest, context: RouteContext) => { |
75 | | - const session = await getSession() |
76 | | - if (!session?.user?.id) { |
77 | | - return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) |
78 | | - } |
79 | | - |
80 | | - const parsed = await parseRequest(deleteCustomBlockContract, request, context) |
81 | | - if (!parsed.success) return parsed.response |
82 | | - |
83 | | - const { id } = parsed.data.params |
84 | | - const authz = await authorizeManage(session.user.id, id) |
85 | | - if (authz.error) return authz.error |
86 | | - const { ctx } = authz |
87 | | - |
88 | | - const usageCounts = await getCustomBlockUsageCounts(ctx.organizationId, ctx.type) |
89 | | - await deleteCustomBlock(id) |
90 | | - recordAudit({ |
91 | | - workspaceId: ctx.sourceWorkspaceId, |
92 | | - actorId: session.user.id, |
93 | | - actorName: session.user.name, |
94 | | - actorEmail: session.user.email, |
95 | | - action: AuditAction.CUSTOM_BLOCK_DELETED, |
96 | | - resourceType: AuditResourceType.CUSTOM_BLOCK, |
97 | | - resourceId: id, |
98 | | - resourceName: ctx.name, |
99 | | - description: `Unpublished custom block "${ctx.name}"`, |
100 | | - metadata: { |
101 | | - organizationId: ctx.organizationId, |
102 | | - type: ctx.type, |
103 | | - usageCount: usageCounts.usageCount, |
104 | | - deployedUsageCount: usageCounts.deployedUsageCount, |
105 | | - }, |
106 | | - request, |
107 | | - }) |
108 | | - return NextResponse.json({ success: true as const }) |
| 27 | +export const DELETE = defineInternalJsonRoute({ |
| 28 | + contract: deleteCustomBlockContract, |
| 29 | + auth: internalSessionAuth, |
| 30 | + operation: customBlockSettingsOperations.delete, |
| 31 | + rateLimit: internalRateLimits.none({ reason: 'Preserve existing custom block deletion policy.' }), |
| 32 | + errorPolicy: { project: customBlockError }, |
| 33 | + mapInput: ({ params }) => params, |
| 34 | + useCase: deleteCustomBlockSettings, |
| 35 | + present: () => ({ success: true as const }), |
109 | 36 | }) |
0 commit comments