@open-mercato/core 0.6.6-develop.6184.1.b7e55f8d61 → 0.6.6-develop.6201.1.8ceb502c4b

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 (63) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/modules/auth/frontend/login.js +5 -5
  3. package/dist/modules/auth/frontend/login.js.map +2 -2
  4. package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js +3 -2
  5. package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js.map +2 -2
  6. package/dist/modules/catalog/widgets/injection/product-seo/widget.client.js +26 -14
  7. package/dist/modules/catalog/widgets/injection/product-seo/widget.client.js.map +2 -2
  8. package/dist/modules/customers/api/deals/[id]/route.js +169 -149
  9. package/dist/modules/customers/api/deals/[id]/route.js.map +3 -3
  10. package/dist/modules/customers/components/detail/InlineEditors.js +9 -4
  11. package/dist/modules/customers/components/detail/InlineEditors.js.map +2 -2
  12. package/dist/modules/integrations/backend/integrations/[id]/page.js +13 -9
  13. package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
  14. package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js +81 -37
  15. package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js.map +2 -2
  16. package/dist/modules/integrations/backend/integrations/detail-page-refresh.js +17 -0
  17. package/dist/modules/integrations/backend/integrations/detail-page-refresh.js.map +7 -0
  18. package/dist/modules/integrations/backend/integrations/page.js +45 -24
  19. package/dist/modules/integrations/backend/integrations/page.js.map +2 -2
  20. package/dist/modules/notifications/api/[id]/action/route.js +18 -3
  21. package/dist/modules/notifications/api/[id]/action/route.js.map +2 -2
  22. package/dist/modules/notifications/api/[id]/restore/route.js +19 -3
  23. package/dist/modules/notifications/api/[id]/restore/route.js.map +2 -2
  24. package/dist/modules/notifications/api/mark-all-read/route.js +18 -4
  25. package/dist/modules/notifications/api/mark-all-read/route.js.map +2 -2
  26. package/dist/modules/notifications/api/route.js +17 -4
  27. package/dist/modules/notifications/api/route.js.map +2 -2
  28. package/dist/modules/notifications/api/settings/route.js +26 -5
  29. package/dist/modules/notifications/api/settings/route.js.map +2 -2
  30. package/dist/modules/notifications/lib/routeHelpers.js +64 -5
  31. package/dist/modules/notifications/lib/routeHelpers.js.map +2 -2
  32. package/dist/modules/sales/components/documents/SalesDocumentForm.js +299 -297
  33. package/dist/modules/sales/components/documents/SalesDocumentForm.js.map +2 -2
  34. package/dist/modules/workflows/components/EdgeEditDialog.js +120 -141
  35. package/dist/modules/workflows/components/EdgeEditDialog.js.map +2 -2
  36. package/dist/modules/workflows/components/NodeEditDialog.js +114 -118
  37. package/dist/modules/workflows/components/NodeEditDialog.js.map +2 -2
  38. package/dist/modules/workflows/frontend/checkout-demo/page.js +155 -260
  39. package/dist/modules/workflows/frontend/checkout-demo/page.js.map +2 -2
  40. package/package.json +7 -7
  41. package/src/modules/auth/frontend/login.tsx +5 -5
  42. package/src/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.tsx +4 -3
  43. package/src/modules/catalog/widgets/injection/product-seo/widget.client.tsx +27 -17
  44. package/src/modules/customers/api/deals/[id]/route.ts +208 -174
  45. package/src/modules/customers/components/detail/InlineEditors.tsx +6 -10
  46. package/src/modules/integrations/backend/integrations/[id]/page.tsx +13 -9
  47. package/src/modules/integrations/backend/integrations/bundle/[id]/page.tsx +78 -35
  48. package/src/modules/integrations/backend/integrations/detail-page-refresh.ts +36 -0
  49. package/src/modules/integrations/backend/integrations/page.tsx +42 -21
  50. package/src/modules/notifications/api/[id]/action/route.ts +17 -2
  51. package/src/modules/notifications/api/[id]/restore/route.ts +19 -3
  52. package/src/modules/notifications/api/mark-all-read/route.ts +18 -4
  53. package/src/modules/notifications/api/route.ts +16 -3
  54. package/src/modules/notifications/api/settings/route.ts +26 -5
  55. package/src/modules/notifications/lib/routeHelpers.ts +101 -4
  56. package/src/modules/sales/components/documents/SalesDocumentForm.tsx +351 -327
  57. package/src/modules/workflows/components/EdgeEditDialog.tsx +132 -157
  58. package/src/modules/workflows/components/NodeEditDialog.tsx +116 -121
  59. package/src/modules/workflows/frontend/checkout-demo/page.tsx +172 -239
  60. package/src/modules/workflows/i18n/de.json +2 -0
  61. package/src/modules/workflows/i18n/en.json +2 -0
  62. package/src/modules/workflows/i18n/es.json +2 -0
  63. package/src/modules/workflows/i18n/pl.json +2 -0
@@ -1,9 +1,24 @@
1
1
  import { z } from 'zod'
2
+ import type { AwilixContainer } from 'awilix'
2
3
  import { resolveRequestContext } from '@open-mercato/shared/lib/api/context'
3
4
  import { isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'
5
+ import {
6
+ runCrudMutationGuardAfterSuccess,
7
+ validateCrudMutationGuard,
8
+ } from '@open-mercato/shared/lib/crud/mutation-guard'
4
9
  import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
5
10
  import { resolveNotificationService, type NotificationService } from './notificationService'
6
11
 
12
+ /**
13
+ * Mutation-guard resource kind for notification rows.
14
+ */
15
+ export const NOTIFICATION_RESOURCE_KIND = 'notifications.notification'
16
+
17
+ /**
18
+ * Mutation-guard resource kind for notification delivery settings.
19
+ */
20
+ export const NOTIFICATION_SETTINGS_RESOURCE_KIND = 'notifications.settings'
21
+
7
22
  /**
8
23
  * Notification scope context for service calls
9
24
  */
@@ -63,6 +78,65 @@ export async function resolveNotificationContext(req: Request): Promise<Notifica
63
78
  }
64
79
  }
65
80
 
81
+ /**
82
+ * Mutation-guard options for a notification write.
83
+ */
84
+ export interface NotificationMutationGuardOptions {
85
+ resourceKind: string
86
+ resourceId?: string | null
87
+ operation: 'create' | 'update' | 'delete' | 'custom'
88
+ payload?: Record<string, unknown> | null
89
+ }
90
+
91
+ export type GuardedNotificationWriteResult<T> =
92
+ | { ok: true; result: T }
93
+ | { ok: false; response: Response }
94
+
95
+ /**
96
+ * Run a notification write through the mutation guard lifecycle.
97
+ * Validates before the mutation, performs the write, then runs after-success
98
+ * hooks only when the write succeeded and the guard requested them. Returns the
99
+ * guard's own block response when validation fails so authorization behavior and
100
+ * conflict shapes are preserved.
101
+ */
102
+ export async function runGuardedNotificationWrite<T>(
103
+ container: AwilixContainer,
104
+ scope: NotificationScope,
105
+ req: Request,
106
+ options: NotificationMutationGuardOptions,
107
+ write: () => Promise<T>,
108
+ ): Promise<GuardedNotificationWriteResult<T>> {
109
+ const guardScope = {
110
+ tenantId: scope.tenantId,
111
+ organizationId: scope.organizationId,
112
+ userId: scope.userId ?? '',
113
+ resourceKind: options.resourceKind,
114
+ resourceId: options.resourceId ?? '',
115
+ operation: options.operation,
116
+ requestMethod: req.method,
117
+ requestHeaders: req.headers,
118
+ }
119
+
120
+ const guardResult = await validateCrudMutationGuard(container, {
121
+ ...guardScope,
122
+ mutationPayload: options.payload ?? null,
123
+ })
124
+ if (guardResult && !guardResult.ok) {
125
+ return { ok: false, response: Response.json(guardResult.body, { status: guardResult.status }) }
126
+ }
127
+
128
+ const result = await write()
129
+
130
+ if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {
131
+ await runCrudMutationGuardAfterSuccess(container, {
132
+ ...guardScope,
133
+ metadata: guardResult.metadata ?? null,
134
+ })
135
+ }
136
+
137
+ return { ok: true, result }
138
+ }
139
+
66
140
  /**
67
141
  * Create a POST handler for bulk notification creation routes.
68
142
  * Used by batch, role, and feature notification endpoints.
@@ -72,7 +146,7 @@ export function createBulkNotificationRoute<TSchema extends z.ZodTypeAny>(
72
146
  serviceMethod: 'createBatch' | 'createForRole' | 'createForFeature'
73
147
  ) {
74
148
  return async function POST(req: Request) {
75
- const { service, scope } = await resolveNotificationContext(req)
149
+ const { service, scope, ctx } = await resolveNotificationContext(req)
76
150
 
77
151
  const body = await req.json().catch(() => ({}))
78
152
  const parsed = schema.safeParse(body)
@@ -81,7 +155,19 @@ export function createBulkNotificationRoute<TSchema extends z.ZodTypeAny>(
81
155
  }
82
156
 
83
157
  try {
84
- const notifications = await service[serviceMethod](parsed.data as never, scope)
158
+ const guarded = await runGuardedNotificationWrite(
159
+ ctx.container,
160
+ scope,
161
+ req,
162
+ {
163
+ resourceKind: NOTIFICATION_RESOURCE_KIND,
164
+ operation: 'create',
165
+ payload: parsed.data as Record<string, unknown>,
166
+ },
167
+ () => service[serviceMethod](parsed.data as never, scope),
168
+ )
169
+ if (!guarded.ok) return guarded.response
170
+ const notifications = guarded.result
85
171
 
86
172
  return Response.json({
87
173
  ok: true,
@@ -144,10 +230,21 @@ export function createSingleNotificationActionRoute(
144
230
  ) {
145
231
  return async function PUT(req: Request, { params }: { params: Promise<{ id: string }> }) {
146
232
  const { id } = await params
147
- const { service, scope } = await resolveNotificationContext(req)
233
+ const { service, scope, ctx } = await resolveNotificationContext(req)
148
234
 
149
235
  try {
150
- await service[serviceMethod](id, scope)
236
+ const guarded = await runGuardedNotificationWrite(
237
+ ctx.container,
238
+ scope,
239
+ req,
240
+ {
241
+ resourceKind: NOTIFICATION_RESOURCE_KIND,
242
+ resourceId: id,
243
+ operation: 'update',
244
+ },
245
+ () => service[serviceMethod](id, scope),
246
+ )
247
+ if (!guarded.ok) return guarded.response
151
248
  } catch (error) {
152
249
  const errorResponse = notificationCrudErrorResponse(error)
153
250
  if (errorResponse) return errorResponse