@open-mercato/core 0.6.3-develop.3876.1.d40fe4ec2d → 0.6.3-develop.3894.1.352abf4240

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 (140) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/modules/attachments/api/file/[id]/route.js +7 -2
  3. package/dist/modules/attachments/api/file/[id]/route.js.map +2 -2
  4. package/dist/modules/attachments/api/image/[id]/[[...slug]]/route.js +7 -4
  5. package/dist/modules/attachments/api/image/[id]/[[...slug]]/route.js.map +2 -2
  6. package/dist/modules/audit_logs/services/accessLogService.js +127 -8
  7. package/dist/modules/audit_logs/services/accessLogService.js.map +2 -2
  8. package/dist/modules/auth/backend/auth/profile/page.js +1 -1
  9. package/dist/modules/auth/backend/auth/profile/page.js.map +2 -2
  10. package/dist/modules/auth/backend/profile/change-password/page.js +1 -1
  11. package/dist/modules/auth/backend/profile/change-password/page.js.map +2 -2
  12. package/dist/modules/auth/backend/users/[id]/edit/page.js +1 -1
  13. package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
  14. package/dist/modules/auth/backend/users/create/page.js +6 -1
  15. package/dist/modules/auth/backend/users/create/page.js.map +2 -2
  16. package/dist/modules/auth/di.js +17 -3
  17. package/dist/modules/auth/di.js.map +2 -2
  18. package/dist/modules/auth/services/rbacDefaultCache.js +110 -0
  19. package/dist/modules/auth/services/rbacDefaultCache.js.map +7 -0
  20. package/dist/modules/catalog/backend/catalog/products/[id]/page.js +8 -1
  21. package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
  22. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js +3 -2
  23. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js.map +2 -2
  24. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/create/page.js +3 -2
  25. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/create/page.js.map +2 -2
  26. package/dist/modules/configs/cli.js +27 -14
  27. package/dist/modules/configs/cli.js.map +2 -2
  28. package/dist/modules/currencies/api/currencies/route.js +3 -4
  29. package/dist/modules/currencies/api/currencies/route.js.map +2 -2
  30. package/dist/modules/currencies/api/exchange-rates/route.js +3 -4
  31. package/dist/modules/currencies/api/exchange-rates/route.js.map +2 -2
  32. package/dist/modules/customers/api/people/route.js +26 -24
  33. package/dist/modules/customers/api/people/route.js.map +2 -2
  34. package/dist/modules/directory/subscribers/invalidateOrgScopeCache.js +26 -0
  35. package/dist/modules/directory/subscribers/invalidateOrgScopeCache.js.map +7 -0
  36. package/dist/modules/directory/utils/organizationScope.js +85 -0
  37. package/dist/modules/directory/utils/organizationScope.js.map +2 -2
  38. package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js +1 -1
  39. package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js.map +2 -2
  40. package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js +1 -1
  41. package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js.map +2 -2
  42. package/dist/modules/sales/components/channels/ChannelOfferForm.js +1 -1
  43. package/dist/modules/sales/components/channels/ChannelOfferForm.js.map +2 -2
  44. package/dist/modules/workflows/backend/definitions/[id]/page.js +2 -1
  45. package/dist/modules/workflows/backend/definitions/[id]/page.js.map +2 -2
  46. package/dist/modules/workflows/backend/definitions/create/page.js +4 -2
  47. package/dist/modules/workflows/backend/definitions/create/page.js.map +2 -2
  48. package/dist/modules/workflows/backend/definitions/visual-editor/page.js +20 -3
  49. package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
  50. package/dist/modules/workflows/components/ActivitiesEditor.js +34 -1
  51. package/dist/modules/workflows/components/ActivitiesEditor.js.map +2 -2
  52. package/dist/modules/workflows/components/NodeEditDialog.js +153 -17
  53. package/dist/modules/workflows/components/NodeEditDialog.js.map +2 -2
  54. package/dist/modules/workflows/components/StepsEditor.js +31 -0
  55. package/dist/modules/workflows/components/StepsEditor.js.map +2 -2
  56. package/dist/modules/workflows/components/WorkflowGraph.js +3 -2
  57. package/dist/modules/workflows/components/WorkflowGraph.js.map +2 -2
  58. package/dist/modules/workflows/components/nodes/WaitForTimerNode.js +54 -0
  59. package/dist/modules/workflows/components/nodes/WaitForTimerNode.js.map +7 -0
  60. package/dist/modules/workflows/components/nodes/index.js +3 -1
  61. package/dist/modules/workflows/components/nodes/index.js.map +2 -2
  62. package/dist/modules/workflows/data/validators.js +117 -0
  63. package/dist/modules/workflows/data/validators.js.map +2 -2
  64. package/dist/modules/workflows/di.js +5 -1
  65. package/dist/modules/workflows/di.js.map +2 -2
  66. package/dist/modules/workflows/lib/activity-executor.js +42 -1
  67. package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
  68. package/dist/modules/workflows/lib/activity-queue-types.js.map +2 -2
  69. package/dist/modules/workflows/lib/activity-worker-handler.js +24 -0
  70. package/dist/modules/workflows/lib/activity-worker-handler.js.map +2 -2
  71. package/dist/modules/workflows/lib/duration.js +32 -0
  72. package/dist/modules/workflows/lib/duration.js.map +7 -0
  73. package/dist/modules/workflows/lib/event-logger.js +1 -0
  74. package/dist/modules/workflows/lib/event-logger.js.map +2 -2
  75. package/dist/modules/workflows/lib/format-validation-error.js +12 -0
  76. package/dist/modules/workflows/lib/format-validation-error.js.map +7 -0
  77. package/dist/modules/workflows/lib/graph-utils.js +6 -3
  78. package/dist/modules/workflows/lib/graph-utils.js.map +2 -2
  79. package/dist/modules/workflows/lib/node-type-icons.js +9 -5
  80. package/dist/modules/workflows/lib/node-type-icons.js.map +2 -2
  81. package/dist/modules/workflows/lib/signal-handler.js +55 -23
  82. package/dist/modules/workflows/lib/signal-handler.js.map +2 -2
  83. package/dist/modules/workflows/lib/step-handler.js +79 -29
  84. package/dist/modules/workflows/lib/step-handler.js.map +2 -2
  85. package/dist/modules/workflows/lib/timer-handler.js +159 -0
  86. package/dist/modules/workflows/lib/timer-handler.js.map +7 -0
  87. package/dist/modules/workflows/lib/workflow-executor.js +1 -1
  88. package/dist/modules/workflows/lib/workflow-executor.js.map +2 -2
  89. package/dist/modules/workflows/workers/workflow-activities.worker.js +20 -4
  90. package/dist/modules/workflows/workers/workflow-activities.worker.js.map +2 -2
  91. package/package.json +7 -7
  92. package/src/modules/attachments/api/file/[id]/route.ts +7 -2
  93. package/src/modules/attachments/api/image/[id]/[[...slug]]/route.ts +7 -4
  94. package/src/modules/audit_logs/services/accessLogService.ts +179 -15
  95. package/src/modules/auth/backend/auth/profile/page.tsx +1 -1
  96. package/src/modules/auth/backend/profile/change-password/page.tsx +1 -1
  97. package/src/modules/auth/backend/users/[id]/edit/page.tsx +1 -1
  98. package/src/modules/auth/backend/users/create/page.tsx +6 -1
  99. package/src/modules/auth/di.ts +26 -3
  100. package/src/modules/auth/services/rbacDefaultCache.ts +145 -0
  101. package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +8 -1
  102. package/src/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.tsx +3 -2
  103. package/src/modules/catalog/backend/catalog/products/[productId]/variants/create/page.tsx +3 -2
  104. package/src/modules/configs/cli.ts +34 -13
  105. package/src/modules/currencies/api/currencies/route.ts +3 -4
  106. package/src/modules/currencies/api/exchange-rates/route.ts +3 -4
  107. package/src/modules/customers/api/people/route.ts +27 -25
  108. package/src/modules/directory/subscribers/invalidateOrgScopeCache.ts +39 -0
  109. package/src/modules/directory/utils/organizationScope.ts +121 -0
  110. package/src/modules/resources/backend/resources/resource-types/[id]/edit/page.tsx +1 -1
  111. package/src/modules/sales/backend/sales/channels/[channelId]/edit/page.tsx +1 -1
  112. package/src/modules/sales/components/channels/ChannelOfferForm.tsx +1 -1
  113. package/src/modules/workflows/backend/definitions/[id]/page.tsx +3 -2
  114. package/src/modules/workflows/backend/definitions/create/page.tsx +4 -2
  115. package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +18 -1
  116. package/src/modules/workflows/components/ActivitiesEditor.tsx +40 -0
  117. package/src/modules/workflows/components/NodeEditDialog.tsx +218 -30
  118. package/src/modules/workflows/components/StepsEditor.tsx +36 -0
  119. package/src/modules/workflows/components/WorkflowGraph.tsx +2 -1
  120. package/src/modules/workflows/components/nodes/WaitForTimerNode.tsx +70 -0
  121. package/src/modules/workflows/components/nodes/index.ts +3 -0
  122. package/src/modules/workflows/data/validators.ts +121 -0
  123. package/src/modules/workflows/di.ts +4 -0
  124. package/src/modules/workflows/i18n/de.json +10 -1
  125. package/src/modules/workflows/i18n/en.json +10 -1
  126. package/src/modules/workflows/i18n/es.json +10 -1
  127. package/src/modules/workflows/i18n/pl.json +10 -1
  128. package/src/modules/workflows/lib/activity-executor.ts +86 -2
  129. package/src/modules/workflows/lib/activity-queue-types.ts +18 -11
  130. package/src/modules/workflows/lib/activity-worker-handler.ts +29 -0
  131. package/src/modules/workflows/lib/duration.ts +51 -0
  132. package/src/modules/workflows/lib/event-logger.ts +1 -0
  133. package/src/modules/workflows/lib/format-validation-error.ts +30 -0
  134. package/src/modules/workflows/lib/graph-utils.ts +3 -0
  135. package/src/modules/workflows/lib/node-type-icons.ts +6 -2
  136. package/src/modules/workflows/lib/signal-handler.ts +62 -24
  137. package/src/modules/workflows/lib/step-handler.ts +107 -50
  138. package/src/modules/workflows/lib/timer-handler.ts +213 -0
  139. package/src/modules/workflows/lib/workflow-executor.ts +1 -1
  140. package/src/modules/workflows/workers/workflow-activities.worker.ts +33 -7
@@ -0,0 +1,213 @@
1
+ /**
2
+ * Timer Handler Service
3
+ *
4
+ * Fires timers for WAIT_FOR_TIMER steps: resumes a paused workflow instance
5
+ * when its scheduled timer job is processed by the activity worker.
6
+ */
7
+
8
+ import { EntityManager } from '@mikro-orm/core'
9
+ import type { EntityManager as PostgreSqlEntityManager } from '@mikro-orm/postgresql'
10
+ import type { AwilixContainer } from 'awilix'
11
+ import { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
12
+ import { WorkflowInstance, WorkflowDefinition, StepInstance } from '../data/entities'
13
+ import type * as eventLoggerModule from './event-logger'
14
+ import type * as stepHandlerModule from './step-handler'
15
+ import type * as transitionHandlerModule from './transition-handler'
16
+ import type * as workflowExecutorModule from './workflow-executor'
17
+
18
+ export interface FireTimerOptions {
19
+ instanceId: string
20
+ stepInstanceId?: string
21
+ userId?: string
22
+ tenantId: string
23
+ organizationId: string
24
+ }
25
+
26
+ export class TimerError extends Error {
27
+ constructor(
28
+ message: string,
29
+ public code: string,
30
+ public details?: any
31
+ ) {
32
+ super(message)
33
+ this.name = 'TimerError'
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Fire a timer and resume workflow execution.
39
+ *
40
+ * Mirrors `sendSignal` from signal-handler.ts — verifies the instance is
41
+ * paused at a WAIT_FOR_TIMER step, logs TIMER_FIRED, exits the step, then
42
+ * executes auto transitions and resumes the workflow.
43
+ */
44
+ export async function fireTimer(
45
+ em: EntityManager,
46
+ container: AwilixContainer,
47
+ options: FireTimerOptions
48
+ ): Promise<void> {
49
+ const { instanceId, stepInstanceId, userId, tenantId, organizationId } = options
50
+
51
+ const eventLogger = container.resolve<typeof eventLoggerModule>('eventLogger')
52
+ const stepHandler = container.resolve<typeof stepHandlerModule>('stepHandler')
53
+ const transitionHandler = container.resolve<typeof transitionHandlerModule>('transitionHandler')
54
+ const workflowExecutor = container.resolve<typeof workflowExecutorModule>('workflowExecutor')
55
+
56
+ const instance = await findOneWithDecryption(
57
+ em as PostgreSqlEntityManager,
58
+ WorkflowInstance,
59
+ {
60
+ id: instanceId,
61
+ tenantId,
62
+ organizationId,
63
+ },
64
+ undefined,
65
+ { tenantId, organizationId },
66
+ )
67
+
68
+ if (!instance) {
69
+ throw new TimerError(
70
+ 'Workflow instance not found',
71
+ 'INSTANCE_NOT_FOUND',
72
+ { instanceId }
73
+ )
74
+ }
75
+
76
+ if (instance.status !== 'PAUSED') {
77
+ throw new TimerError(
78
+ 'Workflow is not paused',
79
+ 'WORKFLOW_NOT_PAUSED',
80
+ { instanceId, status: instance.status }
81
+ )
82
+ }
83
+
84
+ const definition = await findOneWithDecryption(
85
+ em as PostgreSqlEntityManager,
86
+ WorkflowDefinition,
87
+ {
88
+ id: instance.definitionId,
89
+ tenantId: instance.tenantId,
90
+ organizationId: instance.organizationId,
91
+ deletedAt: null,
92
+ },
93
+ undefined,
94
+ { tenantId: instance.tenantId, organizationId: instance.organizationId },
95
+ )
96
+ if (!definition) {
97
+ throw new TimerError(
98
+ 'Workflow definition not found',
99
+ 'DEFINITION_NOT_FOUND',
100
+ { definitionId: instance.definitionId }
101
+ )
102
+ }
103
+
104
+ const currentStep = definition.definition.steps.find(
105
+ (s: any) => s.stepId === instance.currentStepId
106
+ )
107
+
108
+ if (!currentStep || currentStep.stepType !== 'WAIT_FOR_TIMER') {
109
+ throw new TimerError(
110
+ 'Workflow is not waiting for timer',
111
+ 'NOT_WAITING_FOR_TIMER',
112
+ { instanceId, currentStepId: instance.currentStepId }
113
+ )
114
+ }
115
+
116
+ const now = new Date()
117
+ instance.updatedAt = now
118
+
119
+ await eventLogger.logWorkflowEvent(em, {
120
+ workflowInstanceId: instance.id,
121
+ stepInstanceId,
122
+ eventType: 'TIMER_FIRED',
123
+ eventData: {
124
+ stepId: instance.currentStepId,
125
+ firedAt: now.toISOString(),
126
+ },
127
+ userId,
128
+ tenantId: instance.tenantId,
129
+ organizationId: instance.organizationId,
130
+ })
131
+
132
+ const stepInstance = stepInstanceId
133
+ ? await findOneWithDecryption(
134
+ em as PostgreSqlEntityManager,
135
+ StepInstance,
136
+ {
137
+ id: stepInstanceId,
138
+ workflowInstanceId: instance.id,
139
+ tenantId: instance.tenantId,
140
+ organizationId: instance.organizationId,
141
+ },
142
+ undefined,
143
+ { tenantId: instance.tenantId, organizationId: instance.organizationId },
144
+ )
145
+ : await findOneWithDecryption(
146
+ em as PostgreSqlEntityManager,
147
+ StepInstance,
148
+ {
149
+ workflowInstanceId: instance.id,
150
+ stepId: instance.currentStepId,
151
+ status: 'ACTIVE',
152
+ tenantId: instance.tenantId,
153
+ organizationId: instance.organizationId,
154
+ },
155
+ undefined,
156
+ { tenantId: instance.tenantId, organizationId: instance.organizationId },
157
+ )
158
+
159
+ if (stepInstance) {
160
+ await stepHandler.exitStep(em, stepInstance, {
161
+ firedAt: now.toISOString(),
162
+ })
163
+ }
164
+
165
+ const autoTransitions = (definition.definition.transitions || []).filter(
166
+ (t: any) => t.fromStepId === instance.currentStepId && t.trigger === 'auto'
167
+ )
168
+
169
+ if (autoTransitions.length === 0) {
170
+ instance.status = 'RUNNING'
171
+ await em.flush()
172
+ return
173
+ }
174
+
175
+ const transitionContext = {
176
+ workflowContext: instance.context,
177
+ userId,
178
+ }
179
+
180
+ const validTransitions = await transitionHandler.findValidTransitions(
181
+ em,
182
+ instance,
183
+ instance.currentStepId,
184
+ transitionContext
185
+ )
186
+
187
+ const firstValidTransition = validTransitions.find((t) => t.isValid)
188
+
189
+ if (!firstValidTransition || !firstValidTransition.transition) {
190
+ instance.status = 'RUNNING'
191
+ await em.flush()
192
+ return
193
+ }
194
+
195
+ const transitionResult = await transitionHandler.executeTransition(
196
+ em,
197
+ container,
198
+ instance,
199
+ instance.currentStepId,
200
+ firstValidTransition.transition.toStepId,
201
+ transitionContext
202
+ )
203
+
204
+ if (!transitionResult.success) {
205
+ throw new TimerError(
206
+ 'Transition failed after timer fired',
207
+ 'TRANSITION_FAILED',
208
+ { error: transitionResult.error }
209
+ )
210
+ }
211
+
212
+ await workflowExecutor.executeWorkflow(em, container, instance.id, { userId })
213
+ }
@@ -325,7 +325,7 @@ export async function executeWorkflow(
325
325
  if (
326
326
  currentStep?.stepType === 'USER_TASK' ||
327
327
  currentStep?.stepType === 'WAIT_FOR_SIGNAL' ||
328
- currentStep?.stepType === 'TIMER'
328
+ currentStep?.stepType === 'WAIT_FOR_TIMER'
329
329
  ) {
330
330
  return {
331
331
  status: 'RUNNING',
@@ -9,7 +9,7 @@
9
9
  */
10
10
 
11
11
  import type { QueuedJob, JobContext, WorkerMeta } from '@open-mercato/queue'
12
- import { WORKFLOW_ACTIVITIES_QUEUE_NAME, type WorkflowActivityJob } from '../lib/activity-queue-types'
12
+ import type { WorkflowActivityJob } from '../lib/activity-queue-types'
13
13
  import type { EntityManager } from '@mikro-orm/core'
14
14
  import type { AwilixContainer } from 'awilix'
15
15
  import { WorkflowInstance } from '../data/entities'
@@ -23,12 +23,18 @@ import {
23
23
  executeFunction,
24
24
  } from '../lib/activity-executor'
25
25
 
26
- // Worker metadata for auto-discovery
26
+ // Worker metadata for auto-discovery.
27
+ // NOTE: `queue` MUST be a string literal (or locally-declared const) so the
28
+ // generator's AST-based extractor can resolve it when Node cannot import the
29
+ // .ts source file directly. Importing `WORKFLOW_ACTIVITIES_QUEUE_NAME` from
30
+ // another module breaks auto-discovery and silently drops the worker from
31
+ // `modules.generated.ts`.
32
+ const WORKFLOW_ACTIVITIES_QUEUE = 'workflow-activities'
27
33
  const DEFAULT_CONCURRENCY = 1
28
34
  const envConcurrency = process.env.WORKERS_WORKFLOW_ACTIVITIES_CONCURRENCY
29
35
 
30
36
  export const metadata: WorkerMeta = {
31
- queue: WORKFLOW_ACTIVITIES_QUEUE_NAME,
37
+ queue: WORKFLOW_ACTIVITIES_QUEUE,
32
38
  id: 'workflows:workflow-activities',
33
39
  concurrency: envConcurrency ? parseInt(envConcurrency, 10) : DEFAULT_CONCURRENCY,
34
40
  }
@@ -54,10 +60,6 @@ export default async function handle(
54
60
  const { payload } = job
55
61
  const startTime = Date.now()
56
62
 
57
- console.log(
58
- `[workflows:activity-worker] Processing activity ${payload.activityId} (${payload.activityType}) for workflow instance ${payload.workflowInstanceId} (job ${ctx.jobId}, attempt ${ctx.attemptNumber})`
59
- )
60
-
61
63
  // Resolve services from DI container
62
64
  const em = ctx.resolve<EntityManager>('em')
63
65
 
@@ -65,6 +67,27 @@ export default async function handle(
65
67
  // The ctx already has the resolve method we need, we just need to cast it
66
68
  const container = ctx as unknown as AwilixContainer
67
69
 
70
+ // Timer jobs (kind: 'timer') are a distinct flow — they resume a paused
71
+ // workflow at a WAIT_FOR_TIMER step rather than running an activity.
72
+ if (payload.kind === 'timer') {
73
+ console.log(
74
+ `[workflows:activity-worker] Firing timer for instance ${payload.workflowInstanceId} (job ${ctx.jobId})`
75
+ )
76
+ const { fireTimer } = await import('../lib/timer-handler')
77
+ await fireTimer(em, container, {
78
+ instanceId: payload.workflowInstanceId,
79
+ stepInstanceId: payload.stepInstanceId,
80
+ tenantId: payload.tenantId,
81
+ organizationId: payload.organizationId,
82
+ userId: payload.userId,
83
+ })
84
+ return
85
+ }
86
+
87
+ console.log(
88
+ `[workflows:activity-worker] Processing activity ${payload.activityId} (${payload.activityType}) for workflow instance ${payload.workflowInstanceId} (job ${ctx.jobId}, attempt ${ctx.attemptNumber})`
89
+ )
90
+
68
91
  try {
69
92
  // Fetch workflow instance with tenant/org scoping
70
93
  const instance = await em.findOne(WorkflowInstance, {
@@ -114,6 +137,9 @@ export default async function handle(
114
137
  return await executeCallWebhook(payload.activityConfig, activityContext, { signal })
115
138
  case 'EXECUTE_FUNCTION':
116
139
  return await executeFunction(payload.activityConfig, activityContext, container)
140
+ case 'WAIT':
141
+ // Delay already handled by queue's delayMs — return success immediately
142
+ return { waited: true }
117
143
  default:
118
144
  throw new Error(`Unsupported activity type: ${payload.activityType}`)
119
145
  }