@open-mercato/core 0.6.2-develop.3400.1.d948268f50 → 0.6.2-develop.3406.1.2b403f40da

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/generated/entities/workflow_definition/index.js +2 -0
  3. package/dist/generated/entities/workflow_definition/index.js.map +2 -2
  4. package/dist/generated/entity-fields-registry.js +1 -0
  5. package/dist/generated/entity-fields-registry.js.map +2 -2
  6. package/dist/modules/sales/workflows.js +180 -0
  7. package/dist/modules/sales/workflows.js.map +7 -0
  8. package/dist/modules/workflows/api/definitions/[id]/customize/route.js +172 -0
  9. package/dist/modules/workflows/api/definitions/[id]/customize/route.js.map +7 -0
  10. package/dist/modules/workflows/api/definitions/[id]/reset-to-code/route.js +205 -0
  11. package/dist/modules/workflows/api/definitions/[id]/reset-to-code/route.js.map +7 -0
  12. package/dist/modules/workflows/api/definitions/[id]/route.js +91 -2
  13. package/dist/modules/workflows/api/definitions/[id]/route.js.map +2 -2
  14. package/dist/modules/workflows/api/definitions/route.js +32 -9
  15. package/dist/modules/workflows/api/definitions/route.js.map +2 -2
  16. package/dist/modules/workflows/api/definitions/serialize.js +36 -1
  17. package/dist/modules/workflows/api/definitions/serialize.js.map +2 -2
  18. package/dist/modules/workflows/backend/definitions/[id]/page.js +161 -52
  19. package/dist/modules/workflows/backend/definitions/[id]/page.js.map +2 -2
  20. package/dist/modules/workflows/backend/definitions/page.js +37 -34
  21. package/dist/modules/workflows/backend/definitions/page.js.map +2 -2
  22. package/dist/modules/workflows/backend/definitions/visual-editor/page.js +134 -41
  23. package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
  24. package/dist/modules/workflows/cli.js +19 -121
  25. package/dist/modules/workflows/cli.js.map +2 -2
  26. package/dist/modules/workflows/components/formConfig.js +1 -1
  27. package/dist/modules/workflows/components/formConfig.js.map +2 -2
  28. package/dist/modules/workflows/data/entities.js +3 -0
  29. package/dist/modules/workflows/data/entities.js.map +2 -2
  30. package/dist/modules/workflows/data/validators.js +2 -2
  31. package/dist/modules/workflows/data/validators.js.map +2 -2
  32. package/dist/modules/workflows/events.js +2 -0
  33. package/dist/modules/workflows/events.js.map +2 -2
  34. package/dist/modules/workflows/examples/guard-rules-example.json +6 -6
  35. package/dist/modules/workflows/examples/order-approval-guard-rules.json +2 -2
  36. package/dist/modules/workflows/frontend/checkout-demo/page.js +4 -4
  37. package/dist/modules/workflows/frontend/checkout-demo/page.js.map +2 -2
  38. package/dist/modules/workflows/lib/code-registry.js +40 -0
  39. package/dist/modules/workflows/lib/code-registry.js.map +7 -0
  40. package/dist/modules/workflows/lib/find-definition.js +58 -0
  41. package/dist/modules/workflows/lib/find-definition.js.map +7 -0
  42. package/dist/modules/workflows/lib/seeds.js +0 -3
  43. package/dist/modules/workflows/lib/seeds.js.map +2 -2
  44. package/dist/modules/workflows/lib/start-validator.js +1 -20
  45. package/dist/modules/workflows/lib/start-validator.js.map +2 -2
  46. package/dist/modules/workflows/lib/workflow-executor.js +1 -19
  47. package/dist/modules/workflows/lib/workflow-executor.js.map +2 -2
  48. package/dist/modules/workflows/migrations/Migration20260414120000.js +13 -0
  49. package/dist/modules/workflows/migrations/Migration20260414120000.js.map +7 -0
  50. package/dist/modules/workflows/migrations/Migration20260428102318.js +32 -0
  51. package/dist/modules/workflows/migrations/Migration20260428102318.js.map +7 -0
  52. package/dist/modules/workflows/widgets/injection/order-approval/widget.client.js +1 -1
  53. package/dist/modules/workflows/widgets/injection/order-approval/widget.client.js.map +1 -1
  54. package/dist/modules/workflows/workflows.js +260 -0
  55. package/dist/modules/workflows/workflows.js.map +7 -0
  56. package/generated/entities/workflow_definition/index.ts +1 -0
  57. package/generated/entity-fields-registry.ts +1 -0
  58. package/package.json +7 -7
  59. package/src/modules/sales/workflows.ts +184 -0
  60. package/src/modules/workflows/api/definitions/[id]/customize/route.ts +197 -0
  61. package/src/modules/workflows/api/definitions/[id]/reset-to-code/route.ts +252 -0
  62. package/src/modules/workflows/api/definitions/[id]/route.ts +108 -4
  63. package/src/modules/workflows/api/definitions/route.ts +54 -10
  64. package/src/modules/workflows/api/definitions/serialize.ts +42 -0
  65. package/src/modules/workflows/backend/definitions/[id]/page.tsx +135 -11
  66. package/src/modules/workflows/backend/definitions/page.tsx +45 -33
  67. package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +222 -97
  68. package/src/modules/workflows/cli.ts +32 -155
  69. package/src/modules/workflows/components/formConfig.tsx +2 -2
  70. package/src/modules/workflows/data/entities.ts +4 -1
  71. package/src/modules/workflows/data/validators.ts +4 -3
  72. package/src/modules/workflows/events.ts +2 -0
  73. package/src/modules/workflows/examples/guard-rules-example.json +6 -6
  74. package/src/modules/workflows/examples/order-approval-guard-rules.json +2 -2
  75. package/src/modules/workflows/frontend/checkout-demo/page.tsx +4 -4
  76. package/src/modules/workflows/i18n/de.json +16 -0
  77. package/src/modules/workflows/i18n/en.json +16 -0
  78. package/src/modules/workflows/i18n/es.json +16 -0
  79. package/src/modules/workflows/i18n/pl.json +16 -0
  80. package/src/modules/workflows/lib/code-registry.ts +65 -0
  81. package/src/modules/workflows/lib/find-definition.ts +100 -0
  82. package/src/modules/workflows/lib/seeds.ts +4 -3
  83. package/src/modules/workflows/lib/start-validator.ts +2 -35
  84. package/src/modules/workflows/lib/workflow-executor.ts +2 -39
  85. package/src/modules/workflows/migrations/.snapshot-open-mercato.json +10 -0
  86. package/src/modules/workflows/migrations/Migration20260414120000.ts +13 -0
  87. package/src/modules/workflows/migrations/Migration20260428102318.ts +57 -0
  88. package/src/modules/workflows/widgets/injection/order-approval/widget.client.tsx +1 -1
  89. package/src/modules/workflows/workflows.ts +278 -0
  90. package/dist/modules/workflows/examples/checkout-demo-definition.json +0 -486
  91. package/dist/modules/workflows/examples/order-approval-definition.json +0 -257
  92. package/dist/modules/workflows/examples/simple-approval-definition.json +0 -134
  93. package/src/modules/workflows/examples/checkout-demo-definition.json +0 -486
  94. package/src/modules/workflows/examples/order-approval-definition.json +0 -257
  95. package/src/modules/workflows/examples/simple-approval-definition.json +0 -134
@@ -0,0 +1,180 @@
1
+ import { defineWorkflow, createWorkflowsModuleConfig } from "@open-mercato/shared/modules/workflows";
2
+ const orderApproval = defineWorkflow({
3
+ workflowId: "sales.order-approval",
4
+ workflowName: "Sales Order Approval Workflow",
5
+ description: "Approval workflow for sales orders requiring authorization before processing",
6
+ metadata: { category: "Sales", tags: ["sales", "approval", "order"], icon: "check-circle" },
7
+ steps: [
8
+ { stepId: "start", stepName: "Start", stepType: "START", description: "Initialize order approval workflow" },
9
+ {
10
+ stepId: "pending_approval",
11
+ stepName: "Pending Approval",
12
+ stepType: "USER_TASK",
13
+ description: "Order awaiting approval decision",
14
+ userTaskConfig: {
15
+ formSchema: {
16
+ type: "object",
17
+ required: ["decision"],
18
+ properties: {
19
+ comments: { type: "string", title: "Comments", description: "Optional comments for the decision" },
20
+ decision: { enum: ["approve", "reject"], type: "string", title: "Decision", description: "Approve or reject the order" }
21
+ }
22
+ },
23
+ slaDuration: "PT24H"
24
+ }
25
+ },
26
+ { stepId: "approved", stepName: "Approved", stepType: "AUTOMATED", description: "Order has been approved" },
27
+ { stepId: "rejected", stepName: "Rejected", stepType: "AUTOMATED", description: "Order has been rejected" },
28
+ { stepId: "end", stepName: "Complete", stepType: "END", description: "Workflow complete" }
29
+ ],
30
+ transitions: [
31
+ {
32
+ transitionId: "start_to_pending",
33
+ transitionName: "Submit for Approval",
34
+ fromStepId: "start",
35
+ toStepId: "pending_approval",
36
+ trigger: "auto",
37
+ priority: 100,
38
+ continueOnActivityFailure: true,
39
+ activities: [
40
+ {
41
+ activityId: "set_pending_status",
42
+ activityName: "Set Order to Pending Approval",
43
+ activityType: "UPDATE_ENTITY",
44
+ async: false,
45
+ config: {
46
+ commandId: "sales.orders.update",
47
+ statusDictionary: "sales.order_status",
48
+ input: { id: "{{context.id}}", statusValue: "pending_approval" }
49
+ },
50
+ retryPolicy: { maxAttempts: 3, initialIntervalMs: 1e3, backoffCoefficient: 2, maxIntervalMs: 1e4 }
51
+ },
52
+ {
53
+ activityId: "emit_approval_requested",
54
+ activityName: "Emit Approval Requested Event",
55
+ activityType: "EMIT_EVENT",
56
+ async: true,
57
+ config: {
58
+ eventName: "sales.order.approval.requested",
59
+ payload: { orderId: "{{context.id}}", workflowInstanceId: "{{workflow.instanceId}}" }
60
+ }
61
+ }
62
+ ]
63
+ },
64
+ {
65
+ transitionId: "pending_approval_to_approved",
66
+ transitionName: "Approve Order",
67
+ fromStepId: "pending_approval",
68
+ toStepId: "approved",
69
+ trigger: "auto",
70
+ priority: 100,
71
+ preConditions: [{ ruleId: "workflow_order_approval_check_approved", required: true }],
72
+ continueOnActivityFailure: true,
73
+ activities: [
74
+ {
75
+ activityId: "set_approved_status",
76
+ activityName: "Set Order to Approved",
77
+ activityType: "UPDATE_ENTITY",
78
+ async: false,
79
+ config: {
80
+ commandId: "sales.orders.update",
81
+ statusDictionary: "sales.order_status",
82
+ input: { id: "{{context.id}}", statusValue: "approved" }
83
+ },
84
+ retryPolicy: { maxAttempts: 3, initialIntervalMs: 1e3, backoffCoefficient: 2, maxIntervalMs: 1e4 }
85
+ },
86
+ {
87
+ activityId: "emit_order_approved",
88
+ activityName: "Emit Order Approved Event",
89
+ activityType: "EMIT_EVENT",
90
+ async: true,
91
+ config: {
92
+ eventName: "sales.order.approval.approved",
93
+ payload: {
94
+ orderId: "{{context.id}}",
95
+ workflowInstanceId: "{{workflow.instanceId}}",
96
+ approvedBy: "{{context.completedBy}}",
97
+ comments: "{{context.comments}}"
98
+ }
99
+ }
100
+ }
101
+ ]
102
+ },
103
+ {
104
+ transitionId: "pending_approval_to_rejected",
105
+ transitionName: "Reject Order",
106
+ fromStepId: "pending_approval",
107
+ toStepId: "rejected",
108
+ trigger: "auto",
109
+ priority: 90,
110
+ preConditions: [{ ruleId: "workflow_order_approval_check_rejected", required: true }],
111
+ continueOnActivityFailure: true,
112
+ activities: [
113
+ {
114
+ activityId: "set_rejected_status",
115
+ activityName: "Set Order to Rejected",
116
+ activityType: "UPDATE_ENTITY",
117
+ async: false,
118
+ config: {
119
+ commandId: "sales.orders.update",
120
+ statusDictionary: "sales.order_status",
121
+ input: { id: "{{context.id}}", statusValue: "rejected" }
122
+ },
123
+ retryPolicy: { maxAttempts: 3, initialIntervalMs: 1e3, backoffCoefficient: 2, maxIntervalMs: 1e4 }
124
+ },
125
+ {
126
+ activityId: "emit_order_rejected",
127
+ activityName: "Emit Order Rejected Event",
128
+ activityType: "EMIT_EVENT",
129
+ async: true,
130
+ config: {
131
+ eventName: "sales.order.approval.rejected",
132
+ payload: {
133
+ orderId: "{{context.id}}",
134
+ workflowInstanceId: "{{workflow.instanceId}}",
135
+ rejectedBy: "{{context.completedBy}}",
136
+ comments: "{{context.comments}}"
137
+ }
138
+ }
139
+ }
140
+ ]
141
+ },
142
+ {
143
+ transitionId: "approved_to_end",
144
+ transitionName: "Complete After Approval",
145
+ fromStepId: "approved",
146
+ toStepId: "end",
147
+ trigger: "auto",
148
+ priority: 100,
149
+ continueOnActivityFailure: true
150
+ },
151
+ {
152
+ transitionId: "rejected_to_end",
153
+ transitionName: "Complete After Rejection",
154
+ fromStepId: "rejected",
155
+ toStepId: "end",
156
+ trigger: "auto",
157
+ priority: 100,
158
+ continueOnActivityFailure: true
159
+ }
160
+ ],
161
+ triggers: [{
162
+ triggerId: "order_approval_trigger",
163
+ name: "Order Approval Trigger",
164
+ description: "Triggers when a new sales order is created",
165
+ eventPattern: "sales.orders.created",
166
+ config: { entityType: "SalesOrder" },
167
+ enabled: true,
168
+ priority: 0
169
+ }]
170
+ });
171
+ const workflowsConfig = createWorkflowsModuleConfig({
172
+ moduleId: "sales",
173
+ workflows: [orderApproval]
174
+ });
175
+ var workflows_default = workflowsConfig;
176
+ export {
177
+ workflows_default as default,
178
+ workflowsConfig
179
+ };
180
+ //# sourceMappingURL=workflows.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/modules/sales/workflows.ts"],
4
+ "sourcesContent": ["/**\n * Sales Module \u2014 Code-Based Workflow Definitions\n *\n * Order approval workflow shipped with the sales module.\n */\n\nimport { defineWorkflow, createWorkflowsModuleConfig } from '@open-mercato/shared/modules/workflows'\n\nconst orderApproval = defineWorkflow({\n workflowId: 'sales.order-approval',\n workflowName: 'Sales Order Approval Workflow',\n description: 'Approval workflow for sales orders requiring authorization before processing',\n metadata: { category: 'Sales', tags: ['sales', 'approval', 'order'], icon: 'check-circle' },\n steps: [\n { stepId: 'start', stepName: 'Start', stepType: 'START', description: 'Initialize order approval workflow' },\n {\n stepId: 'pending_approval',\n stepName: 'Pending Approval',\n stepType: 'USER_TASK',\n description: 'Order awaiting approval decision',\n userTaskConfig: {\n formSchema: {\n type: 'object',\n required: ['decision'],\n properties: {\n comments: { type: 'string', title: 'Comments', description: 'Optional comments for the decision' },\n decision: { enum: ['approve', 'reject'], type: 'string', title: 'Decision', description: 'Approve or reject the order' },\n },\n },\n slaDuration: 'PT24H',\n },\n },\n { stepId: 'approved', stepName: 'Approved', stepType: 'AUTOMATED', description: 'Order has been approved' },\n { stepId: 'rejected', stepName: 'Rejected', stepType: 'AUTOMATED', description: 'Order has been rejected' },\n { stepId: 'end', stepName: 'Complete', stepType: 'END', description: 'Workflow complete' },\n ] as const,\n transitions: [\n {\n transitionId: 'start_to_pending',\n transitionName: 'Submit for Approval',\n fromStepId: 'start',\n toStepId: 'pending_approval',\n trigger: 'auto',\n priority: 100,\n continueOnActivityFailure: true,\n activities: [\n {\n activityId: 'set_pending_status',\n activityName: 'Set Order to Pending Approval',\n activityType: 'UPDATE_ENTITY',\n async: false,\n config: {\n commandId: 'sales.orders.update',\n statusDictionary: 'sales.order_status',\n input: { id: '{{context.id}}', statusValue: 'pending_approval' },\n },\n retryPolicy: { maxAttempts: 3, initialIntervalMs: 1000, backoffCoefficient: 2, maxIntervalMs: 10000 },\n },\n {\n activityId: 'emit_approval_requested',\n activityName: 'Emit Approval Requested Event',\n activityType: 'EMIT_EVENT',\n async: true,\n config: {\n eventName: 'sales.order.approval.requested',\n payload: { orderId: '{{context.id}}', workflowInstanceId: '{{workflow.instanceId}}' },\n },\n },\n ],\n },\n {\n transitionId: 'pending_approval_to_approved',\n transitionName: 'Approve Order',\n fromStepId: 'pending_approval',\n toStepId: 'approved',\n trigger: 'auto',\n priority: 100,\n preConditions: [{ ruleId: 'workflow_order_approval_check_approved', required: true }],\n continueOnActivityFailure: true,\n activities: [\n {\n activityId: 'set_approved_status',\n activityName: 'Set Order to Approved',\n activityType: 'UPDATE_ENTITY',\n async: false,\n config: {\n commandId: 'sales.orders.update',\n statusDictionary: 'sales.order_status',\n input: { id: '{{context.id}}', statusValue: 'approved' },\n },\n retryPolicy: { maxAttempts: 3, initialIntervalMs: 1000, backoffCoefficient: 2, maxIntervalMs: 10000 },\n },\n {\n activityId: 'emit_order_approved',\n activityName: 'Emit Order Approved Event',\n activityType: 'EMIT_EVENT',\n async: true,\n config: {\n eventName: 'sales.order.approval.approved',\n payload: {\n orderId: '{{context.id}}',\n workflowInstanceId: '{{workflow.instanceId}}',\n approvedBy: '{{context.completedBy}}',\n comments: '{{context.comments}}',\n },\n },\n },\n ],\n },\n {\n transitionId: 'pending_approval_to_rejected',\n transitionName: 'Reject Order',\n fromStepId: 'pending_approval',\n toStepId: 'rejected',\n trigger: 'auto',\n priority: 90,\n preConditions: [{ ruleId: 'workflow_order_approval_check_rejected', required: true }],\n continueOnActivityFailure: true,\n activities: [\n {\n activityId: 'set_rejected_status',\n activityName: 'Set Order to Rejected',\n activityType: 'UPDATE_ENTITY',\n async: false,\n config: {\n commandId: 'sales.orders.update',\n statusDictionary: 'sales.order_status',\n input: { id: '{{context.id}}', statusValue: 'rejected' },\n },\n retryPolicy: { maxAttempts: 3, initialIntervalMs: 1000, backoffCoefficient: 2, maxIntervalMs: 10000 },\n },\n {\n activityId: 'emit_order_rejected',\n activityName: 'Emit Order Rejected Event',\n activityType: 'EMIT_EVENT',\n async: true,\n config: {\n eventName: 'sales.order.approval.rejected',\n payload: {\n orderId: '{{context.id}}',\n workflowInstanceId: '{{workflow.instanceId}}',\n rejectedBy: '{{context.completedBy}}',\n comments: '{{context.comments}}',\n },\n },\n },\n ],\n },\n {\n transitionId: 'approved_to_end',\n transitionName: 'Complete After Approval',\n fromStepId: 'approved',\n toStepId: 'end',\n trigger: 'auto',\n priority: 100,\n continueOnActivityFailure: true,\n },\n {\n transitionId: 'rejected_to_end',\n transitionName: 'Complete After Rejection',\n fromStepId: 'rejected',\n toStepId: 'end',\n trigger: 'auto',\n priority: 100,\n continueOnActivityFailure: true,\n },\n ],\n triggers: [{\n triggerId: 'order_approval_trigger',\n name: 'Order Approval Trigger',\n description: 'Triggers when a new sales order is created',\n eventPattern: 'sales.orders.created',\n config: { entityType: 'SalesOrder' },\n enabled: true,\n priority: 0,\n }],\n})\n\nexport const workflowsConfig = createWorkflowsModuleConfig({\n moduleId: 'sales',\n workflows: [orderApproval],\n})\n\nexport default workflowsConfig\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,172 @@
1
+ import { NextResponse } from "next/server";
2
+ import { z } from "zod";
3
+ import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
4
+ import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
5
+ import { resolveOrganizationScopeForRequest } from "@open-mercato/core/modules/directory/utils/organizationScope";
6
+ import { validateCrudMutationGuard, runCrudMutationGuardAfterSuccess } from "@open-mercato/shared/lib/crud/mutation-guard";
7
+ import { WorkflowDefinition } from "../../../../data/entities.js";
8
+ import { serializeWorkflowDefinition } from "../../serialize.js";
9
+ import { getCodeWorkflow } from "../../../../lib/code-registry.js";
10
+ const metadata = {
11
+ requireAuth: true,
12
+ requireFeatures: ["workflows.definitions.edit"]
13
+ };
14
+ async function POST(request, context) {
15
+ try {
16
+ const params = await context.params;
17
+ const container = await createRequestContainer();
18
+ const em = container.resolve("em");
19
+ const auth = await getAuthFromRequest(request);
20
+ if (!auth) {
21
+ return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
22
+ }
23
+ const scope = await resolveOrganizationScopeForRequest({ container, auth, request });
24
+ const tenantId = auth.tenantId;
25
+ const organizationId = scope?.selectedId ?? auth.orgId;
26
+ if (!params.id.startsWith("code:")) {
27
+ return NextResponse.json(
28
+ { error: "Customize is only supported for code-based workflow definitions" },
29
+ { status: 400 }
30
+ );
31
+ }
32
+ const workflowId = params.id.slice(5);
33
+ const codeDef = getCodeWorkflow(workflowId);
34
+ if (!codeDef) {
35
+ return NextResponse.json({ error: "Workflow definition not found" }, { status: 404 });
36
+ }
37
+ const guardResult = await validateCrudMutationGuard(container, {
38
+ tenantId: tenantId ?? "",
39
+ organizationId: organizationId ?? null,
40
+ userId: auth.sub ?? "",
41
+ resourceKind: "workflows.definition",
42
+ resourceId: params.id,
43
+ operation: "custom",
44
+ requestMethod: "POST",
45
+ requestHeaders: request.headers
46
+ });
47
+ if (guardResult && !guardResult.ok) {
48
+ return NextResponse.json(guardResult.body, { status: guardResult.status });
49
+ }
50
+ const existingOverride = await em.findOne(WorkflowDefinition, {
51
+ workflowId: codeDef.workflowId,
52
+ tenantId
53
+ });
54
+ let saved;
55
+ if (existingOverride) {
56
+ existingOverride.deletedAt = null;
57
+ existingOverride.workflowName = codeDef.workflowName;
58
+ existingOverride.description = codeDef.description;
59
+ existingOverride.version = codeDef.version;
60
+ existingOverride.definition = codeDef.definition;
61
+ existingOverride.metadata = codeDef.metadata ?? null;
62
+ existingOverride.enabled = codeDef.enabled;
63
+ existingOverride.codeWorkflowId = codeDef.workflowId;
64
+ existingOverride.updatedBy = auth.sub;
65
+ existingOverride.updatedAt = /* @__PURE__ */ new Date();
66
+ await em.flush();
67
+ saved = existingOverride;
68
+ } else {
69
+ const override = em.create(WorkflowDefinition, {
70
+ workflowId: codeDef.workflowId,
71
+ workflowName: codeDef.workflowName,
72
+ description: codeDef.description,
73
+ version: codeDef.version,
74
+ definition: codeDef.definition,
75
+ metadata: codeDef.metadata,
76
+ enabled: codeDef.enabled,
77
+ codeWorkflowId: codeDef.workflowId,
78
+ tenantId,
79
+ organizationId,
80
+ createdBy: auth.sub,
81
+ updatedBy: auth.sub,
82
+ createdAt: /* @__PURE__ */ new Date(),
83
+ updatedAt: /* @__PURE__ */ new Date()
84
+ });
85
+ em.persist(override);
86
+ await em.flush();
87
+ saved = override;
88
+ }
89
+ if (guardResult?.shouldRunAfterSuccess) {
90
+ await runCrudMutationGuardAfterSuccess(container, {
91
+ tenantId: tenantId ?? "",
92
+ organizationId: organizationId ?? null,
93
+ userId: auth.sub ?? "",
94
+ resourceKind: "workflows.definition",
95
+ resourceId: String(saved.id),
96
+ operation: "custom",
97
+ requestMethod: "POST",
98
+ requestHeaders: request.headers,
99
+ metadata: guardResult.metadata
100
+ });
101
+ }
102
+ try {
103
+ const eventBus = container.resolve("eventBus");
104
+ if (eventBus && typeof eventBus.emitEvent === "function") {
105
+ await eventBus.emitEvent(
106
+ "workflows.definition.customized",
107
+ {
108
+ id: saved.id,
109
+ workflowId: saved.workflowId,
110
+ codeWorkflowId: saved.codeWorkflowId ?? null,
111
+ tenantId: saved.tenantId,
112
+ organizationId: saved.organizationId,
113
+ userId: auth.sub ?? null
114
+ },
115
+ { tenantId: saved.tenantId, organizationId: saved.organizationId, persistent: true }
116
+ );
117
+ }
118
+ } catch (eventError) {
119
+ console.error("Failed to emit workflows.definition.customized event:", eventError);
120
+ }
121
+ return NextResponse.json({
122
+ data: serializeWorkflowDefinition(saved),
123
+ message: "Workflow definition customized successfully"
124
+ });
125
+ } catch (error) {
126
+ console.error("Error customizing workflow definition:", error);
127
+ return NextResponse.json({ error: "Failed to customize workflow definition" }, { status: 500 });
128
+ }
129
+ }
130
+ const openApi = {
131
+ methods: {
132
+ POST: {
133
+ summary: "Customize code-based workflow definition",
134
+ description: 'Creates a DB override for a code-based workflow definition, seeded from the current code registry values. The id param must be of the form "code:<workflowId>".',
135
+ tags: ["Workflows"],
136
+ pathParams: z.object({
137
+ id: z.string().describe('Must be of the form "code:<workflowId>"')
138
+ }),
139
+ responses: [
140
+ {
141
+ status: 200,
142
+ description: "Workflow definition customized successfully",
143
+ example: {
144
+ data: {
145
+ id: "123e4567-e89b-12d3-a456-426614174000",
146
+ workflowId: "workflows.simple-approval",
147
+ workflowName: "Simple Approval Workflow",
148
+ source: "code_override"
149
+ },
150
+ message: "Workflow definition customized successfully"
151
+ }
152
+ },
153
+ {
154
+ status: 400,
155
+ description: "Not a code-based id",
156
+ example: { error: "Customize is only supported for code-based workflow definitions" }
157
+ },
158
+ {
159
+ status: 404,
160
+ description: "Code workflow not found",
161
+ example: { error: "Workflow definition not found" }
162
+ }
163
+ ]
164
+ }
165
+ }
166
+ };
167
+ export {
168
+ POST,
169
+ metadata,
170
+ openApi
171
+ };
172
+ //# sourceMappingURL=route.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../src/modules/workflows/api/definitions/%5Bid%5D/customize/route.ts"],
4
+ "sourcesContent": ["/**\n * Customize Code-Based Workflow Definition\n *\n * POST /api/workflows/definitions/[id]/customize\n *\n * Creates a DB override row for a code-based workflow definition, seeded from\n * the current code registry values. The id param must be of the form\n * \"code:<workflowId>\".\n */\n\nimport { NextRequest, NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { validateCrudMutationGuard, runCrudMutationGuardAfterSuccess } from '@open-mercato/shared/lib/crud/mutation-guard'\nimport { WorkflowDefinition } from '../../../../data/entities'\nimport { serializeWorkflowDefinition } from '../../serialize'\nimport { getCodeWorkflow } from '../../../../lib/code-registry'\n\nexport const metadata = {\n requireAuth: true,\n requireFeatures: ['workflows.definitions.edit'],\n}\n\ninterface RouteContext {\n params: Promise<{\n id: string\n }>\n}\n\nexport async function POST(request: NextRequest, context: RouteContext) {\n try {\n const params = await context.params\n const container = await createRequestContainer()\n const em = container.resolve('em')\n const auth = await getAuthFromRequest(request)\n\n if (!auth) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request })\n const tenantId = auth.tenantId\n const organizationId = scope?.selectedId ?? auth.orgId\n\n if (!params.id.startsWith('code:')) {\n return NextResponse.json(\n { error: 'Customize is only supported for code-based workflow definitions' },\n { status: 400 },\n )\n }\n\n const workflowId = params.id.slice(5)\n const codeDef = getCodeWorkflow(workflowId)\n if (!codeDef) {\n return NextResponse.json({ error: 'Workflow definition not found' }, { status: 404 })\n }\n\n const guardResult = await validateCrudMutationGuard(container, {\n tenantId: tenantId ?? '',\n organizationId: organizationId ?? null,\n userId: auth.sub ?? '',\n resourceKind: 'workflows.definition',\n resourceId: params.id,\n operation: 'custom',\n requestMethod: 'POST',\n requestHeaders: request.headers,\n })\n if (guardResult && !guardResult.ok) {\n return NextResponse.json(guardResult.body, { status: guardResult.status })\n }\n\n const existingOverride = await em.findOne(WorkflowDefinition, {\n workflowId: codeDef.workflowId,\n tenantId,\n })\n\n let saved: WorkflowDefinition\n if (existingOverride) {\n existingOverride.deletedAt = null\n existingOverride.workflowName = codeDef.workflowName\n existingOverride.description = codeDef.description\n existingOverride.version = codeDef.version\n existingOverride.definition = codeDef.definition\n existingOverride.metadata = codeDef.metadata ?? null\n existingOverride.enabled = codeDef.enabled\n existingOverride.codeWorkflowId = codeDef.workflowId\n existingOverride.updatedBy = auth.sub\n existingOverride.updatedAt = new Date()\n await em.flush()\n saved = existingOverride\n } else {\n const override = em.create(WorkflowDefinition, {\n workflowId: codeDef.workflowId,\n workflowName: codeDef.workflowName,\n description: codeDef.description,\n version: codeDef.version,\n definition: codeDef.definition,\n metadata: codeDef.metadata,\n enabled: codeDef.enabled,\n codeWorkflowId: codeDef.workflowId,\n tenantId,\n organizationId,\n createdBy: auth.sub,\n updatedBy: auth.sub,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(override)\n await em.flush()\n saved = override\n }\n\n if (guardResult?.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(container, {\n tenantId: tenantId ?? '',\n organizationId: organizationId ?? null,\n userId: auth.sub ?? '',\n resourceKind: 'workflows.definition',\n resourceId: String(saved.id),\n operation: 'custom',\n requestMethod: 'POST',\n requestHeaders: request.headers,\n metadata: guardResult.metadata,\n })\n }\n\n try {\n const eventBus = container.resolve('eventBus') as\n | { emitEvent(event: string, payload: unknown, options?: unknown): Promise<void> }\n | undefined\n if (eventBus && typeof eventBus.emitEvent === 'function') {\n await eventBus.emitEvent(\n 'workflows.definition.customized',\n {\n id: saved.id,\n workflowId: saved.workflowId,\n codeWorkflowId: saved.codeWorkflowId ?? null,\n tenantId: saved.tenantId,\n organizationId: saved.organizationId,\n userId: auth.sub ?? null,\n },\n { tenantId: saved.tenantId, organizationId: saved.organizationId, persistent: true },\n )\n }\n } catch (eventError) {\n console.error('Failed to emit workflows.definition.customized event:', eventError)\n }\n\n return NextResponse.json({\n data: serializeWorkflowDefinition(saved),\n message: 'Workflow definition customized successfully',\n })\n } catch (error) {\n console.error('Error customizing workflow definition:', error)\n return NextResponse.json({ error: 'Failed to customize workflow definition' }, { status: 500 })\n }\n}\n\nexport const openApi = {\n methods: {\n POST: {\n summary: 'Customize code-based workflow definition',\n description: 'Creates a DB override for a code-based workflow definition, seeded from the current code registry values. The id param must be of the form \"code:<workflowId>\".',\n tags: ['Workflows'],\n pathParams: z.object({\n id: z.string().describe('Must be of the form \"code:<workflowId>\"'),\n }),\n responses: [\n {\n status: 200,\n description: 'Workflow definition customized successfully',\n example: {\n data: {\n id: '123e4567-e89b-12d3-a456-426614174000',\n workflowId: 'workflows.simple-approval',\n workflowName: 'Simple Approval Workflow',\n source: 'code_override',\n },\n message: 'Workflow definition customized successfully',\n },\n },\n {\n status: 400,\n description: 'Not a code-based id',\n example: { error: 'Customize is only supported for code-based workflow definitions' },\n },\n {\n status: 404,\n description: 'Code workflow not found',\n example: { error: 'Workflow definition not found' },\n },\n ],\n },\n },\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,205 @@
1
+ import { NextResponse } from "next/server";
2
+ import { z } from "zod";
3
+ import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
4
+ import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
5
+ import { resolveOrganizationScopeForRequest } from "@open-mercato/core/modules/directory/utils/organizationScope";
6
+ import { validateCrudMutationGuard, runCrudMutationGuardAfterSuccess } from "@open-mercato/shared/lib/crud/mutation-guard";
7
+ import { WorkflowDefinition, WorkflowInstance } from "../../../../data/entities.js";
8
+ import { serializeCodeWorkflowDefinition } from "../../serialize.js";
9
+ import { getCodeWorkflow } from "../../../../lib/code-registry.js";
10
+ const metadata = {
11
+ requireAuth: true,
12
+ requireFeatures: ["workflows.definitions.edit"]
13
+ };
14
+ async function POST(request, context) {
15
+ try {
16
+ const params = await context.params;
17
+ const container = await createRequestContainer();
18
+ const em = container.resolve("em");
19
+ const auth = await getAuthFromRequest(request);
20
+ if (!auth) {
21
+ return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
22
+ }
23
+ const scope = await resolveOrganizationScopeForRequest({ container, auth, request });
24
+ const tenantId = auth.tenantId;
25
+ const organizationId = scope?.selectedId ?? auth.orgId;
26
+ const rbacService = container.resolve("rbacService");
27
+ const hasPermission = await rbacService.userHasAllFeatures(
28
+ auth.sub,
29
+ ["workflows.definitions.edit"],
30
+ {
31
+ tenantId,
32
+ organizationId
33
+ }
34
+ );
35
+ if (!hasPermission) {
36
+ return NextResponse.json(
37
+ { error: "Insufficient permissions" },
38
+ { status: 403 }
39
+ );
40
+ }
41
+ const definition = await em.findOne(WorkflowDefinition, {
42
+ id: params.id,
43
+ tenantId,
44
+ organizationId,
45
+ deletedAt: null
46
+ });
47
+ if (!definition) {
48
+ return NextResponse.json(
49
+ { error: "Workflow definition not found" },
50
+ { status: 404 }
51
+ );
52
+ }
53
+ if (!definition.codeWorkflowId) {
54
+ return NextResponse.json(
55
+ { error: "This workflow definition is not a code-based override and cannot be reset" },
56
+ { status: 400 }
57
+ );
58
+ }
59
+ const activeInstances = await em.count(WorkflowInstance, {
60
+ definitionId: definition.id,
61
+ status: { $in: ["RUNNING", "WAITING"] }
62
+ });
63
+ if (activeInstances > 0) {
64
+ return NextResponse.json(
65
+ {
66
+ error: `Cannot reset workflow definition with ${activeInstances} active instance(s)`
67
+ },
68
+ { status: 409 }
69
+ );
70
+ }
71
+ const guardResult = await validateCrudMutationGuard(container, {
72
+ tenantId: tenantId ?? "",
73
+ organizationId: organizationId ?? null,
74
+ userId: auth.sub ?? "",
75
+ resourceKind: "workflows.definition",
76
+ resourceId: String(definition.id),
77
+ operation: "custom",
78
+ requestMethod: "POST",
79
+ requestHeaders: request.headers
80
+ });
81
+ if (guardResult && !guardResult.ok) {
82
+ return NextResponse.json(guardResult.body, { status: guardResult.status });
83
+ }
84
+ const codeDef = getCodeWorkflow(definition.codeWorkflowId);
85
+ const removedSnapshot = {
86
+ id: String(definition.id),
87
+ workflowId: definition.workflowId,
88
+ codeWorkflowId: definition.codeWorkflowId,
89
+ tenantId: definition.tenantId,
90
+ organizationId: definition.organizationId
91
+ };
92
+ em.remove(definition);
93
+ await em.flush();
94
+ if (guardResult?.shouldRunAfterSuccess) {
95
+ await runCrudMutationGuardAfterSuccess(container, {
96
+ tenantId: tenantId ?? "",
97
+ organizationId: organizationId ?? null,
98
+ userId: auth.sub ?? "",
99
+ resourceKind: "workflows.definition",
100
+ resourceId: removedSnapshot.id,
101
+ operation: "custom",
102
+ requestMethod: "POST",
103
+ requestHeaders: request.headers,
104
+ metadata: guardResult.metadata
105
+ });
106
+ }
107
+ try {
108
+ const eventBus = container.resolve("eventBus");
109
+ if (eventBus && typeof eventBus.emitEvent === "function") {
110
+ await eventBus.emitEvent(
111
+ "workflows.definition.reset_to_code",
112
+ {
113
+ id: removedSnapshot.id,
114
+ workflowId: removedSnapshot.workflowId,
115
+ codeWorkflowId: removedSnapshot.codeWorkflowId,
116
+ tenantId: removedSnapshot.tenantId,
117
+ organizationId: removedSnapshot.organizationId,
118
+ userId: auth.sub ?? null
119
+ },
120
+ {
121
+ tenantId: removedSnapshot.tenantId,
122
+ organizationId: removedSnapshot.organizationId,
123
+ persistent: true
124
+ }
125
+ );
126
+ }
127
+ } catch (eventError) {
128
+ console.error("Failed to emit workflows.definition.reset_to_code event:", eventError);
129
+ }
130
+ if (!codeDef) {
131
+ return NextResponse.json({
132
+ message: "Workflow definition reset to code version (code definition no longer registered)",
133
+ data: null
134
+ });
135
+ }
136
+ const syntheticId = `code:${codeDef.workflowId}`;
137
+ return NextResponse.json({
138
+ data: serializeCodeWorkflowDefinition(codeDef, syntheticId),
139
+ message: "Workflow definition reset to code version"
140
+ });
141
+ } catch (error) {
142
+ console.error("Error resetting workflow definition to code:", error);
143
+ return NextResponse.json(
144
+ { error: "Failed to reset workflow definition to code" },
145
+ { status: 500 }
146
+ );
147
+ }
148
+ }
149
+ const openApi = {
150
+ methods: {
151
+ POST: {
152
+ summary: "Reset workflow definition to code version",
153
+ description: "Deletes the DB override for a code-based workflow definition, reverting it to the original code registry version. Cannot be reset if there are active instances.",
154
+ tags: ["Workflows"],
155
+ pathParams: z.object({
156
+ id: z.string().uuid()
157
+ }),
158
+ responses: [
159
+ {
160
+ status: 200,
161
+ description: "Workflow definition reset to code version",
162
+ example: {
163
+ data: {
164
+ id: "code:checkout-flow",
165
+ workflowId: "checkout-flow",
166
+ workflowName: "Checkout Flow",
167
+ description: "Code-defined checkout workflow",
168
+ version: 1,
169
+ source: "code",
170
+ isCodeBased: true
171
+ },
172
+ message: "Workflow definition reset to code version"
173
+ }
174
+ },
175
+ {
176
+ status: 400,
177
+ description: "Definition is not a code-based override",
178
+ example: {
179
+ error: "This workflow definition is not a code-based override and cannot be reset"
180
+ }
181
+ },
182
+ {
183
+ status: 404,
184
+ description: "Workflow definition not found",
185
+ example: {
186
+ error: "Workflow definition not found"
187
+ }
188
+ },
189
+ {
190
+ status: 409,
191
+ description: "Cannot reset - active workflow instances exist",
192
+ example: {
193
+ error: "Cannot reset workflow definition with 3 active instance(s)"
194
+ }
195
+ }
196
+ ]
197
+ }
198
+ }
199
+ };
200
+ export {
201
+ POST,
202
+ metadata,
203
+ openApi
204
+ };
205
+ //# sourceMappingURL=route.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../src/modules/workflows/api/definitions/%5Bid%5D/reset-to-code/route.ts"],
4
+ "sourcesContent": ["/**\n * Reset Customized Workflow Definition to Code\n *\n * POST /api/workflows/definitions/[id]/reset-to-code\n *\n * Deletes the DB override row for a code-based workflow definition,\n * reverting it back to the original code registry version.\n */\n\nimport { NextRequest, NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { validateCrudMutationGuard, runCrudMutationGuardAfterSuccess } from '@open-mercato/shared/lib/crud/mutation-guard'\nimport { WorkflowDefinition, WorkflowInstance } from '../../../../data/entities'\nimport { serializeCodeWorkflowDefinition } from '../../serialize'\nimport { getCodeWorkflow } from '../../../../lib/code-registry'\n\nexport const metadata = {\n requireAuth: true,\n requireFeatures: ['workflows.definitions.edit'],\n}\n\ninterface RouteContext {\n params: Promise<{\n id: string\n }>\n}\n\n/**\n * POST /api/workflows/definitions/[id]/reset-to-code\n *\n * Reset a customized code workflow definition back to its original code version.\n */\nexport async function POST(\n request: NextRequest,\n context: RouteContext\n) {\n try {\n const params = await context.params\n const container = await createRequestContainer()\n const em = container.resolve('em')\n const auth = await getAuthFromRequest(request)\n\n if (!auth) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request })\n const tenantId = auth.tenantId\n const organizationId = scope?.selectedId ?? auth.orgId\n\n // Check edit permission\n const rbacService = container.resolve('rbacService')\n const hasPermission = await rbacService.userHasAllFeatures(\n auth.sub,\n ['workflows.definitions.edit'],\n {\n tenantId,\n organizationId,\n }\n )\n\n if (!hasPermission) {\n return NextResponse.json(\n { error: 'Insufficient permissions' },\n { status: 403 }\n )\n }\n\n // Find existing definition\n const definition = await em.findOne(WorkflowDefinition, {\n id: params.id,\n tenantId,\n organizationId,\n deletedAt: null,\n })\n\n if (!definition) {\n return NextResponse.json(\n { error: 'Workflow definition not found' },\n { status: 404 }\n )\n }\n\n // Verify this is a code-based override\n if (!definition.codeWorkflowId) {\n return NextResponse.json(\n { error: 'This workflow definition is not a code-based override and cannot be reset' },\n { status: 400 }\n )\n }\n\n // Check if there are active workflow instances using this definition\n const activeInstances = await em.count(WorkflowInstance, {\n definitionId: definition.id,\n status: { $in: ['RUNNING', 'WAITING'] },\n })\n\n if (activeInstances > 0) {\n return NextResponse.json(\n {\n error: `Cannot reset workflow definition with ${activeInstances} active instance(s)`,\n },\n { status: 409 }\n )\n }\n\n const guardResult = await validateCrudMutationGuard(container, {\n tenantId: tenantId ?? '',\n organizationId: organizationId ?? null,\n userId: auth.sub ?? '',\n resourceKind: 'workflows.definition',\n resourceId: String(definition.id),\n operation: 'custom',\n requestMethod: 'POST',\n requestHeaders: request.headers,\n })\n if (guardResult && !guardResult.ok) {\n return NextResponse.json(guardResult.body, { status: guardResult.status })\n }\n\n // Look up the original code definition before deleting\n const codeDef = getCodeWorkflow(definition.codeWorkflowId)\n\n // Snapshot identifying fields before remove() detaches the entity\n const removedSnapshot = {\n id: String(definition.id),\n workflowId: definition.workflowId,\n codeWorkflowId: definition.codeWorkflowId,\n tenantId: definition.tenantId,\n organizationId: definition.organizationId,\n }\n\n // Hard-delete the DB override row\n em.remove(definition)\n await em.flush()\n\n if (guardResult?.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(container, {\n tenantId: tenantId ?? '',\n organizationId: organizationId ?? null,\n userId: auth.sub ?? '',\n resourceKind: 'workflows.definition',\n resourceId: removedSnapshot.id,\n operation: 'custom',\n requestMethod: 'POST',\n requestHeaders: request.headers,\n metadata: guardResult.metadata,\n })\n }\n\n try {\n const eventBus = container.resolve('eventBus') as\n | { emitEvent(event: string, payload: unknown, options?: unknown): Promise<void> }\n | undefined\n if (eventBus && typeof eventBus.emitEvent === 'function') {\n await eventBus.emitEvent(\n 'workflows.definition.reset_to_code',\n {\n id: removedSnapshot.id,\n workflowId: removedSnapshot.workflowId,\n codeWorkflowId: removedSnapshot.codeWorkflowId,\n tenantId: removedSnapshot.tenantId,\n organizationId: removedSnapshot.organizationId,\n userId: auth.sub ?? null,\n },\n {\n tenantId: removedSnapshot.tenantId,\n organizationId: removedSnapshot.organizationId,\n persistent: true,\n },\n )\n }\n } catch (eventError) {\n console.error('Failed to emit workflows.definition.reset_to_code event:', eventError)\n }\n\n if (!codeDef) {\n return NextResponse.json({\n message: 'Workflow definition reset to code version (code definition no longer registered)',\n data: null,\n })\n }\n\n const syntheticId = `code:${codeDef.workflowId}`\n\n return NextResponse.json({\n data: serializeCodeWorkflowDefinition(codeDef, syntheticId),\n message: 'Workflow definition reset to code version',\n })\n } catch (error) {\n console.error('Error resetting workflow definition to code:', error)\n return NextResponse.json(\n { error: 'Failed to reset workflow definition to code' },\n { status: 500 }\n )\n }\n}\n\nexport const openApi = {\n methods: {\n POST: {\n summary: 'Reset workflow definition to code version',\n description: 'Deletes the DB override for a code-based workflow definition, reverting it to the original code registry version. Cannot be reset if there are active instances.',\n tags: ['Workflows'],\n pathParams: z.object({\n id: z.string().uuid(),\n }),\n responses: [\n {\n status: 200,\n description: 'Workflow definition reset to code version',\n example: {\n data: {\n id: 'code:checkout-flow',\n workflowId: 'checkout-flow',\n workflowName: 'Checkout Flow',\n description: 'Code-defined checkout workflow',\n version: 1,\n source: 'code',\n isCodeBased: true,\n },\n message: 'Workflow definition reset to code version',\n },\n },\n {\n status: 400,\n description: 'Definition is not a code-based override',\n example: {\n error: 'This workflow definition is not a code-based override and cannot be reset',\n },\n },\n {\n status: 404,\n description: 'Workflow definition not found',\n example: {\n error: 'Workflow definition not found',\n },\n },\n {\n status: 409,\n description: 'Cannot reset - active workflow instances exist',\n example: {\n error: 'Cannot reset workflow definition with 3 active instance(s)',\n },\n },\n ],\n },\n },\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }