@open-mercato/core 0.9.1-develop.7499.1.fcec456e4e → 0.9.1-develop.7515.1.e2712c8b00

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 (89) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/modules/audit_logs/components/AuditLogsActions.js +1 -1
  3. package/dist/modules/audit_logs/components/AuditLogsActions.js.map +2 -2
  4. package/dist/modules/auth/frontend/reset.js +7 -3
  5. package/dist/modules/auth/frontend/reset.js.map +2 -2
  6. package/dist/modules/business_rules/api/rules/route.js +12 -1
  7. package/dist/modules/business_rules/api/rules/route.js.map +2 -2
  8. package/dist/modules/catalog/backend/catalog/products/[id]/page.js +17 -2
  9. package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
  10. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js +3 -2
  11. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js.map +2 -2
  12. package/dist/modules/catalog/backend/catalog/products/create/page.js +1 -0
  13. package/dist/modules/catalog/backend/catalog/products/create/page.js.map +2 -2
  14. package/dist/modules/catalog/components/products/productFormUtils.js +9 -0
  15. package/dist/modules/catalog/components/products/productFormUtils.js.map +2 -2
  16. package/dist/modules/customers/backend/customers/companies/page.js +32 -32
  17. package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
  18. package/dist/modules/customers/backend/customers/deals/page.js +22 -22
  19. package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
  20. package/dist/modules/customers/backend/customers/people/page.js +34 -34
  21. package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
  22. package/dist/modules/ecommerce/search.js +1 -2
  23. package/dist/modules/ecommerce/search.js.map +2 -2
  24. package/dist/modules/shipping_carriers/api/webhook/[provider]/route.js +4 -7
  25. package/dist/modules/shipping_carriers/api/webhook/[provider]/route.js.map +2 -2
  26. package/dist/modules/shipping_carriers/lib/shipping-service.js +29 -11
  27. package/dist/modules/shipping_carriers/lib/shipping-service.js.map +2 -2
  28. package/dist/modules/shipping_carriers/lib/status-sync.js +2 -2
  29. package/dist/modules/shipping_carriers/lib/status-sync.js.map +2 -2
  30. package/dist/modules/shipping_carriers/workers/webhook-processor.js +60 -33
  31. package/dist/modules/shipping_carriers/workers/webhook-processor.js.map +3 -3
  32. package/dist/modules/staff/backend/staff/time-tracking/entries/page.js +10 -7
  33. package/dist/modules/staff/backend/staff/time-tracking/entries/page.js.map +2 -2
  34. package/dist/modules/warranty_claims/commands/claim-lines.js +89 -68
  35. package/dist/modules/warranty_claims/commands/claim-lines.js.map +2 -2
  36. package/dist/modules/warranty_claims/commands/claims.js +14 -13
  37. package/dist/modules/warranty_claims/commands/claims.js.map +2 -2
  38. package/dist/modules/warranty_claims/commands/shared.js +8 -2
  39. package/dist/modules/warranty_claims/commands/shared.js.map +2 -2
  40. package/dist/modules/wms/api/interceptors.js +3 -0
  41. package/dist/modules/wms/api/interceptors.js.map +2 -2
  42. package/dist/modules/wms/commands/configuration.js +16 -16
  43. package/dist/modules/wms/commands/configuration.js.map +2 -2
  44. package/dist/modules/wms/events.js +1 -0
  45. package/dist/modules/wms/events.js.map +2 -2
  46. package/dist/modules/wms/lib/catalogInventoryProfileIntent.js +9 -0
  47. package/dist/modules/wms/lib/catalogInventoryProfileIntent.js.map +2 -2
  48. package/dist/modules/wms/widgets/injection/catalog-inventory-profile/widget.js +11 -3
  49. package/dist/modules/wms/widgets/injection/catalog-inventory-profile/widget.js.map +2 -2
  50. package/package.json +7 -7
  51. package/src/modules/audit_logs/components/AuditLogsActions.tsx +1 -1
  52. package/src/modules/auth/frontend/reset.tsx +8 -3
  53. package/src/modules/business_rules/api/rules/route.ts +11 -0
  54. package/src/modules/business_rules/i18n/de.json +1 -0
  55. package/src/modules/business_rules/i18n/en.json +1 -0
  56. package/src/modules/business_rules/i18n/es.json +1 -0
  57. package/src/modules/business_rules/i18n/ko.json +1 -0
  58. package/src/modules/business_rules/i18n/pl.json +1 -0
  59. package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +20 -1
  60. package/src/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.tsx +2 -1
  61. package/src/modules/catalog/backend/catalog/products/create/page.tsx +1 -0
  62. package/src/modules/catalog/components/products/productFormUtils.ts +9 -0
  63. package/src/modules/customers/backend/customers/companies/page.tsx +32 -32
  64. package/src/modules/customers/backend/customers/deals/page.tsx +22 -22
  65. package/src/modules/customers/backend/customers/people/page.tsx +34 -34
  66. package/src/modules/customers/i18n/de.json +12 -0
  67. package/src/modules/customers/i18n/en.json +12 -0
  68. package/src/modules/customers/i18n/es.json +12 -0
  69. package/src/modules/customers/i18n/ko.json +12 -0
  70. package/src/modules/customers/i18n/pl.json +12 -0
  71. package/src/modules/ecommerce/i18n/de.json +2 -1
  72. package/src/modules/ecommerce/i18n/en.json +2 -1
  73. package/src/modules/ecommerce/i18n/es.json +2 -1
  74. package/src/modules/ecommerce/i18n/ko.json +2 -1
  75. package/src/modules/ecommerce/i18n/pl.json +2 -1
  76. package/src/modules/ecommerce/search.ts +0 -1
  77. package/src/modules/shipping_carriers/api/webhook/[provider]/route.ts +4 -7
  78. package/src/modules/shipping_carriers/lib/shipping-service.ts +29 -11
  79. package/src/modules/shipping_carriers/lib/status-sync.ts +2 -2
  80. package/src/modules/shipping_carriers/workers/webhook-processor.ts +71 -39
  81. package/src/modules/staff/backend/staff/time-tracking/entries/page.tsx +20 -14
  82. package/src/modules/warranty_claims/commands/claim-lines.ts +107 -66
  83. package/src/modules/warranty_claims/commands/claims.ts +14 -13
  84. package/src/modules/warranty_claims/commands/shared.ts +7 -1
  85. package/src/modules/wms/api/interceptors.ts +9 -0
  86. package/src/modules/wms/commands/configuration.ts +28 -16
  87. package/src/modules/wms/events.ts +1 -0
  88. package/src/modules/wms/lib/catalogInventoryProfileIntent.ts +9 -0
  89. package/src/modules/wms/widgets/injection/catalog-inventory-profile/widget.ts +13 -4
@@ -1,4 +1,4 @@
1
- [build:core] found 5727 entry points
1
+ [build:core] found 5732 entry points
2
2
  [build:core] built successfully
3
3
  [build:core:generated] found 252 entry points
4
4
  [build:core:generated] built successfully
@@ -153,7 +153,7 @@ function AuditLogsActions({
153
153
  const showRedo = itemCanRedo && item.executionState === "undone";
154
154
  const canRedo = showRedo && isRedoCandidate(item);
155
155
  if (!canUndo && !showRedo) return null;
156
- return /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-1", children: [
156
+ return /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-1", "data-actions-cell": true, children: [
157
157
  canUndo ? /* @__PURE__ */ jsx(
158
158
  Button,
159
159
  {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/audit_logs/components/AuditLogsActions.tsx"],
4
- "sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { extensionPoints } from '@open-mercato/core/modules/audit_logs/extension-points'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport { DataTable, type PaginationProps } from '@open-mercato/ui/backend/DataTable'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { apiCallOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { ActionLogDetailsDialog } from './ActionLogDetailsDialog'\nimport { Undo2, RotateCcw } from 'lucide-react'\nimport { markRedoConsumed, markUndoSuccess } from '@open-mercato/ui/backend/operations/store'\nimport { useAuditPermissions, canUndoEntry, canRedoEntry } from '@open-mercato/ui/backend/version-history'\nimport { Alert, AlertDescription } from '@open-mercato/ui/primitives/alert'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('audit_logs').child({ component: 'AuditLogsActions' })\n\n/**\n * `raiseCrudError` prefers the server's `error` body over the fallback message and stamps\n * `status` on anything it builds from an HTTP response, so a numeric `status` is what\n * distinguishes a route's refusal from a client-side failure. Without that check an\n * offline or aborted request would put a raw \"Failed to fetch\" into the operator's\n * banner; those keep the generic fallback instead.\n */\nfunction resolveServerReason(err: unknown): string | undefined {\n if (!(err instanceof Error)) return undefined\n const status = (err as Error & { status?: unknown }).status\n if (typeof status !== 'number') return undefined\n const message = err.message?.trim()\n return message ? message : undefined\n}\n\nexport type ActionLogItem = {\n id: string\n commandId: string\n actionLabel: string | null\n executionState: string\n actorUserId: string | null\n actorUserName: string | null\n tenantId: string | null\n tenantName: string | null\n organizationId: string | null\n organizationName: string | null\n resourceKind: string | null\n resourceId: string | null\n undoToken: string | null\n createdAt: string\n updatedAt: string\n snapshotBefore?: unknown | null\n snapshotAfter?: unknown | null\n changes?: Record<string, unknown> | null\n context?: Record<string, unknown> | null\n}\n\nexport function AuditLogsActions({\n items,\n onRefresh,\n isLoading,\n headerExtras,\n onUndoError,\n onRedoError,\n pagination,\n}: {\n items: ActionLogItem[] | undefined\n onRefresh: () => Promise<void>\n isLoading?: boolean\n headerExtras?: React.ReactNode\n /** Receives the server's reason when it sent one, so the page can show why the undo was refused. */\n onUndoError?: (reason?: string) => void\n onRedoError?: (reason?: string) => void\n pagination?: PaginationProps\n}) {\n const t = useT()\n const permissions = useAuditPermissions(true)\n const [undoingToken, setUndoingToken] = React.useState<string | null>(null)\n const [redoingId, setRedoingId] = React.useState<string | null>(null)\n const [selected, setSelected] = React.useState<ActionLogItem | null>(null)\n const actionItems = Array.isArray(items) ? items : []\n const latestUndoable = React.useMemo(() => actionItems.find((item) => !!item.undoToken && item.executionState === 'done'), [actionItems])\n const noneLabel = t('audit_logs.common.none')\n const latestPerResource = React.useMemo(() => {\n const map = new Map<string, string>()\n let fallback: string | null = null\n for (const item of actionItems) {\n if (!item.undoToken || item.executionState !== 'done') continue\n const key = buildResourceKey(item)\n if (key) {\n if (!map.has(key)) map.set(key, item.id)\n } else if (!fallback) {\n fallback = item.id\n }\n }\n return { map, fallback }\n }, [actionItems])\n const latestUndoneId = React.useMemo(() => {\n const undone = actionItems.filter((item) => item.executionState === 'undone')\n if (!undone.length) return null\n const sorted = [...undone].sort((a, b) => {\n const aTs = Date.parse(a.updatedAt)\n const bTs = Date.parse(b.updatedAt)\n return (Number.isFinite(bTs) ? bTs : 0) - (Number.isFinite(aTs) ? aTs : 0)\n })\n return sorted[0]?.id ?? null\n }, [actionItems])\n\n const isLatestUndoableForItem = React.useCallback((item: ActionLogItem) => {\n const key = buildResourceKey(item)\n if (key) return latestPerResource.map.get(key) === item.id\n return latestPerResource.fallback === item.id\n }, [latestPerResource])\n\n const isRedoCandidate = React.useCallback((item: ActionLogItem) => item.executionState === 'undone' && latestUndoneId === item.id, [latestUndoneId])\n\n const handleUndo = React.useCallback(async (token: string | null) => {\n if (!token) return\n setUndoingToken(token)\n try {\n await apiCallOrThrow('/api/audit_logs/audit-logs/actions/undo', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ undoToken: token }),\n }, { errorMessage: t('audit_logs.error.undo') })\n markUndoSuccess(token)\n await onRefresh()\n } catch (err) {\n logger.error('Undo action failed', { err })\n onUndoError?.(resolveServerReason(err))\n } finally {\n setUndoingToken(null)\n }\n }, [onRefresh, onUndoError, t])\n\n const handleRedo = React.useCallback(async (logId: string | null) => {\n if (!logId) return\n setRedoingId(logId)\n try {\n await apiCallOrThrow('/api/audit_logs/audit-logs/actions/redo', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ logId }),\n }, { errorMessage: t('audit_logs.error.redo') })\n markRedoConsumed(logId)\n await onRefresh()\n } catch (err) {\n logger.error('Redo action failed', { err })\n onRedoError?.(resolveServerReason(err))\n } finally {\n setRedoingId(null)\n }\n }, [onRefresh, onRedoError, t])\n\n const columns = React.useMemo<ColumnDef<ActionLogItem, any>[]>(() => [\n {\n accessorKey: 'actionLabel',\n header: t('audit_logs.actions.columns.action'),\n cell: (info) => info.row.original.actionLabel || info.row.original.commandId,\n },\n {\n accessorKey: 'resourceKind',\n header: t('audit_logs.actions.columns.resource'),\n cell: (info) => formatResource(info.row.original, noneLabel),\n },\n {\n accessorKey: 'actorUserId',\n header: t('audit_logs.actions.columns.user'),\n cell: (info) => info.row.original.actorUserName || info.getValue() || noneLabel,\n meta: { priority: 3 },\n },\n {\n accessorKey: 'tenantId',\n header: t('audit_logs.actions.columns.tenant'),\n cell: (info) => info.row.original.tenantName || info.getValue() || noneLabel,\n meta: { priority: 4 },\n },\n {\n accessorKey: 'organizationId',\n header: t('audit_logs.actions.columns.organization'),\n cell: (info) => info.row.original.organizationName || info.getValue() || noneLabel,\n meta: { priority: 4 },\n },\n {\n accessorKey: 'createdAt',\n header: t('audit_logs.actions.columns.when'),\n cell: (info) => formatDate(info.getValue() as string),\n },\n {\n accessorKey: 'executionState',\n header: t('audit_logs.actions.columns.status'),\n },\n {\n id: 'controls',\n header: t('audit_logs.actions.columns.controls'),\n enableSorting: false,\n cell: (info) => {\n const item = info.row.original\n const itemCanUndo = canUndoEntry(permissions, item.actorUserId)\n const itemCanRedo = canRedoEntry(permissions, item.actorUserId)\n const canUndo = itemCanUndo && Boolean(item.undoToken) && item.executionState === 'done' && isLatestUndoableForItem(item)\n const showRedo = itemCanRedo && item.executionState === 'undone'\n const canRedo = showRedo && isRedoCandidate(item)\n if (!canUndo && !showRedo) return null\n return (\n <div className=\"flex justify-end gap-1\">\n {canUndo ? (\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label={t('audit_logs.actions.undo')}\n onClick={() => { void handleUndo(item.undoToken) }}\n disabled={undoingToken === item.undoToken || Boolean(redoingId)}\n >\n <Undo2 className=\"size-4\" aria-hidden=\"true\" />\n </Button>\n ) : null}\n {showRedo ? (\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label={t('audit_logs.actions.redo')}\n onClick={() => { void handleRedo(item.id) }}\n disabled={!canRedo || redoingId === item.id || Boolean(undoingToken)}\n >\n <RotateCcw className=\"size-4\" aria-hidden=\"true\" />\n </Button>\n ) : null}\n </div>\n )\n },\n meta: { align: 'right' },\n },\n ], [t, noneLabel, handleUndo, handleRedo, isLatestUndoableForItem, isRedoCandidate, undoingToken, redoingId, permissions])\n\n const undoButton = latestUndoable?.undoToken && canUndoEntry(permissions, latestUndoable.actorUserId) ? (\n <Button\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => { void handleUndo(latestUndoable.undoToken) }}\n disabled={Boolean(undoingToken) || Boolean(redoingId)}\n >\n {undoingToken ? t('audit_logs.actions.undoing') : t('audit_logs.actions.undo')}\n </Button>\n ) : null\n\n const combinedActions = undoButton || headerExtras\n ? <div className=\"flex items-center gap-2\">{headerExtras}{undoButton}</div>\n : undefined\n\n const showSelfOnlyHint = !permissions.isLoading && !permissions.canViewTenant && !!permissions.currentUserId\n\n return (\n <>\n {showSelfOnlyHint ? (\n <Alert status=\"information\" className=\"mb-4\">\n <AlertDescription>\n {t('audit_logs.hint.view_self_only', 'Showing only your own changes. Contact an administrator for broader access.')}\n </AlertDescription>\n </Alert>\n ) : null}\n <DataTable<ActionLogItem>\n title={t('audit_logs.actions.title')}\n titleHeadingLevel={2}\n data={actionItems}\n columns={columns}\n actions={combinedActions}\n perspective={{ tableId: extensionPoints.hosts.actionsTable.tableId }}\n isLoading={Boolean(isLoading) || Boolean(undoingToken) || Boolean(redoingId)}\n onRowClick={(item) => setSelected(item)}\n pagination={pagination}\n />\n {selected ? (\n <ActionLogDetailsDialog\n item={selected}\n onClose={() => setSelected(null)}\n />\n ) : null}\n </>\n )\n}\n\nfunction formatResource(item: { resourceKind?: string | null; resourceId?: string | null }, fallback: string) {\n if (!item.resourceKind && !item.resourceId) return fallback\n return [item.resourceKind, item.resourceId].filter(Boolean).join(' \u00B7 ')\n}\n\nfunction buildResourceKey(item: { resourceKind?: string | null; resourceId?: string | null }) {\n const kind = typeof item.resourceKind === 'string' ? item.resourceKind.trim() : ''\n const id = typeof item.resourceId === 'string' ? item.resourceId.trim() : ''\n if (!kind && !id) return null\n return `${kind}::${id}`\n}\n\nfunction formatDate(value: string) {\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) return value\n return new Intl.DateTimeFormat(undefined, {\n dateStyle: 'medium',\n timeStyle: 'short',\n }).format(date)\n}\n"],
5
- "mappings": ";AA2MU,SAgDN,UAvCY,KATN;AAzMV,YAAY,WAAW;AACvB,SAAS,uBAAuB;AAEhC,SAAS,iBAAuC;AAChD,SAAS,cAAc;AACvB,SAAS,sBAAsB;AAC/B,SAAS,YAAY;AACrB,SAAS,8BAA8B;AACvC,SAAS,OAAO,iBAAiB;AACjC,SAAS,kBAAkB,uBAAuB;AAClD,SAAS,qBAAqB,cAAc,oBAAoB;AAChE,SAAS,OAAO,wBAAwB;AACxC,SAAS,oBAAoB;AAE7B,MAAM,SAAS,aAAa,YAAY,EAAE,MAAM,EAAE,WAAW,mBAAmB,CAAC;AASjF,SAAS,oBAAoB,KAAkC;AAC7D,MAAI,EAAE,eAAe,OAAQ,QAAO;AACpC,QAAM,SAAU,IAAqC;AACrD,MAAI,OAAO,WAAW,SAAU,QAAO;AACvC,QAAM,UAAU,IAAI,SAAS,KAAK;AAClC,SAAO,UAAU,UAAU;AAC7B;AAwBO,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GASG;AACD,QAAM,IAAI,KAAK;AACf,QAAM,cAAc,oBAAoB,IAAI;AAC5C,QAAM,CAAC,cAAc,eAAe,IAAI,MAAM,SAAwB,IAAI;AAC1E,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAAwB,IAAI;AACpE,QAAM,CAAC,UAAU,WAAW,IAAI,MAAM,SAA+B,IAAI;AACzE,QAAM,cAAc,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC;AACpD,QAAM,iBAAiB,MAAM,QAAQ,MAAM,YAAY,KAAK,CAAC,SAAS,CAAC,CAAC,KAAK,aAAa,KAAK,mBAAmB,MAAM,GAAG,CAAC,WAAW,CAAC;AACxI,QAAM,YAAY,EAAE,wBAAwB;AAC5C,QAAM,oBAAoB,MAAM,QAAQ,MAAM;AAC5C,UAAM,MAAM,oBAAI,IAAoB;AACpC,QAAI,WAA0B;AAC9B,eAAW,QAAQ,aAAa;AAC9B,UAAI,CAAC,KAAK,aAAa,KAAK,mBAAmB,OAAQ;AACvD,YAAM,MAAM,iBAAiB,IAAI;AACjC,UAAI,KAAK;AACP,YAAI,CAAC,IAAI,IAAI,GAAG,EAAG,KAAI,IAAI,KAAK,KAAK,EAAE;AAAA,MACzC,WAAW,CAAC,UAAU;AACpB,mBAAW,KAAK;AAAA,MAClB;AAAA,IACF;AACA,WAAO,EAAE,KAAK,SAAS;AAAA,EACzB,GAAG,CAAC,WAAW,CAAC;AAChB,QAAM,iBAAiB,MAAM,QAAQ,MAAM;AACzC,UAAM,SAAS,YAAY,OAAO,CAAC,SAAS,KAAK,mBAAmB,QAAQ;AAC5E,QAAI,CAAC,OAAO,OAAQ,QAAO;AAC3B,UAAM,SAAS,CAAC,GAAG,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM;AACxC,YAAM,MAAM,KAAK,MAAM,EAAE,SAAS;AAClC,YAAM,MAAM,KAAK,MAAM,EAAE,SAAS;AAClC,cAAQ,OAAO,SAAS,GAAG,IAAI,MAAM,MAAM,OAAO,SAAS,GAAG,IAAI,MAAM;AAAA,IAC1E,CAAC;AACD,WAAO,OAAO,CAAC,GAAG,MAAM;AAAA,EAC1B,GAAG,CAAC,WAAW,CAAC;AAEhB,QAAM,0BAA0B,MAAM,YAAY,CAAC,SAAwB;AACzE,UAAM,MAAM,iBAAiB,IAAI;AACjC,QAAI,IAAK,QAAO,kBAAkB,IAAI,IAAI,GAAG,MAAM,KAAK;AACxD,WAAO,kBAAkB,aAAa,KAAK;AAAA,EAC7C,GAAG,CAAC,iBAAiB,CAAC;AAEtB,QAAM,kBAAkB,MAAM,YAAY,CAAC,SAAwB,KAAK,mBAAmB,YAAY,mBAAmB,KAAK,IAAI,CAAC,cAAc,CAAC;AAEnJ,QAAM,aAAa,MAAM,YAAY,OAAO,UAAyB;AACnE,QAAI,CAAC,MAAO;AACZ,oBAAgB,KAAK;AACrB,QAAI;AACF,YAAM,eAAe,2CAA2C;AAAA,QAC9D,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,EAAE,WAAW,MAAM,CAAC;AAAA,MAC3C,GAAG,EAAE,cAAc,EAAE,uBAAuB,EAAE,CAAC;AAC/C,sBAAgB,KAAK;AACrB,YAAM,UAAU;AAAA,IAClB,SAAS,KAAK;AACZ,aAAO,MAAM,sBAAsB,EAAE,IAAI,CAAC;AAC1C,oBAAc,oBAAoB,GAAG,CAAC;AAAA,IACxC,UAAE;AACA,sBAAgB,IAAI;AAAA,IACtB;AAAA,EACF,GAAG,CAAC,WAAW,aAAa,CAAC,CAAC;AAE9B,QAAM,aAAa,MAAM,YAAY,OAAO,UAAyB;AACnE,QAAI,CAAC,MAAO;AACZ,iBAAa,KAAK;AAClB,QAAI;AACF,YAAM,eAAe,2CAA2C;AAAA,QAC9D,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,EAAE,MAAM,CAAC;AAAA,MAChC,GAAG,EAAE,cAAc,EAAE,uBAAuB,EAAE,CAAC;AAC/C,uBAAiB,KAAK;AACtB,YAAM,UAAU;AAAA,IAClB,SAAS,KAAK;AACZ,aAAO,MAAM,sBAAsB,EAAE,IAAI,CAAC;AAC1C,oBAAc,oBAAoB,GAAG,CAAC;AAAA,IACxC,UAAE;AACA,mBAAa,IAAI;AAAA,IACnB;AAAA,EACF,GAAG,CAAC,WAAW,aAAa,CAAC,CAAC;AAE9B,QAAM,UAAU,MAAM,QAAyC,MAAM;AAAA,IACnE;AAAA,MACE,aAAa;AAAA,MACb,QAAQ,EAAE,mCAAmC;AAAA,MAC7C,MAAM,CAAC,SAAS,KAAK,IAAI,SAAS,eAAe,KAAK,IAAI,SAAS;AAAA,IACrE;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,QAAQ,EAAE,qCAAqC;AAAA,MAC/C,MAAM,CAAC,SAAS,eAAe,KAAK,IAAI,UAAU,SAAS;AAAA,IAC7D;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,QAAQ,EAAE,iCAAiC;AAAA,MAC3C,MAAM,CAAC,SAAS,KAAK,IAAI,SAAS,iBAAiB,KAAK,SAAS,KAAK;AAAA,MACtE,MAAM,EAAE,UAAU,EAAE;AAAA,IACtB;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,QAAQ,EAAE,mCAAmC;AAAA,MAC7C,MAAM,CAAC,SAAS,KAAK,IAAI,SAAS,cAAc,KAAK,SAAS,KAAK;AAAA,MACnE,MAAM,EAAE,UAAU,EAAE;AAAA,IACtB;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,QAAQ,EAAE,yCAAyC;AAAA,MACnD,MAAM,CAAC,SAAS,KAAK,IAAI,SAAS,oBAAoB,KAAK,SAAS,KAAK;AAAA,MACzE,MAAM,EAAE,UAAU,EAAE;AAAA,IACtB;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,QAAQ,EAAE,iCAAiC;AAAA,MAC3C,MAAM,CAAC,SAAS,WAAW,KAAK,SAAS,CAAW;AAAA,IACtD;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,QAAQ,EAAE,mCAAmC;AAAA,IAC/C;AAAA,IACA;AAAA,MACE,IAAI;AAAA,MACJ,QAAQ,EAAE,qCAAqC;AAAA,MAC/C,eAAe;AAAA,MACf,MAAM,CAAC,SAAS;AACd,cAAM,OAAO,KAAK,IAAI;AACtB,cAAM,cAAc,aAAa,aAAa,KAAK,WAAW;AAC9D,cAAM,cAAc,aAAa,aAAa,KAAK,WAAW;AAC9D,cAAM,UAAU,eAAe,QAAQ,KAAK,SAAS,KAAK,KAAK,mBAAmB,UAAU,wBAAwB,IAAI;AACxH,cAAM,WAAW,eAAe,KAAK,mBAAmB;AACxD,cAAM,UAAU,YAAY,gBAAgB,IAAI;AAChD,YAAI,CAAC,WAAW,CAAC,SAAU,QAAO;AAClC,eACE,qBAAC,SAAI,WAAU,0BACZ;AAAA,oBACC;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,cAAY,EAAE,yBAAyB;AAAA,cACvC,SAAS,MAAM;AAAE,qBAAK,WAAW,KAAK,SAAS;AAAA,cAAE;AAAA,cACjD,UAAU,iBAAiB,KAAK,aAAa,QAAQ,SAAS;AAAA,cAE9D,8BAAC,SAAM,WAAU,UAAS,eAAY,QAAO;AAAA;AAAA,UAC/C,IACE;AAAA,UACH,WACC;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,cAAY,EAAE,yBAAyB;AAAA,cACvC,SAAS,MAAM;AAAE,qBAAK,WAAW,KAAK,EAAE;AAAA,cAAE;AAAA,cAC1C,UAAU,CAAC,WAAW,cAAc,KAAK,MAAM,QAAQ,YAAY;AAAA,cAEnE,8BAAC,aAAU,WAAU,UAAS,eAAY,QAAO;AAAA;AAAA,UACnD,IACE;AAAA,WACN;AAAA,MAEJ;AAAA,MACA,MAAM,EAAE,OAAO,QAAQ;AAAA,IACzB;AAAA,EACF,GAAG,CAAC,GAAG,WAAW,YAAY,YAAY,yBAAyB,iBAAiB,cAAc,WAAW,WAAW,CAAC;AAEzH,QAAM,aAAa,gBAAgB,aAAa,aAAa,aAAa,eAAe,WAAW,IAClG;AAAA,IAAC;AAAA;AAAA,MACC,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,SAAS,MAAM;AAAE,aAAK,WAAW,eAAe,SAAS;AAAA,MAAE;AAAA,MAC3D,UAAU,QAAQ,YAAY,KAAK,QAAQ,SAAS;AAAA,MAEnD,yBAAe,EAAE,4BAA4B,IAAI,EAAE,yBAAyB;AAAA;AAAA,EAC/E,IACE;AAEJ,QAAM,kBAAkB,cAAc,eAClC,qBAAC,SAAI,WAAU,2BAA2B;AAAA;AAAA,IAAc;AAAA,KAAW,IACnE;AAEJ,QAAM,mBAAmB,CAAC,YAAY,aAAa,CAAC,YAAY,iBAAiB,CAAC,CAAC,YAAY;AAE/F,SACE,iCACG;AAAA,uBACC,oBAAC,SAAM,QAAO,eAAc,WAAU,QACpC,8BAAC,oBACE,YAAE,kCAAkC,6EAA6E,GACpH,GACF,IACE;AAAA,IACJ;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,EAAE,0BAA0B;AAAA,QACnC,mBAAmB;AAAA,QACnB,MAAM;AAAA,QACN;AAAA,QACA,SAAS;AAAA,QACT,aAAa,EAAE,SAAS,gBAAgB,MAAM,aAAa,QAAQ;AAAA,QACnE,WAAW,QAAQ,SAAS,KAAK,QAAQ,YAAY,KAAK,QAAQ,SAAS;AAAA,QAC3E,YAAY,CAAC,SAAS,YAAY,IAAI;AAAA,QACtC;AAAA;AAAA,IACF;AAAA,IACC,WACC;AAAA,MAAC;AAAA;AAAA,QACC,MAAM;AAAA,QACN,SAAS,MAAM,YAAY,IAAI;AAAA;AAAA,IACjC,IACE;AAAA,KACN;AAEJ;AAEA,SAAS,eAAe,MAAoE,UAAkB;AAC5G,MAAI,CAAC,KAAK,gBAAgB,CAAC,KAAK,WAAY,QAAO;AACnD,SAAO,CAAC,KAAK,cAAc,KAAK,UAAU,EAAE,OAAO,OAAO,EAAE,KAAK,QAAK;AACxE;AAEA,SAAS,iBAAiB,MAAoE;AAC5F,QAAM,OAAO,OAAO,KAAK,iBAAiB,WAAW,KAAK,aAAa,KAAK,IAAI;AAChF,QAAM,KAAK,OAAO,KAAK,eAAe,WAAW,KAAK,WAAW,KAAK,IAAI;AAC1E,MAAI,CAAC,QAAQ,CAAC,GAAI,QAAO;AACzB,SAAO,GAAG,IAAI,KAAK,EAAE;AACvB;AAEA,SAAS,WAAW,OAAe;AACjC,QAAM,OAAO,IAAI,KAAK,KAAK;AAC3B,MAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,EAAG,QAAO;AACzC,SAAO,IAAI,KAAK,eAAe,QAAW;AAAA,IACxC,WAAW;AAAA,IACX,WAAW;AAAA,EACb,CAAC,EAAE,OAAO,IAAI;AAChB;",
4
+ "sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { extensionPoints } from '@open-mercato/core/modules/audit_logs/extension-points'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport { DataTable, type PaginationProps } from '@open-mercato/ui/backend/DataTable'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { apiCallOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { ActionLogDetailsDialog } from './ActionLogDetailsDialog'\nimport { Undo2, RotateCcw } from 'lucide-react'\nimport { markRedoConsumed, markUndoSuccess } from '@open-mercato/ui/backend/operations/store'\nimport { useAuditPermissions, canUndoEntry, canRedoEntry } from '@open-mercato/ui/backend/version-history'\nimport { Alert, AlertDescription } from '@open-mercato/ui/primitives/alert'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('audit_logs').child({ component: 'AuditLogsActions' })\n\n/**\n * `raiseCrudError` prefers the server's `error` body over the fallback message and stamps\n * `status` on anything it builds from an HTTP response, so a numeric `status` is what\n * distinguishes a route's refusal from a client-side failure. Without that check an\n * offline or aborted request would put a raw \"Failed to fetch\" into the operator's\n * banner; those keep the generic fallback instead.\n */\nfunction resolveServerReason(err: unknown): string | undefined {\n if (!(err instanceof Error)) return undefined\n const status = (err as Error & { status?: unknown }).status\n if (typeof status !== 'number') return undefined\n const message = err.message?.trim()\n return message ? message : undefined\n}\n\nexport type ActionLogItem = {\n id: string\n commandId: string\n actionLabel: string | null\n executionState: string\n actorUserId: string | null\n actorUserName: string | null\n tenantId: string | null\n tenantName: string | null\n organizationId: string | null\n organizationName: string | null\n resourceKind: string | null\n resourceId: string | null\n undoToken: string | null\n createdAt: string\n updatedAt: string\n snapshotBefore?: unknown | null\n snapshotAfter?: unknown | null\n changes?: Record<string, unknown> | null\n context?: Record<string, unknown> | null\n}\n\nexport function AuditLogsActions({\n items,\n onRefresh,\n isLoading,\n headerExtras,\n onUndoError,\n onRedoError,\n pagination,\n}: {\n items: ActionLogItem[] | undefined\n onRefresh: () => Promise<void>\n isLoading?: boolean\n headerExtras?: React.ReactNode\n /** Receives the server's reason when it sent one, so the page can show why the undo was refused. */\n onUndoError?: (reason?: string) => void\n onRedoError?: (reason?: string) => void\n pagination?: PaginationProps\n}) {\n const t = useT()\n const permissions = useAuditPermissions(true)\n const [undoingToken, setUndoingToken] = React.useState<string | null>(null)\n const [redoingId, setRedoingId] = React.useState<string | null>(null)\n const [selected, setSelected] = React.useState<ActionLogItem | null>(null)\n const actionItems = Array.isArray(items) ? items : []\n const latestUndoable = React.useMemo(() => actionItems.find((item) => !!item.undoToken && item.executionState === 'done'), [actionItems])\n const noneLabel = t('audit_logs.common.none')\n const latestPerResource = React.useMemo(() => {\n const map = new Map<string, string>()\n let fallback: string | null = null\n for (const item of actionItems) {\n if (!item.undoToken || item.executionState !== 'done') continue\n const key = buildResourceKey(item)\n if (key) {\n if (!map.has(key)) map.set(key, item.id)\n } else if (!fallback) {\n fallback = item.id\n }\n }\n return { map, fallback }\n }, [actionItems])\n const latestUndoneId = React.useMemo(() => {\n const undone = actionItems.filter((item) => item.executionState === 'undone')\n if (!undone.length) return null\n const sorted = [...undone].sort((a, b) => {\n const aTs = Date.parse(a.updatedAt)\n const bTs = Date.parse(b.updatedAt)\n return (Number.isFinite(bTs) ? bTs : 0) - (Number.isFinite(aTs) ? aTs : 0)\n })\n return sorted[0]?.id ?? null\n }, [actionItems])\n\n const isLatestUndoableForItem = React.useCallback((item: ActionLogItem) => {\n const key = buildResourceKey(item)\n if (key) return latestPerResource.map.get(key) === item.id\n return latestPerResource.fallback === item.id\n }, [latestPerResource])\n\n const isRedoCandidate = React.useCallback((item: ActionLogItem) => item.executionState === 'undone' && latestUndoneId === item.id, [latestUndoneId])\n\n const handleUndo = React.useCallback(async (token: string | null) => {\n if (!token) return\n setUndoingToken(token)\n try {\n await apiCallOrThrow('/api/audit_logs/audit-logs/actions/undo', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ undoToken: token }),\n }, { errorMessage: t('audit_logs.error.undo') })\n markUndoSuccess(token)\n await onRefresh()\n } catch (err) {\n logger.error('Undo action failed', { err })\n onUndoError?.(resolveServerReason(err))\n } finally {\n setUndoingToken(null)\n }\n }, [onRefresh, onUndoError, t])\n\n const handleRedo = React.useCallback(async (logId: string | null) => {\n if (!logId) return\n setRedoingId(logId)\n try {\n await apiCallOrThrow('/api/audit_logs/audit-logs/actions/redo', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ logId }),\n }, { errorMessage: t('audit_logs.error.redo') })\n markRedoConsumed(logId)\n await onRefresh()\n } catch (err) {\n logger.error('Redo action failed', { err })\n onRedoError?.(resolveServerReason(err))\n } finally {\n setRedoingId(null)\n }\n }, [onRefresh, onRedoError, t])\n\n const columns = React.useMemo<ColumnDef<ActionLogItem, any>[]>(() => [\n {\n accessorKey: 'actionLabel',\n header: t('audit_logs.actions.columns.action'),\n cell: (info) => info.row.original.actionLabel || info.row.original.commandId,\n },\n {\n accessorKey: 'resourceKind',\n header: t('audit_logs.actions.columns.resource'),\n cell: (info) => formatResource(info.row.original, noneLabel),\n },\n {\n accessorKey: 'actorUserId',\n header: t('audit_logs.actions.columns.user'),\n cell: (info) => info.row.original.actorUserName || info.getValue() || noneLabel,\n meta: { priority: 3 },\n },\n {\n accessorKey: 'tenantId',\n header: t('audit_logs.actions.columns.tenant'),\n cell: (info) => info.row.original.tenantName || info.getValue() || noneLabel,\n meta: { priority: 4 },\n },\n {\n accessorKey: 'organizationId',\n header: t('audit_logs.actions.columns.organization'),\n cell: (info) => info.row.original.organizationName || info.getValue() || noneLabel,\n meta: { priority: 4 },\n },\n {\n accessorKey: 'createdAt',\n header: t('audit_logs.actions.columns.when'),\n cell: (info) => formatDate(info.getValue() as string),\n },\n {\n accessorKey: 'executionState',\n header: t('audit_logs.actions.columns.status'),\n },\n {\n id: 'controls',\n header: t('audit_logs.actions.columns.controls'),\n enableSorting: false,\n cell: (info) => {\n const item = info.row.original\n const itemCanUndo = canUndoEntry(permissions, item.actorUserId)\n const itemCanRedo = canRedoEntry(permissions, item.actorUserId)\n const canUndo = itemCanUndo && Boolean(item.undoToken) && item.executionState === 'done' && isLatestUndoableForItem(item)\n const showRedo = itemCanRedo && item.executionState === 'undone'\n const canRedo = showRedo && isRedoCandidate(item)\n if (!canUndo && !showRedo) return null\n return (\n <div className=\"flex justify-end gap-1\" data-actions-cell>\n {canUndo ? (\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label={t('audit_logs.actions.undo')}\n onClick={() => { void handleUndo(item.undoToken) }}\n disabled={undoingToken === item.undoToken || Boolean(redoingId)}\n >\n <Undo2 className=\"size-4\" aria-hidden=\"true\" />\n </Button>\n ) : null}\n {showRedo ? (\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label={t('audit_logs.actions.redo')}\n onClick={() => { void handleRedo(item.id) }}\n disabled={!canRedo || redoingId === item.id || Boolean(undoingToken)}\n >\n <RotateCcw className=\"size-4\" aria-hidden=\"true\" />\n </Button>\n ) : null}\n </div>\n )\n },\n meta: { align: 'right' },\n },\n ], [t, noneLabel, handleUndo, handleRedo, isLatestUndoableForItem, isRedoCandidate, undoingToken, redoingId, permissions])\n\n const undoButton = latestUndoable?.undoToken && canUndoEntry(permissions, latestUndoable.actorUserId) ? (\n <Button\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => { void handleUndo(latestUndoable.undoToken) }}\n disabled={Boolean(undoingToken) || Boolean(redoingId)}\n >\n {undoingToken ? t('audit_logs.actions.undoing') : t('audit_logs.actions.undo')}\n </Button>\n ) : null\n\n const combinedActions = undoButton || headerExtras\n ? <div className=\"flex items-center gap-2\">{headerExtras}{undoButton}</div>\n : undefined\n\n const showSelfOnlyHint = !permissions.isLoading && !permissions.canViewTenant && !!permissions.currentUserId\n\n return (\n <>\n {showSelfOnlyHint ? (\n <Alert status=\"information\" className=\"mb-4\">\n <AlertDescription>\n {t('audit_logs.hint.view_self_only', 'Showing only your own changes. Contact an administrator for broader access.')}\n </AlertDescription>\n </Alert>\n ) : null}\n <DataTable<ActionLogItem>\n title={t('audit_logs.actions.title')}\n titleHeadingLevel={2}\n data={actionItems}\n columns={columns}\n actions={combinedActions}\n perspective={{ tableId: extensionPoints.hosts.actionsTable.tableId }}\n isLoading={Boolean(isLoading) || Boolean(undoingToken) || Boolean(redoingId)}\n onRowClick={(item) => setSelected(item)}\n pagination={pagination}\n />\n {selected ? (\n <ActionLogDetailsDialog\n item={selected}\n onClose={() => setSelected(null)}\n />\n ) : null}\n </>\n )\n}\n\nfunction formatResource(item: { resourceKind?: string | null; resourceId?: string | null }, fallback: string) {\n if (!item.resourceKind && !item.resourceId) return fallback\n return [item.resourceKind, item.resourceId].filter(Boolean).join(' \u00B7 ')\n}\n\nfunction buildResourceKey(item: { resourceKind?: string | null; resourceId?: string | null }) {\n const kind = typeof item.resourceKind === 'string' ? item.resourceKind.trim() : ''\n const id = typeof item.resourceId === 'string' ? item.resourceId.trim() : ''\n if (!kind && !id) return null\n return `${kind}::${id}`\n}\n\nfunction formatDate(value: string) {\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) return value\n return new Intl.DateTimeFormat(undefined, {\n dateStyle: 'medium',\n timeStyle: 'short',\n }).format(date)\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
- import { useState } from "react";
3
+ import { useEffect, useState } from "react";
4
4
  import Link from "next/link";
5
5
  import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@open-mercato/ui/primitives/card";
6
6
  import { Button } from "@open-mercato/ui/primitives/button";
@@ -13,6 +13,10 @@ function ResetPage() {
13
13
  const [submitting, setSubmitting] = useState(false);
14
14
  const [error, setError] = useState(null);
15
15
  const [fieldError, setFieldError] = useState(null);
16
+ const [clientReady, setClientReady] = useState(false);
17
+ useEffect(() => {
18
+ setClientReady(true);
19
+ }, []);
16
20
  async function onSubmit(e) {
17
21
  e.preventDefault();
18
22
  setError(null);
@@ -43,14 +47,14 @@ function ResetPage() {
43
47
  /* @__PURE__ */ jsx(CardContent, { children: sent ? /* @__PURE__ */ jsxs("div", { className: "grid gap-3", children: [
44
48
  /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t("auth.reset.sent", "If an account with that email exists, we sent a reset link. Please check your inbox.") }),
45
49
  /* @__PURE__ */ jsx(Link, { href: "/login", className: "text-sm underline", children: t("auth.reset.backToLogin", "Back to login") })
46
- ] }) : /* @__PURE__ */ jsxs("form", { className: "grid gap-3", onSubmit, noValidate: true, children: [
50
+ ] }) : /* @__PURE__ */ jsxs("form", { className: "grid gap-3", method: "post", onSubmit, noValidate: true, "data-auth-ready": clientReady ? "1" : "0", children: [
47
51
  error && /* @__PURE__ */ jsx("div", { className: "text-sm text-status-error-text", children: error }),
48
52
  /* @__PURE__ */ jsxs("div", { className: "grid gap-1", children: [
49
53
  /* @__PURE__ */ jsx(Label, { htmlFor: "email", children: t("auth.email") }),
50
54
  /* @__PURE__ */ jsx(EmailInput, { id: "email", name: "email", required: true, "aria-invalid": !!fieldError, "aria-describedby": fieldError ? "email-error" : void 0 }),
51
55
  fieldError && /* @__PURE__ */ jsx("p", { id: "email-error", className: "text-sm text-status-error-text", children: fieldError })
52
56
  ] }),
53
- /* @__PURE__ */ jsx(Button, { type: "submit", className: "mt-2 w-full", disabled: submitting, children: submitting ? "..." : t("auth.sendResetLink") }),
57
+ /* @__PURE__ */ jsx(Button, { type: "submit", className: "mt-2 w-full", disabled: submitting || !clientReady, children: submitting ? "..." : t("auth.sendResetLink") }),
54
58
  /* @__PURE__ */ jsx("div", { className: "text-center", children: /* @__PURE__ */ jsx(Link, { href: "/login", className: "text-xs text-muted-foreground underline", children: t("auth.reset.backToLogin", "Back to login") }) })
55
59
  ] }) })
56
60
  ] }) });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/auth/frontend/reset.tsx"],
4
- "sourcesContent": ["\"use client\"\nimport { useState } from 'react'\nimport Link from 'next/link'\nimport { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@open-mercato/ui/primitives/card'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { EmailInput } from '@open-mercato/ui/primitives/email-input'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\nexport default function ResetPage() {\n const t = useT()\n const [sent, setSent] = useState(false)\n const [submitting, setSubmitting] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const [fieldError, setFieldError] = useState<string | null>(null)\n\n async function onSubmit(e: React.FormEvent<HTMLFormElement>) {\n e.preventDefault()\n setError(null)\n setFieldError(null)\n setSubmitting(true)\n try {\n const form = new FormData(e.currentTarget)\n const res = await fetch('/api/auth/reset', { method: 'POST', body: form })\n if (!res.ok) {\n const data = await res.json().catch(() => null)\n if (data?.fieldErrors?.email?.length) {\n setFieldError(t('auth.reset.errors.emailInvalid', 'Please enter a valid email address.'))\n return\n }\n setError(data?.error || t('auth.reset.error', 'Something went wrong'))\n return\n }\n setSent(true)\n } finally {\n setSubmitting(false)\n }\n }\n\n return (\n <div className=\"min-h-svh flex items-center justify-center p-4\">\n <Card className=\"w-full max-w-sm\">\n <CardHeader>\n <CardTitle>{t('auth.resetPassword')}</CardTitle>\n <CardDescription>{t('auth.reset.description', 'Enter your email to receive reset link')}</CardDescription>\n </CardHeader>\n <CardContent>\n {sent ? (\n <div className=\"grid gap-3\">\n <p className=\"text-sm text-muted-foreground\">\n {t('auth.reset.sent', 'If an account with that email exists, we sent a reset link. Please check your inbox.')}\n </p>\n <Link href=\"/login\" className=\"text-sm underline\">\n {t('auth.reset.backToLogin', 'Back to login')}\n </Link>\n </div>\n ) : (\n <form className=\"grid gap-3\" onSubmit={onSubmit} noValidate>\n {error && <div className=\"text-sm text-status-error-text\">{error}</div>}\n <div className=\"grid gap-1\">\n <Label htmlFor=\"email\">{t('auth.email')}</Label>\n <EmailInput id=\"email\" name=\"email\" required aria-invalid={!!fieldError} aria-describedby={fieldError ? 'email-error' : undefined} />\n {fieldError && <p id=\"email-error\" className=\"text-sm text-status-error-text\">{fieldError}</p>}\n </div>\n <Button type=\"submit\" className=\"mt-2 w-full\" disabled={submitting}>\n {submitting ? '...' : t('auth.sendResetLink')}\n </Button>\n <div className=\"text-center\">\n <Link href=\"/login\" className=\"text-xs text-muted-foreground underline\">\n {t('auth.reset.backToLogin', 'Back to login')}\n </Link>\n </div>\n </form>\n )}\n </CardContent>\n </Card>\n </div>\n )\n}\n"],
5
- "mappings": ";AA0CQ,SACE,KADF;AAzCR,SAAS,gBAAgB;AACzB,OAAO,UAAU;AACjB,SAAS,MAAM,aAAa,YAAY,WAAW,uBAAuB;AAC1E,SAAS,cAAc;AACvB,SAAS,kBAAkB;AAC3B,SAAS,aAAa;AACtB,SAAS,YAAY;AAEN,SAAR,YAA6B;AAClC,QAAM,IAAI,KAAK;AACf,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AACtC,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,KAAK;AAClD,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAwB,IAAI;AACtD,QAAM,CAAC,YAAY,aAAa,IAAI,SAAwB,IAAI;AAEhE,iBAAe,SAAS,GAAqC;AAC3D,MAAE,eAAe;AACjB,aAAS,IAAI;AACb,kBAAc,IAAI;AAClB,kBAAc,IAAI;AAClB,QAAI;AACF,YAAM,OAAO,IAAI,SAAS,EAAE,aAAa;AACzC,YAAM,MAAM,MAAM,MAAM,mBAAmB,EAAE,QAAQ,QAAQ,MAAM,KAAK,CAAC;AACzE,UAAI,CAAC,IAAI,IAAI;AACX,cAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,IAAI;AAC9C,YAAI,MAAM,aAAa,OAAO,QAAQ;AACpC,wBAAc,EAAE,kCAAkC,qCAAqC,CAAC;AACxF;AAAA,QACF;AACA,iBAAS,MAAM,SAAS,EAAE,oBAAoB,sBAAsB,CAAC;AACrE;AAAA,MACF;AACA,cAAQ,IAAI;AAAA,IACd,UAAE;AACA,oBAAc,KAAK;AAAA,IACrB;AAAA,EACF;AAEA,SACE,oBAAC,SAAI,WAAU,kDACb,+BAAC,QAAK,WAAU,mBACd;AAAA,yBAAC,cACC;AAAA,0BAAC,aAAW,YAAE,oBAAoB,GAAE;AAAA,MACpC,oBAAC,mBAAiB,YAAE,0BAA0B,wCAAwC,GAAE;AAAA,OAC1F;AAAA,IACA,oBAAC,eACE,iBACC,qBAAC,SAAI,WAAU,cACb;AAAA,0BAAC,OAAE,WAAU,iCACV,YAAE,mBAAmB,sFAAsF,GAC9G;AAAA,MACA,oBAAC,QAAK,MAAK,UAAS,WAAU,qBAC3B,YAAE,0BAA0B,eAAe,GAC9C;AAAA,OACF,IAEA,qBAAC,UAAK,WAAU,cAAa,UAAoB,YAAU,MACxD;AAAA,eAAS,oBAAC,SAAI,WAAU,kCAAkC,iBAAM;AAAA,MACjE,qBAAC,SAAI,WAAU,cACb;AAAA,4BAAC,SAAM,SAAQ,SAAS,YAAE,YAAY,GAAE;AAAA,QACxC,oBAAC,cAAW,IAAG,SAAQ,MAAK,SAAQ,UAAQ,MAAC,gBAAc,CAAC,CAAC,YAAY,oBAAkB,aAAa,gBAAgB,QAAW;AAAA,QAClI,cAAc,oBAAC,OAAE,IAAG,eAAc,WAAU,kCAAkC,sBAAW;AAAA,SAC5F;AAAA,MACA,oBAAC,UAAO,MAAK,UAAS,WAAU,eAAc,UAAU,YACrD,uBAAa,QAAQ,EAAE,oBAAoB,GAC9C;AAAA,MACA,oBAAC,SAAI,WAAU,eACb,8BAAC,QAAK,MAAK,UAAS,WAAU,2CAC3B,YAAE,0BAA0B,eAAe,GAC9C,GACF;AAAA,OACF,GAEJ;AAAA,KACF,GACF;AAEJ;",
4
+ "sourcesContent": ["\"use client\"\nimport { useEffect, useState } from 'react'\nimport Link from 'next/link'\nimport { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@open-mercato/ui/primitives/card'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { EmailInput } from '@open-mercato/ui/primitives/email-input'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\nexport default function ResetPage() {\n const t = useT()\n const [sent, setSent] = useState(false)\n const [submitting, setSubmitting] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const [fieldError, setFieldError] = useState<string | null>(null)\n const [clientReady, setClientReady] = useState(false)\n\n useEffect(() => {\n setClientReady(true)\n }, [])\n\n async function onSubmit(e: React.FormEvent<HTMLFormElement>) {\n e.preventDefault()\n setError(null)\n setFieldError(null)\n setSubmitting(true)\n try {\n const form = new FormData(e.currentTarget)\n const res = await fetch('/api/auth/reset', { method: 'POST', body: form })\n if (!res.ok) {\n const data = await res.json().catch(() => null)\n if (data?.fieldErrors?.email?.length) {\n setFieldError(t('auth.reset.errors.emailInvalid', 'Please enter a valid email address.'))\n return\n }\n setError(data?.error || t('auth.reset.error', 'Something went wrong'))\n return\n }\n setSent(true)\n } finally {\n setSubmitting(false)\n }\n }\n\n return (\n <div className=\"min-h-svh flex items-center justify-center p-4\">\n <Card className=\"w-full max-w-sm\">\n <CardHeader>\n <CardTitle>{t('auth.resetPassword')}</CardTitle>\n <CardDescription>{t('auth.reset.description', 'Enter your email to receive reset link')}</CardDescription>\n </CardHeader>\n <CardContent>\n {sent ? (\n <div className=\"grid gap-3\">\n <p className=\"text-sm text-muted-foreground\">\n {t('auth.reset.sent', 'If an account with that email exists, we sent a reset link. Please check your inbox.')}\n </p>\n <Link href=\"/login\" className=\"text-sm underline\">\n {t('auth.reset.backToLogin', 'Back to login')}\n </Link>\n </div>\n ) : (\n <form className=\"grid gap-3\" method=\"post\" onSubmit={onSubmit} noValidate data-auth-ready={clientReady ? '1' : '0'}>\n {error && <div className=\"text-sm text-status-error-text\">{error}</div>}\n <div className=\"grid gap-1\">\n <Label htmlFor=\"email\">{t('auth.email')}</Label>\n <EmailInput id=\"email\" name=\"email\" required aria-invalid={!!fieldError} aria-describedby={fieldError ? 'email-error' : undefined} />\n {fieldError && <p id=\"email-error\" className=\"text-sm text-status-error-text\">{fieldError}</p>}\n </div>\n <Button type=\"submit\" className=\"mt-2 w-full\" disabled={submitting || !clientReady}>\n {submitting ? '...' : t('auth.sendResetLink')}\n </Button>\n <div className=\"text-center\">\n <Link href=\"/login\" className=\"text-xs text-muted-foreground underline\">\n {t('auth.reset.backToLogin', 'Back to login')}\n </Link>\n </div>\n </form>\n )}\n </CardContent>\n </Card>\n </div>\n )\n}\n"],
5
+ "mappings": ";AA+CQ,SACE,KADF;AA9CR,SAAS,WAAW,gBAAgB;AACpC,OAAO,UAAU;AACjB,SAAS,MAAM,aAAa,YAAY,WAAW,uBAAuB;AAC1E,SAAS,cAAc;AACvB,SAAS,kBAAkB;AAC3B,SAAS,aAAa;AACtB,SAAS,YAAY;AAEN,SAAR,YAA6B;AAClC,QAAM,IAAI,KAAK;AACf,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AACtC,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,KAAK;AAClD,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAwB,IAAI;AACtD,QAAM,CAAC,YAAY,aAAa,IAAI,SAAwB,IAAI;AAChE,QAAM,CAAC,aAAa,cAAc,IAAI,SAAS,KAAK;AAEpD,YAAU,MAAM;AACd,mBAAe,IAAI;AAAA,EACrB,GAAG,CAAC,CAAC;AAEL,iBAAe,SAAS,GAAqC;AAC3D,MAAE,eAAe;AACjB,aAAS,IAAI;AACb,kBAAc,IAAI;AAClB,kBAAc,IAAI;AAClB,QAAI;AACF,YAAM,OAAO,IAAI,SAAS,EAAE,aAAa;AACzC,YAAM,MAAM,MAAM,MAAM,mBAAmB,EAAE,QAAQ,QAAQ,MAAM,KAAK,CAAC;AACzE,UAAI,CAAC,IAAI,IAAI;AACX,cAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,IAAI;AAC9C,YAAI,MAAM,aAAa,OAAO,QAAQ;AACpC,wBAAc,EAAE,kCAAkC,qCAAqC,CAAC;AACxF;AAAA,QACF;AACA,iBAAS,MAAM,SAAS,EAAE,oBAAoB,sBAAsB,CAAC;AACrE;AAAA,MACF;AACA,cAAQ,IAAI;AAAA,IACd,UAAE;AACA,oBAAc,KAAK;AAAA,IACrB;AAAA,EACF;AAEA,SACE,oBAAC,SAAI,WAAU,kDACb,+BAAC,QAAK,WAAU,mBACd;AAAA,yBAAC,cACC;AAAA,0BAAC,aAAW,YAAE,oBAAoB,GAAE;AAAA,MACpC,oBAAC,mBAAiB,YAAE,0BAA0B,wCAAwC,GAAE;AAAA,OAC1F;AAAA,IACA,oBAAC,eACE,iBACC,qBAAC,SAAI,WAAU,cACb;AAAA,0BAAC,OAAE,WAAU,iCACV,YAAE,mBAAmB,sFAAsF,GAC9G;AAAA,MACA,oBAAC,QAAK,MAAK,UAAS,WAAU,qBAC3B,YAAE,0BAA0B,eAAe,GAC9C;AAAA,OACF,IAEA,qBAAC,UAAK,WAAU,cAAa,QAAO,QAAO,UAAoB,YAAU,MAAC,mBAAiB,cAAc,MAAM,KAC5G;AAAA,eAAS,oBAAC,SAAI,WAAU,kCAAkC,iBAAM;AAAA,MACjE,qBAAC,SAAI,WAAU,cACb;AAAA,4BAAC,SAAM,SAAQ,SAAS,YAAE,YAAY,GAAE;AAAA,QACxC,oBAAC,cAAW,IAAG,SAAQ,MAAK,SAAQ,UAAQ,MAAC,gBAAc,CAAC,CAAC,YAAY,oBAAkB,aAAa,gBAAgB,QAAW;AAAA,QAClI,cAAc,oBAAC,OAAE,IAAG,eAAc,WAAU,kCAAkC,sBAAW;AAAA,SAC5F;AAAA,MACA,oBAAC,UAAO,MAAK,UAAS,WAAU,eAAc,UAAU,cAAc,CAAC,aACpE,uBAAa,QAAQ,EAAE,oBAAoB,GAC9C;AAAA,MACA,oBAAC,SAAI,WAAU,eACb,8BAAC,QAAK,MAAK,UAAS,WAAU,2CAC3B,YAAE,0BAA0B,eAAe,GAC9C,GACF;AAAA,OACF,GAEJ;AAAA,KACF,GACF;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -4,6 +4,7 @@ import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
4
4
  import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
5
5
  import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
6
6
  import { isCrudHttpError } from "@open-mercato/shared/lib/crud/errors";
7
+ import { isUniqueViolation } from "@open-mercato/shared/lib/db/pg-errors";
7
8
  import { enforceCommandOptimisticLockWithGuards } from "@open-mercato/shared/lib/crud/optimistic-lock-command";
8
9
  import { BusinessRule } from "../../data/entities.js";
9
10
  import { escapeLikePattern } from "@open-mercato/shared/lib/db/escapeLikePattern";
@@ -235,6 +236,15 @@ async function POST(req) {
235
236
  await em.persist(rule).flush();
236
237
  await invalidateBusinessRuleDiscoveryCache(cache, rule.tenantId, rule.organizationId);
237
238
  } catch (error) {
239
+ if (isUniqueViolation(error)) {
240
+ return NextResponse.json(
241
+ {
242
+ error: t("business_rules.errors.duplicateRuleId", { ruleId: parsed.data.ruleId }),
243
+ fieldErrors: { ruleId: t("business_rules.errors.duplicateRuleId", { ruleId: parsed.data.ruleId }) }
244
+ },
245
+ { status: 409 }
246
+ );
247
+ }
238
248
  logger.error("Failed to persist new rule", { err: error });
239
249
  return NextResponse.json(
240
250
  { error: t("business_rules.errors.createFailed") },
@@ -404,7 +414,8 @@ const openApi = {
404
414
  ],
405
415
  errors: [
406
416
  { status: 400, description: "Invalid payload", schema: errorResponseSchema },
407
- { status: 401, description: "Unauthorized", schema: errorResponseSchema }
417
+ { status: 401, description: "Unauthorized", schema: errorResponseSchema },
418
+ { status: 409, description: "A rule with this Rule ID already exists for the tenant", schema: errorResponseSchema }
408
419
  ]
409
420
  },
410
421
  PUT: {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/business_rules/api/rules/route.ts"],
4
- "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { enforceCommandOptimisticLockWithGuards } from '@open-mercato/shared/lib/crud/optimistic-lock-command'\nimport { BusinessRule } from '../../data/entities'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { escapeLikePattern } from '@open-mercato/shared/lib/db/escapeLikePattern'\nimport {\n createBusinessRuleSchema,\n updateBusinessRuleSchema,\n createLocalizedBusinessRuleSchema,\n createLocalizedUpdateBusinessRuleSchema,\n businessRuleFilterSchema,\n ruleTypeSchema,\n} from '../../data/validators'\nimport {\n invalidateBusinessRuleDiscoveryCache,\n resolveBusinessRuleDiscoveryCache,\n} from '../../lib/rule-engine'\nimport { validateOpenMercatoCallActions } from '../../lib/openmercato-call-options'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('business_rules').child({ component: 'rules-api' })\n\nconst querySchema = z.looseObject({\n id: z.uuid().optional(),\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(50),\n search: z.string().optional(),\n ruleId: z.string().optional(),\n ruleType: ruleTypeSchema.optional(),\n entityType: z.string().optional(),\n eventType: z.string().optional(),\n enabled: z.coerce.boolean().optional(),\n ruleCategory: z.string().optional(),\n sortField: z.string().optional(),\n sortDir: z.enum(['asc', 'desc']).optional().default('desc'),\n})\n\nconst ruleListItemSchema = z.object({\n id: z.string().uuid(),\n ruleId: z.string(),\n ruleName: z.string(),\n description: z.string().nullable(),\n ruleType: ruleTypeSchema,\n ruleCategory: z.string().nullable(),\n entityType: z.string(),\n eventType: z.string().nullable(),\n enabled: z.boolean(),\n priority: z.number(),\n version: z.number(),\n effectiveFrom: z.string().nullable(),\n effectiveTo: z.string().nullable(),\n tenantId: z.string().uuid(),\n organizationId: z.string().uuid(),\n createdAt: z.string(),\n updatedAt: z.string(),\n})\n\nconst ruleListResponseSchema = z.object({\n items: z.array(ruleListItemSchema),\n total: z.number().int().nonnegative(),\n totalPages: z.number().int().positive(),\n})\n\nconst ruleCreateResponseSchema = z.object({\n id: z.string().uuid(),\n})\n\nconst okResponseSchema = z.object({\n ok: z.literal(true),\n})\n\nconst errorResponseSchema = z.object({\n error: z.string(),\n})\n\nconst routeMetadata = {\n GET: { requireAuth: true, requireFeatures: ['business_rules.view'] },\n POST: { requireAuth: true, requireFeatures: ['business_rules.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['business_rules.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['business_rules.manage'] },\n}\n\nexport const metadata = routeMetadata\n\nfunction hasOpenMercatoCallAction(actions: unknown): boolean {\n return Array.isArray(actions)\n && actions.some((action) => action && typeof action === 'object' && (action as { type?: unknown }).type === 'CALL_OPEN_MERCATO')\n}\n\nasync function requireOpenMercatoCallConfiguratorAccess(\n container: ReturnType<typeof createRequestContainer> extends Promise<infer T> ? T : never,\n auth: NonNullable<Awaited<ReturnType<typeof getAuthFromRequest>>>,\n): Promise<Response | null> {\n if (!auth.sub) {\n return NextResponse.json(\n { error: 'Forbidden', requiredFeatures: ['api_keys.create'] },\n { status: 403 },\n )\n }\n\n const rbac = container.resolve('rbacService') as {\n userHasAllFeatures?: (\n userId: string,\n required: string[],\n scope: { tenantId: string | null; organizationId: string | null },\n ) => Promise<boolean>\n } | undefined\n const allowed = await rbac?.userHasAllFeatures?.(auth.sub, ['api_keys.create'], {\n tenantId: auth.tenantId ?? null,\n organizationId: auth.orgId ?? null,\n })\n if (allowed) return null\n\n return NextResponse.json(\n { error: 'Forbidden', requiredFeatures: ['api_keys.create'] },\n { status: 403 },\n )\n}\n\nexport async function GET(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n const url = new URL(req.url)\n const parsed = querySchema.safeParse({\n id: url.searchParams.get('id') || undefined,\n page: url.searchParams.get('page') || undefined,\n pageSize: url.searchParams.get('pageSize') || undefined,\n search: url.searchParams.get('search') || undefined,\n ruleId: url.searchParams.get('ruleId') || undefined,\n ruleType: url.searchParams.get('ruleType') || undefined,\n entityType: url.searchParams.get('entityType') || undefined,\n eventType: url.searchParams.get('eventType') || undefined,\n enabled: url.searchParams.get('enabled') || undefined,\n ruleCategory: url.searchParams.get('ruleCategory') || undefined,\n sortField: url.searchParams.get('sortField') || undefined,\n sortDir: url.searchParams.get('sortDir') || undefined,\n })\n\n if (!parsed.success) {\n return NextResponse.json({ error: 'Invalid query parameters' }, { status: 400 })\n }\n\n const container = await createRequestContainer()\n const em = container.resolve('em') as EntityManager\n\n const { id, page, pageSize, search, ruleId, ruleType, entityType, eventType, enabled, ruleCategory, sortField, sortDir } = parsed.data\n\n const filters: Record<string, any> = {\n tenantId: auth.tenantId,\n organizationId: auth.orgId,\n deletedAt: null,\n }\n\n if (id) filters.id = id\n if (ruleId) filters.ruleId = { $ilike: `%${escapeLikePattern(ruleId)}%` }\n if (search) filters.ruleName = { $ilike: `%${escapeLikePattern(search)}%` }\n if (ruleType) filters.ruleType = ruleType\n if (entityType) filters.entityType = entityType\n if (eventType) filters.eventType = eventType\n if (enabled !== undefined) filters.enabled = enabled\n if (ruleCategory) filters.ruleCategory = ruleCategory\n\n const sortFieldMap: Record<string, string> = {\n ruleId: 'ruleId',\n ruleName: 'ruleName',\n ruleType: 'ruleType',\n entityType: 'entityType',\n priority: 'priority',\n createdAt: 'createdAt',\n updatedAt: 'updatedAt',\n }\n\n const orderByField = sortField && sortFieldMap[sortField] ? sortFieldMap[sortField] : 'priority'\n const orderBy = { [orderByField]: sortDir, ruleId: 'asc' as const }\n\n const [rows, count] = await em.findAndCount(\n BusinessRule,\n filters,\n {\n limit: pageSize,\n offset: (page - 1) * pageSize,\n orderBy,\n }\n )\n\n const items = rows.map((rule) => ({\n id: rule.id,\n ruleId: rule.ruleId,\n ruleName: rule.ruleName,\n description: rule.description ?? null,\n ruleType: rule.ruleType,\n ruleCategory: rule.ruleCategory ?? null,\n entityType: rule.entityType,\n eventType: rule.eventType ?? null,\n enabled: rule.enabled,\n priority: rule.priority,\n version: rule.version,\n effectiveFrom: rule.effectiveFrom ? rule.effectiveFrom.toISOString() : null,\n effectiveTo: rule.effectiveTo ? rule.effectiveTo.toISOString() : null,\n tenantId: rule.tenantId,\n organizationId: rule.organizationId,\n createdAt: rule.createdAt.toISOString(),\n updatedAt: rule.updatedAt.toISOString(),\n }))\n\n const totalPages = Math.max(1, Math.ceil(count / pageSize))\n\n return NextResponse.json({ items, total: count, totalPages })\n}\n\nexport async function POST(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n if (!auth.tenantId || !auth.orgId) {\n return NextResponse.json({ error: 'Tenant and organization context required' }, { status: 400 })\n }\n const tenantId = auth.tenantId\n const organizationId = auth.orgId\n\n const container = await createRequestContainer()\n const em = container.resolve('em') as EntityManager\n const cache = resolveBusinessRuleDiscoveryCache(container.resolve.bind(container))\n\n let body: any\n try {\n body = await req.json()\n } catch {\n return NextResponse.json({ error: 'Invalid JSON body' }, { status: 400 })\n }\n\n const payload = {\n ...body,\n tenantId,\n organizationId,\n createdBy: auth.sub ?? auth.email ?? null,\n }\n\n const { t } = await resolveTranslations()\n const schema = createLocalizedBusinessRuleSchema(t)\n const parsed = schema.safeParse(payload)\n if (!parsed.success) {\n const errors = parsed.error.issues.map(e => `${e.path.join('.')}: ${e.message}`)\n return NextResponse.json({ error: `Validation failed: ${errors.join(', ')}` }, { status: 400 })\n }\n\n if (hasOpenMercatoCallAction(parsed.data.successActions) || hasOpenMercatoCallAction(parsed.data.failureActions)) {\n const accessError = await requireOpenMercatoCallConfiguratorAccess(container, auth)\n if (accessError) return accessError\n }\n\n const actionErrors = [\n ...await validateOpenMercatoCallActions(em as EntityManager, parsed.data.successActions, {\n tenantId,\n organizationId,\n }),\n ...await validateOpenMercatoCallActions(em as EntityManager, parsed.data.failureActions, {\n tenantId,\n organizationId,\n }),\n ]\n if (actionErrors.length > 0) {\n return NextResponse.json({ error: `Validation failed: ${actionErrors.join(', ')}` }, { status: 400 })\n }\n\n const data = {\n ...parsed.data,\n conditionExpression: parsed.data.conditionExpression ?? null,\n }\n\n const rule = em.create(BusinessRule, data)\n\n try {\n await em.persist(rule).flush()\n await invalidateBusinessRuleDiscoveryCache(cache, rule.tenantId, rule.organizationId)\n } catch (error) {\n logger.error('Failed to persist new rule', { err: error })\n return NextResponse.json(\n { error: t('business_rules.errors.createFailed') },\n { status: 500 },\n )\n }\n\n return NextResponse.json({ id: rule.id }, { status: 201 })\n}\n\nexport async function PUT(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n if (!auth.tenantId || !auth.orgId) {\n return NextResponse.json({ error: 'Tenant and organization context required' }, { status: 400 })\n }\n const tenantId = auth.tenantId\n const organizationId = auth.orgId\n\n const container = await createRequestContainer()\n const em = container.resolve('em') as EntityManager\n const cache = resolveBusinessRuleDiscoveryCache(container.resolve.bind(container))\n\n let body: any\n try {\n body = await req.json()\n } catch {\n return NextResponse.json({ error: 'Invalid JSON body' }, { status: 400 })\n }\n\n if (!body.id) {\n return NextResponse.json({ error: 'Rule id is required' }, { status: 400 })\n }\n\n const payload = {\n ...body,\n updatedBy: auth.sub ?? auth.email ?? null,\n }\n delete (payload as Record<string, unknown>).tenantId\n delete (payload as Record<string, unknown>).organizationId\n delete (payload as Record<string, unknown>).createdBy\n\n const { t } = await resolveTranslations()\n const schema = createLocalizedUpdateBusinessRuleSchema(t)\n const parsed = schema.safeParse(payload)\n if (!parsed.success) {\n const errors = parsed.error.issues.map(e => `${e.path.join('.')}: ${e.message}`)\n return NextResponse.json({ error: `Validation failed: ${errors.join(', ')}` }, { status: 400 })\n }\n\n const rule = await em.findOne(BusinessRule, {\n id: parsed.data.id,\n tenantId,\n organizationId,\n deletedAt: null,\n })\n\n if (!rule) {\n return NextResponse.json({ error: 'Rule not found' }, { status: 404 })\n }\n\n const touchesOpenMercatoCall = hasOpenMercatoCallAction(parsed.data.successActions)\n || hasOpenMercatoCallAction(parsed.data.failureActions)\n || hasOpenMercatoCallAction(rule.successActions)\n || hasOpenMercatoCallAction(rule.failureActions)\n if (touchesOpenMercatoCall) {\n const accessError = await requireOpenMercatoCallConfiguratorAccess(container, auth)\n if (accessError) return accessError\n }\n\n const actionErrors = [\n ...await validateOpenMercatoCallActions(em as EntityManager, parsed.data.successActions, {\n tenantId,\n organizationId,\n }),\n ...await validateOpenMercatoCallActions(em as EntityManager, parsed.data.failureActions, {\n tenantId,\n organizationId,\n }),\n ]\n if (actionErrors.length > 0) {\n return NextResponse.json({ error: `Validation failed: ${actionErrors.join(', ')}` }, { status: 400 })\n }\n\n try {\n await enforceCommandOptimisticLockWithGuards(container, {\n resourceKind: 'business_rules.rule',\n resourceId: rule.id,\n current: rule.updatedAt ?? null,\n request: req,\n })\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n throw err\n }\n\n em.assign(rule, parsed.data)\n\n try {\n await em.persist(rule).flush()\n await invalidateBusinessRuleDiscoveryCache(cache, rule.tenantId, rule.organizationId)\n } catch (error) {\n logger.error('Failed to persist rule update', { err: error })\n return NextResponse.json(\n { error: t('business_rules.errors.updateFailed') },\n { status: 500 },\n )\n }\n\n return NextResponse.json({ ok: true })\n}\n\nexport async function DELETE(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n const url = new URL(req.url)\n const id = url.searchParams.get('id')\n\n if (!id) {\n return NextResponse.json({ error: 'Rule id is required' }, { status: 400 })\n }\n\n const container = await createRequestContainer()\n const em = container.resolve('em') as EntityManager\n const cache = resolveBusinessRuleDiscoveryCache(container.resolve.bind(container))\n\n const rule = await em.findOne(BusinessRule, {\n id,\n tenantId: auth.tenantId,\n organizationId: auth.orgId,\n deletedAt: null,\n })\n\n if (!rule) {\n return NextResponse.json({ error: 'Rule not found' }, { status: 404 })\n }\n\n try {\n await enforceCommandOptimisticLockWithGuards(container, {\n resourceKind: 'business_rules.rule',\n resourceId: rule.id,\n current: rule.updatedAt ?? null,\n request: req,\n })\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n throw err\n }\n\n rule.deletedAt = new Date()\n await em.persist(rule).flush()\n await invalidateBusinessRuleDiscoveryCache(cache, rule.tenantId, rule.organizationId)\n\n return NextResponse.json({ ok: true })\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Business Rules',\n summary: 'Business rule management',\n methods: {\n GET: {\n summary: 'List business rules',\n description: 'Returns business rules for the current tenant and organization with filtering and pagination.',\n query: querySchema,\n responses: [\n { status: 200, description: 'Business rules collection', schema: ruleListResponseSchema },\n ],\n errors: [\n { status: 400, description: 'Invalid query parameters', schema: errorResponseSchema },\n { status: 401, description: 'Unauthorized', schema: errorResponseSchema },\n ],\n },\n POST: {\n summary: 'Create business rule',\n description: 'Creates a new business rule for the current tenant and organization.',\n requestBody: {\n contentType: 'application/json',\n schema: createBusinessRuleSchema,\n },\n responses: [\n {\n status: 201,\n description: 'Business rule created',\n schema: ruleCreateResponseSchema,\n },\n ],\n errors: [\n { status: 400, description: 'Invalid payload', schema: errorResponseSchema },\n { status: 401, description: 'Unauthorized', schema: errorResponseSchema },\n ],\n },\n PUT: {\n summary: 'Update business rule',\n description: 'Updates an existing business rule.',\n requestBody: {\n contentType: 'application/json',\n schema: updateBusinessRuleSchema,\n },\n responses: [\n {\n status: 200,\n description: 'Business rule updated',\n schema: okResponseSchema,\n },\n ],\n errors: [\n { status: 400, description: 'Invalid payload', schema: errorResponseSchema },\n { status: 401, description: 'Unauthorized', schema: errorResponseSchema },\n { status: 404, description: 'Business rule not found', schema: errorResponseSchema },\n ],\n },\n DELETE: {\n summary: 'Delete business rule',\n description: 'Soft deletes a business rule by identifier.',\n query: z.object({ id: z.string().uuid().describe('Business rule identifier') }),\n responses: [\n { status: 200, description: 'Business rule deleted', schema: okResponseSchema },\n ],\n errors: [\n { status: 400, description: 'Invalid identifier', schema: errorResponseSchema },\n { status: 401, description: 'Unauthorized', schema: errorResponseSchema },\n { status: 404, description: 'Business rule not found', schema: errorResponseSchema },\n ],\n },\n },\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { isUniqueViolation } from '@open-mercato/shared/lib/db/pg-errors'\nimport { enforceCommandOptimisticLockWithGuards } from '@open-mercato/shared/lib/crud/optimistic-lock-command'\nimport { BusinessRule } from '../../data/entities'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { escapeLikePattern } from '@open-mercato/shared/lib/db/escapeLikePattern'\nimport {\n createBusinessRuleSchema,\n updateBusinessRuleSchema,\n createLocalizedBusinessRuleSchema,\n createLocalizedUpdateBusinessRuleSchema,\n businessRuleFilterSchema,\n ruleTypeSchema,\n} from '../../data/validators'\nimport {\n invalidateBusinessRuleDiscoveryCache,\n resolveBusinessRuleDiscoveryCache,\n} from '../../lib/rule-engine'\nimport { validateOpenMercatoCallActions } from '../../lib/openmercato-call-options'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('business_rules').child({ component: 'rules-api' })\n\nconst querySchema = z.looseObject({\n id: z.uuid().optional(),\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(50),\n search: z.string().optional(),\n ruleId: z.string().optional(),\n ruleType: ruleTypeSchema.optional(),\n entityType: z.string().optional(),\n eventType: z.string().optional(),\n enabled: z.coerce.boolean().optional(),\n ruleCategory: z.string().optional(),\n sortField: z.string().optional(),\n sortDir: z.enum(['asc', 'desc']).optional().default('desc'),\n})\n\nconst ruleListItemSchema = z.object({\n id: z.string().uuid(),\n ruleId: z.string(),\n ruleName: z.string(),\n description: z.string().nullable(),\n ruleType: ruleTypeSchema,\n ruleCategory: z.string().nullable(),\n entityType: z.string(),\n eventType: z.string().nullable(),\n enabled: z.boolean(),\n priority: z.number(),\n version: z.number(),\n effectiveFrom: z.string().nullable(),\n effectiveTo: z.string().nullable(),\n tenantId: z.string().uuid(),\n organizationId: z.string().uuid(),\n createdAt: z.string(),\n updatedAt: z.string(),\n})\n\nconst ruleListResponseSchema = z.object({\n items: z.array(ruleListItemSchema),\n total: z.number().int().nonnegative(),\n totalPages: z.number().int().positive(),\n})\n\nconst ruleCreateResponseSchema = z.object({\n id: z.string().uuid(),\n})\n\nconst okResponseSchema = z.object({\n ok: z.literal(true),\n})\n\nconst errorResponseSchema = z.object({\n error: z.string(),\n})\n\nconst routeMetadata = {\n GET: { requireAuth: true, requireFeatures: ['business_rules.view'] },\n POST: { requireAuth: true, requireFeatures: ['business_rules.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['business_rules.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['business_rules.manage'] },\n}\n\nexport const metadata = routeMetadata\n\nfunction hasOpenMercatoCallAction(actions: unknown): boolean {\n return Array.isArray(actions)\n && actions.some((action) => action && typeof action === 'object' && (action as { type?: unknown }).type === 'CALL_OPEN_MERCATO')\n}\n\nasync function requireOpenMercatoCallConfiguratorAccess(\n container: ReturnType<typeof createRequestContainer> extends Promise<infer T> ? T : never,\n auth: NonNullable<Awaited<ReturnType<typeof getAuthFromRequest>>>,\n): Promise<Response | null> {\n if (!auth.sub) {\n return NextResponse.json(\n { error: 'Forbidden', requiredFeatures: ['api_keys.create'] },\n { status: 403 },\n )\n }\n\n const rbac = container.resolve('rbacService') as {\n userHasAllFeatures?: (\n userId: string,\n required: string[],\n scope: { tenantId: string | null; organizationId: string | null },\n ) => Promise<boolean>\n } | undefined\n const allowed = await rbac?.userHasAllFeatures?.(auth.sub, ['api_keys.create'], {\n tenantId: auth.tenantId ?? null,\n organizationId: auth.orgId ?? null,\n })\n if (allowed) return null\n\n return NextResponse.json(\n { error: 'Forbidden', requiredFeatures: ['api_keys.create'] },\n { status: 403 },\n )\n}\n\nexport async function GET(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n const url = new URL(req.url)\n const parsed = querySchema.safeParse({\n id: url.searchParams.get('id') || undefined,\n page: url.searchParams.get('page') || undefined,\n pageSize: url.searchParams.get('pageSize') || undefined,\n search: url.searchParams.get('search') || undefined,\n ruleId: url.searchParams.get('ruleId') || undefined,\n ruleType: url.searchParams.get('ruleType') || undefined,\n entityType: url.searchParams.get('entityType') || undefined,\n eventType: url.searchParams.get('eventType') || undefined,\n enabled: url.searchParams.get('enabled') || undefined,\n ruleCategory: url.searchParams.get('ruleCategory') || undefined,\n sortField: url.searchParams.get('sortField') || undefined,\n sortDir: url.searchParams.get('sortDir') || undefined,\n })\n\n if (!parsed.success) {\n return NextResponse.json({ error: 'Invalid query parameters' }, { status: 400 })\n }\n\n const container = await createRequestContainer()\n const em = container.resolve('em') as EntityManager\n\n const { id, page, pageSize, search, ruleId, ruleType, entityType, eventType, enabled, ruleCategory, sortField, sortDir } = parsed.data\n\n const filters: Record<string, any> = {\n tenantId: auth.tenantId,\n organizationId: auth.orgId,\n deletedAt: null,\n }\n\n if (id) filters.id = id\n if (ruleId) filters.ruleId = { $ilike: `%${escapeLikePattern(ruleId)}%` }\n if (search) filters.ruleName = { $ilike: `%${escapeLikePattern(search)}%` }\n if (ruleType) filters.ruleType = ruleType\n if (entityType) filters.entityType = entityType\n if (eventType) filters.eventType = eventType\n if (enabled !== undefined) filters.enabled = enabled\n if (ruleCategory) filters.ruleCategory = ruleCategory\n\n const sortFieldMap: Record<string, string> = {\n ruleId: 'ruleId',\n ruleName: 'ruleName',\n ruleType: 'ruleType',\n entityType: 'entityType',\n priority: 'priority',\n createdAt: 'createdAt',\n updatedAt: 'updatedAt',\n }\n\n const orderByField = sortField && sortFieldMap[sortField] ? sortFieldMap[sortField] : 'priority'\n const orderBy = { [orderByField]: sortDir, ruleId: 'asc' as const }\n\n const [rows, count] = await em.findAndCount(\n BusinessRule,\n filters,\n {\n limit: pageSize,\n offset: (page - 1) * pageSize,\n orderBy,\n }\n )\n\n const items = rows.map((rule) => ({\n id: rule.id,\n ruleId: rule.ruleId,\n ruleName: rule.ruleName,\n description: rule.description ?? null,\n ruleType: rule.ruleType,\n ruleCategory: rule.ruleCategory ?? null,\n entityType: rule.entityType,\n eventType: rule.eventType ?? null,\n enabled: rule.enabled,\n priority: rule.priority,\n version: rule.version,\n effectiveFrom: rule.effectiveFrom ? rule.effectiveFrom.toISOString() : null,\n effectiveTo: rule.effectiveTo ? rule.effectiveTo.toISOString() : null,\n tenantId: rule.tenantId,\n organizationId: rule.organizationId,\n createdAt: rule.createdAt.toISOString(),\n updatedAt: rule.updatedAt.toISOString(),\n }))\n\n const totalPages = Math.max(1, Math.ceil(count / pageSize))\n\n return NextResponse.json({ items, total: count, totalPages })\n}\n\nexport async function POST(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n if (!auth.tenantId || !auth.orgId) {\n return NextResponse.json({ error: 'Tenant and organization context required' }, { status: 400 })\n }\n const tenantId = auth.tenantId\n const organizationId = auth.orgId\n\n const container = await createRequestContainer()\n const em = container.resolve('em') as EntityManager\n const cache = resolveBusinessRuleDiscoveryCache(container.resolve.bind(container))\n\n let body: any\n try {\n body = await req.json()\n } catch {\n return NextResponse.json({ error: 'Invalid JSON body' }, { status: 400 })\n }\n\n const payload = {\n ...body,\n tenantId,\n organizationId,\n createdBy: auth.sub ?? auth.email ?? null,\n }\n\n const { t } = await resolveTranslations()\n const schema = createLocalizedBusinessRuleSchema(t)\n const parsed = schema.safeParse(payload)\n if (!parsed.success) {\n const errors = parsed.error.issues.map(e => `${e.path.join('.')}: ${e.message}`)\n return NextResponse.json({ error: `Validation failed: ${errors.join(', ')}` }, { status: 400 })\n }\n\n if (hasOpenMercatoCallAction(parsed.data.successActions) || hasOpenMercatoCallAction(parsed.data.failureActions)) {\n const accessError = await requireOpenMercatoCallConfiguratorAccess(container, auth)\n if (accessError) return accessError\n }\n\n const actionErrors = [\n ...await validateOpenMercatoCallActions(em as EntityManager, parsed.data.successActions, {\n tenantId,\n organizationId,\n }),\n ...await validateOpenMercatoCallActions(em as EntityManager, parsed.data.failureActions, {\n tenantId,\n organizationId,\n }),\n ]\n if (actionErrors.length > 0) {\n return NextResponse.json({ error: `Validation failed: ${actionErrors.join(', ')}` }, { status: 400 })\n }\n\n const data = {\n ...parsed.data,\n conditionExpression: parsed.data.conditionExpression ?? null,\n }\n\n const rule = em.create(BusinessRule, data)\n\n try {\n await em.persist(rule).flush()\n await invalidateBusinessRuleDiscoveryCache(cache, rule.tenantId, rule.organizationId)\n } catch (error) {\n if (isUniqueViolation(error)) {\n return NextResponse.json(\n {\n error: t('business_rules.errors.duplicateRuleId', { ruleId: parsed.data.ruleId }),\n fieldErrors: { ruleId: t('business_rules.errors.duplicateRuleId', { ruleId: parsed.data.ruleId }) },\n },\n { status: 409 },\n )\n }\n logger.error('Failed to persist new rule', { err: error })\n return NextResponse.json(\n { error: t('business_rules.errors.createFailed') },\n { status: 500 },\n )\n }\n\n return NextResponse.json({ id: rule.id }, { status: 201 })\n}\n\nexport async function PUT(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n if (!auth.tenantId || !auth.orgId) {\n return NextResponse.json({ error: 'Tenant and organization context required' }, { status: 400 })\n }\n const tenantId = auth.tenantId\n const organizationId = auth.orgId\n\n const container = await createRequestContainer()\n const em = container.resolve('em') as EntityManager\n const cache = resolveBusinessRuleDiscoveryCache(container.resolve.bind(container))\n\n let body: any\n try {\n body = await req.json()\n } catch {\n return NextResponse.json({ error: 'Invalid JSON body' }, { status: 400 })\n }\n\n if (!body.id) {\n return NextResponse.json({ error: 'Rule id is required' }, { status: 400 })\n }\n\n const payload = {\n ...body,\n updatedBy: auth.sub ?? auth.email ?? null,\n }\n delete (payload as Record<string, unknown>).tenantId\n delete (payload as Record<string, unknown>).organizationId\n delete (payload as Record<string, unknown>).createdBy\n\n const { t } = await resolveTranslations()\n const schema = createLocalizedUpdateBusinessRuleSchema(t)\n const parsed = schema.safeParse(payload)\n if (!parsed.success) {\n const errors = parsed.error.issues.map(e => `${e.path.join('.')}: ${e.message}`)\n return NextResponse.json({ error: `Validation failed: ${errors.join(', ')}` }, { status: 400 })\n }\n\n const rule = await em.findOne(BusinessRule, {\n id: parsed.data.id,\n tenantId,\n organizationId,\n deletedAt: null,\n })\n\n if (!rule) {\n return NextResponse.json({ error: 'Rule not found' }, { status: 404 })\n }\n\n const touchesOpenMercatoCall = hasOpenMercatoCallAction(parsed.data.successActions)\n || hasOpenMercatoCallAction(parsed.data.failureActions)\n || hasOpenMercatoCallAction(rule.successActions)\n || hasOpenMercatoCallAction(rule.failureActions)\n if (touchesOpenMercatoCall) {\n const accessError = await requireOpenMercatoCallConfiguratorAccess(container, auth)\n if (accessError) return accessError\n }\n\n const actionErrors = [\n ...await validateOpenMercatoCallActions(em as EntityManager, parsed.data.successActions, {\n tenantId,\n organizationId,\n }),\n ...await validateOpenMercatoCallActions(em as EntityManager, parsed.data.failureActions, {\n tenantId,\n organizationId,\n }),\n ]\n if (actionErrors.length > 0) {\n return NextResponse.json({ error: `Validation failed: ${actionErrors.join(', ')}` }, { status: 400 })\n }\n\n try {\n await enforceCommandOptimisticLockWithGuards(container, {\n resourceKind: 'business_rules.rule',\n resourceId: rule.id,\n current: rule.updatedAt ?? null,\n request: req,\n })\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n throw err\n }\n\n em.assign(rule, parsed.data)\n\n try {\n await em.persist(rule).flush()\n await invalidateBusinessRuleDiscoveryCache(cache, rule.tenantId, rule.organizationId)\n } catch (error) {\n logger.error('Failed to persist rule update', { err: error })\n return NextResponse.json(\n { error: t('business_rules.errors.updateFailed') },\n { status: 500 },\n )\n }\n\n return NextResponse.json({ ok: true })\n}\n\nexport async function DELETE(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n const url = new URL(req.url)\n const id = url.searchParams.get('id')\n\n if (!id) {\n return NextResponse.json({ error: 'Rule id is required' }, { status: 400 })\n }\n\n const container = await createRequestContainer()\n const em = container.resolve('em') as EntityManager\n const cache = resolveBusinessRuleDiscoveryCache(container.resolve.bind(container))\n\n const rule = await em.findOne(BusinessRule, {\n id,\n tenantId: auth.tenantId,\n organizationId: auth.orgId,\n deletedAt: null,\n })\n\n if (!rule) {\n return NextResponse.json({ error: 'Rule not found' }, { status: 404 })\n }\n\n try {\n await enforceCommandOptimisticLockWithGuards(container, {\n resourceKind: 'business_rules.rule',\n resourceId: rule.id,\n current: rule.updatedAt ?? null,\n request: req,\n })\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n throw err\n }\n\n rule.deletedAt = new Date()\n await em.persist(rule).flush()\n await invalidateBusinessRuleDiscoveryCache(cache, rule.tenantId, rule.organizationId)\n\n return NextResponse.json({ ok: true })\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Business Rules',\n summary: 'Business rule management',\n methods: {\n GET: {\n summary: 'List business rules',\n description: 'Returns business rules for the current tenant and organization with filtering and pagination.',\n query: querySchema,\n responses: [\n { status: 200, description: 'Business rules collection', schema: ruleListResponseSchema },\n ],\n errors: [\n { status: 400, description: 'Invalid query parameters', schema: errorResponseSchema },\n { status: 401, description: 'Unauthorized', schema: errorResponseSchema },\n ],\n },\n POST: {\n summary: 'Create business rule',\n description: 'Creates a new business rule for the current tenant and organization.',\n requestBody: {\n contentType: 'application/json',\n schema: createBusinessRuleSchema,\n },\n responses: [\n {\n status: 201,\n description: 'Business rule created',\n schema: ruleCreateResponseSchema,\n },\n ],\n errors: [\n { status: 400, description: 'Invalid payload', schema: errorResponseSchema },\n { status: 401, description: 'Unauthorized', schema: errorResponseSchema },\n { status: 409, description: 'A rule with this Rule ID already exists for the tenant', schema: errorResponseSchema },\n ],\n },\n PUT: {\n summary: 'Update business rule',\n description: 'Updates an existing business rule.',\n requestBody: {\n contentType: 'application/json',\n schema: updateBusinessRuleSchema,\n },\n responses: [\n {\n status: 200,\n description: 'Business rule updated',\n schema: okResponseSchema,\n },\n ],\n errors: [\n { status: 400, description: 'Invalid payload', schema: errorResponseSchema },\n { status: 401, description: 'Unauthorized', schema: errorResponseSchema },\n { status: 404, description: 'Business rule not found', schema: errorResponseSchema },\n ],\n },\n DELETE: {\n summary: 'Delete business rule',\n description: 'Soft deletes a business rule by identifier.',\n query: z.object({ id: z.string().uuid().describe('Business rule identifier') }),\n responses: [\n { status: 200, description: 'Business rule deleted', schema: okResponseSchema },\n ],\n errors: [\n { status: 400, description: 'Invalid identifier', schema: errorResponseSchema },\n { status: 401, description: 'Unauthorized', schema: errorResponseSchema },\n { status: 404, description: 'Business rule not found', schema: errorResponseSchema },\n ],\n },\n },\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -99,7 +99,8 @@ import {
99
99
  toTrimmedOrNull,
100
100
  toPositiveNumberOrNull,
101
101
  toIntegerInRangeOrDefault,
102
- normalizeProductConversionInputs
102
+ normalizeProductConversionInputs,
103
+ pickEnrichmentNamespaces
103
104
  } from "@open-mercato/core/modules/catalog/components/products/productFormUtils";
104
105
  import {
105
106
  AlignLeft,
@@ -515,7 +516,11 @@ function EditCatalogProductPage({
515
516
  updatedAt: typeof record.updatedAt === "string" ? record.updatedAt : typeof record.updated_at === "string" ? record.updated_at : null
516
517
  };
517
518
  if (!cancelled) {
518
- setInitialValues({ ...initial, ...customValues });
519
+ setInitialValues({
520
+ ...initial,
521
+ ...customValues,
522
+ ...pickEnrichmentNamespaces(record)
523
+ });
519
524
  setCategorizeOptions({
520
525
  categories: categoryOptions,
521
526
  channels: channelOptionEntries,
@@ -1057,10 +1062,20 @@ function EditCatalogProductPage({
1057
1062
  }
1058
1063
  const updateResult = await updateCrud("catalog/products", payload);
1059
1064
  const refreshedUpdatedAt = typeof updateResult.result?.updatedAt === "string" ? updateResult.result.updatedAt : null;
1065
+ let refreshedEnrichments = {};
1066
+ if (Object.keys(pickEnrichmentNamespaces(formValues)).length > 0) {
1067
+ const refreshedProductRes = await apiCall(
1068
+ `/api/catalog/products?id=${encodeURIComponent(productId)}&page=1&pageSize=1&withDeleted=false`
1069
+ );
1070
+ refreshedEnrichments = pickEnrichmentNamespaces(
1071
+ refreshedProductRes.ok ? refreshedProductRes.result?.items?.[0] : void 0
1072
+ );
1073
+ }
1060
1074
  setInitialValues(
1061
1075
  (prev) => prev ? {
1062
1076
  ...prev,
1063
1077
  ...values,
1078
+ ...refreshedEnrichments,
1064
1079
  updatedAt: refreshedUpdatedAt ?? prev.updatedAt
1065
1080
  } : prev
1066
1081
  );