@open-mercato/core 0.6.2-develop.3461.1.605f31c2c9 → 0.6.2

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 (173) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/helpers/integration/queue-runner.js +15 -3
  3. package/dist/helpers/integration/queue-runner.js.map +2 -2
  4. package/dist/helpers/integration/queue.js +1 -1
  5. package/dist/helpers/integration/queue.js.map +2 -2
  6. package/dist/helpers/integration/salesUi.js +24 -1
  7. package/dist/helpers/integration/salesUi.js.map +2 -2
  8. package/dist/modules/auth/api/roles/acl/route.js +37 -1
  9. package/dist/modules/auth/api/roles/acl/route.js.map +2 -2
  10. package/dist/modules/auth/api/roles/route.js +36 -2
  11. package/dist/modules/auth/api/roles/route.js.map +2 -2
  12. package/dist/modules/auth/api/users/acl/route.js +36 -1
  13. package/dist/modules/auth/api/users/acl/route.js.map +2 -2
  14. package/dist/modules/auth/api/users/route.js +101 -13
  15. package/dist/modules/auth/api/users/route.js.map +2 -2
  16. package/dist/modules/auth/backend/roles/[id]/edit/page.js +32 -14
  17. package/dist/modules/auth/backend/roles/[id]/edit/page.js.map +2 -2
  18. package/dist/modules/auth/backend/users/[id]/edit/page.js +1 -1
  19. package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
  20. package/dist/modules/auth/backend/users/create/page.js +1 -1
  21. package/dist/modules/auth/backend/users/create/page.js.map +2 -2
  22. package/dist/modules/auth/backend/users/roleOptions.js +1 -1
  23. package/dist/modules/auth/backend/users/roleOptions.js.map +2 -2
  24. package/dist/modules/auth/commands/roles.js +8 -0
  25. package/dist/modules/auth/commands/roles.js.map +2 -2
  26. package/dist/modules/auth/commands/users.js +3 -0
  27. package/dist/modules/auth/commands/users.js.map +2 -2
  28. package/dist/modules/auth/components/AclEditor.js +53 -26
  29. package/dist/modules/auth/components/AclEditor.js.map +2 -2
  30. package/dist/modules/auth/frontend/login.js +35 -0
  31. package/dist/modules/auth/frontend/login.js.map +2 -2
  32. package/dist/modules/auth/lib/grantChecks.js +97 -2
  33. package/dist/modules/auth/lib/grantChecks.js.map +2 -2
  34. package/dist/modules/business_rules/lib/expression-evaluator.js +9 -7
  35. package/dist/modules/business_rules/lib/expression-evaluator.js.map +2 -2
  36. package/dist/modules/business_rules/lib/rule-evaluator.js +3 -3
  37. package/dist/modules/business_rules/lib/rule-evaluator.js.map +2 -2
  38. package/dist/modules/customers/ai-agents.js +10 -1
  39. package/dist/modules/customers/ai-agents.js.map +2 -2
  40. package/dist/modules/customers/ai-tools/settings-pack.js +55 -1
  41. package/dist/modules/customers/ai-tools/settings-pack.js.map +2 -2
  42. package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js +13 -5
  43. package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js.map +2 -2
  44. package/dist/modules/customers/lib/personCompanyLinkTable.js +4 -30
  45. package/dist/modules/customers/lib/personCompanyLinkTable.js.map +2 -2
  46. package/dist/modules/customers/migrations/Migration20260521175027.js +12 -0
  47. package/dist/modules/customers/migrations/Migration20260521175027.js.map +7 -0
  48. package/dist/modules/dashboards/components/WidgetVisibilityEditor.js +41 -12
  49. package/dist/modules/dashboards/components/WidgetVisibilityEditor.js.map +2 -2
  50. package/dist/modules/data_sync/api/options.js +2 -0
  51. package/dist/modules/data_sync/api/options.js.map +2 -2
  52. package/dist/modules/data_sync/api/run.js +77 -58
  53. package/dist/modules/data_sync/api/run.js.map +2 -2
  54. package/dist/modules/data_sync/backend/data-sync/page.js +3 -2
  55. package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
  56. package/dist/modules/data_sync/components/IntegrationScheduleTab.js +8 -3
  57. package/dist/modules/data_sync/components/IntegrationScheduleTab.js.map +2 -2
  58. package/dist/modules/integrations/backend/integrations/[id]/page.js +15 -13
  59. package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
  60. package/dist/modules/integrations/data/validators.js +9 -6
  61. package/dist/modules/integrations/data/validators.js.map +2 -2
  62. package/dist/modules/messages/api/route.js +2 -2
  63. package/dist/modules/messages/api/route.js.map +2 -2
  64. package/dist/modules/messages/commands/messages.js +42 -2
  65. package/dist/modules/messages/commands/messages.js.map +2 -2
  66. package/dist/modules/messages/components/MessagesInboxPageClient.js +70 -89
  67. package/dist/modules/messages/components/MessagesInboxPageClient.js.map +2 -2
  68. package/dist/modules/messages/components/defaults/DefaultMessageListItem.js +8 -6
  69. package/dist/modules/messages/components/defaults/DefaultMessageListItem.js.map +2 -2
  70. package/dist/modules/messages/components/inboxFilters.js +133 -0
  71. package/dist/modules/messages/components/inboxFilters.js.map +7 -0
  72. package/dist/modules/messages/components/messageListLabels.js +14 -0
  73. package/dist/modules/messages/components/messageListLabels.js.map +7 -0
  74. package/dist/modules/messages/components/useMessagesInboxBulkActions.js +47 -23
  75. package/dist/modules/messages/components/useMessagesInboxBulkActions.js.map +2 -2
  76. package/dist/modules/messages/data/validators.js +8 -6
  77. package/dist/modules/messages/data/validators.js.map +2 -2
  78. package/dist/modules/progress/api/jobs/route.js +26 -16
  79. package/dist/modules/progress/api/jobs/route.js.map +2 -2
  80. package/dist/modules/query_index/di.js +8 -6
  81. package/dist/modules/query_index/di.js.map +2 -2
  82. package/dist/modules/query_index/lib/indexer.js +12 -10
  83. package/dist/modules/query_index/lib/indexer.js.map +2 -2
  84. package/dist/modules/query_index/subscribers/upsert_one.js +7 -1
  85. package/dist/modules/query_index/subscribers/upsert_one.js.map +2 -2
  86. package/dist/modules/sales/api/order-adjustments/route.js.map +2 -2
  87. package/dist/modules/sales/api/quote-adjustments/route.js.map +2 -2
  88. package/dist/modules/sales/commands/documents.js +104 -0
  89. package/dist/modules/sales/commands/documents.js.map +2 -2
  90. package/dist/modules/sales/data/validators.js +20 -1
  91. package/dist/modules/sales/data/validators.js.map +2 -2
  92. package/dist/modules/sales/lib/makeSalesLineRoute.js.map +2 -2
  93. package/dist/modules/sync_excel/api/import/route.js +126 -116
  94. package/dist/modules/sync_excel/api/import/route.js.map +2 -2
  95. package/dist/modules/sync_excel/lib/adapters/customers.js +1 -0
  96. package/dist/modules/sync_excel/lib/adapters/customers.js.map +2 -2
  97. package/dist/modules/translations/components/TranslationManager.js +9 -4
  98. package/dist/modules/translations/components/TranslationManager.js.map +2 -2
  99. package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
  100. package/dist/modules/workflows/lib/event-trigger-service.js +23 -11
  101. package/dist/modules/workflows/lib/event-trigger-service.js.map +2 -2
  102. package/jest.config.cjs +4 -1
  103. package/package.json +15 -16
  104. package/src/helpers/integration/queue-runner.ts +21 -2
  105. package/src/helpers/integration/queue.ts +1 -1
  106. package/src/helpers/integration/salesUi.ts +26 -1
  107. package/src/modules/auth/api/roles/acl/route.ts +39 -1
  108. package/src/modules/auth/api/roles/route.ts +38 -2
  109. package/src/modules/auth/api/users/acl/route.ts +41 -1
  110. package/src/modules/auth/api/users/route.ts +105 -12
  111. package/src/modules/auth/backend/roles/[id]/edit/page.tsx +35 -13
  112. package/src/modules/auth/backend/users/[id]/edit/page.tsx +1 -1
  113. package/src/modules/auth/backend/users/create/page.tsx +1 -1
  114. package/src/modules/auth/backend/users/roleOptions.ts +2 -1
  115. package/src/modules/auth/commands/roles.ts +8 -0
  116. package/src/modules/auth/commands/users.ts +3 -0
  117. package/src/modules/auth/components/AclEditor.tsx +50 -24
  118. package/src/modules/auth/frontend/login.tsx +40 -0
  119. package/src/modules/auth/lib/grantChecks.ts +116 -2
  120. package/src/modules/business_rules/lib/expression-evaluator.ts +9 -13
  121. package/src/modules/business_rules/lib/rule-evaluator.ts +3 -3
  122. package/src/modules/customers/ai-agents.ts +10 -1
  123. package/src/modules/customers/ai-tools/settings-pack.ts +62 -1
  124. package/src/modules/customers/components/detail/schedule/useScheduleFormState.ts +18 -7
  125. package/src/modules/customers/lib/personCompanyLinkTable.ts +33 -41
  126. package/src/modules/customers/migrations/Migration20260521175027.ts +39 -0
  127. package/src/modules/dashboards/components/WidgetVisibilityEditor.tsx +38 -12
  128. package/src/modules/data_sync/api/options.ts +2 -0
  129. package/src/modules/data_sync/api/run.ts +80 -61
  130. package/src/modules/data_sync/backend/data-sync/page.tsx +10 -0
  131. package/src/modules/data_sync/components/IntegrationScheduleTab.tsx +17 -3
  132. package/src/modules/data_sync/i18n/de.json +3 -0
  133. package/src/modules/data_sync/i18n/en.json +3 -0
  134. package/src/modules/data_sync/i18n/es.json +3 -0
  135. package/src/modules/data_sync/i18n/pl.json +3 -0
  136. package/src/modules/data_sync/lib/adapter.ts +9 -0
  137. package/src/modules/integrations/backend/integrations/[id]/page.tsx +15 -13
  138. package/src/modules/integrations/data/validators.ts +5 -4
  139. package/src/modules/messages/api/route.ts +2 -2
  140. package/src/modules/messages/commands/messages.ts +54 -2
  141. package/src/modules/messages/components/MessagesInboxPageClient.tsx +80 -92
  142. package/src/modules/messages/components/defaults/DefaultMessageListItem.tsx +9 -5
  143. package/src/modules/messages/components/inboxFilters.ts +162 -0
  144. package/src/modules/messages/components/messageListLabels.ts +29 -0
  145. package/src/modules/messages/components/useMessagesInboxBulkActions.ts +58 -26
  146. package/src/modules/messages/data/validators.ts +7 -5
  147. package/src/modules/messages/i18n/de.json +7 -4
  148. package/src/modules/messages/i18n/en.json +7 -4
  149. package/src/modules/messages/i18n/es.json +7 -4
  150. package/src/modules/messages/i18n/pl.json +7 -4
  151. package/src/modules/progress/api/jobs/route.ts +30 -20
  152. package/src/modules/query_index/di.ts +9 -7
  153. package/src/modules/query_index/lib/indexer.ts +13 -11
  154. package/src/modules/query_index/subscribers/upsert_one.ts +9 -1
  155. package/src/modules/sales/api/order-adjustments/route.ts +2 -1
  156. package/src/modules/sales/api/quote-adjustments/route.ts +2 -1
  157. package/src/modules/sales/commands/documents.ts +116 -0
  158. package/src/modules/sales/data/validators.ts +38 -0
  159. package/src/modules/sales/i18n/de.json +2 -0
  160. package/src/modules/sales/i18n/en.json +2 -0
  161. package/src/modules/sales/i18n/es.json +2 -0
  162. package/src/modules/sales/i18n/pl.json +2 -0
  163. package/src/modules/sales/lib/makeSalesLineRoute.ts +2 -1
  164. package/src/modules/staff/i18n/de.json +1 -0
  165. package/src/modules/staff/i18n/en.json +1 -0
  166. package/src/modules/staff/i18n/es.json +1 -0
  167. package/src/modules/staff/i18n/pl.json +1 -0
  168. package/src/modules/sync_excel/api/import/route.ts +141 -131
  169. package/src/modules/sync_excel/lib/adapters/customers.ts +1 -0
  170. package/src/modules/translations/components/TranslationManager.tsx +9 -4
  171. package/src/modules/workflows/lib/activity-executor.ts +4 -3
  172. package/src/modules/workflows/lib/event-trigger-service.ts +24 -11
  173. package/tsconfig.json +1 -0
@@ -46,137 +46,147 @@ export const openApi = {
46
46
  }
47
47
 
48
48
  export async function POST(request: Request) {
49
- const auth = await getAuthFromRequest(request)
50
- if (!auth?.tenantId) {
51
- return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
52
- }
53
-
54
- const payload = await readJsonSafe(request)
55
- const parsedPayload = syncExcelImportRequestSchema.safeParse(payload)
56
- if (!parsedPayload.success) {
57
- return NextResponse.json({ error: 'Invalid import payload.' }, { status: 422 })
58
- }
59
-
60
- const container = await createRequestContainer()
61
- const em = container.resolve('em') as EntityManager
62
- const syncRunService = container.resolve('dataSyncRunService') as SyncRunService
63
- const progressService = container.resolve('progressService') as ProgressService
64
- const credentialsService = container.resolve('integrationCredentialsService') as CredentialsService
65
- const integrationStateService = container.resolve('integrationStateService') as IntegrationStateService
66
- const scopeResult = await resolveSyncExcelConcreteScope({ auth, container, request })
67
- if (!scopeResult.ok) {
68
- return NextResponse.json({ error: scopeResult.error }, { status: scopeResult.status })
69
- }
70
- const { scope } = scopeResult
71
-
72
- const upload = await findOneWithDecryption(
73
- em,
74
- SyncExcelUpload,
75
- {
76
- id: parsedPayload.data.uploadId,
77
- organizationId: scope.organizationId,
78
- tenantId: scope.tenantId,
79
- },
80
- undefined,
81
- scope,
82
- )
83
-
84
- if (!upload) {
85
- return NextResponse.json({ error: 'Upload preview not found.' }, { status: 404 })
86
- }
87
-
88
- const attachment = await findOneWithDecryption(
89
- em,
90
- Attachment,
91
- {
92
- id: upload.attachmentId,
93
- organizationId: scope.organizationId,
94
- tenantId: scope.tenantId,
95
- },
96
- undefined,
97
- scope,
98
- )
99
-
100
- if (!attachment) {
101
- return NextResponse.json({ error: 'Upload attachment not found.' }, { status: 404 })
102
- }
103
-
104
- if (upload.entityType !== parsedPayload.data.entityType) {
105
- return NextResponse.json({ error: 'Upload entity type does not match requested import target.' }, { status: 422 })
106
- }
107
-
108
- if (parsedPayload.data.mapping.entityType !== parsedPayload.data.entityType) {
109
- return NextResponse.json({ error: 'Mapping entity type does not match requested import target.' }, { status: 422 })
110
- }
111
-
112
- const overlap = await syncRunService.findRunningOverlap('sync_excel', parsedPayload.data.entityType, 'import', scope)
113
- if (overlap) {
114
- return NextResponse.json({ error: 'A sync_excel import is already in progress for this entity type.' }, { status: 409 })
115
- }
116
-
117
- const existingMapping = await findOneWithDecryption(
118
- em,
119
- SyncMapping,
120
- {
121
- integrationId: 'sync_excel',
122
- entityType: parsedPayload.data.entityType,
123
- organizationId: scope.organizationId,
124
- tenantId: scope.tenantId,
125
- },
126
- undefined,
127
- scope,
128
- )
129
-
130
- if (existingMapping) {
131
- existingMapping.mapping = parsedPayload.data.mapping
132
- } else {
133
- em.persist(em.create(SyncMapping, {
134
- integrationId: 'sync_excel',
135
- entityType: parsedPayload.data.entityType,
136
- mapping: parsedPayload.data.mapping,
137
- organizationId: scope.organizationId,
138
- tenantId: scope.tenantId,
139
- }))
140
- }
141
-
142
- await credentialsService.save('sync_excel', {}, scope)
143
- await integrationStateService.upsert('sync_excel', { isEnabled: true }, scope)
144
- await em.flush()
145
-
146
- const { run, progressJob } = await startDataSyncRun({
147
- syncRunService,
148
- progressService,
149
- scope: {
150
- ...scope,
151
- userId: auth.sub,
152
- },
153
- input: {
154
- integrationId: 'sync_excel',
155
- entityType: parsedPayload.data.entityType,
156
- direction: 'import',
157
- cursor: createCursor(upload.id, 0),
158
- triggeredBy: auth.sub,
159
- batchSize: parsedPayload.data.batchSize ?? 100,
160
- progressJob: {
161
- jobType: 'sync_excel:import',
162
- name: `CSV import — ${parsedPayload.data.entityType}`,
163
- description: upload.filename,
164
- meta: {
165
- integrationId: 'sync_excel',
166
- uploadId: upload.id,
167
- hiddenFromTopBar: false,
49
+ try {
50
+ const auth = await getAuthFromRequest(request)
51
+ if (!auth?.tenantId) {
52
+ return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
53
+ }
54
+
55
+ const payload = await readJsonSafe(request)
56
+ const parsedPayload = syncExcelImportRequestSchema.safeParse(payload)
57
+ if (!parsedPayload.success) {
58
+ return NextResponse.json({ error: 'Invalid import payload.' }, { status: 422 })
59
+ }
60
+
61
+ const container = await createRequestContainer()
62
+ const em = container.resolve('em') as EntityManager
63
+ const syncRunService = container.resolve('dataSyncRunService') as SyncRunService
64
+ const progressService = container.resolve('progressService') as ProgressService
65
+ const credentialsService = container.resolve('integrationCredentialsService') as CredentialsService
66
+ const integrationStateService = container.resolve('integrationStateService') as IntegrationStateService
67
+ const scopeResult = await resolveSyncExcelConcreteScope({ auth, container, request })
68
+ if (!scopeResult.ok) {
69
+ return NextResponse.json({ error: scopeResult.error }, { status: scopeResult.status })
70
+ }
71
+ const { scope } = scopeResult
72
+
73
+ const upload = await findOneWithDecryption(
74
+ em,
75
+ SyncExcelUpload,
76
+ {
77
+ id: parsedPayload.data.uploadId,
78
+ organizationId: scope.organizationId,
79
+ tenantId: scope.tenantId,
80
+ },
81
+ undefined,
82
+ scope,
83
+ )
84
+
85
+ if (!upload) {
86
+ return NextResponse.json({ error: 'Upload preview not found.' }, { status: 404 })
87
+ }
88
+
89
+ const attachment = await findOneWithDecryption(
90
+ em,
91
+ Attachment,
92
+ {
93
+ id: upload.attachmentId,
94
+ organizationId: scope.organizationId,
95
+ tenantId: scope.tenantId,
96
+ },
97
+ undefined,
98
+ scope,
99
+ )
100
+
101
+ if (!attachment) {
102
+ return NextResponse.json({ error: 'Upload attachment not found.' }, { status: 404 })
103
+ }
104
+
105
+ if (upload.entityType !== parsedPayload.data.entityType) {
106
+ return NextResponse.json({ error: 'Upload entity type does not match requested import target.' }, { status: 422 })
107
+ }
108
+
109
+ if (parsedPayload.data.mapping.entityType !== parsedPayload.data.entityType) {
110
+ return NextResponse.json({ error: 'Mapping entity type does not match requested import target.' }, { status: 422 })
111
+ }
112
+
113
+ const overlap = await syncRunService.findRunningOverlap('sync_excel', parsedPayload.data.entityType, 'import', scope)
114
+ if (overlap) {
115
+ return NextResponse.json({ error: 'A sync_excel import is already in progress for this entity type.' }, { status: 409 })
116
+ }
117
+
118
+ const existingMapping = await findOneWithDecryption(
119
+ em,
120
+ SyncMapping,
121
+ {
122
+ integrationId: 'sync_excel',
123
+ entityType: parsedPayload.data.entityType,
124
+ organizationId: scope.organizationId,
125
+ tenantId: scope.tenantId,
126
+ },
127
+ undefined,
128
+ scope,
129
+ )
130
+
131
+ if (existingMapping) {
132
+ existingMapping.mapping = parsedPayload.data.mapping
133
+ } else {
134
+ em.persist(em.create(SyncMapping, {
135
+ integrationId: 'sync_excel',
136
+ entityType: parsedPayload.data.entityType,
137
+ mapping: parsedPayload.data.mapping,
138
+ organizationId: scope.organizationId,
139
+ tenantId: scope.tenantId,
140
+ }))
141
+ }
142
+
143
+ await credentialsService.save('sync_excel', {}, scope)
144
+ await integrationStateService.upsert('sync_excel', { isEnabled: true }, scope)
145
+ await em.flush()
146
+
147
+ const { run, progressJob } = await startDataSyncRun({
148
+ syncRunService,
149
+ progressService,
150
+ scope: {
151
+ ...scope,
152
+ userId: auth.sub,
153
+ },
154
+ input: {
155
+ integrationId: 'sync_excel',
156
+ entityType: parsedPayload.data.entityType,
157
+ direction: 'import',
158
+ cursor: createCursor(upload.id, 0),
159
+ triggeredBy: auth.sub,
160
+ batchSize: parsedPayload.data.batchSize ?? 100,
161
+ progressJob: {
162
+ jobType: 'sync_excel:import',
163
+ name: `CSV import — ${parsedPayload.data.entityType}`,
164
+ description: upload.filename,
165
+ meta: {
166
+ integrationId: 'sync_excel',
167
+ uploadId: upload.id,
168
+ hiddenFromTopBar: false,
169
+ },
168
170
  },
169
171
  },
170
- },
171
- })
172
-
173
- upload.syncRunId = run.id
174
- upload.status = 'importing'
175
- await em.flush()
176
-
177
- return NextResponse.json(syncExcelImportResponseSchema.parse({
178
- runId: run.id,
179
- progressJobId: progressJob?.id ?? null,
180
- status: run.status,
181
- }), { status: 201 })
172
+ })
173
+
174
+ upload.syncRunId = run.id
175
+ upload.status = 'importing'
176
+ await em.flush()
177
+
178
+ return NextResponse.json(syncExcelImportResponseSchema.parse({
179
+ runId: run.id,
180
+ progressJobId: progressJob?.id ?? null,
181
+ status: run.status,
182
+ }), { status: 201 })
183
+ } catch (error) {
184
+ const message = error instanceof Error ? error.message : String(error)
185
+ const stack = error instanceof Error ? error.stack : undefined
186
+ console.error('[sync_excel.import] unhandled error', { message, stack })
187
+ return NextResponse.json(
188
+ { error: 'Failed to start sync_excel import.', message, stack },
189
+ { status: 500 },
190
+ )
191
+ }
182
192
  }
@@ -993,6 +993,7 @@ async function processRow(params: {
993
993
 
994
994
  export const syncExcelCustomersAdapter: DataSyncAdapter = {
995
995
  providerKey: 'excel',
996
+ runMode: 'provider',
996
997
  operationalTelemetry: true,
997
998
  direction: 'import',
998
999
  supportedEntities: ['customers.person'],
@@ -69,6 +69,7 @@ export function TranslationManager({
69
69
  const [editedTranslations, setEditedTranslations] = React.useState<Record<string, Record<string, string>>>({})
70
70
  const editedTranslationsRef = React.useRef<Record<string, Record<string, string>>>({})
71
71
  const [hasUserEdited, setHasUserEdited] = React.useState(false)
72
+ const hasUserEditedRef = React.useRef(false)
72
73
 
73
74
  const entityType = isEmbedded ? (propEntityType ?? '') : selectedEntityType
74
75
  const recordId = isEmbedded ? (propRecordId ?? '') : selectedRecordId
@@ -191,11 +192,11 @@ export function TranslationManager({
191
192
 
192
193
  React.useEffect(() => {
193
194
  const sig = translationSignature
194
- if (sig === lastTranslationSignatureRef.current && hasUserEdited) return
195
+ if (sig === lastTranslationSignatureRef.current && hasUserEditedRef.current) return
195
196
  lastTranslationSignatureRef.current = sig
196
197
 
197
198
  if (!translationData?.translations) {
198
- if (!hasUserEdited) {
199
+ if (!hasUserEditedRef.current) {
199
200
  editedTranslationsRef.current = {}
200
201
  setEditedTranslations({})
201
202
  }
@@ -210,11 +211,11 @@ export function TranslationManager({
210
211
  parsed[locale][key] = typeof val === 'string' ? val : ''
211
212
  }
212
213
  }
213
- if (!hasUserEdited) {
214
+ if (!hasUserEditedRef.current) {
214
215
  editedTranslationsRef.current = parsed
215
216
  setEditedTranslations(parsed)
216
217
  }
217
- }, [translationSignature, translationData, hasUserEdited])
218
+ }, [translationSignature, translationData])
218
219
 
219
220
  const mutation = useMutation({
220
221
  mutationFn: async () => {
@@ -252,6 +253,7 @@ export function TranslationManager({
252
253
  },
253
254
  onSuccess: () => {
254
255
  flash(t('translations.manager.flash.saved', 'Translations saved'), 'success')
256
+ hasUserEditedRef.current = false
255
257
  setHasUserEdited(false)
256
258
  void refetchTranslation()
257
259
  },
@@ -262,6 +264,7 @@ export function TranslationManager({
262
264
  })
263
265
 
264
266
  const updateFieldValue = (locale: string, fieldKey: string, value: string) => {
267
+ hasUserEditedRef.current = true
265
268
  setHasUserEdited(true)
266
269
  const next = {
267
270
  ...editedTranslationsRef.current,
@@ -288,6 +291,7 @@ export function TranslationManager({
288
291
  value={selectedRecordId}
289
292
  onChange={(next) => {
290
293
  setSelectedRecordId(next)
294
+ hasUserEditedRef.current = false
291
295
  setHasUserEdited(false)
292
296
  }}
293
297
  placeholder={t('translations.manager.searchRecords', 'Search records...')}
@@ -482,6 +486,7 @@ export function TranslationManager({
482
486
  onChange={(next) => {
483
487
  setSelectedEntityType(next)
484
488
  setSelectedRecordId('')
489
+ hasUserEditedRef.current = false
485
490
  setHasUserEdited(false)
486
491
  }}
487
492
  placeholder={t('translations.manager.placeholder', 'Select an entity')}
@@ -11,6 +11,7 @@
11
11
  */
12
12
 
13
13
  import { EntityManager } from '@mikro-orm/core'
14
+ import type { EntityManager as PostgreSqlEntityManager } from '@mikro-orm/postgresql'
14
15
  import type { AwilixContainer } from 'awilix'
15
16
  import { WorkflowInstance } from '../data/entities'
16
17
  import { createModuleQueue, Queue } from '@open-mercato/queue'
@@ -406,7 +407,7 @@ export async function executeSendEmail(
406
407
 
407
408
  // Check if email service is available in container
408
409
  try {
409
- const emailService = container.resolve('emailService')
410
+ const emailService = container.resolve<{ send: (input: unknown) => Promise<unknown> | unknown }>('emailService')
410
411
  if (emailService && typeof emailService.send === 'function') {
411
412
  await emailService.send({
412
413
  to,
@@ -441,7 +442,7 @@ export async function executeEmitEvent(
441
442
  }
442
443
 
443
444
  // Get event bus from container
444
- const eventBus = container.resolve('eventBus')
445
+ const eventBus = container.resolve<{ emitEvent: (event: string, payload: unknown, options?: unknown) => Promise<unknown> | unknown }>('eventBus')
445
446
 
446
447
  if (!eventBus || typeof eventBus.emitEvent !== 'function') {
447
448
  throw new Error('Event bus not available in container')
@@ -789,7 +790,7 @@ export async function executeCallApi(
789
790
  const { withOnetimeApiKey } = await import('../../api_keys/services/apiKeyService')
790
791
 
791
792
  // 4. Get EntityManager from container (for correct type)
792
- const apiKeyEm = container.resolve('em')
793
+ const apiKeyEm = container.resolve<PostgreSqlEntityManager>('em')
793
794
 
794
795
  // 5. Resolve the roles that the one-time API key will inherit.
795
796
  //
@@ -6,9 +6,12 @@
6
6
  */
7
7
 
8
8
  import type { EntityManager } from '@mikro-orm/core'
9
+ import type { EntityManager as PostgreSqlEntityManager } from '@mikro-orm/postgresql'
9
10
  import type { AwilixContainer } from 'awilix'
10
11
  import type { CacheService } from '@open-mercato/cache'
11
12
  import { matchEventPattern } from '@open-mercato/shared/lib/events/patterns'
13
+ import { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'
14
+ import { testLinearRegex } from '@open-mercato/shared/lib/regex/linear'
12
15
  import {
13
16
  WorkflowEventTrigger,
14
17
  WorkflowDefinition,
@@ -257,11 +260,12 @@ function evaluateCondition(condition: TriggerFilterCondition, payload: Record<st
257
260
  if (typeof value !== 'string' || typeof expected !== 'string') return false
258
261
  if (value.length > MAX_WORKFLOW_REGEX_INPUT_LENGTH) return false
259
262
  if (!isSafeWorkflowRegexPattern(expected)) return false
260
- try {
261
- const regex = new RegExp(expected)
262
- return regex.test(value)
263
- } catch {
264
- return false
263
+ {
264
+ const result = testLinearRegex(expected, value, {
265
+ maxPatternLength: MAX_WORKFLOW_REGEX_PATTERN_LENGTH,
266
+ maxInputLength: MAX_WORKFLOW_REGEX_INPUT_LENGTH,
267
+ })
268
+ return result.ok ? result.matched : false
265
269
  }
266
270
 
267
271
  default:
@@ -325,7 +329,9 @@ async function loadLegacyTriggers(
325
329
  tenantId: string,
326
330
  organizationId: string
327
331
  ): Promise<UnifiedTrigger[]> {
328
- const legacyTriggers = await em.find(
332
+ const postgresEm = em as unknown as PostgreSqlEntityManager
333
+ const legacyTriggers = await findWithDecryption(
334
+ postgresEm,
329
335
  WorkflowEventTrigger,
330
336
  {
331
337
  tenantId,
@@ -335,16 +341,19 @@ async function loadLegacyTriggers(
335
341
  },
336
342
  {
337
343
  orderBy: { priority: 'DESC', createdAt: 'ASC' },
338
- }
344
+ },
345
+ { tenantId, organizationId },
339
346
  )
340
347
 
341
348
  // Get definitions for these triggers to get workflowId
342
349
  const definitionIds = [...new Set(legacyTriggers.map(t => t.workflowDefinitionId))]
343
- const definitions = definitionIds.length > 0 ? await em.find(WorkflowDefinition, {
350
+ const definitions = definitionIds.length > 0 ? await findWithDecryption(postgresEm, WorkflowDefinition, {
344
351
  id: { $in: definitionIds },
352
+ tenantId,
353
+ organizationId,
345
354
  enabled: true,
346
355
  deletedAt: null,
347
- }) : []
356
+ }, {}, { tenantId, organizationId }) : []
348
357
  const definitionMap = new Map(definitions.map(d => [d.id, d]))
349
358
 
350
359
  return legacyTriggers
@@ -379,15 +388,19 @@ async function loadEmbeddedTriggers(
379
388
  tenantId: string,
380
389
  organizationId: string
381
390
  ): Promise<UnifiedTrigger[]> {
391
+ const postgresEm = em as unknown as PostgreSqlEntityManager
382
392
  // Load all enabled definitions that may have triggers
383
- const definitions = await em.find(
393
+ const definitions = await findWithDecryption(
394
+ postgresEm,
384
395
  WorkflowDefinition,
385
396
  {
386
397
  tenantId,
387
398
  organizationId,
388
399
  enabled: true,
389
400
  deletedAt: null,
390
- }
401
+ },
402
+ {},
403
+ { tenantId, organizationId },
391
404
  )
392
405
 
393
406
  const triggers: UnifiedTrigger[] = []
package/tsconfig.json CHANGED
@@ -4,6 +4,7 @@
4
4
  "compilerOptions": {
5
5
  "noEmit": true,
6
6
  "baseUrl": ".",
7
+ "ignoreDeprecations": "6.0",
7
8
  "paths": {
8
9
  "@open-mercato/core/modules/core/__integration__/helpers/*": [
9
10
  "./src/modules/core/__integration__/helpers/*"