@open-mercato/core 0.5.1-develop.3045.b4b3320cc2 → 0.6.0

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 (106) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/AGENTS.md +21 -1
  3. package/dist/modules/api_keys/api/keys/route.js +9 -0
  4. package/dist/modules/api_keys/api/keys/route.js.map +2 -2
  5. package/dist/modules/audit_logs/services/accessLogService.js +13 -0
  6. package/dist/modules/audit_logs/services/accessLogService.js.map +3 -3
  7. package/dist/modules/audit_logs/services/actionLogService.js +6 -5
  8. package/dist/modules/audit_logs/services/actionLogService.js.map +2 -2
  9. package/dist/modules/auth/api/roles/acl/route.js +27 -37
  10. package/dist/modules/auth/api/roles/acl/route.js.map +2 -2
  11. package/dist/modules/auth/api/users/route.js +41 -28
  12. package/dist/modules/auth/api/users/route.js.map +3 -3
  13. package/dist/modules/auth/lib/grantChecks.js +160 -0
  14. package/dist/modules/auth/lib/grantChecks.js.map +7 -0
  15. package/dist/modules/configs/cli.js +11 -0
  16. package/dist/modules/configs/cli.js.map +2 -2
  17. package/dist/modules/configs/lib/touchGeneratedBarrels.js +46 -0
  18. package/dist/modules/configs/lib/touchGeneratedBarrels.js.map +7 -0
  19. package/dist/modules/customers/api/activities/route.js +1 -52
  20. package/dist/modules/customers/api/activities/route.js.map +2 -2
  21. package/dist/modules/customers/api/interactions/counts/route.js +2 -1
  22. package/dist/modules/customers/api/interactions/counts/route.js.map +2 -2
  23. package/dist/modules/customers/api/interactions/route.js +21 -1
  24. package/dist/modules/customers/api/interactions/route.js.map +2 -2
  25. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +7 -3
  26. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
  27. package/dist/modules/customers/backend/customers/deals/[id]/page.js +5 -1
  28. package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
  29. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +7 -3
  30. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
  31. package/dist/modules/customers/components/detail/ActivitiesCard.js +62 -6
  32. package/dist/modules/customers/components/detail/ActivitiesCard.js.map +2 -2
  33. package/dist/modules/customers/components/detail/ActivitiesDayStrip.js +21 -6
  34. package/dist/modules/customers/components/detail/ActivitiesDayStrip.js.map +2 -2
  35. package/dist/modules/customers/components/detail/ActivitiesSection.js +37 -5
  36. package/dist/modules/customers/components/detail/ActivitiesSection.js.map +2 -2
  37. package/dist/modules/customers/components/detail/ActivityCard.js +69 -17
  38. package/dist/modules/customers/components/detail/ActivityCard.js.map +2 -2
  39. package/dist/modules/customers/components/detail/ActivityHistorySection.js +94 -34
  40. package/dist/modules/customers/components/detail/ActivityHistorySection.js.map +2 -2
  41. package/dist/modules/customers/components/detail/ActivityLogTab.js +3 -1
  42. package/dist/modules/customers/components/detail/ActivityLogTab.js.map +2 -2
  43. package/dist/modules/customers/components/detail/ActivityTimeline.js +41 -8
  44. package/dist/modules/customers/components/detail/ActivityTimeline.js.map +2 -2
  45. package/dist/modules/customers/components/detail/ActivityTimelineFilters.js +19 -6
  46. package/dist/modules/customers/components/detail/ActivityTimelineFilters.js.map +2 -2
  47. package/dist/modules/customers/components/detail/ActivityTypeSelector.js +4 -3
  48. package/dist/modules/customers/components/detail/ActivityTypeSelector.js.map +2 -2
  49. package/dist/modules/customers/components/detail/ScheduleActivityDialog.js +80 -12
  50. package/dist/modules/customers/components/detail/ScheduleActivityDialog.js.map +2 -2
  51. package/dist/modules/customers/components/detail/schedule/DateTimeFields.js +65 -10
  52. package/dist/modules/customers/components/detail/schedule/DateTimeFields.js.map +2 -2
  53. package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js +10 -5
  54. package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js.map +2 -2
  55. package/dist/modules/customers/data/validators.js +74 -2
  56. package/dist/modules/customers/data/validators.js.map +2 -2
  57. package/dist/modules/customers/lib/legacyActivityBridge.js +61 -0
  58. package/dist/modules/customers/lib/legacyActivityBridge.js.map +7 -0
  59. package/dist/modules/integrations/data/validators.js +2 -2
  60. package/dist/modules/integrations/data/validators.js.map +2 -2
  61. package/dist/modules/integrations/lib/credentials-service.js +12 -1
  62. package/dist/modules/integrations/lib/credentials-service.js.map +2 -2
  63. package/dist/modules/messages/commands/actions.js +29 -14
  64. package/dist/modules/messages/commands/actions.js.map +2 -2
  65. package/dist/modules/messages/lib/actions.js +24 -4
  66. package/dist/modules/messages/lib/actions.js.map +2 -2
  67. package/dist/modules/sales/api/documents/factory.js +49 -36
  68. package/dist/modules/sales/api/documents/factory.js.map +2 -2
  69. package/package.json +9 -10
  70. package/src/modules/api_keys/api/keys/route.ts +9 -0
  71. package/src/modules/audit_logs/services/accessLogService.ts +20 -0
  72. package/src/modules/audit_logs/services/actionLogService.ts +13 -5
  73. package/src/modules/auth/api/roles/acl/route.ts +32 -46
  74. package/src/modules/auth/api/users/route.ts +48 -33
  75. package/src/modules/auth/lib/grantChecks.ts +234 -0
  76. package/src/modules/configs/cli.ts +11 -0
  77. package/src/modules/configs/lib/touchGeneratedBarrels.ts +61 -0
  78. package/src/modules/customers/api/activities/route.ts +1 -76
  79. package/src/modules/customers/api/interactions/counts/route.ts +2 -1
  80. package/src/modules/customers/api/interactions/route.ts +28 -1
  81. package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +13 -3
  82. package/src/modules/customers/backend/customers/deals/[id]/page.tsx +14 -2
  83. package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +13 -3
  84. package/src/modules/customers/components/detail/ActivitiesCard.tsx +92 -5
  85. package/src/modules/customers/components/detail/ActivitiesDayStrip.tsx +38 -6
  86. package/src/modules/customers/components/detail/ActivitiesSection.tsx +37 -3
  87. package/src/modules/customers/components/detail/ActivityCard.tsx +79 -14
  88. package/src/modules/customers/components/detail/ActivityHistorySection.tsx +102 -33
  89. package/src/modules/customers/components/detail/ActivityLogTab.tsx +7 -1
  90. package/src/modules/customers/components/detail/ActivityTimeline.tsx +39 -5
  91. package/src/modules/customers/components/detail/ActivityTimelineFilters.tsx +29 -7
  92. package/src/modules/customers/components/detail/ActivityTypeSelector.tsx +3 -2
  93. package/src/modules/customers/components/detail/ScheduleActivityDialog.tsx +96 -13
  94. package/src/modules/customers/components/detail/schedule/DateTimeFields.tsx +50 -4
  95. package/src/modules/customers/components/detail/schedule/useScheduleFormState.ts +21 -5
  96. package/src/modules/customers/data/validators.ts +85 -2
  97. package/src/modules/customers/i18n/de.json +11 -0
  98. package/src/modules/customers/i18n/en.json +11 -0
  99. package/src/modules/customers/i18n/es.json +11 -0
  100. package/src/modules/customers/i18n/pl.json +11 -0
  101. package/src/modules/customers/lib/legacyActivityBridge.ts +106 -0
  102. package/src/modules/integrations/data/validators.ts +8 -6
  103. package/src/modules/integrations/lib/credentials-service.ts +15 -1
  104. package/src/modules/messages/commands/actions.ts +28 -13
  105. package/src/modules/messages/lib/actions.ts +34 -3
  106. package/src/modules/sales/api/documents/factory.ts +55 -38
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/messages/commands/actions.ts"],
4
- "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { z } from 'zod'\nimport { registerCommand, type CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { extractUndoPayload, type UndoPayload } from '@open-mercato/shared/lib/commands/undo'\nimport { Message, MessageObject, MessageRecipient } from '../data/entities'\nimport { emitMessagesEvent } from '../events'\nimport {\n findResolvedMessageActionById,\n isTerminalMessageAction,\n resolveActionCommandInput,\n resolveActionHref,\n} from '../lib/actions'\nimport { getMessageType } from '../lib/message-types-registry'\nimport { assertOrganizationAccess, type MessageScopeInput } from './shared'\n\nconst recordTerminalActionSchema = z.object({\n messageId: z.string().uuid(),\n actionId: z.string().min(1),\n result: z.record(z.string(), z.unknown()),\n tenantId: z.string().uuid(),\n organizationId: z.string().uuid().nullable(),\n userId: z.string().uuid(),\n})\n\ntype RecordTerminalActionInput = z.infer<typeof recordTerminalActionSchema>\n\nconst executeActionSchema = z.object({\n messageId: z.string().uuid(),\n actionId: z.string().min(1),\n payload: z.record(z.string(), z.unknown()).optional(),\n tenantId: z.string().uuid(),\n organizationId: z.string().uuid().nullable(),\n userId: z.string().uuid(),\n})\n\ntype ExecuteActionInput = z.infer<typeof executeActionSchema>\n\ntype ActionStateSnapshot = {\n actionTaken: string | null\n actionTakenByUserId: string | null\n actionTakenAt: string | null\n actionResult: Record<string, unknown> | null\n}\n\nfunction toIso(value: Date | null | undefined): string | null {\n return value ? value.toISOString() : null\n}\n\nfunction toDate(value: string | null | undefined): Date | null {\n if (!value) return null\n return new Date(value)\n}\n\nasync function requireActionTarget(em: EntityManager, input: RecordTerminalActionInput) {\n const message = await em.findOne(Message, {\n id: input.messageId,\n tenantId: input.tenantId,\n deletedAt: null,\n })\n if (!message) throw new Error('Message not found')\n assertOrganizationAccess(input as MessageScopeInput, message)\n\n const recipient = await em.findOne(MessageRecipient, {\n messageId: input.messageId,\n recipientUserId: input.userId,\n deletedAt: null,\n })\n if (!recipient) throw new Error('Access denied')\n return message\n}\n\nasync function requireActionMessage(em: EntityManager, input: ExecuteActionInput) {\n const message = await em.findOne(Message, {\n id: input.messageId,\n tenantId: input.tenantId,\n deletedAt: null,\n })\n if (!message) throw new Error('Message not found')\n assertOrganizationAccess(input as MessageScopeInput, message)\n const recipient = await em.findOne(MessageRecipient, {\n messageId: input.messageId,\n recipientUserId: input.userId,\n deletedAt: null,\n })\n if (!recipient) throw new Error('Access denied')\n return message\n}\n\nfunction snapshotActionState(message: Message): ActionStateSnapshot {\n return {\n actionTaken: message.actionTaken ?? null,\n actionTakenByUserId: message.actionTakenByUserId ?? null,\n actionTakenAt: toIso(message.actionTakenAt),\n actionResult: message.actionResult ?? null,\n }\n}\n\nconst recordTerminalActionCommand: CommandHandler<unknown, { ok: true }> = {\n id: 'messages.actions.record_terminal',\n async prepare(rawInput, ctx) {\n const input = recordTerminalActionSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await requireActionTarget(em, input)\n return { before: snapshotActionState(message) }\n },\n async execute(rawInput, ctx) {\n const input = recordTerminalActionSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await requireActionTarget(em, input)\n if (message.actionTaken) {\n throw new Error('Action already taken')\n }\n message.actionTaken = input.actionId\n message.actionTakenByUserId = input.userId\n message.actionTakenAt = new Date()\n message.actionResult = input.result\n await em.flush()\n return { ok: true }\n },\n async captureAfter(rawInput, _result, ctx) {\n const input = recordTerminalActionSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await requireActionTarget(em, input)\n return snapshotActionState(message)\n },\n buildLog: async ({ input, snapshots }) => {\n const parsed = recordTerminalActionSchema.parse(input)\n return {\n actionLabel: 'Execute message terminal action',\n resourceKind: 'messages.message',\n resourceId: parsed.messageId,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n payload: {\n undo: {\n before: (snapshots.before as ActionStateSnapshot | undefined) ?? null,\n after: (snapshots.after as ActionStateSnapshot | undefined) ?? null,\n } satisfies UndoPayload<ActionStateSnapshot>,\n },\n snapshotBefore: snapshots.before ?? null,\n snapshotAfter: snapshots.after ?? null,\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const undo = extractUndoPayload<UndoPayload<ActionStateSnapshot>>(logEntry)\n const before = undo?.before\n if (!before) return\n const messageId = logEntry?.resourceId as string | null\n if (!messageId) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await em.findOne(Message, { id: messageId })\n if (!message) return\n message.actionTaken = before.actionTaken\n message.actionTakenByUserId = before.actionTakenByUserId\n message.actionTakenAt = toDate(before.actionTakenAt)\n message.actionResult = before.actionResult\n await em.flush()\n },\n}\n\nconst executeActionCommand: CommandHandler<\n unknown,\n { ok: true; actionId: string; result: Record<string, unknown>; operationLogEntry: unknown | null }\n> = {\n id: 'messages.actions.execute',\n async execute(rawInput, ctx) {\n const input = executeActionSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await requireActionMessage(em, input)\n const objects = await em.find(MessageObject, { messageId: message.id })\n const action = findResolvedMessageActionById(message, objects, input.actionId)\n\n if (!action) {\n throw new Error('Action not found')\n }\n\n if (message.actionTaken) {\n throw Object.assign(new Error('Action already taken'), { actionTaken: message.actionTaken })\n }\n\n const shouldRecordActionTaken = isTerminalMessageAction(action)\n\n if (message.actionData?.expiresAt) {\n if (new Date(message.actionData.expiresAt) < new Date()) {\n throw new Error('Actions have expired')\n }\n } else {\n const messageType = getMessageType(message.type)\n if (messageType?.actionsExpireAfterHours && message.sentAt) {\n const expiry = new Date(message.sentAt.getTime() + messageType.actionsExpireAfterHours * 60 * 60 * 1000)\n if (expiry < new Date()) {\n throw new Error('Actions have expired')\n }\n }\n }\n\n const commandBus = ctx.container.resolve('commandBus') as {\n execute: (\n commandId: string,\n options: { input: unknown; ctx: unknown; metadata?: unknown }\n ) => Promise<{ result: unknown; logEntry?: unknown }>\n }\n\n let result: Record<string, unknown> = {}\n let operationLogEntry: unknown | null = null\n\n if (action.commandId) {\n try {\n const actionInput = resolveActionCommandInput(\n action,\n message,\n {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n userId: input.userId,\n },\n input.payload ?? {},\n )\n\n if (actionInput.id == null) {\n const fallbackId = action.objectRef?.entityId ?? message.sourceEntityId ?? null\n if (typeof fallbackId === 'string' && fallbackId.trim().length > 0) {\n actionInput.id = fallbackId\n }\n }\n\n const commandResult = await commandBus.execute(action.commandId, {\n input: actionInput,\n ctx: {\n container: ctx.container,\n auth: {\n sub: input.userId,\n tenantId: input.tenantId,\n orgId: input.organizationId,\n },\n organizationScope: null,\n selectedOrganizationId: input.organizationId,\n organizationIds: input.organizationId ? [input.organizationId] : null,\n },\n metadata: {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n resourceKind: 'messages',\n },\n })\n\n result = (commandResult.result as Record<string, unknown>) ?? {}\n operationLogEntry = commandResult.logEntry ?? null\n } catch (err) {\n console.error('[messages] executeActionCommand sub-command failed', err)\n throw new Error('Action failed')\n }\n } else if (action.href) {\n result = {\n redirect: resolveActionHref(action, message, {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n userId: input.userId,\n }) ?? action.href,\n }\n } else {\n throw new Error('Action has no executable target')\n }\n\n if (shouldRecordActionTaken) {\n const terminalResult = await commandBus.execute('messages.actions.record_terminal', {\n input: {\n messageId: message.id,\n actionId: action.id,\n result,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n userId: input.userId,\n },\n ctx: {\n container: ctx.container,\n auth: ctx.auth ?? null,\n organizationScope: null,\n selectedOrganizationId: input.organizationId,\n organizationIds: input.organizationId ? [input.organizationId] : null,\n },\n })\n if (!operationLogEntry) {\n operationLogEntry = terminalResult.logEntry ?? null\n }\n await emitMessagesEvent(\n 'messages.message.action_taken',\n {\n messageId: message.id,\n actionId: action.id,\n userId: input.userId,\n recipientUserId: input.userId,\n result,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n },\n { persistent: true }\n )\n }\n\n return {\n ok: true,\n actionId: action.id,\n result,\n operationLogEntry,\n }\n },\n}\n\nregisterCommand(recordTerminalActionCommand)\nregisterCommand(executeActionCommand)\n"],
5
- "mappings": "AACA,SAAS,SAAS;AAClB,SAAS,uBAA4C;AACrD,SAAS,0BAA4C;AACrD,SAAS,SAAS,eAAe,wBAAwB;AACzD,SAAS,yBAAyB;AAClC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,sBAAsB;AAC/B,SAAS,gCAAwD;AAEjE,MAAM,6BAA6B,EAAE,OAAO;AAAA,EAC1C,WAAW,EAAE,OAAO,EAAE,KAAK;AAAA,EAC3B,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC1B,QAAQ,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC;AAAA,EACxC,UAAU,EAAE,OAAO,EAAE,KAAK;AAAA,EAC1B,gBAAgB,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS;AAAA,EAC3C,QAAQ,EAAE,OAAO,EAAE,KAAK;AAC1B,CAAC;AAID,MAAM,sBAAsB,EAAE,OAAO;AAAA,EACnC,WAAW,EAAE,OAAO,EAAE,KAAK;AAAA,EAC3B,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC1B,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,EAAE,SAAS;AAAA,EACpD,UAAU,EAAE,OAAO,EAAE,KAAK;AAAA,EAC1B,gBAAgB,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS;AAAA,EAC3C,QAAQ,EAAE,OAAO,EAAE,KAAK;AAC1B,CAAC;AAWD,SAAS,MAAM,OAA+C;AAC5D,SAAO,QAAQ,MAAM,YAAY,IAAI;AACvC;AAEA,SAAS,OAAO,OAA+C;AAC7D,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,IAAI,KAAK,KAAK;AACvB;AAEA,eAAe,oBAAoB,IAAmB,OAAkC;AACtF,QAAM,UAAU,MAAM,GAAG,QAAQ,SAAS;AAAA,IACxC,IAAI,MAAM;AAAA,IACV,UAAU,MAAM;AAAA,IAChB,WAAW;AAAA,EACb,CAAC;AACD,MAAI,CAAC,QAAS,OAAM,IAAI,MAAM,mBAAmB;AACjD,2BAAyB,OAA4B,OAAO;AAE5D,QAAM,YAAY,MAAM,GAAG,QAAQ,kBAAkB;AAAA,IACnD,WAAW,MAAM;AAAA,IACjB,iBAAiB,MAAM;AAAA,IACvB,WAAW;AAAA,EACb,CAAC;AACD,MAAI,CAAC,UAAW,OAAM,IAAI,MAAM,eAAe;AAC/C,SAAO;AACT;AAEA,eAAe,qBAAqB,IAAmB,OAA2B;AAChF,QAAM,UAAU,MAAM,GAAG,QAAQ,SAAS;AAAA,IACxC,IAAI,MAAM;AAAA,IACV,UAAU,MAAM;AAAA,IAChB,WAAW;AAAA,EACb,CAAC;AACD,MAAI,CAAC,QAAS,OAAM,IAAI,MAAM,mBAAmB;AACjD,2BAAyB,OAA4B,OAAO;AAC5D,QAAM,YAAY,MAAM,GAAG,QAAQ,kBAAkB;AAAA,IACnD,WAAW,MAAM;AAAA,IACjB,iBAAiB,MAAM;AAAA,IACvB,WAAW;AAAA,EACb,CAAC;AACD,MAAI,CAAC,UAAW,OAAM,IAAI,MAAM,eAAe;AAC/C,SAAO;AACT;AAEA,SAAS,oBAAoB,SAAuC;AAClE,SAAO;AAAA,IACL,aAAa,QAAQ,eAAe;AAAA,IACpC,qBAAqB,QAAQ,uBAAuB;AAAA,IACpD,eAAe,MAAM,QAAQ,aAAa;AAAA,IAC1C,cAAc,QAAQ,gBAAgB;AAAA,EACxC;AACF;AAEA,MAAM,8BAAqE;AAAA,EACzE,IAAI;AAAA,EACJ,MAAM,QAAQ,UAAU,KAAK;AAC3B,UAAM,QAAQ,2BAA2B,MAAM,QAAQ;AACvD,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,UAAU,MAAM,oBAAoB,IAAI,KAAK;AACnD,WAAO,EAAE,QAAQ,oBAAoB,OAAO,EAAE;AAAA,EAChD;AAAA,EACA,MAAM,QAAQ,UAAU,KAAK;AAC3B,UAAM,QAAQ,2BAA2B,MAAM,QAAQ;AACvD,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,UAAU,MAAM,oBAAoB,IAAI,KAAK;AACnD,QAAI,QAAQ,aAAa;AACvB,YAAM,IAAI,MAAM,sBAAsB;AAAA,IACxC;AACA,YAAQ,cAAc,MAAM;AAC5B,YAAQ,sBAAsB,MAAM;AACpC,YAAQ,gBAAgB,oBAAI,KAAK;AACjC,YAAQ,eAAe,MAAM;AAC7B,UAAM,GAAG,MAAM;AACf,WAAO,EAAE,IAAI,KAAK;AAAA,EACpB;AAAA,EACA,MAAM,aAAa,UAAU,SAAS,KAAK;AACzC,UAAM,QAAQ,2BAA2B,MAAM,QAAQ;AACvD,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,UAAU,MAAM,oBAAoB,IAAI,KAAK;AACnD,WAAO,oBAAoB,OAAO;AAAA,EACpC;AAAA,EACA,UAAU,OAAO,EAAE,OAAO,UAAU,MAAM;AACxC,UAAM,SAAS,2BAA2B,MAAM,KAAK;AACrD,WAAO;AAAA,MACL,aAAa;AAAA,MACb,cAAc;AAAA,MACd,YAAY,OAAO;AAAA,MACnB,UAAU,OAAO;AAAA,MACjB,gBAAgB,OAAO;AAAA,MACvB,SAAS;AAAA,QACP,MAAM;AAAA,UACJ,QAAS,UAAU,UAA8C;AAAA,UACjE,OAAQ,UAAU,SAA6C;AAAA,QACjE;AAAA,MACF;AAAA,MACA,gBAAgB,UAAU,UAAU;AAAA,MACpC,eAAe,UAAU,SAAS;AAAA,IACpC;AAAA,EACF;AAAA,EACA,MAAM,OAAO,EAAE,UAAU,IAAI,MAAM;AACjC,UAAM,OAAO,mBAAqD,QAAQ;AAC1E,UAAM,SAAS,MAAM;AACrB,QAAI,CAAC,OAAQ;AACb,UAAM,YAAY,UAAU;AAC5B,QAAI,CAAC,UAAW;AAChB,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,UAAU,MAAM,GAAG,QAAQ,SAAS,EAAE,IAAI,UAAU,CAAC;AAC3D,QAAI,CAAC,QAAS;AACd,YAAQ,cAAc,OAAO;AAC7B,YAAQ,sBAAsB,OAAO;AACrC,YAAQ,gBAAgB,OAAO,OAAO,aAAa;AACnD,YAAQ,eAAe,OAAO;AAC9B,UAAM,GAAG,MAAM;AAAA,EACjB;AACF;AAEA,MAAM,uBAGF;AAAA,EACF,IAAI;AAAA,EACJ,MAAM,QAAQ,UAAU,KAAK;AAC3B,UAAM,QAAQ,oBAAoB,MAAM,QAAQ;AAChD,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,UAAU,MAAM,qBAAqB,IAAI,KAAK;AACpD,UAAM,UAAU,MAAM,GAAG,KAAK,eAAe,EAAE,WAAW,QAAQ,GAAG,CAAC;AACtE,UAAM,SAAS,8BAA8B,SAAS,SAAS,MAAM,QAAQ;AAE7E,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,kBAAkB;AAAA,IACpC;AAEA,QAAI,QAAQ,aAAa;AACvB,YAAM,OAAO,OAAO,IAAI,MAAM,sBAAsB,GAAG,EAAE,aAAa,QAAQ,YAAY,CAAC;AAAA,IAC7F;AAEA,UAAM,0BAA0B,wBAAwB,MAAM;AAE9D,QAAI,QAAQ,YAAY,WAAW;AACjC,UAAI,IAAI,KAAK,QAAQ,WAAW,SAAS,IAAI,oBAAI,KAAK,GAAG;AACvD,cAAM,IAAI,MAAM,sBAAsB;AAAA,MACxC;AAAA,IACF,OAAO;AACL,YAAM,cAAc,eAAe,QAAQ,IAAI;AAC/C,UAAI,aAAa,2BAA2B,QAAQ,QAAQ;AAC1D,cAAM,SAAS,IAAI,KAAK,QAAQ,OAAO,QAAQ,IAAI,YAAY,0BAA0B,KAAK,KAAK,GAAI;AACvG,YAAI,SAAS,oBAAI,KAAK,GAAG;AACvB,gBAAM,IAAI,MAAM,sBAAsB;AAAA,QACxC;AAAA,MACF;AAAA,IACF;AAEA,UAAM,aAAa,IAAI,UAAU,QAAQ,YAAY;AAOrD,QAAI,SAAkC,CAAC;AACvC,QAAI,oBAAoC;AAExC,QAAI,OAAO,WAAW;AACpB,UAAI;AACF,cAAM,cAAc;AAAA,UAClB;AAAA,UACA;AAAA,UACA;AAAA,YACE,UAAU,MAAM;AAAA,YAChB,gBAAgB,MAAM;AAAA,YACtB,QAAQ,MAAM;AAAA,UAChB;AAAA,UACA,MAAM,WAAW,CAAC;AAAA,QACpB;AAEA,YAAI,YAAY,MAAM,MAAM;AAC1B,gBAAM,aAAa,OAAO,WAAW,YAAY,QAAQ,kBAAkB;AAC3E,cAAI,OAAO,eAAe,YAAY,WAAW,KAAK,EAAE,SAAS,GAAG;AAClE,wBAAY,KAAK;AAAA,UACnB;AAAA,QACF;AAEA,cAAM,gBAAgB,MAAM,WAAW,QAAQ,OAAO,WAAW;AAAA,UAC/D,OAAO;AAAA,UACP,KAAK;AAAA,YACH,WAAW,IAAI;AAAA,YACf,MAAM;AAAA,cACJ,KAAK,MAAM;AAAA,cACX,UAAU,MAAM;AAAA,cAChB,OAAO,MAAM;AAAA,YACf;AAAA,YACA,mBAAmB;AAAA,YACnB,wBAAwB,MAAM;AAAA,YAC9B,iBAAiB,MAAM,iBAAiB,CAAC,MAAM,cAAc,IAAI;AAAA,UACnE;AAAA,UACA,UAAU;AAAA,YACR,UAAU,MAAM;AAAA,YAChB,gBAAgB,MAAM;AAAA,YACtB,cAAc;AAAA,UAChB;AAAA,QACF,CAAC;AAED,iBAAU,cAAc,UAAsC,CAAC;AAC/D,4BAAoB,cAAc,YAAY;AAAA,MAChD,SAAS,KAAK;AACZ,gBAAQ,MAAM,sDAAsD,GAAG;AACvE,cAAM,IAAI,MAAM,eAAe;AAAA,MACjC;AAAA,IACF,WAAW,OAAO,MAAM;AACtB,eAAS;AAAA,QACP,UAAU,kBAAkB,QAAQ,SAAS;AAAA,UAC3C,UAAU,MAAM;AAAA,UAChB,gBAAgB,MAAM;AAAA,UACtB,QAAQ,MAAM;AAAA,QAChB,CAAC,KAAK,OAAO;AAAA,MACf;AAAA,IACF,OAAO;AACL,YAAM,IAAI,MAAM,iCAAiC;AAAA,IACnD;AAEA,QAAI,yBAAyB;AAC3B,YAAM,iBAAiB,MAAM,WAAW,QAAQ,oCAAoC;AAAA,QAClF,OAAO;AAAA,UACL,WAAW,QAAQ;AAAA,UACnB,UAAU,OAAO;AAAA,UACjB;AAAA,UACA,UAAU,MAAM;AAAA,UAChB,gBAAgB,MAAM;AAAA,UACtB,QAAQ,MAAM;AAAA,QAChB;AAAA,QACA,KAAK;AAAA,UACH,WAAW,IAAI;AAAA,UACf,MAAM,IAAI,QAAQ;AAAA,UAClB,mBAAmB;AAAA,UACnB,wBAAwB,MAAM;AAAA,UAC9B,iBAAiB,MAAM,iBAAiB,CAAC,MAAM,cAAc,IAAI;AAAA,QACnE;AAAA,MACF,CAAC;AACD,UAAI,CAAC,mBAAmB;AACtB,4BAAoB,eAAe,YAAY;AAAA,MACjD;AACA,YAAM;AAAA,QACJ;AAAA,QACA;AAAA,UACE,WAAW,QAAQ;AAAA,UACnB,UAAU,OAAO;AAAA,UACjB,QAAQ,MAAM;AAAA,UACd,iBAAiB,MAAM;AAAA,UACvB;AAAA,UACA,UAAU,MAAM;AAAA,UAChB,gBAAgB,MAAM;AAAA,QACxB;AAAA,QACA,EAAE,YAAY,KAAK;AAAA,MACrB;AAAA,IACF;AAEA,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,UAAU,OAAO;AAAA,MACjB;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;AAEA,gBAAgB,2BAA2B;AAC3C,gBAAgB,oBAAoB;",
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { z } from 'zod'\nimport { registerCommand, type CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { extractUndoPayload, type UndoPayload } from '@open-mercato/shared/lib/commands/undo'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { Message, MessageObject, MessageRecipient } from '../data/entities'\nimport { emitMessagesEvent } from '../events'\nimport {\n findResolvedMessageActionById,\n isTerminalMessageAction,\n resolveActionCommandInput,\n resolveActionHref,\n resolveMessageActionData,\n} from '../lib/actions'\nimport { getMessageType } from '../lib/message-types-registry'\nimport { assertOrganizationAccess, type MessageScopeInput } from './shared'\n\nconst recordTerminalActionSchema = z.object({\n messageId: z.string().uuid(),\n actionId: z.string().min(1),\n result: z.record(z.string(), z.unknown()),\n tenantId: z.string().uuid(),\n organizationId: z.string().uuid().nullable(),\n userId: z.string().uuid(),\n})\n\ntype RecordTerminalActionInput = z.infer<typeof recordTerminalActionSchema>\n\nconst executeActionSchema = z.object({\n messageId: z.string().uuid(),\n actionId: z.string().min(1),\n payload: z.record(z.string(), z.unknown()).optional(),\n tenantId: z.string().uuid(),\n organizationId: z.string().uuid().nullable(),\n userId: z.string().uuid(),\n})\n\ntype ExecuteActionInput = z.infer<typeof executeActionSchema>\n\ntype ActionStateSnapshot = {\n actionTaken: string | null\n actionTakenByUserId: string | null\n actionTakenAt: string | null\n actionResult: Record<string, unknown> | null\n}\n\nfunction toIso(value: Date | null | undefined): string | null {\n return value ? value.toISOString() : null\n}\n\nfunction toDate(value: string | null | undefined): Date | null {\n if (!value) return null\n return new Date(value)\n}\n\nasync function requireActionTarget(em: EntityManager, input: RecordTerminalActionInput) {\n const message = await findOneWithDecryption(\n em,\n Message,\n {\n id: input.messageId,\n tenantId: input.tenantId,\n deletedAt: null,\n },\n undefined,\n { tenantId: input.tenantId, organizationId: input.organizationId },\n )\n if (!message) throw new Error('Message not found')\n assertOrganizationAccess(input as MessageScopeInput, message)\n\n const recipient = await em.findOne(MessageRecipient, {\n messageId: input.messageId,\n recipientUserId: input.userId,\n deletedAt: null,\n })\n if (!recipient) throw new Error('Access denied')\n return message\n}\n\nasync function requireActionMessage(em: EntityManager, input: ExecuteActionInput) {\n const message = await findOneWithDecryption(\n em,\n Message,\n {\n id: input.messageId,\n tenantId: input.tenantId,\n deletedAt: null,\n },\n undefined,\n { tenantId: input.tenantId, organizationId: input.organizationId },\n )\n if (!message) throw new Error('Message not found')\n assertOrganizationAccess(input as MessageScopeInput, message)\n const recipient = await em.findOne(MessageRecipient, {\n messageId: input.messageId,\n recipientUserId: input.userId,\n deletedAt: null,\n })\n if (!recipient) throw new Error('Access denied')\n return message\n}\n\nfunction snapshotActionState(message: Message): ActionStateSnapshot {\n return {\n actionTaken: message.actionTaken ?? null,\n actionTakenByUserId: message.actionTakenByUserId ?? null,\n actionTakenAt: toIso(message.actionTakenAt),\n actionResult: message.actionResult ?? null,\n }\n}\n\nconst recordTerminalActionCommand: CommandHandler<unknown, { ok: true }> = {\n id: 'messages.actions.record_terminal',\n async prepare(rawInput, ctx) {\n const input = recordTerminalActionSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await requireActionTarget(em, input)\n return { before: snapshotActionState(message) }\n },\n async execute(rawInput, ctx) {\n const input = recordTerminalActionSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await requireActionTarget(em, input)\n if (message.actionTaken) {\n throw new Error('Action already taken')\n }\n message.actionTaken = input.actionId\n message.actionTakenByUserId = input.userId\n message.actionTakenAt = new Date()\n message.actionResult = input.result\n await em.flush()\n return { ok: true }\n },\n async captureAfter(rawInput, _result, ctx) {\n const input = recordTerminalActionSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await requireActionTarget(em, input)\n return snapshotActionState(message)\n },\n buildLog: async ({ input, snapshots }) => {\n const parsed = recordTerminalActionSchema.parse(input)\n return {\n actionLabel: 'Execute message terminal action',\n resourceKind: 'messages.message',\n resourceId: parsed.messageId,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n payload: {\n undo: {\n before: (snapshots.before as ActionStateSnapshot | undefined) ?? null,\n after: (snapshots.after as ActionStateSnapshot | undefined) ?? null,\n } satisfies UndoPayload<ActionStateSnapshot>,\n },\n snapshotBefore: snapshots.before ?? null,\n snapshotAfter: snapshots.after ?? null,\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const undo = extractUndoPayload<UndoPayload<ActionStateSnapshot>>(logEntry)\n const before = undo?.before\n if (!before) return\n const messageId = logEntry?.resourceId as string | null\n if (!messageId) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await findOneWithDecryption(em, Message, { id: messageId })\n if (!message) return\n message.actionTaken = before.actionTaken\n message.actionTakenByUserId = before.actionTakenByUserId\n message.actionTakenAt = toDate(before.actionTakenAt)\n message.actionResult = before.actionResult\n await em.flush()\n },\n}\n\nconst executeActionCommand: CommandHandler<\n unknown,\n { ok: true; actionId: string; result: Record<string, unknown>; operationLogEntry: unknown | null }\n> = {\n id: 'messages.actions.execute',\n async execute(rawInput, ctx) {\n const input = executeActionSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await requireActionMessage(em, input)\n const objects = await em.find(MessageObject, { messageId: message.id })\n const action = findResolvedMessageActionById(message, objects, input.actionId)\n\n if (!action) {\n throw new Error('Action not found')\n }\n\n if (message.actionTaken) {\n throw Object.assign(new Error('Action already taken'), { actionTaken: message.actionTaken })\n }\n\n const shouldRecordActionTaken = isTerminalMessageAction(action)\n\n const actionData = resolveMessageActionData(message)\n if (actionData?.expiresAt) {\n if (new Date(actionData.expiresAt) < new Date()) {\n throw new Error('Actions have expired')\n }\n } else {\n const messageType = getMessageType(message.type)\n if (messageType?.actionsExpireAfterHours && message.sentAt) {\n const expiry = new Date(message.sentAt.getTime() + messageType.actionsExpireAfterHours * 60 * 60 * 1000)\n if (expiry < new Date()) {\n throw new Error('Actions have expired')\n }\n }\n }\n\n const commandBus = ctx.container.resolve('commandBus') as {\n execute: (\n commandId: string,\n options: { input: unknown; ctx: unknown; metadata?: unknown }\n ) => Promise<{ result: unknown; logEntry?: unknown }>\n }\n\n let result: Record<string, unknown> = {}\n let operationLogEntry: unknown | null = null\n\n if (action.commandId) {\n try {\n const actionInput = resolveActionCommandInput(\n action,\n message,\n {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n userId: input.userId,\n },\n input.payload ?? {},\n )\n\n if (actionInput.id == null) {\n const fallbackId = action.objectRef?.entityId ?? message.sourceEntityId ?? null\n if (typeof fallbackId === 'string' && fallbackId.trim().length > 0) {\n actionInput.id = fallbackId\n }\n }\n\n const commandResult = await commandBus.execute(action.commandId, {\n input: actionInput,\n ctx: {\n container: ctx.container,\n auth: {\n sub: input.userId,\n tenantId: input.tenantId,\n orgId: input.organizationId,\n },\n organizationScope: null,\n selectedOrganizationId: input.organizationId,\n organizationIds: input.organizationId ? [input.organizationId] : null,\n },\n metadata: {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n resourceKind: 'messages',\n },\n })\n\n result = (commandResult.result as Record<string, unknown>) ?? {}\n operationLogEntry = commandResult.logEntry ?? null\n } catch (err) {\n console.error('[messages] executeActionCommand sub-command failed', err)\n throw new Error('Action failed')\n }\n } else if (action.href) {\n result = {\n redirect: resolveActionHref(action, message, {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n userId: input.userId,\n }) ?? action.href,\n }\n } else {\n throw new Error('Action has no executable target')\n }\n\n if (shouldRecordActionTaken) {\n const terminalResult = await commandBus.execute('messages.actions.record_terminal', {\n input: {\n messageId: message.id,\n actionId: action.id,\n result,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n userId: input.userId,\n },\n ctx: {\n container: ctx.container,\n auth: ctx.auth ?? null,\n organizationScope: null,\n selectedOrganizationId: input.organizationId,\n organizationIds: input.organizationId ? [input.organizationId] : null,\n },\n })\n if (!operationLogEntry) {\n operationLogEntry = terminalResult.logEntry ?? null\n }\n await emitMessagesEvent(\n 'messages.message.action_taken',\n {\n messageId: message.id,\n actionId: action.id,\n userId: input.userId,\n recipientUserId: input.userId,\n result,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n },\n { persistent: true }\n )\n }\n\n return {\n ok: true,\n actionId: action.id,\n result,\n operationLogEntry,\n }\n },\n}\n\nregisterCommand(recordTerminalActionCommand)\nregisterCommand(executeActionCommand)\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,5 +1,22 @@
1
+ import { parseDecryptedFieldValue } from "@open-mercato/shared/lib/encryption/tenantDataEncryptionService";
1
2
  import { getMessageObjectType } from "./message-objects-registry.js";
2
3
  import { getMessageType } from "./message-types-registry.js";
4
+ function isRecordValue(value) {
5
+ return !!value && typeof value === "object" && !Array.isArray(value);
6
+ }
7
+ function resolveMessageActionData(message) {
8
+ const rawActionData = message.actionData;
9
+ const parsedActionData = typeof rawActionData === "string" ? parseDecryptedFieldValue(rawActionData) : rawActionData;
10
+ if (!isRecordValue(parsedActionData)) return null;
11
+ const actions = Array.isArray(parsedActionData.actions) ? parsedActionData.actions.filter(isRecordValue) : [];
12
+ const primaryActionId = typeof parsedActionData.primaryActionId === "string" ? parsedActionData.primaryActionId : void 0;
13
+ const expiresAt = typeof parsedActionData.expiresAt === "string" ? parsedActionData.expiresAt : void 0;
14
+ return {
15
+ actions,
16
+ ...primaryActionId ? { primaryActionId } : {},
17
+ ...expiresAt ? { expiresAt } : {}
18
+ };
19
+ }
3
20
  function normalizeActionLabel(action, fallback) {
4
21
  if (typeof action.label === "string" && action.label.trim().length > 0) {
5
22
  return action.label;
@@ -19,7 +36,8 @@ function buildMessageObjectActionId(objectId, actionId) {
19
36
  return `object:${objectId}:${actionId}`;
20
37
  }
21
38
  function readActionDataExpiry(message) {
22
- if (message.actionData?.expiresAt) return message.actionData.expiresAt;
39
+ const actionData = resolveMessageActionData(message);
40
+ if (actionData?.expiresAt) return actionData.expiresAt;
23
41
  const messageType = getMessageType(message.type);
24
42
  if (!messageType?.actionsExpireAfterHours || !message.sentAt) return void 0;
25
43
  return new Date(
@@ -29,6 +47,7 @@ function readActionDataExpiry(message) {
29
47
  function buildResolvedMessageActions(message, objects) {
30
48
  const resolved = [];
31
49
  const usedIds = /* @__PURE__ */ new Set();
50
+ const actionData = resolveMessageActionData(message);
32
51
  const pushAction = (action, source, objectRef, labelFallback) => {
33
52
  const id = typeof action.id === "string" ? action.id.trim() : "";
34
53
  if (!id || usedIds.has(id)) return;
@@ -41,7 +60,7 @@ function buildResolvedMessageActions(message, objects) {
41
60
  objectRef
42
61
  });
43
62
  };
44
- for (const action of message.actionData?.actions ?? []) {
63
+ for (const action of actionData?.actions ?? []) {
45
64
  pushAction(action, "message");
46
65
  }
47
66
  const messageType = getMessageType(message.type);
@@ -81,7 +100,7 @@ function buildResolvedMessageActions(message, objects) {
81
100
  if (resolved.length === 0 && !expiresAt) {
82
101
  return null;
83
102
  }
84
- const configuredPrimaryActionId = message.actionData?.primaryActionId;
103
+ const configuredPrimaryActionId = actionData?.primaryActionId;
85
104
  const primaryActionId = configuredPrimaryActionId && resolved.some((entry) => entry.id === configuredPrimaryActionId) ? configuredPrimaryActionId : resolved[0]?.id;
86
105
  return {
87
106
  actions: resolved,
@@ -136,6 +155,7 @@ export {
136
155
  findResolvedMessageActionById,
137
156
  isTerminalMessageAction,
138
157
  resolveActionCommandInput,
139
- resolveActionHref
158
+ resolveActionHref,
159
+ resolveMessageActionData
140
160
  };
141
161
  //# sourceMappingURL=actions.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/messages/lib/actions.ts"],
4
- "sourcesContent": ["import type { Message, MessageAction, MessageActionData, MessageObject } from '../data/entities'\nimport { getMessageObjectType } from './message-objects-registry'\nimport { getMessageType } from './message-types-registry'\n\ntype MessageActionSource = 'message' | 'type_default' | 'object'\n\nexport type MessageActionObjectRef = {\n objectId: string\n entityModule: string\n entityType: string\n entityId: string\n}\n\nexport type ResolvedMessageAction = MessageAction & {\n source: MessageActionSource\n objectRef?: MessageActionObjectRef\n}\n\nexport type MessageActionResolutionContext = {\n tenantId: string\n organizationId?: string | null\n userId: string\n}\n\nfunction normalizeActionLabel(\n action: Pick<MessageAction, 'label' | 'id'>,\n fallback?: string | null,\n): string {\n if (typeof action.label === 'string' && action.label.trim().length > 0) {\n return action.label\n }\n if (typeof fallback === 'string' && fallback.trim().length > 0) {\n return fallback.trim()\n }\n return action.id\n}\n\nexport function isTerminalMessageAction(\n action: Pick<MessageAction, 'isTerminal' | 'commandId' | 'href'>,\n): boolean {\n if (typeof action.isTerminal === 'boolean') return action.isTerminal\n if (typeof action.commandId === 'string' && action.commandId.trim().length > 0) return true\n if (typeof action.href === 'string' && action.href.trim().length > 0) return false\n return true\n}\n\nexport function buildMessageObjectActionId(objectId: string, actionId: string): string {\n return `object:${objectId}:${actionId}`\n}\n\nfunction readActionDataExpiry(message: Message): string | undefined {\n if (message.actionData?.expiresAt) return message.actionData.expiresAt\n const messageType = getMessageType(message.type)\n if (!messageType?.actionsExpireAfterHours || !message.sentAt) return undefined\n return new Date(\n message.sentAt.getTime() + messageType.actionsExpireAfterHours * 60 * 60 * 1000,\n ).toISOString()\n}\n\nexport function buildResolvedMessageActions(\n message: Message,\n objects: MessageObject[],\n): MessageActionData | null {\n const resolved: ResolvedMessageAction[] = []\n const usedIds = new Set<string>()\n\n const pushAction = (\n action: MessageAction,\n source: MessageActionSource,\n objectRef?: MessageActionObjectRef,\n labelFallback?: string | null,\n ) => {\n const id = typeof action.id === 'string' ? action.id.trim() : ''\n if (!id || usedIds.has(id)) return\n usedIds.add(id)\n\n resolved.push({\n ...action,\n id,\n label: normalizeActionLabel(action, labelFallback),\n source,\n objectRef,\n })\n }\n\n for (const action of message.actionData?.actions ?? []) {\n pushAction(action, 'message')\n }\n\n const messageType = getMessageType(message.type)\n for (const action of messageType?.defaultActions ?? []) {\n pushAction(action, 'type_default')\n }\n\n for (const object of objects) {\n if (!object.actionRequired || !object.actionType) continue\n const objectType = getMessageObjectType(object.entityModule, object.entityType)\n if (!objectType) continue\n const actionDef = objectType.actions.find((entry) => entry.id === object.actionType)\n if (!actionDef) continue\n\n pushAction(\n {\n id: buildMessageObjectActionId(object.id, actionDef.id),\n label: object.actionLabel ?? actionDef.id,\n labelKey: actionDef.labelKey,\n variant: actionDef.variant,\n icon: actionDef.icon,\n commandId: actionDef.commandId,\n href: actionDef.href,\n isTerminal: actionDef.isTerminal,\n confirmRequired: actionDef.confirmRequired,\n confirmMessage: actionDef.confirmMessage,\n },\n 'object',\n {\n objectId: object.id,\n entityModule: object.entityModule,\n entityType: object.entityType,\n entityId: object.entityId,\n },\n object.actionLabel ?? actionDef.id,\n )\n }\n\n const expiresAt = readActionDataExpiry(message)\n if (resolved.length === 0 && !expiresAt) {\n return null\n }\n\n const configuredPrimaryActionId = message.actionData?.primaryActionId\n const primaryActionId = configuredPrimaryActionId && resolved.some((entry) => entry.id === configuredPrimaryActionId)\n ? configuredPrimaryActionId\n : resolved[0]?.id\n\n return {\n actions: resolved,\n primaryActionId,\n expiresAt,\n }\n}\n\nexport function findResolvedMessageActionById(\n message: Message,\n objects: MessageObject[],\n actionId: string,\n): ResolvedMessageAction | null {\n const actionData = buildResolvedMessageActions(message, objects)\n const match = actionData?.actions.find((entry) => entry.id === actionId)\n return (match as ResolvedMessageAction | undefined) ?? null\n}\n\nfunction buildTemplateContext(\n message: Message,\n resolutionContext: MessageActionResolutionContext,\n objectRef?: MessageActionObjectRef,\n): Record<string, unknown> {\n return {\n messageId: message.id,\n sourceEntityId: message.sourceEntityId ?? message.id,\n sourceEntityType: message.sourceEntityType ?? null,\n threadId: message.threadId ?? null,\n parentMessageId: message.parentMessageId ?? null,\n messageType: message.type,\n tenantId: resolutionContext.tenantId,\n organizationId: resolutionContext.organizationId ?? null,\n userId: resolutionContext.userId,\n objectId: objectRef?.objectId ?? null,\n entityId: objectRef?.entityId ?? null,\n entityType: objectRef?.entityType ?? null,\n entityModule: objectRef?.entityModule ?? null,\n }\n}\n\nfunction resolveTemplateString(template: string, context: Record<string, unknown>): string {\n return template.replace(/\\{([a-zA-Z0-9_]+)\\}/g, (fullMatch, key: string) => {\n const value = context[key]\n if (value == null) return fullMatch\n return String(value)\n })\n}\n\nexport function resolveActionHref(\n action: ResolvedMessageAction,\n message: Message,\n resolutionContext: MessageActionResolutionContext,\n): string | null {\n if (!action.href) return null\n const context = buildTemplateContext(message, resolutionContext, action.objectRef)\n return resolveTemplateString(action.href, context)\n}\n\nexport function resolveActionCommandInput(\n action: ResolvedMessageAction,\n message: Message,\n _resolutionContext: MessageActionResolutionContext,\n requestInput: Record<string, unknown>,\n): Record<string, unknown> {\n return {\n ...requestInput,\n messageId: message.id,\n actionId: action.id,\n }\n}\n"],
5
- "mappings": "AACA,SAAS,4BAA4B;AACrC,SAAS,sBAAsB;AAsB/B,SAAS,qBACP,QACA,UACQ;AACR,MAAI,OAAO,OAAO,UAAU,YAAY,OAAO,MAAM,KAAK,EAAE,SAAS,GAAG;AACtE,WAAO,OAAO;AAAA,EAChB;AACA,MAAI,OAAO,aAAa,YAAY,SAAS,KAAK,EAAE,SAAS,GAAG;AAC9D,WAAO,SAAS,KAAK;AAAA,EACvB;AACA,SAAO,OAAO;AAChB;AAEO,SAAS,wBACd,QACS;AACT,MAAI,OAAO,OAAO,eAAe,UAAW,QAAO,OAAO;AAC1D,MAAI,OAAO,OAAO,cAAc,YAAY,OAAO,UAAU,KAAK,EAAE,SAAS,EAAG,QAAO;AACvF,MAAI,OAAO,OAAO,SAAS,YAAY,OAAO,KAAK,KAAK,EAAE,SAAS,EAAG,QAAO;AAC7E,SAAO;AACT;AAEO,SAAS,2BAA2B,UAAkB,UAA0B;AACrF,SAAO,UAAU,QAAQ,IAAI,QAAQ;AACvC;AAEA,SAAS,qBAAqB,SAAsC;AAClE,MAAI,QAAQ,YAAY,UAAW,QAAO,QAAQ,WAAW;AAC7D,QAAM,cAAc,eAAe,QAAQ,IAAI;AAC/C,MAAI,CAAC,aAAa,2BAA2B,CAAC,QAAQ,OAAQ,QAAO;AACrE,SAAO,IAAI;AAAA,IACT,QAAQ,OAAO,QAAQ,IAAI,YAAY,0BAA0B,KAAK,KAAK;AAAA,EAC7E,EAAE,YAAY;AAChB;AAEO,SAAS,4BACd,SACA,SAC0B;AAC1B,QAAM,WAAoC,CAAC;AAC3C,QAAM,UAAU,oBAAI,IAAY;AAEhC,QAAM,aAAa,CACjB,QACA,QACA,WACA,kBACG;AACH,UAAM,KAAK,OAAO,OAAO,OAAO,WAAW,OAAO,GAAG,KAAK,IAAI;AAC9D,QAAI,CAAC,MAAM,QAAQ,IAAI,EAAE,EAAG;AAC5B,YAAQ,IAAI,EAAE;AAEd,aAAS,KAAK;AAAA,MACZ,GAAG;AAAA,MACH;AAAA,MACA,OAAO,qBAAqB,QAAQ,aAAa;AAAA,MACjD;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAEA,aAAW,UAAU,QAAQ,YAAY,WAAW,CAAC,GAAG;AACtD,eAAW,QAAQ,SAAS;AAAA,EAC9B;AAEA,QAAM,cAAc,eAAe,QAAQ,IAAI;AAC/C,aAAW,UAAU,aAAa,kBAAkB,CAAC,GAAG;AACtD,eAAW,QAAQ,cAAc;AAAA,EACnC;AAEA,aAAW,UAAU,SAAS;AAC5B,QAAI,CAAC,OAAO,kBAAkB,CAAC,OAAO,WAAY;AAClD,UAAM,aAAa,qBAAqB,OAAO,cAAc,OAAO,UAAU;AAC9E,QAAI,CAAC,WAAY;AACjB,UAAM,YAAY,WAAW,QAAQ,KAAK,CAAC,UAAU,MAAM,OAAO,OAAO,UAAU;AACnF,QAAI,CAAC,UAAW;AAEhB;AAAA,MACE;AAAA,QACE,IAAI,2BAA2B,OAAO,IAAI,UAAU,EAAE;AAAA,QACtD,OAAO,OAAO,eAAe,UAAU;AAAA,QACvC,UAAU,UAAU;AAAA,QACpB,SAAS,UAAU;AAAA,QACnB,MAAM,UAAU;AAAA,QAChB,WAAW,UAAU;AAAA,QACrB,MAAM,UAAU;AAAA,QAChB,YAAY,UAAU;AAAA,QACtB,iBAAiB,UAAU;AAAA,QAC3B,gBAAgB,UAAU;AAAA,MAC5B;AAAA,MACA;AAAA,MACA;AAAA,QACE,UAAU,OAAO;AAAA,QACjB,cAAc,OAAO;AAAA,QACrB,YAAY,OAAO;AAAA,QACnB,UAAU,OAAO;AAAA,MACnB;AAAA,MACA,OAAO,eAAe,UAAU;AAAA,IAClC;AAAA,EACF;AAEA,QAAM,YAAY,qBAAqB,OAAO;AAC9C,MAAI,SAAS,WAAW,KAAK,CAAC,WAAW;AACvC,WAAO;AAAA,EACT;AAEA,QAAM,4BAA4B,QAAQ,YAAY;AACtD,QAAM,kBAAkB,6BAA6B,SAAS,KAAK,CAAC,UAAU,MAAM,OAAO,yBAAyB,IAChH,4BACA,SAAS,CAAC,GAAG;AAEjB,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,IACA;AAAA,EACF;AACF;AAEO,SAAS,8BACd,SACA,SACA,UAC8B;AAC9B,QAAM,aAAa,4BAA4B,SAAS,OAAO;AAC/D,QAAM,QAAQ,YAAY,QAAQ,KAAK,CAAC,UAAU,MAAM,OAAO,QAAQ;AACvE,SAAQ,SAA+C;AACzD;AAEA,SAAS,qBACP,SACA,mBACA,WACyB;AACzB,SAAO;AAAA,IACL,WAAW,QAAQ;AAAA,IACnB,gBAAgB,QAAQ,kBAAkB,QAAQ;AAAA,IAClD,kBAAkB,QAAQ,oBAAoB;AAAA,IAC9C,UAAU,QAAQ,YAAY;AAAA,IAC9B,iBAAiB,QAAQ,mBAAmB;AAAA,IAC5C,aAAa,QAAQ;AAAA,IACrB,UAAU,kBAAkB;AAAA,IAC5B,gBAAgB,kBAAkB,kBAAkB;AAAA,IACpD,QAAQ,kBAAkB;AAAA,IAC1B,UAAU,WAAW,YAAY;AAAA,IACjC,UAAU,WAAW,YAAY;AAAA,IACjC,YAAY,WAAW,cAAc;AAAA,IACrC,cAAc,WAAW,gBAAgB;AAAA,EAC3C;AACF;AAEA,SAAS,sBAAsB,UAAkB,SAA0C;AACzF,SAAO,SAAS,QAAQ,wBAAwB,CAAC,WAAW,QAAgB;AAC1E,UAAM,QAAQ,QAAQ,GAAG;AACzB,QAAI,SAAS,KAAM,QAAO;AAC1B,WAAO,OAAO,KAAK;AAAA,EACrB,CAAC;AACH;AAEO,SAAS,kBACd,QACA,SACA,mBACe;AACf,MAAI,CAAC,OAAO,KAAM,QAAO;AACzB,QAAM,UAAU,qBAAqB,SAAS,mBAAmB,OAAO,SAAS;AACjF,SAAO,sBAAsB,OAAO,MAAM,OAAO;AACnD;AAEO,SAAS,0BACd,QACA,SACA,oBACA,cACyB;AACzB,SAAO;AAAA,IACL,GAAG;AAAA,IACH,WAAW,QAAQ;AAAA,IACnB,UAAU,OAAO;AAAA,EACnB;AACF;",
4
+ "sourcesContent": ["import { parseDecryptedFieldValue } from '@open-mercato/shared/lib/encryption/tenantDataEncryptionService'\nimport type { Message, MessageAction, MessageActionData, MessageObject } from '../data/entities'\nimport { getMessageObjectType } from './message-objects-registry'\nimport { getMessageType } from './message-types-registry'\n\ntype MessageActionSource = 'message' | 'type_default' | 'object'\n\nexport type MessageActionObjectRef = {\n objectId: string\n entityModule: string\n entityType: string\n entityId: string\n}\n\nexport type ResolvedMessageAction = MessageAction & {\n source: MessageActionSource\n objectRef?: MessageActionObjectRef\n}\n\nexport type MessageActionResolutionContext = {\n tenantId: string\n organizationId?: string | null\n userId: string\n}\n\nfunction isRecordValue(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === 'object' && !Array.isArray(value)\n}\n\nexport function resolveMessageActionData(message: Pick<Message, 'actionData'>): MessageActionData | null {\n const rawActionData = message.actionData as unknown\n const parsedActionData = typeof rawActionData === 'string'\n ? parseDecryptedFieldValue(rawActionData)\n : rawActionData\n if (!isRecordValue(parsedActionData)) return null\n\n const actions = Array.isArray(parsedActionData.actions)\n ? parsedActionData.actions.filter(isRecordValue) as MessageAction[]\n : []\n const primaryActionId = typeof parsedActionData.primaryActionId === 'string'\n ? parsedActionData.primaryActionId\n : undefined\n const expiresAt = typeof parsedActionData.expiresAt === 'string'\n ? parsedActionData.expiresAt\n : undefined\n\n return {\n actions,\n ...(primaryActionId ? { primaryActionId } : {}),\n ...(expiresAt ? { expiresAt } : {}),\n }\n}\n\nfunction normalizeActionLabel(\n action: Pick<MessageAction, 'label' | 'id'>,\n fallback?: string | null,\n): string {\n if (typeof action.label === 'string' && action.label.trim().length > 0) {\n return action.label\n }\n if (typeof fallback === 'string' && fallback.trim().length > 0) {\n return fallback.trim()\n }\n return action.id\n}\n\nexport function isTerminalMessageAction(\n action: Pick<MessageAction, 'isTerminal' | 'commandId' | 'href'>,\n): boolean {\n if (typeof action.isTerminal === 'boolean') return action.isTerminal\n if (typeof action.commandId === 'string' && action.commandId.trim().length > 0) return true\n if (typeof action.href === 'string' && action.href.trim().length > 0) return false\n return true\n}\n\nexport function buildMessageObjectActionId(objectId: string, actionId: string): string {\n return `object:${objectId}:${actionId}`\n}\n\nfunction readActionDataExpiry(message: Message): string | undefined {\n const actionData = resolveMessageActionData(message)\n if (actionData?.expiresAt) return actionData.expiresAt\n const messageType = getMessageType(message.type)\n if (!messageType?.actionsExpireAfterHours || !message.sentAt) return undefined\n return new Date(\n message.sentAt.getTime() + messageType.actionsExpireAfterHours * 60 * 60 * 1000,\n ).toISOString()\n}\n\nexport function buildResolvedMessageActions(\n message: Message,\n objects: MessageObject[],\n): MessageActionData | null {\n const resolved: ResolvedMessageAction[] = []\n const usedIds = new Set<string>()\n const actionData = resolveMessageActionData(message)\n\n const pushAction = (\n action: MessageAction,\n source: MessageActionSource,\n objectRef?: MessageActionObjectRef,\n labelFallback?: string | null,\n ) => {\n const id = typeof action.id === 'string' ? action.id.trim() : ''\n if (!id || usedIds.has(id)) return\n usedIds.add(id)\n\n resolved.push({\n ...action,\n id,\n label: normalizeActionLabel(action, labelFallback),\n source,\n objectRef,\n })\n }\n\n for (const action of actionData?.actions ?? []) {\n pushAction(action, 'message')\n }\n\n const messageType = getMessageType(message.type)\n for (const action of messageType?.defaultActions ?? []) {\n pushAction(action, 'type_default')\n }\n\n for (const object of objects) {\n if (!object.actionRequired || !object.actionType) continue\n const objectType = getMessageObjectType(object.entityModule, object.entityType)\n if (!objectType) continue\n const actionDef = objectType.actions.find((entry) => entry.id === object.actionType)\n if (!actionDef) continue\n\n pushAction(\n {\n id: buildMessageObjectActionId(object.id, actionDef.id),\n label: object.actionLabel ?? actionDef.id,\n labelKey: actionDef.labelKey,\n variant: actionDef.variant,\n icon: actionDef.icon,\n commandId: actionDef.commandId,\n href: actionDef.href,\n isTerminal: actionDef.isTerminal,\n confirmRequired: actionDef.confirmRequired,\n confirmMessage: actionDef.confirmMessage,\n },\n 'object',\n {\n objectId: object.id,\n entityModule: object.entityModule,\n entityType: object.entityType,\n entityId: object.entityId,\n },\n object.actionLabel ?? actionDef.id,\n )\n }\n\n const expiresAt = readActionDataExpiry(message)\n if (resolved.length === 0 && !expiresAt) {\n return null\n }\n\n const configuredPrimaryActionId = actionData?.primaryActionId\n const primaryActionId = configuredPrimaryActionId && resolved.some((entry) => entry.id === configuredPrimaryActionId)\n ? configuredPrimaryActionId\n : resolved[0]?.id\n\n return {\n actions: resolved,\n primaryActionId,\n expiresAt,\n }\n}\n\nexport function findResolvedMessageActionById(\n message: Message,\n objects: MessageObject[],\n actionId: string,\n): ResolvedMessageAction | null {\n const actionData = buildResolvedMessageActions(message, objects)\n const match = actionData?.actions.find((entry) => entry.id === actionId)\n return (match as ResolvedMessageAction | undefined) ?? null\n}\n\nfunction buildTemplateContext(\n message: Message,\n resolutionContext: MessageActionResolutionContext,\n objectRef?: MessageActionObjectRef,\n): Record<string, unknown> {\n return {\n messageId: message.id,\n sourceEntityId: message.sourceEntityId ?? message.id,\n sourceEntityType: message.sourceEntityType ?? null,\n threadId: message.threadId ?? null,\n parentMessageId: message.parentMessageId ?? null,\n messageType: message.type,\n tenantId: resolutionContext.tenantId,\n organizationId: resolutionContext.organizationId ?? null,\n userId: resolutionContext.userId,\n objectId: objectRef?.objectId ?? null,\n entityId: objectRef?.entityId ?? null,\n entityType: objectRef?.entityType ?? null,\n entityModule: objectRef?.entityModule ?? null,\n }\n}\n\nfunction resolveTemplateString(template: string, context: Record<string, unknown>): string {\n return template.replace(/\\{([a-zA-Z0-9_]+)\\}/g, (fullMatch, key: string) => {\n const value = context[key]\n if (value == null) return fullMatch\n return String(value)\n })\n}\n\nexport function resolveActionHref(\n action: ResolvedMessageAction,\n message: Message,\n resolutionContext: MessageActionResolutionContext,\n): string | null {\n if (!action.href) return null\n const context = buildTemplateContext(message, resolutionContext, action.objectRef)\n return resolveTemplateString(action.href, context)\n}\n\nexport function resolveActionCommandInput(\n action: ResolvedMessageAction,\n message: Message,\n _resolutionContext: MessageActionResolutionContext,\n requestInput: Record<string, unknown>,\n): Record<string, unknown> {\n return {\n ...requestInput,\n messageId: message.id,\n actionId: action.id,\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -18,7 +18,16 @@ import { documentUpdateSchema } from "../../commands/documents.js";
18
18
  import { escapeLikePattern } from "@open-mercato/shared/lib/db/escapeLikePattern";
19
19
  import { parseBooleanToken } from "@open-mercato/shared/lib/boolean";
20
20
  import { recalculateOrderTotalsForDisplay } from "../../commands/returns.js";
21
+ import { parseDecryptedFieldValue } from "@open-mercato/shared/lib/encryption/tenantDataEncryptionService";
21
22
  const rawBodySchema = z.object({}).passthrough();
23
+ const normalizeJsonRecord = (value) => {
24
+ if (value && typeof value === "object" && !Array.isArray(value)) {
25
+ return value;
26
+ }
27
+ if (typeof value !== "string") return null;
28
+ const parsed = parseDecryptedFieldValue(value);
29
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
30
+ };
22
31
  const resolveCustomerName = (snapshot, fallback) => {
23
32
  if (!snapshot) return fallback ?? null;
24
33
  const customer = snapshot.customer;
@@ -124,36 +133,40 @@ function buildSortMap(numberColumn) {
124
133
  updatedAt: "updated_at"
125
134
  };
126
135
  }
127
- const mapUpdateResponse = (entity) => ({
128
- id: entity?.id ?? null,
129
- orderNumber: entity?.orderNumber ?? null,
130
- quoteNumber: entity?.quoteNumber ?? null,
131
- customerEntityId: entity?.customerEntityId ?? null,
132
- customerContactId: entity?.customerContactId ?? null,
133
- customerSnapshot: entity?.customerSnapshot ?? null,
134
- metadata: entity?.metadata ?? null,
135
- externalReference: entity?.externalReference ?? null,
136
- customerReference: entity?.customerReference ?? null,
137
- comment: entity?.comments ?? null,
138
- statusEntryId: entity?.statusEntryId ?? null,
139
- status: entity?.status ?? null,
140
- channelId: entity?.channelId ?? null,
141
- customerName: resolveCustomerName(entity?.customerSnapshot ?? null, entity?.customerEntityId ?? null),
142
- contactEmail: resolveCustomerEmail(entity?.customerSnapshot ?? null) ?? (typeof entity?.metadata?.customerEmail === "string" ? entity.metadata.customerEmail : null),
143
- currencyCode: entity?.currencyCode ?? null,
144
- placedAt: entity?.placedAt ? entity.placedAt.toISOString() : null,
145
- expectedDeliveryAt: entity?.expectedDeliveryAt ? entity.expectedDeliveryAt.toISOString() : null,
146
- shippingAddressId: entity?.shippingAddressId ?? null,
147
- billingAddressId: entity?.billingAddressId ?? null,
148
- shippingAddressSnapshot: entity?.shippingAddressSnapshot ?? null,
149
- billingAddressSnapshot: entity?.billingAddressSnapshot ?? null,
150
- shippingMethodId: entity?.shippingMethodId ?? null,
151
- shippingMethodCode: entity?.shippingMethodCode ?? null,
152
- shippingMethodSnapshot: entity?.shippingMethodSnapshot ?? null,
153
- paymentMethodId: entity?.paymentMethodId ?? null,
154
- paymentMethodCode: entity?.paymentMethodCode ?? null,
155
- paymentMethodSnapshot: entity?.paymentMethodSnapshot ?? null
156
- });
136
+ const mapUpdateResponse = (entity) => {
137
+ const customerSnapshot = normalizeJsonRecord(entity?.customerSnapshot);
138
+ const metadata = normalizeJsonRecord(entity?.metadata);
139
+ return {
140
+ id: entity?.id ?? null,
141
+ orderNumber: entity?.orderNumber ?? null,
142
+ quoteNumber: entity?.quoteNumber ?? null,
143
+ customerEntityId: entity?.customerEntityId ?? null,
144
+ customerContactId: entity?.customerContactId ?? null,
145
+ customerSnapshot,
146
+ metadata,
147
+ externalReference: entity?.externalReference ?? null,
148
+ customerReference: entity?.customerReference ?? null,
149
+ comment: entity?.comments ?? null,
150
+ statusEntryId: entity?.statusEntryId ?? null,
151
+ status: entity?.status ?? null,
152
+ channelId: entity?.channelId ?? null,
153
+ customerName: resolveCustomerName(customerSnapshot, entity?.customerEntityId ?? null),
154
+ contactEmail: resolveCustomerEmail(customerSnapshot) ?? (typeof metadata?.customerEmail === "string" ? metadata.customerEmail : null),
155
+ currencyCode: entity?.currencyCode ?? null,
156
+ placedAt: entity?.placedAt ? entity.placedAt.toISOString() : null,
157
+ expectedDeliveryAt: entity?.expectedDeliveryAt ? entity.expectedDeliveryAt.toISOString() : null,
158
+ shippingAddressId: entity?.shippingAddressId ?? null,
159
+ billingAddressId: entity?.billingAddressId ?? null,
160
+ shippingAddressSnapshot: normalizeJsonRecord(entity?.shippingAddressSnapshot),
161
+ billingAddressSnapshot: normalizeJsonRecord(entity?.billingAddressSnapshot),
162
+ shippingMethodId: entity?.shippingMethodId ?? null,
163
+ shippingMethodCode: entity?.shippingMethodCode ?? null,
164
+ shippingMethodSnapshot: normalizeJsonRecord(entity?.shippingMethodSnapshot),
165
+ paymentMethodId: entity?.paymentMethodId ?? null,
166
+ paymentMethodCode: entity?.paymentMethodCode ?? null,
167
+ paymentMethodSnapshot: normalizeJsonRecord(entity?.paymentMethodSnapshot)
168
+ };
169
+ };
157
170
  const attachTags = async (payload, ctx) => {
158
171
  const items = Array.isArray(payload?.items) ? payload.items : [];
159
172
  if (!items.length) return;
@@ -317,10 +330,10 @@ function buildDocumentCrudOptions(binding) {
317
330
  shippingAddressId: item.shipping_address_id ?? null,
318
331
  shippingMethodId: item.shipping_method_id ?? null,
319
332
  shippingMethodCode: item.shipping_method_code ?? null,
320
- shippingMethodSnapshot: item.shipping_method_snapshot ?? null,
333
+ shippingMethodSnapshot: normalizeJsonRecord(item.shipping_method_snapshot),
321
334
  paymentMethodId: item.payment_method_id ?? null,
322
335
  paymentMethodCode: item.payment_method_code ?? null,
323
- paymentMethodSnapshot: item.payment_method_snapshot ?? null,
336
+ paymentMethodSnapshot: normalizeJsonRecord(item.payment_method_snapshot),
324
337
  currencyCode: item.currency_code ?? null,
325
338
  channelId: item.channel_id ?? null,
326
339
  externalReference: item.external_reference ?? null,
@@ -343,10 +356,10 @@ function buildDocumentCrudOptions(binding) {
343
356
  paidTotalAmount: toNumber(item.paid_total_amount),
344
357
  refundedTotalAmount: toNumber(item.refunded_total_amount),
345
358
  outstandingAmount: toNumber(item.outstanding_amount),
346
- customerSnapshot: item.customer_snapshot ?? null,
347
- billingAddressSnapshot: item.billing_address_snapshot ?? null,
348
- shippingAddressSnapshot: item.shipping_address_snapshot ?? null,
349
- metadata: item.metadata ?? null,
359
+ customerSnapshot: normalizeJsonRecord(item.customer_snapshot),
360
+ billingAddressSnapshot: normalizeJsonRecord(item.billing_address_snapshot),
361
+ shippingAddressSnapshot: normalizeJsonRecord(item.shipping_address_snapshot),
362
+ metadata: normalizeJsonRecord(item.metadata),
350
363
  organizationId: item.organization_id ?? null,
351
364
  tenantId: item.tenant_id ?? null,
352
365
  createdAt: item.created_at,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/sales/api/documents/factory.ts"],
4
- "sourcesContent": ["import { z } from 'zod'\nimport { makeCrudRoute, type CrudCtx } from '@open-mercato/shared/lib/crud/factory'\nimport { splitCustomFieldPayload, extractAllCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { E } from '#generated/entities.ids.generated'\nimport type { SalesOrder, SalesQuote } from '../../data/entities'\nimport { SalesDocumentTagAssignment } from '../../data/entities'\nimport {\n orderCreateSchema,\n quoteCreateSchema,\n} from '../../data/validators'\nimport {\n createPagedListResponseSchema,\n createSalesCrudOpenApi,\n defaultDeleteRequestSchema,\n} from '../openapi'\nimport { parseScopedCommandInput, resolveCrudRecordId } from '../utils'\nimport { documentUpdateSchema } from '../../commands/documents'\nimport { escapeLikePattern } from '@open-mercato/shared/lib/db/escapeLikePattern'\nimport { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\nimport type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\nimport { recalculateOrderTotalsForDisplay } from '../../commands/returns'\n\ntype DocumentKind = 'order' | 'quote'\n\ntype DocumentBinding = {\n kind: DocumentKind\n entity: typeof SalesOrder | typeof SalesQuote\n entityId: (typeof E.sales)[keyof typeof E.sales]\n numberField: 'orderNumber' | 'quoteNumber'\n createCommandId: string\n updateCommandId: string\n deleteCommandId: string\n manageFeature: string\n viewFeature: string\n}\n\nconst rawBodySchema = z.object({}).passthrough()\n\nconst resolveCustomerName = (snapshot: Record<string, unknown> | null, fallback?: string | null) => {\n if (!snapshot) return fallback ?? null\n const customer = snapshot.customer as Record<string, unknown> | undefined\n const contact = snapshot.contact as Record<string, unknown> | undefined\n const displayName = typeof customer?.displayName === 'string' ? customer.displayName : null\n if (displayName) return displayName\n const first = typeof contact?.firstName === 'string' ? contact.firstName : null\n const last = typeof contact?.lastName === 'string' ? contact.lastName : null\n const preferred = typeof contact?.preferredName === 'string' ? contact.preferredName : null\n const parts = [preferred ?? first, last].filter((part) => part && part.trim().length)\n if (parts.length) return parts.join(' ')\n return fallback ?? null\n}\n\nconst resolveCustomerEmail = (snapshot: Record<string, unknown> | null) => {\n if (!snapshot) return null\n const customer = snapshot.customer as Record<string, unknown> | undefined\n const primary = typeof customer?.primaryEmail === 'string' ? customer.primaryEmail : null\n return primary ?? null\n}\n\nconst listSchema = z\n .object({\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 id: z.string().uuid().optional(),\n customerId: z.string().uuid().optional(),\n channelId: z.string().uuid().optional(),\n lineItemCountMin: z.coerce.number().min(0).optional(),\n lineItemCountMax: z.coerce.number().min(0).optional(),\n totalNetMin: z.coerce.number().optional(),\n totalNetMax: z.coerce.number().optional(),\n totalGrossMin: z.coerce.number().optional(),\n totalGrossMax: z.coerce.number().optional(),\n dateFrom: z.string().optional(),\n dateTo: z.string().optional(),\n tagIds: z.string().optional(),\n tagIdsEmpty: z.string().optional(),\n sortField: z.string().optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n withDeleted: z.coerce.boolean().optional(),\n })\n .passthrough()\n\ntype ListQuery = z.infer<typeof listSchema>\n\nfunction buildFilters(query: ListQuery, numberColumn: string, kind: DocumentKind) {\n const filters: Record<string, unknown> = {}\n if (query.id) filters.id = { $eq: query.id }\n if (query.search && query.search.trim().length > 0) {\n const term = `%${escapeLikePattern(query.search.trim())}%`\n filters[numberColumn] = { $ilike: term }\n }\n if (query.customerId) {\n filters.customer_entity_id = { $eq: query.customerId }\n }\n if (query.channelId) {\n filters.channel_id = { $eq: query.channelId }\n }\n const lineRange: Record<string, number> = {}\n if (typeof query.lineItemCountMin === 'number') lineRange.$gte = query.lineItemCountMin\n if (typeof query.lineItemCountMax === 'number') lineRange.$lte = query.lineItemCountMax\n if (Object.keys(lineRange).length) {\n filters.line_item_count = lineRange\n }\n const netRange: Record<string, number> = {}\n if (typeof query.totalNetMin === 'number') netRange.$gte = query.totalNetMin\n if (typeof query.totalNetMax === 'number') netRange.$lte = query.totalNetMax\n if (Object.keys(netRange).length) {\n filters.grand_total_net_amount = netRange\n }\n const grossRange: Record<string, number> = {}\n if (typeof query.totalGrossMin === 'number') grossRange.$gte = query.totalGrossMin\n if (typeof query.totalGrossMax === 'number') grossRange.$lte = query.totalGrossMax\n if (Object.keys(grossRange).length) {\n filters.grand_total_gross_amount = grossRange\n }\n const dateRange: Record<string, Date> = {}\n if (query.dateFrom) {\n const from = new Date(query.dateFrom)\n if (!Number.isNaN(from.getTime())) dateRange.$gte = from\n }\n if (query.dateTo) {\n const to = new Date(query.dateTo)\n if (!Number.isNaN(to.getTime())) dateRange.$lte = to\n }\n if (Object.keys(dateRange).length) {\n filters.created_at = dateRange\n }\n const tagIdsRaw = typeof query.tagIds === 'string' ? query.tagIds : ''\n const tagIds = tagIdsRaw\n .split(',')\n .map((value) => value.trim())\n .filter((value) => value.length > 0)\n if (parseBooleanToken(query.tagIdsEmpty) === true) {\n filters.id = { $eq: '00000000-0000-0000-0000-000000000000' }\n } else if (tagIds.length) {\n filters['tag_assignments.tag_id'] = { $in: tagIds }\n filters['tag_assignments.document_kind'] = { $eq: kind }\n }\n return filters\n}\n\nfunction buildSortMap(numberColumn: string) {\n return {\n id: 'id',\n number: numberColumn,\n placedAt: 'placed_at',\n lineItemCount: 'line_item_count',\n grandTotalNetAmount: 'grand_total_net_amount',\n grandTotalGrossAmount: 'grand_total_gross_amount',\n createdAt: 'created_at',\n updatedAt: 'updated_at',\n }\n}\n\nconst mapUpdateResponse = (entity: any) => ({\n id: entity?.id ?? null,\n orderNumber: entity?.orderNumber ?? null,\n quoteNumber: entity?.quoteNumber ?? null,\n customerEntityId: entity?.customerEntityId ?? null,\n customerContactId: entity?.customerContactId ?? null,\n customerSnapshot: entity?.customerSnapshot ?? null,\n metadata: entity?.metadata ?? null,\n externalReference: entity?.externalReference ?? null,\n customerReference: entity?.customerReference ?? null,\n comment: entity?.comments ?? null,\n statusEntryId: (entity as any)?.statusEntryId ?? null,\n status: (entity as any)?.status ?? null,\n channelId: (entity as any)?.channelId ?? null,\n customerName: resolveCustomerName(entity?.customerSnapshot ?? null, entity?.customerEntityId ?? null),\n contactEmail:\n resolveCustomerEmail(entity?.customerSnapshot ?? null) ??\n (typeof entity?.metadata?.customerEmail === 'string' ? entity.metadata.customerEmail : null),\n currencyCode: entity?.currencyCode ?? null,\n placedAt: entity?.placedAt ? entity.placedAt.toISOString() : null,\n expectedDeliveryAt: entity?.expectedDeliveryAt ? entity.expectedDeliveryAt.toISOString() : null,\n shippingAddressId: entity?.shippingAddressId ?? null,\n billingAddressId: entity?.billingAddressId ?? null,\n shippingAddressSnapshot: entity?.shippingAddressSnapshot ?? null,\n billingAddressSnapshot: entity?.billingAddressSnapshot ?? null,\n shippingMethodId: entity?.shippingMethodId ?? null,\n shippingMethodCode: entity?.shippingMethodCode ?? null,\n shippingMethodSnapshot: entity?.shippingMethodSnapshot ?? null,\n paymentMethodId: entity?.paymentMethodId ?? null,\n paymentMethodCode: entity?.paymentMethodCode ?? null,\n paymentMethodSnapshot: entity?.paymentMethodSnapshot ?? null,\n})\n\nconst attachTags = async (payload: any, ctx: any) => {\n const items = Array.isArray(payload?.items) ? (payload.items as Array<Record<string, any>>) : []\n if (!items.length) return\n const ids = items\n .map((item) => (item && typeof item.id === 'string' ? item.id : null))\n .filter((id): id is string => !!id)\n if (!ids.length) return\n const em = ctx?.container?.resolve ? (ctx.container.resolve('em') as any) : null\n if (!em) return\n const where: Record<string, unknown> = {\n documentId: { $in: ids },\n documentKind: ctx?.bindingKind ?? null,\n }\n if (ctx?.auth?.tenantId) where.tenantId = ctx.auth.tenantId\n const orgIds =\n Array.isArray(ctx?.organizationIds) && ctx.organizationIds.length\n ? ctx.organizationIds.filter((val: string | null) => !!val)\n : ctx?.selectedOrganizationId\n ? [ctx.selectedOrganizationId]\n : []\n if (orgIds.length) where.organizationId = { $in: orgIds }\n const assignments = await em.find(\n SalesDocumentTagAssignment,\n where,\n { populate: ['tag'] },\n )\n const grouped = new Map<string, Array<{ id: string; label: string; color: string | null }>>()\n assignments.forEach((assignment: any) => {\n const tag = assignment?.tag\n const documentId = assignment?.documentId\n if (!tag || typeof tag.id !== 'string' || typeof documentId !== 'string') return\n const entry = {\n id: tag.id,\n label: typeof tag.label === 'string' && tag.label.trim().length ? tag.label : tag.slug ?? tag.id,\n color: typeof tag.color === 'string' && tag.color.trim().length ? tag.color : null,\n }\n const list = grouped.get(documentId) ?? []\n list.push(entry)\n grouped.set(documentId, list)\n })\n items.forEach((item: Record<string, any>) => {\n const id = item && typeof item.id === 'string' ? item.id : null\n if (!id) return\n const list = grouped.get(id)\n if (list) item.tags = list\n })\n}\n\nasync function ensureNumberEditPermission(\n ctx: CrudCtx,\n translate: (key: string, fallback?: string) => string\n) {\n const rbac = ctx.container?.resolve?.('rbacService') as RbacService | null\n const auth = ctx.auth\n if (!rbac || !auth?.sub) return\n const ok = await rbac.userHasAllFeatures(auth.sub, ['sales.documents.number.edit'], {\n tenantId: auth.tenantId ?? null,\n organizationId: ctx.selectedOrganizationId ?? auth.orgId ?? null,\n })\n if (!ok) {\n throw new CrudHttpError(403, {\n error: translate('sales.documents.errors.number_edit_forbidden', 'You cannot edit document numbers.'),\n })\n }\n}\n\nexport function buildDocumentCrudOptions(binding: DocumentBinding) {\n const numberColumn = binding.numberField === 'orderNumber' ? 'order_number' : 'quote_number'\n const createSchema = binding.kind === 'order' ? orderCreateSchema : quoteCreateSchema\n\n const routeMetadata = {\n GET: { requireAuth: true, requireFeatures: [binding.viewFeature] },\n POST: { requireAuth: true, requireFeatures: [binding.manageFeature] },\n PUT: { requireAuth: true, requireFeatures: [binding.manageFeature] },\n DELETE: { requireAuth: true, requireFeatures: [binding.manageFeature] },\n }\n\n const commonFields = [\n 'id',\n numberColumn,\n 'status',\n 'status_entry_id',\n 'customer_entity_id',\n 'customer_contact_id',\n 'billing_address_id',\n 'shipping_address_id',\n 'customer_snapshot',\n 'billing_address_snapshot',\n 'shipping_address_snapshot',\n 'shipping_method_id',\n 'shipping_method_code',\n 'shipping_method_snapshot',\n 'payment_method_id',\n 'payment_method_code',\n 'payment_method_snapshot',\n 'customer_reference',\n 'metadata',\n 'external_reference',\n 'currency_code',\n 'comments',\n 'channel_id',\n 'placed_at',\n 'line_item_count',\n 'subtotal_net_amount',\n 'subtotal_gross_amount',\n 'tax_total_amount',\n 'discount_total_amount',\n 'grand_total_net_amount',\n 'grand_total_gross_amount',\n 'totals_snapshot',\n 'organization_id',\n 'tenant_id',\n 'created_at',\n 'updated_at',\n ]\n\n const orderOnlyFields = [\n 'expected_delivery_at',\n 'shipping_net_amount',\n 'shipping_gross_amount',\n 'surcharge_total_amount',\n 'paid_total_amount',\n 'refunded_total_amount',\n 'outstanding_amount',\n ]\n\n const quoteOnlyFields = ['valid_from', 'valid_until']\n\n const listFields = [\n ...commonFields,\n ...(binding.kind === 'order' ? orderOnlyFields : quoteOnlyFields),\n ]\n\n return {\n metadata: routeMetadata,\n orm: {\n entity: binding.entity as any,\n idField: 'id',\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n indexer: {\n entityType: binding.entityId,\n },\n list: {\n schema: listSchema,\n entityId: binding.entityId,\n fields: listFields,\n sortFieldMap: buildSortMap(numberColumn),\n buildFilters: async (query: any) => buildFilters(query, numberColumn, binding.kind),\n decorateCustomFields: { entityIds: [binding.entityId] },\n joins: [\n {\n alias: 'tag_assignments',\n table: 'sales_document_tag_assignments',\n from: { field: 'id' },\n to: { field: 'document_id' },\n type: 'left' as const,\n },\n ],\n transformItem: (item: any) => {\n const toNumber = (value: unknown): number | null => {\n if (typeof value === 'number') return Number.isNaN(value) ? null : value\n if (typeof value === 'string' && value.trim().length) {\n const parsed = Number(value)\n return Number.isNaN(parsed) ? null : parsed\n }\n return null\n }\n const base = {\n id: item.id,\n [binding.numberField]: item[numberColumn] ?? null,\n status: item.status ?? null,\n statusEntryId: item.status_entry_id ?? null,\n customerEntityId: item.customer_entity_id ?? null,\n customerContactId: item.customer_contact_id ?? null,\n billingAddressId: item.billing_address_id ?? null,\n shippingAddressId: item.shipping_address_id ?? null,\n shippingMethodId: item.shipping_method_id ?? null,\n shippingMethodCode: item.shipping_method_code ?? null,\n shippingMethodSnapshot: item.shipping_method_snapshot ?? null,\n paymentMethodId: item.payment_method_id ?? null,\n paymentMethodCode: item.payment_method_code ?? null,\n paymentMethodSnapshot: item.payment_method_snapshot ?? null,\n currencyCode: item.currency_code ?? null,\n channelId: item.channel_id ?? null,\n externalReference: item.external_reference ?? null,\n customerReference: item.customer_reference ?? null,\n placedAt: item.placed_at ?? null,\n expectedDeliveryAt: item.expected_delivery_at ?? null,\n comment: item.comments ?? null,\n validFrom: item.valid_from ?? null,\n validUntil: item.valid_until ?? null,\n lineItemCount: toNumber(item.line_item_count),\n subtotalNetAmount: toNumber(item.subtotal_net_amount),\n subtotalGrossAmount: toNumber(item.subtotal_gross_amount),\n discountTotalAmount: toNumber(item.discount_total_amount),\n taxTotalAmount: toNumber(item.tax_total_amount),\n shippingNetAmount: toNumber(item.shipping_net_amount),\n shippingGrossAmount: toNumber(item.shipping_gross_amount),\n surchargeTotalAmount: toNumber(item.surcharge_total_amount),\n grandTotalNetAmount: toNumber(item.grand_total_net_amount),\n grandTotalGrossAmount: toNumber(item.grand_total_gross_amount),\n paidTotalAmount: toNumber(item.paid_total_amount),\n refundedTotalAmount: toNumber(item.refunded_total_amount),\n outstandingAmount: toNumber(item.outstanding_amount),\n customerSnapshot: item.customer_snapshot ?? null,\n billingAddressSnapshot: item.billing_address_snapshot ?? null,\n shippingAddressSnapshot: item.shipping_address_snapshot ?? null,\n metadata: item.metadata ?? null,\n organizationId: item.organization_id ?? null,\n tenantId: item.tenant_id ?? null,\n createdAt: item.created_at,\n updatedAt: item.updated_at,\n }\n const cfEntries = extractAllCustomFieldEntries(item as Record<string, unknown>)\n const normalized = { ...base }\n Object.keys(normalized).forEach((key) => {\n if (key.startsWith('cf:')) delete (normalized as any)[key]\n })\n return Object.keys(cfEntries).length ? { ...normalized, ...cfEntries } : normalized\n },\n },\n actions: {\n create: {\n commandId: binding.createCommandId,\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }: { raw: unknown; ctx: CrudCtx }) => {\n const { translate } = await resolveTranslations()\n const { base, custom } = splitCustomFieldPayload(raw ?? {})\n const parsed = parseScopedCommandInput(\n createSchema,\n Object.keys(custom).length ? { ...base, customFields: custom } : base,\n ctx,\n translate,\n )\n return parsed\n },\n response: ({ result }: { result: any }) => ({ id: result?.orderId ?? result?.quoteId ?? result?.id ?? null }),\n status: 201,\n },\n update: {\n commandId: binding.updateCommandId,\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }: { raw: unknown; ctx: CrudCtx }) => {\n const { translate } = await resolveTranslations()\n const { base, custom } = splitCustomFieldPayload(raw ?? {})\n const numberValue =\n binding.kind === 'order'\n ? (base as Record<string, unknown>).orderNumber\n : (base as Record<string, unknown>).quoteNumber\n if (typeof numberValue === 'string') {\n await ensureNumberEditPermission(ctx, translate)\n }\n const parsed = parseScopedCommandInput(\n documentUpdateSchema,\n Object.keys(custom).length ? { ...base, customFields: custom } : base,\n ctx,\n translate,\n )\n return parsed\n },\n response: ({ result }: { result: any }) =>\n mapUpdateResponse((result as any)?.order ?? (result as any)?.quote ?? result),\n },\n delete: {\n commandId: binding.deleteCommandId,\n schema: rawBodySchema,\n mapInput: async ({ parsed, ctx }: { parsed: any; ctx: CrudCtx }) => {\n const { translate } = await resolveTranslations()\n const id = resolveCrudRecordId(parsed, ctx, translate)\n return { id }\n },\n response: () => ({ ok: true }),\n },\n },\n hooks: {\n afterList: async (payload: any, ctx: CrudCtx) => {\n await attachTags(payload, { ...ctx, bindingKind: binding.kind })\n if (binding.kind === 'order' && Array.isArray(payload?.items) && payload.items.length === 1) {\n const item = payload.items[0] as Record<string, unknown>\n const orderId = typeof item?.id === 'string' ? item.id : null\n const tenantId = typeof item?.tenantId === 'string' ? item.tenantId : ctx?.auth?.tenantId ?? null\n const organizationId =\n typeof item?.organizationId === 'string' ? item.organizationId : ctx?.selectedOrganizationId ?? ctx?.auth?.orgId ?? null\n if (orderId && tenantId && organizationId) {\n const em = ctx?.container?.resolve?.('em') as import('@mikro-orm/postgresql').EntityManager | undefined\n if (em) {\n const totals = await recalculateOrderTotalsForDisplay(\n em,\n ctx.container,\n orderId,\n { tenantId, organizationId },\n )\n if (totals) {\n Object.assign(item, {\n subtotalNetAmount: totals.subtotalNetAmount,\n subtotalGrossAmount: totals.subtotalGrossAmount,\n discountTotalAmount: totals.discountTotalAmount,\n taxTotalAmount: totals.taxTotalAmount,\n shippingNetAmount: totals.shippingNetAmount,\n shippingGrossAmount: totals.shippingGrossAmount,\n surchargeTotalAmount: totals.surchargeTotalAmount,\n grandTotalNetAmount: totals.grandTotalNetAmount,\n grandTotalGrossAmount: totals.grandTotalGrossAmount,\n paidTotalAmount: totals.paidTotalAmount,\n refundedTotalAmount: totals.refundedTotalAmount,\n outstandingAmount: totals.outstandingAmount,\n })\n }\n }\n }\n }\n },\n },\n }\n}\n\nexport function buildDocumentOpenApi(binding: DocumentBinding) {\n const createSchema = binding.kind === 'order' ? orderCreateSchema : quoteCreateSchema\n const itemSchema = z.object({\n id: z.string().uuid(),\n [binding.numberField]: z.string().nullable(),\n status: z.string().nullable(),\n statusEntryId: z.string().uuid().nullable().optional(),\n customerEntityId: z.string().uuid().nullable(),\n customerContactId: z.string().uuid().nullable(),\n billingAddressId: z.string().uuid().nullable(),\n shippingAddressId: z.string().uuid().nullable(),\n customerReference: z.string().nullable().optional(),\n externalReference: z.string().nullable().optional(),\n comment: z.string().nullable().optional(),\n placedAt: z.string().nullable().optional(),\n expectedDeliveryAt: z.string().nullable().optional(),\n customerSnapshot: z.record(z.string(), z.unknown()).nullable().optional(),\n billingAddressSnapshot: z.record(z.string(), z.unknown()).nullable().optional(),\n shippingAddressSnapshot: z.record(z.string(), z.unknown()).nullable().optional(),\n shippingMethodId: z.string().uuid().nullable().optional(),\n shippingMethodCode: z.string().nullable().optional(),\n shippingMethodSnapshot: z.record(z.string(), z.unknown()).nullable().optional(),\n paymentMethodId: z.string().uuid().nullable().optional(),\n paymentMethodCode: z.string().nullable().optional(),\n paymentMethodSnapshot: z.record(z.string(), z.unknown()).nullable().optional(),\n currencyCode: z.string().nullable(),\n channelId: z.string().uuid().nullable(),\n organizationId: z.string().uuid().nullable(),\n tenantId: z.string().uuid().nullable(),\n validFrom: z.string().nullable().optional(),\n validUntil: z.string().nullable().optional(),\n lineItemCount: z.number().nullable().optional(),\n subtotalNetAmount: z.number().nullable().optional(),\n subtotalGrossAmount: z.number().nullable().optional(),\n discountTotalAmount: z.number().nullable().optional(),\n taxTotalAmount: z.number().nullable().optional(),\n shippingNetAmount: z.number().nullable().optional(),\n shippingGrossAmount: z.number().nullable().optional(),\n surchargeTotalAmount: z.number().nullable().optional(),\n grandTotalNetAmount: z.number().nullable().optional(),\n grandTotalGrossAmount: z.number().nullable().optional(),\n paidTotalAmount: z.number().nullable().optional(),\n refundedTotalAmount: z.number().nullable().optional(),\n outstandingAmount: z.number().nullable().optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n customFields: z.record(z.string(), z.unknown()).optional(),\n customValues: z.record(z.string(), z.unknown()).optional(),\n })\n\n const listResponseSchema = createPagedListResponseSchema(itemSchema)\n\n return createSalesCrudOpenApi({\n resourceName: binding.kind === 'order' ? 'Order' : 'Quote',\n querySchema: listSchema,\n listResponseSchema,\n create: {\n schema: createSchema,\n responseSchema: z.object({ id: z.string().uuid().nullable() }),\n description: `Creates a new sales ${binding.kind}.`,\n },\n del: {\n schema: defaultDeleteRequestSchema,\n responseSchema: z.object({ ok: z.boolean() }),\n description: `Deletes a sales ${binding.kind}.`,\n },\n })\n}\n\n// Compatibility wrapper\nexport function createDocumentCrudRoute(binding: DocumentBinding) {\n const crud = makeCrudRoute(buildDocumentCrudOptions(binding))\n const { GET, POST, PUT, DELETE } = crud\n return { GET, POST, PUT, DELETE, openApi: buildDocumentOpenApi(binding), metadata: crud.metadata }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { z } from 'zod'\nimport { makeCrudRoute, type CrudCtx } from '@open-mercato/shared/lib/crud/factory'\nimport { splitCustomFieldPayload, extractAllCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { E } from '#generated/entities.ids.generated'\nimport type { SalesOrder, SalesQuote } from '../../data/entities'\nimport { SalesDocumentTagAssignment } from '../../data/entities'\nimport {\n orderCreateSchema,\n quoteCreateSchema,\n} from '../../data/validators'\nimport {\n createPagedListResponseSchema,\n createSalesCrudOpenApi,\n defaultDeleteRequestSchema,\n} from '../openapi'\nimport { parseScopedCommandInput, resolveCrudRecordId } from '../utils'\nimport { documentUpdateSchema } from '../../commands/documents'\nimport { escapeLikePattern } from '@open-mercato/shared/lib/db/escapeLikePattern'\nimport { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\nimport type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\nimport { recalculateOrderTotalsForDisplay } from '../../commands/returns'\nimport { parseDecryptedFieldValue } from '@open-mercato/shared/lib/encryption/tenantDataEncryptionService'\n\ntype DocumentKind = 'order' | 'quote'\n\ntype DocumentBinding = {\n kind: DocumentKind\n entity: typeof SalesOrder | typeof SalesQuote\n entityId: (typeof E.sales)[keyof typeof E.sales]\n numberField: 'orderNumber' | 'quoteNumber'\n createCommandId: string\n updateCommandId: string\n deleteCommandId: string\n manageFeature: string\n viewFeature: string\n}\n\nconst rawBodySchema = z.object({}).passthrough()\n\nconst normalizeJsonRecord = (value: unknown): Record<string, unknown> | null => {\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n return value as Record<string, unknown>\n }\n if (typeof value !== 'string') return null\n const parsed = parseDecryptedFieldValue(value)\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed)\n ? parsed as Record<string, unknown>\n : null\n}\n\nconst resolveCustomerName = (snapshot: Record<string, unknown> | null, fallback?: string | null) => {\n if (!snapshot) return fallback ?? null\n const customer = snapshot.customer as Record<string, unknown> | undefined\n const contact = snapshot.contact as Record<string, unknown> | undefined\n const displayName = typeof customer?.displayName === 'string' ? customer.displayName : null\n if (displayName) return displayName\n const first = typeof contact?.firstName === 'string' ? contact.firstName : null\n const last = typeof contact?.lastName === 'string' ? contact.lastName : null\n const preferred = typeof contact?.preferredName === 'string' ? contact.preferredName : null\n const parts = [preferred ?? first, last].filter((part) => part && part.trim().length)\n if (parts.length) return parts.join(' ')\n return fallback ?? null\n}\n\nconst resolveCustomerEmail = (snapshot: Record<string, unknown> | null) => {\n if (!snapshot) return null\n const customer = snapshot.customer as Record<string, unknown> | undefined\n const primary = typeof customer?.primaryEmail === 'string' ? customer.primaryEmail : null\n return primary ?? null\n}\n\nconst listSchema = z\n .object({\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 id: z.string().uuid().optional(),\n customerId: z.string().uuid().optional(),\n channelId: z.string().uuid().optional(),\n lineItemCountMin: z.coerce.number().min(0).optional(),\n lineItemCountMax: z.coerce.number().min(0).optional(),\n totalNetMin: z.coerce.number().optional(),\n totalNetMax: z.coerce.number().optional(),\n totalGrossMin: z.coerce.number().optional(),\n totalGrossMax: z.coerce.number().optional(),\n dateFrom: z.string().optional(),\n dateTo: z.string().optional(),\n tagIds: z.string().optional(),\n tagIdsEmpty: z.string().optional(),\n sortField: z.string().optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n withDeleted: z.coerce.boolean().optional(),\n })\n .passthrough()\n\ntype ListQuery = z.infer<typeof listSchema>\n\nfunction buildFilters(query: ListQuery, numberColumn: string, kind: DocumentKind) {\n const filters: Record<string, unknown> = {}\n if (query.id) filters.id = { $eq: query.id }\n if (query.search && query.search.trim().length > 0) {\n const term = `%${escapeLikePattern(query.search.trim())}%`\n filters[numberColumn] = { $ilike: term }\n }\n if (query.customerId) {\n filters.customer_entity_id = { $eq: query.customerId }\n }\n if (query.channelId) {\n filters.channel_id = { $eq: query.channelId }\n }\n const lineRange: Record<string, number> = {}\n if (typeof query.lineItemCountMin === 'number') lineRange.$gte = query.lineItemCountMin\n if (typeof query.lineItemCountMax === 'number') lineRange.$lte = query.lineItemCountMax\n if (Object.keys(lineRange).length) {\n filters.line_item_count = lineRange\n }\n const netRange: Record<string, number> = {}\n if (typeof query.totalNetMin === 'number') netRange.$gte = query.totalNetMin\n if (typeof query.totalNetMax === 'number') netRange.$lte = query.totalNetMax\n if (Object.keys(netRange).length) {\n filters.grand_total_net_amount = netRange\n }\n const grossRange: Record<string, number> = {}\n if (typeof query.totalGrossMin === 'number') grossRange.$gte = query.totalGrossMin\n if (typeof query.totalGrossMax === 'number') grossRange.$lte = query.totalGrossMax\n if (Object.keys(grossRange).length) {\n filters.grand_total_gross_amount = grossRange\n }\n const dateRange: Record<string, Date> = {}\n if (query.dateFrom) {\n const from = new Date(query.dateFrom)\n if (!Number.isNaN(from.getTime())) dateRange.$gte = from\n }\n if (query.dateTo) {\n const to = new Date(query.dateTo)\n if (!Number.isNaN(to.getTime())) dateRange.$lte = to\n }\n if (Object.keys(dateRange).length) {\n filters.created_at = dateRange\n }\n const tagIdsRaw = typeof query.tagIds === 'string' ? query.tagIds : ''\n const tagIds = tagIdsRaw\n .split(',')\n .map((value) => value.trim())\n .filter((value) => value.length > 0)\n if (parseBooleanToken(query.tagIdsEmpty) === true) {\n filters.id = { $eq: '00000000-0000-0000-0000-000000000000' }\n } else if (tagIds.length) {\n filters['tag_assignments.tag_id'] = { $in: tagIds }\n filters['tag_assignments.document_kind'] = { $eq: kind }\n }\n return filters\n}\n\nfunction buildSortMap(numberColumn: string) {\n return {\n id: 'id',\n number: numberColumn,\n placedAt: 'placed_at',\n lineItemCount: 'line_item_count',\n grandTotalNetAmount: 'grand_total_net_amount',\n grandTotalGrossAmount: 'grand_total_gross_amount',\n createdAt: 'created_at',\n updatedAt: 'updated_at',\n }\n}\n\nconst mapUpdateResponse = (entity: any) => {\n const customerSnapshot = normalizeJsonRecord(entity?.customerSnapshot)\n const metadata = normalizeJsonRecord(entity?.metadata)\n\n return {\n id: entity?.id ?? null,\n orderNumber: entity?.orderNumber ?? null,\n quoteNumber: entity?.quoteNumber ?? null,\n customerEntityId: entity?.customerEntityId ?? null,\n customerContactId: entity?.customerContactId ?? null,\n customerSnapshot,\n metadata,\n externalReference: entity?.externalReference ?? null,\n customerReference: entity?.customerReference ?? null,\n comment: entity?.comments ?? null,\n statusEntryId: (entity as any)?.statusEntryId ?? null,\n status: (entity as any)?.status ?? null,\n channelId: (entity as any)?.channelId ?? null,\n customerName: resolveCustomerName(customerSnapshot, entity?.customerEntityId ?? null),\n contactEmail:\n resolveCustomerEmail(customerSnapshot) ??\n (typeof metadata?.customerEmail === 'string' ? metadata.customerEmail : null),\n currencyCode: entity?.currencyCode ?? null,\n placedAt: entity?.placedAt ? entity.placedAt.toISOString() : null,\n expectedDeliveryAt: entity?.expectedDeliveryAt ? entity.expectedDeliveryAt.toISOString() : null,\n shippingAddressId: entity?.shippingAddressId ?? null,\n billingAddressId: entity?.billingAddressId ?? null,\n shippingAddressSnapshot: normalizeJsonRecord(entity?.shippingAddressSnapshot),\n billingAddressSnapshot: normalizeJsonRecord(entity?.billingAddressSnapshot),\n shippingMethodId: entity?.shippingMethodId ?? null,\n shippingMethodCode: entity?.shippingMethodCode ?? null,\n shippingMethodSnapshot: normalizeJsonRecord(entity?.shippingMethodSnapshot),\n paymentMethodId: entity?.paymentMethodId ?? null,\n paymentMethodCode: entity?.paymentMethodCode ?? null,\n paymentMethodSnapshot: normalizeJsonRecord(entity?.paymentMethodSnapshot),\n }\n}\n\nconst attachTags = async (payload: any, ctx: any) => {\n const items = Array.isArray(payload?.items) ? (payload.items as Array<Record<string, any>>) : []\n if (!items.length) return\n const ids = items\n .map((item) => (item && typeof item.id === 'string' ? item.id : null))\n .filter((id): id is string => !!id)\n if (!ids.length) return\n const em = ctx?.container?.resolve ? (ctx.container.resolve('em') as any) : null\n if (!em) return\n const where: Record<string, unknown> = {\n documentId: { $in: ids },\n documentKind: ctx?.bindingKind ?? null,\n }\n if (ctx?.auth?.tenantId) where.tenantId = ctx.auth.tenantId\n const orgIds =\n Array.isArray(ctx?.organizationIds) && ctx.organizationIds.length\n ? ctx.organizationIds.filter((val: string | null) => !!val)\n : ctx?.selectedOrganizationId\n ? [ctx.selectedOrganizationId]\n : []\n if (orgIds.length) where.organizationId = { $in: orgIds }\n const assignments = await em.find(\n SalesDocumentTagAssignment,\n where,\n { populate: ['tag'] },\n )\n const grouped = new Map<string, Array<{ id: string; label: string; color: string | null }>>()\n assignments.forEach((assignment: any) => {\n const tag = assignment?.tag\n const documentId = assignment?.documentId\n if (!tag || typeof tag.id !== 'string' || typeof documentId !== 'string') return\n const entry = {\n id: tag.id,\n label: typeof tag.label === 'string' && tag.label.trim().length ? tag.label : tag.slug ?? tag.id,\n color: typeof tag.color === 'string' && tag.color.trim().length ? tag.color : null,\n }\n const list = grouped.get(documentId) ?? []\n list.push(entry)\n grouped.set(documentId, list)\n })\n items.forEach((item: Record<string, any>) => {\n const id = item && typeof item.id === 'string' ? item.id : null\n if (!id) return\n const list = grouped.get(id)\n if (list) item.tags = list\n })\n}\n\nasync function ensureNumberEditPermission(\n ctx: CrudCtx,\n translate: (key: string, fallback?: string) => string\n) {\n const rbac = ctx.container?.resolve?.('rbacService') as RbacService | null\n const auth = ctx.auth\n if (!rbac || !auth?.sub) return\n const ok = await rbac.userHasAllFeatures(auth.sub, ['sales.documents.number.edit'], {\n tenantId: auth.tenantId ?? null,\n organizationId: ctx.selectedOrganizationId ?? auth.orgId ?? null,\n })\n if (!ok) {\n throw new CrudHttpError(403, {\n error: translate('sales.documents.errors.number_edit_forbidden', 'You cannot edit document numbers.'),\n })\n }\n}\n\nexport function buildDocumentCrudOptions(binding: DocumentBinding) {\n const numberColumn = binding.numberField === 'orderNumber' ? 'order_number' : 'quote_number'\n const createSchema = binding.kind === 'order' ? orderCreateSchema : quoteCreateSchema\n\n const routeMetadata = {\n GET: { requireAuth: true, requireFeatures: [binding.viewFeature] },\n POST: { requireAuth: true, requireFeatures: [binding.manageFeature] },\n PUT: { requireAuth: true, requireFeatures: [binding.manageFeature] },\n DELETE: { requireAuth: true, requireFeatures: [binding.manageFeature] },\n }\n\n const commonFields = [\n 'id',\n numberColumn,\n 'status',\n 'status_entry_id',\n 'customer_entity_id',\n 'customer_contact_id',\n 'billing_address_id',\n 'shipping_address_id',\n 'customer_snapshot',\n 'billing_address_snapshot',\n 'shipping_address_snapshot',\n 'shipping_method_id',\n 'shipping_method_code',\n 'shipping_method_snapshot',\n 'payment_method_id',\n 'payment_method_code',\n 'payment_method_snapshot',\n 'customer_reference',\n 'metadata',\n 'external_reference',\n 'currency_code',\n 'comments',\n 'channel_id',\n 'placed_at',\n 'line_item_count',\n 'subtotal_net_amount',\n 'subtotal_gross_amount',\n 'tax_total_amount',\n 'discount_total_amount',\n 'grand_total_net_amount',\n 'grand_total_gross_amount',\n 'totals_snapshot',\n 'organization_id',\n 'tenant_id',\n 'created_at',\n 'updated_at',\n ]\n\n const orderOnlyFields = [\n 'expected_delivery_at',\n 'shipping_net_amount',\n 'shipping_gross_amount',\n 'surcharge_total_amount',\n 'paid_total_amount',\n 'refunded_total_amount',\n 'outstanding_amount',\n ]\n\n const quoteOnlyFields = ['valid_from', 'valid_until']\n\n const listFields = [\n ...commonFields,\n ...(binding.kind === 'order' ? orderOnlyFields : quoteOnlyFields),\n ]\n\n return {\n metadata: routeMetadata,\n orm: {\n entity: binding.entity as any,\n idField: 'id',\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n indexer: {\n entityType: binding.entityId,\n },\n list: {\n schema: listSchema,\n entityId: binding.entityId,\n fields: listFields,\n sortFieldMap: buildSortMap(numberColumn),\n buildFilters: async (query: any) => buildFilters(query, numberColumn, binding.kind),\n decorateCustomFields: { entityIds: [binding.entityId] },\n joins: [\n {\n alias: 'tag_assignments',\n table: 'sales_document_tag_assignments',\n from: { field: 'id' },\n to: { field: 'document_id' },\n type: 'left' as const,\n },\n ],\n transformItem: (item: any) => {\n const toNumber = (value: unknown): number | null => {\n if (typeof value === 'number') return Number.isNaN(value) ? null : value\n if (typeof value === 'string' && value.trim().length) {\n const parsed = Number(value)\n return Number.isNaN(parsed) ? null : parsed\n }\n return null\n }\n const base = {\n id: item.id,\n [binding.numberField]: item[numberColumn] ?? null,\n status: item.status ?? null,\n statusEntryId: item.status_entry_id ?? null,\n customerEntityId: item.customer_entity_id ?? null,\n customerContactId: item.customer_contact_id ?? null,\n billingAddressId: item.billing_address_id ?? null,\n shippingAddressId: item.shipping_address_id ?? null,\n shippingMethodId: item.shipping_method_id ?? null,\n shippingMethodCode: item.shipping_method_code ?? null,\n shippingMethodSnapshot: normalizeJsonRecord(item.shipping_method_snapshot),\n paymentMethodId: item.payment_method_id ?? null,\n paymentMethodCode: item.payment_method_code ?? null,\n paymentMethodSnapshot: normalizeJsonRecord(item.payment_method_snapshot),\n currencyCode: item.currency_code ?? null,\n channelId: item.channel_id ?? null,\n externalReference: item.external_reference ?? null,\n customerReference: item.customer_reference ?? null,\n placedAt: item.placed_at ?? null,\n expectedDeliveryAt: item.expected_delivery_at ?? null,\n comment: item.comments ?? null,\n validFrom: item.valid_from ?? null,\n validUntil: item.valid_until ?? null,\n lineItemCount: toNumber(item.line_item_count),\n subtotalNetAmount: toNumber(item.subtotal_net_amount),\n subtotalGrossAmount: toNumber(item.subtotal_gross_amount),\n discountTotalAmount: toNumber(item.discount_total_amount),\n taxTotalAmount: toNumber(item.tax_total_amount),\n shippingNetAmount: toNumber(item.shipping_net_amount),\n shippingGrossAmount: toNumber(item.shipping_gross_amount),\n surchargeTotalAmount: toNumber(item.surcharge_total_amount),\n grandTotalNetAmount: toNumber(item.grand_total_net_amount),\n grandTotalGrossAmount: toNumber(item.grand_total_gross_amount),\n paidTotalAmount: toNumber(item.paid_total_amount),\n refundedTotalAmount: toNumber(item.refunded_total_amount),\n outstandingAmount: toNumber(item.outstanding_amount),\n customerSnapshot: normalizeJsonRecord(item.customer_snapshot),\n billingAddressSnapshot: normalizeJsonRecord(item.billing_address_snapshot),\n shippingAddressSnapshot: normalizeJsonRecord(item.shipping_address_snapshot),\n metadata: normalizeJsonRecord(item.metadata),\n organizationId: item.organization_id ?? null,\n tenantId: item.tenant_id ?? null,\n createdAt: item.created_at,\n updatedAt: item.updated_at,\n }\n const cfEntries = extractAllCustomFieldEntries(item as Record<string, unknown>)\n const normalized = { ...base }\n Object.keys(normalized).forEach((key) => {\n if (key.startsWith('cf:')) delete (normalized as any)[key]\n })\n return Object.keys(cfEntries).length ? { ...normalized, ...cfEntries } : normalized\n },\n },\n actions: {\n create: {\n commandId: binding.createCommandId,\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }: { raw: unknown; ctx: CrudCtx }) => {\n const { translate } = await resolveTranslations()\n const { base, custom } = splitCustomFieldPayload(raw ?? {})\n const parsed = parseScopedCommandInput(\n createSchema,\n Object.keys(custom).length ? { ...base, customFields: custom } : base,\n ctx,\n translate,\n )\n return parsed\n },\n response: ({ result }: { result: any }) => ({ id: result?.orderId ?? result?.quoteId ?? result?.id ?? null }),\n status: 201,\n },\n update: {\n commandId: binding.updateCommandId,\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }: { raw: unknown; ctx: CrudCtx }) => {\n const { translate } = await resolveTranslations()\n const { base, custom } = splitCustomFieldPayload(raw ?? {})\n const numberValue =\n binding.kind === 'order'\n ? (base as Record<string, unknown>).orderNumber\n : (base as Record<string, unknown>).quoteNumber\n if (typeof numberValue === 'string') {\n await ensureNumberEditPermission(ctx, translate)\n }\n const parsed = parseScopedCommandInput(\n documentUpdateSchema,\n Object.keys(custom).length ? { ...base, customFields: custom } : base,\n ctx,\n translate,\n )\n return parsed\n },\n response: ({ result }: { result: any }) =>\n mapUpdateResponse((result as any)?.order ?? (result as any)?.quote ?? result),\n },\n delete: {\n commandId: binding.deleteCommandId,\n schema: rawBodySchema,\n mapInput: async ({ parsed, ctx }: { parsed: any; ctx: CrudCtx }) => {\n const { translate } = await resolveTranslations()\n const id = resolveCrudRecordId(parsed, ctx, translate)\n return { id }\n },\n response: () => ({ ok: true }),\n },\n },\n hooks: {\n afterList: async (payload: any, ctx: CrudCtx) => {\n await attachTags(payload, { ...ctx, bindingKind: binding.kind })\n if (binding.kind === 'order' && Array.isArray(payload?.items) && payload.items.length === 1) {\n const item = payload.items[0] as Record<string, unknown>\n const orderId = typeof item?.id === 'string' ? item.id : null\n const tenantId = typeof item?.tenantId === 'string' ? item.tenantId : ctx?.auth?.tenantId ?? null\n const organizationId =\n typeof item?.organizationId === 'string' ? item.organizationId : ctx?.selectedOrganizationId ?? ctx?.auth?.orgId ?? null\n if (orderId && tenantId && organizationId) {\n const em = ctx?.container?.resolve?.('em') as import('@mikro-orm/postgresql').EntityManager | undefined\n if (em) {\n const totals = await recalculateOrderTotalsForDisplay(\n em,\n ctx.container,\n orderId,\n { tenantId, organizationId },\n )\n if (totals) {\n Object.assign(item, {\n subtotalNetAmount: totals.subtotalNetAmount,\n subtotalGrossAmount: totals.subtotalGrossAmount,\n discountTotalAmount: totals.discountTotalAmount,\n taxTotalAmount: totals.taxTotalAmount,\n shippingNetAmount: totals.shippingNetAmount,\n shippingGrossAmount: totals.shippingGrossAmount,\n surchargeTotalAmount: totals.surchargeTotalAmount,\n grandTotalNetAmount: totals.grandTotalNetAmount,\n grandTotalGrossAmount: totals.grandTotalGrossAmount,\n paidTotalAmount: totals.paidTotalAmount,\n refundedTotalAmount: totals.refundedTotalAmount,\n outstandingAmount: totals.outstandingAmount,\n })\n }\n }\n }\n }\n },\n },\n }\n}\n\nexport function buildDocumentOpenApi(binding: DocumentBinding) {\n const createSchema = binding.kind === 'order' ? orderCreateSchema : quoteCreateSchema\n const itemSchema = z.object({\n id: z.string().uuid(),\n [binding.numberField]: z.string().nullable(),\n status: z.string().nullable(),\n statusEntryId: z.string().uuid().nullable().optional(),\n customerEntityId: z.string().uuid().nullable(),\n customerContactId: z.string().uuid().nullable(),\n billingAddressId: z.string().uuid().nullable(),\n shippingAddressId: z.string().uuid().nullable(),\n customerReference: z.string().nullable().optional(),\n externalReference: z.string().nullable().optional(),\n comment: z.string().nullable().optional(),\n placedAt: z.string().nullable().optional(),\n expectedDeliveryAt: z.string().nullable().optional(),\n customerSnapshot: z.record(z.string(), z.unknown()).nullable().optional(),\n billingAddressSnapshot: z.record(z.string(), z.unknown()).nullable().optional(),\n shippingAddressSnapshot: z.record(z.string(), z.unknown()).nullable().optional(),\n shippingMethodId: z.string().uuid().nullable().optional(),\n shippingMethodCode: z.string().nullable().optional(),\n shippingMethodSnapshot: z.record(z.string(), z.unknown()).nullable().optional(),\n paymentMethodId: z.string().uuid().nullable().optional(),\n paymentMethodCode: z.string().nullable().optional(),\n paymentMethodSnapshot: z.record(z.string(), z.unknown()).nullable().optional(),\n currencyCode: z.string().nullable(),\n channelId: z.string().uuid().nullable(),\n organizationId: z.string().uuid().nullable(),\n tenantId: z.string().uuid().nullable(),\n validFrom: z.string().nullable().optional(),\n validUntil: z.string().nullable().optional(),\n lineItemCount: z.number().nullable().optional(),\n subtotalNetAmount: z.number().nullable().optional(),\n subtotalGrossAmount: z.number().nullable().optional(),\n discountTotalAmount: z.number().nullable().optional(),\n taxTotalAmount: z.number().nullable().optional(),\n shippingNetAmount: z.number().nullable().optional(),\n shippingGrossAmount: z.number().nullable().optional(),\n surchargeTotalAmount: z.number().nullable().optional(),\n grandTotalNetAmount: z.number().nullable().optional(),\n grandTotalGrossAmount: z.number().nullable().optional(),\n paidTotalAmount: z.number().nullable().optional(),\n refundedTotalAmount: z.number().nullable().optional(),\n outstandingAmount: z.number().nullable().optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n customFields: z.record(z.string(), z.unknown()).optional(),\n customValues: z.record(z.string(), z.unknown()).optional(),\n })\n\n const listResponseSchema = createPagedListResponseSchema(itemSchema)\n\n return createSalesCrudOpenApi({\n resourceName: binding.kind === 'order' ? 'Order' : 'Quote',\n querySchema: listSchema,\n listResponseSchema,\n create: {\n schema: createSchema,\n responseSchema: z.object({ id: z.string().uuid().nullable() }),\n description: `Creates a new sales ${binding.kind}.`,\n },\n del: {\n schema: defaultDeleteRequestSchema,\n responseSchema: z.object({ ok: z.boolean() }),\n description: `Deletes a sales ${binding.kind}.`,\n },\n })\n}\n\n// Compatibility wrapper\nexport function createDocumentCrudRoute(binding: DocumentBinding) {\n const crud = makeCrudRoute(buildDocumentCrudOptions(binding))\n const { GET, POST, PUT, DELETE } = crud\n return { GET, POST, PUT, DELETE, openApi: buildDocumentOpenApi(binding), metadata: crud.metadata }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/core",
3
- "version": "0.5.1-develop.3045.b4b3320cc2",
3
+ "version": "0.6.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "scripts": {
@@ -223,9 +223,9 @@
223
223
  }
224
224
  },
225
225
  "dependencies": {
226
- "@mikro-orm/core": "^7.0.13",
227
- "@mikro-orm/decorators": "^7.0.13",
228
- "@mikro-orm/postgresql": "^7.0.13",
226
+ "@mikro-orm/core": "^7.0.14",
227
+ "@mikro-orm/decorators": "^7.0.14",
228
+ "@mikro-orm/postgresql": "^7.0.14",
229
229
  "@xyflow/react": "^12.10.2",
230
230
  "ai": "^6.0.168",
231
231
  "date-fns": "^4.1.0",
@@ -237,12 +237,12 @@
237
237
  "ts-pattern": "^5.0.0"
238
238
  },
239
239
  "peerDependencies": {
240
- "@open-mercato/ai-assistant": "0.5.1-develop.3045.b4b3320cc2",
241
- "@open-mercato/shared": "0.5.1-develop.3045.b4b3320cc2"
240
+ "@open-mercato/ai-assistant": "0.6.0",
241
+ "@open-mercato/shared": "0.6.0"
242
242
  },
243
243
  "devDependencies": {
244
- "@open-mercato/ai-assistant": "0.5.1-develop.3045.b4b3320cc2",
245
- "@open-mercato/shared": "0.5.1-develop.3045.b4b3320cc2",
244
+ "@open-mercato/ai-assistant": "0.6.0",
245
+ "@open-mercato/shared": "0.6.0",
246
246
  "@testing-library/dom": "^10.4.1",
247
247
  "@testing-library/jest-dom": "^6.9.1",
248
248
  "@testing-library/react": "^16.3.1",
@@ -262,6 +262,5 @@
262
262
  "type": "git",
263
263
  "url": "https://github.com/open-mercato/open-mercato",
264
264
  "directory": "packages/core"
265
- },
266
- "stableVersion": "0.5.0"
265
+ }
267
266
  }
@@ -12,6 +12,7 @@ import { generateApiKeySecret, hashApiKey } from '../../services/apiKeyService'
12
12
  import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
13
13
  import { enforceTenantSelection, resolveIsSuperAdmin } from '@open-mercato/core/modules/auth/lib/tenantAccess'
14
14
  import { escapeLikePattern } from '@open-mercato/shared/lib/db/escapeLikePattern'
15
+ import { assertActorCanGrantRoles } from '@open-mercato/core/modules/auth/lib/grantChecks'
15
16
 
16
17
  type ApiKeyCrudCtx = CrudCtx & {
17
18
  __apiKeySecret?: { secret: string; prefix: string }
@@ -283,6 +284,14 @@ const crud = makeCrudRoute<
283
284
  roleEntities.push(role)
284
285
  roleIds.push(String(role.id))
285
286
  }
287
+ await assertActorCanGrantRoles({
288
+ em,
289
+ rbacService: ctx.container.resolve('rbacService') as RbacService,
290
+ actorUserId: auth.sub,
291
+ tenantId: targetTenantId,
292
+ organizationId: auth.orgId ?? null,
293
+ roles: roleEntities,
294
+ })
286
295
  scopedCtx.__apiKeyRoles = roleEntities
287
296
  scopedCtx.__apiKeyRoleIds = roleIds
288
297