@open-mercato/core 0.6.3-develop.3609.1.01983ef87a → 0.6.3-develop.3635.1.e4a05c16e8

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.
@@ -30,6 +30,21 @@ async function emitMessageDeletedEvent(_container, payload) {
30
30
  { persistent: true }
31
31
  );
32
32
  }
33
+ async function emitMessageGloballyDeletedEvent(_container, payload) {
34
+ const audience = Array.from(/* @__PURE__ */ new Set([payload.actorUserId, ...payload.recipientUserIds]));
35
+ await emitMessagesEvent(
36
+ "messages.message.deleted",
37
+ {
38
+ messageId: payload.messageId,
39
+ actorUserId: payload.actorUserId,
40
+ target: "global",
41
+ recipientUserIds: audience,
42
+ tenantId: payload.tenantId,
43
+ organizationId: payload.organizationId
44
+ },
45
+ { persistent: true }
46
+ );
47
+ }
33
48
  async function emitMessageIndexUpsert(container, payload) {
34
49
  let bus = null;
35
50
  try {
@@ -263,6 +278,15 @@ const composeMessageCommand = {
263
278
  if (!message) return;
264
279
  message.deletedAt = /* @__PURE__ */ new Date();
265
280
  await em.flush();
281
+ if (!after.message.isDraft) {
282
+ await emitMessageGloballyDeletedEvent(ctx.container, {
283
+ messageId: after.message.id,
284
+ actorUserId: after.message.senderUserId,
285
+ recipientUserIds: after.recipients.map((recipient) => recipient.recipientUserId),
286
+ tenantId: after.message.tenantId,
287
+ organizationId: after.message.organizationId
288
+ });
289
+ }
266
290
  }
267
291
  };
268
292
  const updateDraftCommand = {
@@ -591,6 +615,13 @@ const replyMessageCommand = {
591
615
  if (!message) return;
592
616
  message.deletedAt = /* @__PURE__ */ new Date();
593
617
  await em.flush();
618
+ await emitMessageGloballyDeletedEvent(ctx.container, {
619
+ messageId: after.message.id,
620
+ actorUserId: after.message.senderUserId,
621
+ recipientUserIds: after.recipients.map((recipient) => recipient.recipientUserId),
622
+ tenantId: after.message.tenantId,
623
+ organizationId: after.message.organizationId
624
+ });
594
625
  }
595
626
  };
596
627
  const forwardMessageCommand = {
@@ -729,6 +760,13 @@ const forwardMessageCommand = {
729
760
  if (!message) return;
730
761
  message.deletedAt = /* @__PURE__ */ new Date();
731
762
  await em.flush();
763
+ await emitMessageGloballyDeletedEvent(ctx.container, {
764
+ messageId: after.message.id,
765
+ actorUserId: after.message.senderUserId,
766
+ recipientUserIds: after.recipients.map((recipient) => recipient.recipientUserId),
767
+ tenantId: after.message.tenantId,
768
+ organizationId: after.message.organizationId
769
+ });
732
770
  }
733
771
  };
734
772
  const deleteForActorCommand = {
@@ -775,12 +813,14 @@ const deleteForActorCommand = {
775
813
  return { ok: true };
776
814
  }
777
815
  if (message.senderUserId === input.userId) {
816
+ const recipientRows = await em.find(MessageRecipient, { messageId: input.messageId });
778
817
  message.deletedAt = /* @__PURE__ */ new Date();
779
818
  await em.flush();
780
- await emitMessageDeletedEvent(ctx.container, {
819
+ const recipientUserIds = recipientRows.map((row) => row.recipientUserId).filter((value) => typeof value === "string" && value.length > 0);
820
+ await emitMessageGloballyDeletedEvent(ctx.container, {
781
821
  messageId: input.messageId,
782
822
  actorUserId: input.userId,
783
- target: "sender",
823
+ recipientUserIds,
784
824
  tenantId: input.tenantId,
785
825
  organizationId: input.organizationId
786
826
  });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/messages/commands/messages.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 { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { Message, MessageObject, MessageRecipient, type MessageActionData } from '../data/entities'\nimport { emitMessagesEvent } from '../events'\nimport {\n composeMessageSchema,\n forwardMessageSchema,\n replyMessageSchema,\n updateDraftSchema,\n} from '../data/validators'\nimport { linkAttachmentsToMessage, linkLibraryAttachmentsToMessage, copyAttachmentsForForwardMessages } from '../lib/attachments'\nimport { MESSAGE_ATTACHMENT_ENTITY_ID, MESSAGE_ENTITY_ID } from '../lib/constants'\nimport { getMessageTypeOrDefault } from '../lib/message-types-registry'\nimport { validateMessageObjectsForType } from '../lib/object-validation'\nimport { buildForwardBodyFromLegacyInput, buildForwardPreviewFromThreadSlice, buildForwardThreadSlice } from '../lib/forwarding'\nimport {\n assertOrganizationAccess,\n loadMessageAggregateSnapshot,\n restoreMessageAggregateSnapshot,\n type MessageAggregateSnapshot,\n type MessageScopeInput,\n} from './shared'\n\ntype MessageSentEventPayload = {\n messageId: string\n senderUserId: string\n recipientUserIds: string[]\n sendViaEmail: boolean\n externalEmail?: string | null\n forwardedFrom?: string\n replyTo?: string\n tenantId: string\n organizationId?: string | null\n}\n\ntype ContainerWithResolve = {\n resolve: (name: string) => unknown\n}\n\nasync function emitMessageSentEvent(_container: ContainerWithResolve, payload: MessageSentEventPayload) {\n await emitMessagesEvent('messages.message.sent', payload, { persistent: true })\n}\n\nasync function emitMessageDeletedEvent(_container: ContainerWithResolve, payload: {\n messageId: string\n actorUserId: string\n target: 'sender' | 'recipient'\n tenantId: string\n organizationId: string | null\n}) {\n await emitMessagesEvent(\n 'messages.message.deleted',\n { ...payload, recipientUserId: payload.actorUserId },\n { persistent: true },\n )\n}\n\nasync function emitMessageIndexUpsert(\n container: ContainerWithResolve,\n payload: {\n messageId: string\n tenantId: string\n organizationId: string | null\n },\n) {\n let bus: { emitEvent: (name: string, body: unknown, options?: unknown) => Promise<void> } | null = null\n try {\n bus = container.resolve('eventBus') as { emitEvent: (name: string, body: unknown, options?: unknown) => Promise<void> }\n } catch {\n bus = null\n }\n\n if (!bus) return\n\n await bus.emitEvent(\n 'query_index.upsert_one',\n {\n entityType: MESSAGE_ENTITY_ID,\n recordId: payload.messageId,\n tenantId: payload.tenantId,\n organizationId: payload.organizationId,\n crudAction: 'updated',\n coverageBaseDelta: 1,\n },\n {\n tenantId: payload.tenantId,\n organizationId: payload.organizationId,\n },\n ).catch(() => undefined)\n}\n\nconst scopeSchema = z.object({\n tenantId: z.string().uuid(),\n organizationId: z.string().uuid().nullable(),\n userId: z.string().uuid(),\n})\n\nconst composeCommandSchema = composeMessageSchema.safeExtend({\n tenantId: scopeSchema.shape.tenantId,\n organizationId: scopeSchema.shape.organizationId,\n userId: scopeSchema.shape.userId,\n})\n\nconst updateDraftCommandSchema = updateDraftSchema.safeExtend({\n messageId: z.string().uuid(),\n tenantId: scopeSchema.shape.tenantId,\n organizationId: scopeSchema.shape.organizationId,\n userId: scopeSchema.shape.userId,\n})\n\nconst replyCommandSchema = replyMessageSchema.safeExtend({\n messageId: z.string().uuid(),\n tenantId: scopeSchema.shape.tenantId,\n organizationId: scopeSchema.shape.organizationId,\n userId: scopeSchema.shape.userId,\n})\n\nconst forwardCommandSchema = forwardMessageSchema.safeExtend({\n messageId: z.string().uuid(),\n tenantId: scopeSchema.shape.tenantId,\n organizationId: scopeSchema.shape.organizationId,\n userId: scopeSchema.shape.userId,\n})\n\nconst deleteForActorCommandSchema = z.object({\n messageId: z.string().uuid(),\n tenantId: scopeSchema.shape.tenantId,\n organizationId: scopeSchema.shape.organizationId,\n userId: scopeSchema.shape.userId,\n})\n\ntype ComposeCommandInput = z.infer<typeof composeCommandSchema>\ntype UpdateDraftCommandInput = z.infer<typeof updateDraftCommandSchema>\ntype ReplyCommandInput = z.infer<typeof replyCommandSchema>\ntype ForwardCommandInput = z.infer<typeof forwardCommandSchema>\ntype DeleteForActorCommandInput = z.infer<typeof deleteForActorCommandSchema>\n\ntype MessageDeleteUndoState = {\n messageId: string\n messageDeletedAt: string | null\n recipientId: string | null\n recipientStatus: 'unread' | 'read' | 'archived' | 'deleted' | null\n recipientDeletedAt: string | 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\nfunction buildReplySubject(subject: string): string {\n if (/^re:\\s*/i.test(subject)) return subject\n return `Re: ${subject}`\n}\n\nasync function requireMessageById(\n em: EntityManager,\n scope: MessageScopeInput,\n messageId: string,\n) {\n const message = await findOneWithDecryption(\n em,\n Message,\n {\n id: messageId,\n tenantId: scope.tenantId,\n deletedAt: null,\n },\n undefined,\n {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n },\n )\n if (!message) throw new Error('Message not found')\n assertOrganizationAccess(scope, message)\n return message\n}\n\nconst composeMessageCommand: CommandHandler<unknown, { id: string; threadId: string | null; externalEmail: string | null; isDraft: boolean; recipientUserIds: string[] }> = {\n id: 'messages.messages.compose',\n async execute(rawInput, ctx) {\n const input = composeCommandSchema.parse(rawInput)\n if (input.objects?.length) {\n const objectValidationError = validateMessageObjectsForType(input.type, input.objects)\n if (objectValidationError) throw new Error(objectValidationError)\n }\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n let messageId = ''\n let responseThreadId: string | null = null\n let responseExternalEmail: string | null = null\n\n await em.transactional(async (trx) => {\n const threadId = input.parentMessageId\n ? (\n await trx.findOne(Message, {\n id: input.parentMessageId,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n deletedAt: null,\n })\n )?.threadId ?? input.parentMessageId\n : undefined\n\n const isPublicVisibility = input.visibility === 'public'\n const sendViaEmail = isPublicVisibility ? true : input.sendViaEmail\n const message = trx.create(Message, {\n type: input.type,\n visibility: input.visibility ?? null,\n sourceEntityType: input.sourceEntityType,\n sourceEntityId: input.sourceEntityId,\n externalEmail: input.externalEmail,\n externalName: input.externalName,\n threadId: threadId ?? undefined,\n parentMessageId: input.parentMessageId,\n senderUserId: input.userId,\n subject: input.subject,\n body: input.body,\n bodyFormat: input.bodyFormat,\n priority: input.priority,\n status: input.isDraft ? 'draft' : 'sent',\n isDraft: input.isDraft ?? false,\n sentAt: input.isDraft ? null : new Date(),\n actionData: input.actionData as MessageActionData | undefined,\n sendViaEmail,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n\n await trx.persist(message).flush()\n if (!threadId && !input.isDraft && !message.threadId) {\n message.threadId = message.id\n await trx.flush()\n }\n\n for (const recipient of input.recipients) {\n trx.persist(trx.create(MessageRecipient, {\n messageId: message.id,\n recipientUserId: recipient.userId,\n recipientType: recipient.type,\n status: 'unread',\n }))\n }\n\n if (input.objects) {\n for (const obj of input.objects) {\n trx.persist(trx.create(MessageObject, {\n messageId: message.id,\n entityModule: obj.entityModule,\n entityType: obj.entityType,\n entityId: obj.entityId,\n actionRequired: obj.actionRequired,\n actionType: obj.actionType,\n actionLabel: obj.actionLabel,\n }))\n }\n }\n\n await trx.flush()\n\n if (input.attachmentIds?.length) {\n await linkAttachmentsToMessage(\n trx,\n message.id,\n input.attachmentIds,\n input.organizationId,\n input.tenantId,\n )\n }\n\n if (input.attachmentRecordId) {\n await linkLibraryAttachmentsToMessage(\n trx,\n message.id,\n input.attachmentRecordId,\n input.organizationId,\n input.tenantId,\n )\n }\n\n messageId = message.id\n responseThreadId = message.threadId ?? null\n responseExternalEmail = message.externalEmail ?? null\n })\n\n if (!input.isDraft) {\n await emitMessageSentEvent(ctx.container, {\n messageId,\n senderUserId: input.userId,\n recipientUserIds: input.recipients.map((recipient) => recipient.userId),\n sendViaEmail: input.visibility === 'public' ? true : input.sendViaEmail,\n externalEmail: responseExternalEmail,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n }\n\n await emitMessageIndexUpsert(ctx.container, {\n messageId,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n\n return {\n id: messageId,\n threadId: responseThreadId,\n externalEmail: responseExternalEmail,\n isDraft: input.isDraft,\n recipientUserIds: input.recipients.map((recipient) => recipient.userId),\n }\n },\n async captureAfter(_input, result, ctx) {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return loadMessageAggregateSnapshot(em, result.id)\n },\n buildLog: async ({ input, result, snapshots }) => {\n const parsed = composeCommandSchema.parse(input)\n return {\n actionLabel: parsed.isDraft ? 'Create draft message' : 'Compose message',\n resourceKind: 'messages.message',\n resourceId: result.id,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n payload: {\n undo: {\n after: (snapshots.after as MessageAggregateSnapshot | undefined) ?? null,\n } satisfies UndoPayload<MessageAggregateSnapshot>,\n },\n snapshotAfter: snapshots.after ?? null,\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const undo = extractUndoPayload<UndoPayload<MessageAggregateSnapshot>>(logEntry)\n const after = undo?.after\n if (!after) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await em.findOne(Message, { id: after.message.id })\n if (!message) return\n message.deletedAt = new Date()\n await em.flush()\n },\n}\n\nconst updateDraftCommand: CommandHandler<unknown, { ok: true; id: string }> = {\n id: 'messages.messages.update_draft',\n async prepare(rawInput, ctx) {\n const input = updateDraftCommandSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const snapshot = await loadMessageAggregateSnapshot(em, input.messageId, {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n return snapshot ? { before: snapshot } : {}\n },\n async execute(rawInput, ctx) {\n const input = updateDraftCommandSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await requireMessageById(em, input, input.messageId)\n\n if (message.senderUserId !== input.userId) throw new Error('Access denied')\n if (!message.isDraft) throw new Error('Only draft messages can be edited')\n\n const isSending = input.isDraft === false\n const preloadedRecipients = isSending && !input.recipients\n ? await findWithDecryption(\n em,\n MessageRecipient,\n { messageId: message.id, deletedAt: null },\n undefined,\n {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n },\n )\n : null\n\n const nextMessageType = input.type ?? message.type\n if (input.objects) {\n const objectValidationError = validateMessageObjectsForType(nextMessageType, input.objects)\n if (objectValidationError) throw new Error(objectValidationError)\n } else if (input.type !== undefined) {\n const existingObjects = await em.find(MessageObject, { messageId: message.id })\n if (existingObjects.length > 0) {\n const objectValidationError = validateMessageObjectsForType(\n nextMessageType,\n existingObjects.map((item) => ({\n entityModule: item.entityModule,\n entityType: item.entityType,\n entityId: item.entityId,\n })),\n )\n if (objectValidationError) throw new Error(objectValidationError)\n }\n }\n\n if (input.type !== undefined) message.type = input.type\n if (input.visibility !== undefined) message.visibility = input.visibility\n if (input.sourceEntityType !== undefined) message.sourceEntityType = input.sourceEntityType\n if (input.sourceEntityId !== undefined) message.sourceEntityId = input.sourceEntityId\n if (input.externalEmail !== undefined) message.externalEmail = input.externalEmail\n if (input.externalName !== undefined) message.externalName = input.externalName\n if (input.subject !== undefined) message.subject = input.subject\n if (input.body !== undefined) message.body = input.body\n if (input.bodyFormat !== undefined) message.bodyFormat = input.bodyFormat\n if (input.priority !== undefined) message.priority = input.priority\n if (input.actionData !== undefined) message.actionData = input.actionData\n if (input.sendViaEmail !== undefined) message.sendViaEmail = input.sendViaEmail\n\n if (input.recipients) {\n await em.nativeDelete(MessageRecipient, { messageId: message.id })\n for (const recipient of input.recipients) {\n em.persist(em.create(MessageRecipient, {\n messageId: message.id,\n recipientUserId: recipient.userId,\n recipientType: recipient.type,\n status: 'unread',\n }))\n }\n }\n\n if (input.objects) {\n await em.nativeDelete(MessageObject, { messageId: message.id })\n for (const object of input.objects) {\n em.persist(em.create(MessageObject, {\n messageId: message.id,\n entityModule: object.entityModule,\n entityType: object.entityType,\n entityId: object.entityId,\n actionRequired: object.actionRequired,\n actionType: object.actionType,\n actionLabel: object.actionLabel,\n }))\n }\n }\n\n if (input.attachmentIds) {\n const { Attachment } = await import('@open-mercato/core/modules/attachments/data/entities')\n if (input.attachmentIds.length === 0) {\n await em.nativeDelete(Attachment, {\n entityId: MESSAGE_ATTACHMENT_ENTITY_ID,\n recordId: message.id,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n } else {\n await em.nativeDelete(Attachment, {\n entityId: MESSAGE_ATTACHMENT_ENTITY_ID,\n recordId: message.id,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n id: { $nin: input.attachmentIds },\n })\n }\n await linkAttachmentsToMessage(\n em,\n message.id,\n input.attachmentIds,\n input.organizationId,\n input.tenantId,\n )\n }\n\n if (isSending) {\n const finalVisibility = input.visibility ?? message.visibility\n const finalSubject = input.subject ?? message.subject\n const finalBody = input.body ?? message.body\n const finalRecipientCount = input.recipients\n ? input.recipients.length\n : (preloadedRecipients?.length ?? 0)\n\n if (finalVisibility !== 'public' && finalRecipientCount === 0) {\n throw new Error('at least one recipient is required')\n }\n if (!finalSubject?.trim()) throw new Error('subject is required')\n if (!finalBody?.trim()) throw new Error('body is required')\n\n message.isDraft = false\n message.status = 'sent'\n message.sentAt = new Date()\n if (!message.threadId) message.threadId = message.id\n }\n\n await em.flush()\n await emitMessageIndexUpsert(ctx.container, {\n messageId: message.id,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n\n if (isSending) {\n const recipientUserIds = input.recipients\n ? input.recipients.map((r) => r.userId)\n : (preloadedRecipients ?? []).map((r) => r.recipientUserId)\n const resolvedVisibility = input.visibility ?? message.visibility\n const resolvedSendViaEmail = input.sendViaEmail ?? message.sendViaEmail\n await emitMessageSentEvent(ctx.container, {\n messageId: message.id,\n senderUserId: input.userId,\n recipientUserIds,\n sendViaEmail: resolvedVisibility === 'public' ? true : resolvedSendViaEmail,\n externalEmail: message.externalEmail ?? null,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n }\n\n return { ok: true, id: message.id }\n },\n async captureAfter(rawInput, _result, ctx) {\n const input = updateDraftCommandSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return loadMessageAggregateSnapshot(em, input.messageId, {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n },\n buildLog: async ({ input, snapshots }) => {\n const parsed = updateDraftCommandSchema.parse(input)\n return {\n actionLabel: parsed.isDraft === false ? 'Send draft message' : 'Update draft message',\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 MessageAggregateSnapshot | undefined) ?? null,\n after: (snapshots.after as MessageAggregateSnapshot | undefined) ?? null,\n } satisfies UndoPayload<MessageAggregateSnapshot>,\n },\n snapshotBefore: snapshots.before ?? null,\n snapshotAfter: snapshots.after ?? null,\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const undo = extractUndoPayload<UndoPayload<MessageAggregateSnapshot>>(logEntry)\n const before = undo?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n await restoreMessageAggregateSnapshot(em, before)\n },\n}\n\nconst replyMessageCommand: CommandHandler<unknown, { id: string; externalEmail: string | null; recipientUserIds: string[] }> = {\n id: 'messages.messages.reply',\n async execute(rawInput, ctx) {\n const input = replyCommandSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const original = await requireMessageById(em, input, input.messageId)\n const ownRecipient = await em.findOne(MessageRecipient, {\n messageId: original.id,\n recipientUserId: input.userId,\n deletedAt: null,\n })\n if (original.senderUserId !== input.userId && !ownRecipient) throw new Error('Access denied')\n\n const messageType = getMessageTypeOrDefault(original.type)\n if (messageType.allowReply === false) throw new Error('Reply is not allowed for this message type')\n\n const recipientIds = new Set(\n (input.recipients ?? [])\n .map((recipient) => recipient.userId)\n .filter((recipientUserId) => recipientUserId !== input.userId),\n )\n\n if (recipientIds.size === 0) {\n const originalRecipients = await em.find(MessageRecipient, { messageId: original.id, deletedAt: null })\n if (input.replyAll) {\n if (original.senderUserId !== input.userId) recipientIds.add(original.senderUserId)\n for (const recipient of originalRecipients) {\n if (recipient.recipientUserId !== input.userId) recipientIds.add(recipient.recipientUserId)\n }\n } else if (original.senderUserId !== input.userId) {\n recipientIds.add(original.senderUserId)\n } else {\n for (const recipient of originalRecipients) {\n if (recipient.recipientUserId !== input.userId) {\n recipientIds.add(recipient.recipientUserId)\n break\n }\n }\n }\n\n if (recipientIds.size === 0 && original.senderUserId === input.userId) {\n recipientIds.add(input.userId)\n }\n }\n if (recipientIds.size === 0) throw new Error('No recipients available for reply')\n\n let messageId = ''\n let responseExternalEmail: string | null = null\n await em.transactional(async (trx) => {\n const message = trx.create(Message, {\n type: original.type,\n visibility: original.visibility ?? null,\n sourceEntityType: original.sourceEntityType,\n sourceEntityId: original.sourceEntityId,\n externalEmail: original.externalEmail,\n externalName: original.externalName,\n threadId: original.threadId ?? original.id,\n parentMessageId: original.id,\n senderUserId: input.userId,\n subject: buildReplySubject(original.subject),\n body: input.body,\n bodyFormat: input.bodyFormat,\n priority: original.priority,\n status: 'sent',\n isDraft: false,\n sentAt: new Date(),\n sendViaEmail: input.sendViaEmail,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n await trx.persist(message).flush()\n for (const recipientUserId of recipientIds) {\n trx.persist(trx.create(MessageRecipient, {\n messageId: message.id,\n recipientUserId,\n recipientType: 'to',\n status: 'unread',\n }))\n }\n await trx.flush()\n if (input.attachmentIds?.length) {\n await linkAttachmentsToMessage(\n trx,\n message.id,\n input.attachmentIds,\n input.organizationId,\n input.tenantId,\n )\n }\n if (input.attachmentRecordId) {\n await linkLibraryAttachmentsToMessage(\n trx,\n message.id,\n input.attachmentRecordId,\n input.organizationId,\n input.tenantId,\n )\n }\n messageId = message.id\n responseExternalEmail = message.externalEmail ?? null\n })\n\n await emitMessageSentEvent(ctx.container, {\n messageId,\n senderUserId: input.userId,\n recipientUserIds: Array.from(recipientIds),\n sendViaEmail: input.sendViaEmail,\n externalEmail: responseExternalEmail,\n replyTo: original.id,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n await emitMessageIndexUpsert(ctx.container, {\n messageId,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n\n return {\n id: messageId,\n externalEmail: responseExternalEmail,\n recipientUserIds: Array.from(recipientIds),\n }\n },\n async captureAfter(_input, result, ctx) {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return loadMessageAggregateSnapshot(em, result.id)\n },\n buildLog: async ({ input, result, snapshots }) => {\n const parsed = replyCommandSchema.parse(input)\n return {\n actionLabel: 'Reply to message',\n resourceKind: 'messages.message',\n resourceId: result.id,\n parentResourceKind: 'messages.message',\n parentResourceId: parsed.messageId,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n payload: {\n undo: {\n after: (snapshots.after as MessageAggregateSnapshot | undefined) ?? null,\n } satisfies UndoPayload<MessageAggregateSnapshot>,\n },\n snapshotAfter: snapshots.after ?? null,\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const undo = extractUndoPayload<UndoPayload<MessageAggregateSnapshot>>(logEntry)\n const after = undo?.after\n if (!after) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await em.findOne(Message, { id: after.message.id })\n if (!message) return\n message.deletedAt = new Date()\n await em.flush()\n },\n}\n\nconst forwardMessageCommand: CommandHandler<unknown, { id: string; externalEmail: string | null; recipientUserIds: string[] }> = {\n id: 'messages.messages.forward',\n async execute(rawInput, ctx) {\n const input = forwardCommandSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const original = await requireMessageById(em, input, input.messageId)\n const isRecipient = await em.findOne(MessageRecipient, {\n messageId: input.messageId,\n recipientUserId: input.userId,\n deletedAt: null,\n })\n if (original.senderUserId !== input.userId && !isRecipient) throw new Error('Access denied')\n\n const messageType = getMessageTypeOrDefault(original.type)\n if (messageType.allowForward === false) throw new Error('Forward is not allowed for this message type')\n\n const originalObjects = await em.find(MessageObject, { messageId: input.messageId })\n const forwardThreadSlice = await buildForwardThreadSlice(em, {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n userId: input.userId,\n }, original)\n const generatedPreview = await buildForwardPreviewFromThreadSlice(em, {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n userId: input.userId,\n }, original, forwardThreadSlice)\n const forwardedBody = typeof input.body === 'string'\n ? input.body\n : buildForwardBodyFromLegacyInput(generatedPreview.body, input.additionalBody)\n let newMessageId = ''\n let responseExternalEmail: string | null = null\n await em.transactional(async (trx) => {\n const newMessage = trx.create(Message, {\n type: original.type,\n visibility: original.visibility ?? null,\n sourceEntityType: original.sourceEntityType,\n sourceEntityId: original.sourceEntityId,\n externalEmail: original.externalEmail,\n externalName: original.externalName,\n threadId: original.threadId ?? original.id,\n parentMessageId: original.id,\n senderUserId: input.userId,\n subject: `Fwd: ${original.subject}`,\n body: forwardedBody,\n bodyFormat: original.bodyFormat,\n priority: original.priority,\n status: 'sent',\n isDraft: false,\n sentAt: new Date(),\n sendViaEmail: input.sendViaEmail,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n await trx.persist(newMessage).flush()\n for (const recipient of input.recipients) {\n trx.persist(trx.create(MessageRecipient, {\n messageId: newMessage.id,\n recipientUserId: recipient.userId,\n recipientType: recipient.type,\n status: 'unread',\n }))\n }\n for (const obj of originalObjects) {\n trx.persist(trx.create(MessageObject, {\n messageId: newMessage.id,\n entityModule: obj.entityModule,\n entityType: obj.entityType,\n entityId: obj.entityId,\n actionRequired: obj.actionRequired,\n actionType: obj.actionType,\n actionLabel: obj.actionLabel,\n entitySnapshot: obj.entitySnapshot,\n }))\n }\n await trx.flush()\n if (input.includeAttachments !== false) {\n await copyAttachmentsForForwardMessages(\n trx,\n forwardThreadSlice.map((item) => item.id),\n newMessage.id,\n input.organizationId,\n input.tenantId,\n )\n }\n newMessageId = newMessage.id\n responseExternalEmail = newMessage.externalEmail ?? null\n })\n\n await emitMessageSentEvent(ctx.container, {\n messageId: newMessageId,\n senderUserId: input.userId,\n recipientUserIds: input.recipients.map((item) => item.userId),\n sendViaEmail: input.sendViaEmail,\n externalEmail: responseExternalEmail,\n forwardedFrom: original.id,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n await emitMessageIndexUpsert(ctx.container, {\n messageId: newMessageId,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n\n return {\n id: newMessageId,\n externalEmail: responseExternalEmail,\n recipientUserIds: input.recipients.map((item) => item.userId),\n }\n },\n async captureAfter(_input, result, ctx) {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return loadMessageAggregateSnapshot(em, result.id)\n },\n buildLog: async ({ input, result, snapshots }) => {\n const parsed = forwardCommandSchema.parse(input)\n return {\n actionLabel: 'Forward message',\n resourceKind: 'messages.message',\n resourceId: result.id,\n parentResourceKind: 'messages.message',\n parentResourceId: parsed.messageId,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n payload: {\n undo: {\n after: (snapshots.after as MessageAggregateSnapshot | undefined) ?? null,\n } satisfies UndoPayload<MessageAggregateSnapshot>,\n },\n snapshotAfter: snapshots.after ?? null,\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const undo = extractUndoPayload<UndoPayload<MessageAggregateSnapshot>>(logEntry)\n const after = undo?.after\n if (!after) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await em.findOne(Message, { id: after.message.id })\n if (!message) return\n message.deletedAt = new Date()\n await em.flush()\n },\n}\n\nconst deleteForActorCommand: CommandHandler<unknown, { ok: true }> = {\n id: 'messages.messages.delete_for_actor',\n async prepare(rawInput, ctx) {\n const input = deleteForActorCommandSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await requireMessageById(em, input, input.messageId)\n const recipient = await em.findOne(MessageRecipient, {\n messageId: input.messageId,\n recipientUserId: input.userId,\n deletedAt: null,\n })\n return {\n before: {\n messageId: message.id,\n messageDeletedAt: toIso(message.deletedAt),\n recipientId: recipient?.id ?? null,\n recipientStatus: recipient?.status ?? null,\n recipientDeletedAt: toIso(recipient?.deletedAt),\n } satisfies MessageDeleteUndoState,\n }\n },\n async execute(rawInput, ctx) {\n const input = deleteForActorCommandSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await requireMessageById(em, input, input.messageId)\n const recipient = await em.findOne(MessageRecipient, {\n messageId: input.messageId,\n recipientUserId: input.userId,\n deletedAt: null,\n })\n if (recipient) {\n recipient.status = 'deleted'\n recipient.deletedAt = new Date()\n await em.flush()\n await emitMessageDeletedEvent(ctx.container, {\n messageId: input.messageId,\n actorUserId: input.userId,\n target: 'recipient',\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n return { ok: true }\n }\n if (message.senderUserId === input.userId) {\n message.deletedAt = new Date()\n await em.flush()\n await emitMessageDeletedEvent(ctx.container, {\n messageId: input.messageId,\n actorUserId: input.userId,\n target: 'sender',\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n return { ok: true }\n }\n throw new Error('Access denied')\n },\n async captureAfter(rawInput, _result, ctx) {\n const input = deleteForActorCommandSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await em.findOne(Message, { id: input.messageId, tenantId: input.tenantId })\n const recipient = await em.findOne(MessageRecipient, {\n messageId: input.messageId,\n recipientUserId: input.userId,\n })\n return {\n messageId: input.messageId,\n messageDeletedAt: toIso(message?.deletedAt),\n recipientId: recipient?.id ?? null,\n recipientStatus: recipient?.status ?? null,\n recipientDeletedAt: toIso(recipient?.deletedAt),\n } satisfies MessageDeleteUndoState\n },\n buildLog: async ({ input, snapshots }) => {\n const parsed = deleteForActorCommandSchema.parse(input)\n return {\n actionLabel: 'Delete message for actor',\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 MessageDeleteUndoState | undefined) ?? null,\n after: (snapshots.after as MessageDeleteUndoState | undefined) ?? null,\n } satisfies UndoPayload<MessageDeleteUndoState>,\n },\n snapshotBefore: snapshots.before ?? null,\n snapshotAfter: snapshots.after ?? null,\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const undo = extractUndoPayload<UndoPayload<MessageDeleteUndoState>>(logEntry)\n const before = undo?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await em.findOne(Message, { id: before.messageId })\n if (message) {\n message.deletedAt = toDate(before.messageDeletedAt)\n }\n if (before.recipientId) {\n const recipient = await em.findOne(MessageRecipient, { id: before.recipientId })\n if (recipient) {\n recipient.status = (before.recipientStatus ?? 'unread') as MessageRecipient['status']\n recipient.deletedAt = toDate(before.recipientDeletedAt)\n }\n }\n await em.flush()\n },\n}\n\nregisterCommand(composeMessageCommand)\nregisterCommand(updateDraftCommand)\nregisterCommand(replyMessageCommand)\nregisterCommand(forwardMessageCommand)\nregisterCommand(deleteForActorCommand)\n"],
5
- "mappings": "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",
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, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { Message, MessageObject, MessageRecipient, type MessageActionData } from '../data/entities'\nimport { emitMessagesEvent } from '../events'\nimport {\n composeMessageSchema,\n forwardMessageSchema,\n replyMessageSchema,\n updateDraftSchema,\n} from '../data/validators'\nimport { linkAttachmentsToMessage, linkLibraryAttachmentsToMessage, copyAttachmentsForForwardMessages } from '../lib/attachments'\nimport { MESSAGE_ATTACHMENT_ENTITY_ID, MESSAGE_ENTITY_ID } from '../lib/constants'\nimport { getMessageTypeOrDefault } from '../lib/message-types-registry'\nimport { validateMessageObjectsForType } from '../lib/object-validation'\nimport { buildForwardBodyFromLegacyInput, buildForwardPreviewFromThreadSlice, buildForwardThreadSlice } from '../lib/forwarding'\nimport {\n assertOrganizationAccess,\n loadMessageAggregateSnapshot,\n restoreMessageAggregateSnapshot,\n type MessageAggregateSnapshot,\n type MessageScopeInput,\n} from './shared'\n\ntype MessageSentEventPayload = {\n messageId: string\n senderUserId: string\n recipientUserIds: string[]\n sendViaEmail: boolean\n externalEmail?: string | null\n forwardedFrom?: string\n replyTo?: string\n tenantId: string\n organizationId?: string | null\n}\n\ntype ContainerWithResolve = {\n resolve: (name: string) => unknown\n}\n\nasync function emitMessageSentEvent(_container: ContainerWithResolve, payload: MessageSentEventPayload) {\n await emitMessagesEvent('messages.message.sent', payload, { persistent: true })\n}\n\nasync function emitMessageDeletedEvent(_container: ContainerWithResolve, payload: {\n messageId: string\n actorUserId: string\n target: 'sender' | 'recipient'\n tenantId: string\n organizationId: string | null\n}) {\n await emitMessagesEvent(\n 'messages.message.deleted',\n { ...payload, recipientUserId: payload.actorUserId },\n { persistent: true },\n )\n}\n\nasync function emitMessageGloballyDeletedEvent(_container: ContainerWithResolve, payload: {\n messageId: string\n actorUserId: string\n recipientUserIds: string[]\n tenantId: string\n organizationId: string | null\n}) {\n const audience = Array.from(new Set([payload.actorUserId, ...payload.recipientUserIds]))\n await emitMessagesEvent(\n 'messages.message.deleted',\n {\n messageId: payload.messageId,\n actorUserId: payload.actorUserId,\n target: 'global',\n recipientUserIds: audience,\n tenantId: payload.tenantId,\n organizationId: payload.organizationId,\n },\n { persistent: true },\n )\n}\n\nasync function emitMessageIndexUpsert(\n container: ContainerWithResolve,\n payload: {\n messageId: string\n tenantId: string\n organizationId: string | null\n },\n) {\n let bus: { emitEvent: (name: string, body: unknown, options?: unknown) => Promise<void> } | null = null\n try {\n bus = container.resolve('eventBus') as { emitEvent: (name: string, body: unknown, options?: unknown) => Promise<void> }\n } catch {\n bus = null\n }\n\n if (!bus) return\n\n await bus.emitEvent(\n 'query_index.upsert_one',\n {\n entityType: MESSAGE_ENTITY_ID,\n recordId: payload.messageId,\n tenantId: payload.tenantId,\n organizationId: payload.organizationId,\n crudAction: 'updated',\n coverageBaseDelta: 1,\n },\n {\n tenantId: payload.tenantId,\n organizationId: payload.organizationId,\n },\n ).catch(() => undefined)\n}\n\nconst scopeSchema = z.object({\n tenantId: z.string().uuid(),\n organizationId: z.string().uuid().nullable(),\n userId: z.string().uuid(),\n})\n\nconst composeCommandSchema = composeMessageSchema.safeExtend({\n tenantId: scopeSchema.shape.tenantId,\n organizationId: scopeSchema.shape.organizationId,\n userId: scopeSchema.shape.userId,\n})\n\nconst updateDraftCommandSchema = updateDraftSchema.safeExtend({\n messageId: z.string().uuid(),\n tenantId: scopeSchema.shape.tenantId,\n organizationId: scopeSchema.shape.organizationId,\n userId: scopeSchema.shape.userId,\n})\n\nconst replyCommandSchema = replyMessageSchema.safeExtend({\n messageId: z.string().uuid(),\n tenantId: scopeSchema.shape.tenantId,\n organizationId: scopeSchema.shape.organizationId,\n userId: scopeSchema.shape.userId,\n})\n\nconst forwardCommandSchema = forwardMessageSchema.safeExtend({\n messageId: z.string().uuid(),\n tenantId: scopeSchema.shape.tenantId,\n organizationId: scopeSchema.shape.organizationId,\n userId: scopeSchema.shape.userId,\n})\n\nconst deleteForActorCommandSchema = z.object({\n messageId: z.string().uuid(),\n tenantId: scopeSchema.shape.tenantId,\n organizationId: scopeSchema.shape.organizationId,\n userId: scopeSchema.shape.userId,\n})\n\ntype ComposeCommandInput = z.infer<typeof composeCommandSchema>\ntype UpdateDraftCommandInput = z.infer<typeof updateDraftCommandSchema>\ntype ReplyCommandInput = z.infer<typeof replyCommandSchema>\ntype ForwardCommandInput = z.infer<typeof forwardCommandSchema>\ntype DeleteForActorCommandInput = z.infer<typeof deleteForActorCommandSchema>\n\ntype MessageDeleteUndoState = {\n messageId: string\n messageDeletedAt: string | null\n recipientId: string | null\n recipientStatus: 'unread' | 'read' | 'archived' | 'deleted' | null\n recipientDeletedAt: string | 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\nfunction buildReplySubject(subject: string): string {\n if (/^re:\\s*/i.test(subject)) return subject\n return `Re: ${subject}`\n}\n\nasync function requireMessageById(\n em: EntityManager,\n scope: MessageScopeInput,\n messageId: string,\n) {\n const message = await findOneWithDecryption(\n em,\n Message,\n {\n id: messageId,\n tenantId: scope.tenantId,\n deletedAt: null,\n },\n undefined,\n {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n },\n )\n if (!message) throw new Error('Message not found')\n assertOrganizationAccess(scope, message)\n return message\n}\n\nconst composeMessageCommand: CommandHandler<unknown, { id: string; threadId: string | null; externalEmail: string | null; isDraft: boolean; recipientUserIds: string[] }> = {\n id: 'messages.messages.compose',\n async execute(rawInput, ctx) {\n const input = composeCommandSchema.parse(rawInput)\n if (input.objects?.length) {\n const objectValidationError = validateMessageObjectsForType(input.type, input.objects)\n if (objectValidationError) throw new Error(objectValidationError)\n }\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n let messageId = ''\n let responseThreadId: string | null = null\n let responseExternalEmail: string | null = null\n\n await em.transactional(async (trx) => {\n const threadId = input.parentMessageId\n ? (\n await trx.findOne(Message, {\n id: input.parentMessageId,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n deletedAt: null,\n })\n )?.threadId ?? input.parentMessageId\n : undefined\n\n const isPublicVisibility = input.visibility === 'public'\n const sendViaEmail = isPublicVisibility ? true : input.sendViaEmail\n const message = trx.create(Message, {\n type: input.type,\n visibility: input.visibility ?? null,\n sourceEntityType: input.sourceEntityType,\n sourceEntityId: input.sourceEntityId,\n externalEmail: input.externalEmail,\n externalName: input.externalName,\n threadId: threadId ?? undefined,\n parentMessageId: input.parentMessageId,\n senderUserId: input.userId,\n subject: input.subject,\n body: input.body,\n bodyFormat: input.bodyFormat,\n priority: input.priority,\n status: input.isDraft ? 'draft' : 'sent',\n isDraft: input.isDraft ?? false,\n sentAt: input.isDraft ? null : new Date(),\n actionData: input.actionData as MessageActionData | undefined,\n sendViaEmail,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n\n await trx.persist(message).flush()\n if (!threadId && !input.isDraft && !message.threadId) {\n message.threadId = message.id\n await trx.flush()\n }\n\n for (const recipient of input.recipients) {\n trx.persist(trx.create(MessageRecipient, {\n messageId: message.id,\n recipientUserId: recipient.userId,\n recipientType: recipient.type,\n status: 'unread',\n }))\n }\n\n if (input.objects) {\n for (const obj of input.objects) {\n trx.persist(trx.create(MessageObject, {\n messageId: message.id,\n entityModule: obj.entityModule,\n entityType: obj.entityType,\n entityId: obj.entityId,\n actionRequired: obj.actionRequired,\n actionType: obj.actionType,\n actionLabel: obj.actionLabel,\n }))\n }\n }\n\n await trx.flush()\n\n if (input.attachmentIds?.length) {\n await linkAttachmentsToMessage(\n trx,\n message.id,\n input.attachmentIds,\n input.organizationId,\n input.tenantId,\n )\n }\n\n if (input.attachmentRecordId) {\n await linkLibraryAttachmentsToMessage(\n trx,\n message.id,\n input.attachmentRecordId,\n input.organizationId,\n input.tenantId,\n )\n }\n\n messageId = message.id\n responseThreadId = message.threadId ?? null\n responseExternalEmail = message.externalEmail ?? null\n })\n\n if (!input.isDraft) {\n await emitMessageSentEvent(ctx.container, {\n messageId,\n senderUserId: input.userId,\n recipientUserIds: input.recipients.map((recipient) => recipient.userId),\n sendViaEmail: input.visibility === 'public' ? true : input.sendViaEmail,\n externalEmail: responseExternalEmail,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n }\n\n await emitMessageIndexUpsert(ctx.container, {\n messageId,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n\n return {\n id: messageId,\n threadId: responseThreadId,\n externalEmail: responseExternalEmail,\n isDraft: input.isDraft,\n recipientUserIds: input.recipients.map((recipient) => recipient.userId),\n }\n },\n async captureAfter(_input, result, ctx) {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return loadMessageAggregateSnapshot(em, result.id)\n },\n buildLog: async ({ input, result, snapshots }) => {\n const parsed = composeCommandSchema.parse(input)\n return {\n actionLabel: parsed.isDraft ? 'Create draft message' : 'Compose message',\n resourceKind: 'messages.message',\n resourceId: result.id,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n payload: {\n undo: {\n after: (snapshots.after as MessageAggregateSnapshot | undefined) ?? null,\n } satisfies UndoPayload<MessageAggregateSnapshot>,\n },\n snapshotAfter: snapshots.after ?? null,\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const undo = extractUndoPayload<UndoPayload<MessageAggregateSnapshot>>(logEntry)\n const after = undo?.after\n if (!after) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await em.findOne(Message, { id: after.message.id })\n if (!message) return\n message.deletedAt = new Date()\n await em.flush()\n if (!after.message.isDraft) {\n await emitMessageGloballyDeletedEvent(ctx.container, {\n messageId: after.message.id,\n actorUserId: after.message.senderUserId,\n recipientUserIds: after.recipients.map((recipient) => recipient.recipientUserId),\n tenantId: after.message.tenantId,\n organizationId: after.message.organizationId,\n })\n }\n },\n}\n\nconst updateDraftCommand: CommandHandler<unknown, { ok: true; id: string }> = {\n id: 'messages.messages.update_draft',\n async prepare(rawInput, ctx) {\n const input = updateDraftCommandSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const snapshot = await loadMessageAggregateSnapshot(em, input.messageId, {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n return snapshot ? { before: snapshot } : {}\n },\n async execute(rawInput, ctx) {\n const input = updateDraftCommandSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await requireMessageById(em, input, input.messageId)\n\n if (message.senderUserId !== input.userId) throw new Error('Access denied')\n if (!message.isDraft) throw new Error('Only draft messages can be edited')\n\n const isSending = input.isDraft === false\n const preloadedRecipients = isSending && !input.recipients\n ? await findWithDecryption(\n em,\n MessageRecipient,\n { messageId: message.id, deletedAt: null },\n undefined,\n {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n },\n )\n : null\n\n const nextMessageType = input.type ?? message.type\n if (input.objects) {\n const objectValidationError = validateMessageObjectsForType(nextMessageType, input.objects)\n if (objectValidationError) throw new Error(objectValidationError)\n } else if (input.type !== undefined) {\n const existingObjects = await em.find(MessageObject, { messageId: message.id })\n if (existingObjects.length > 0) {\n const objectValidationError = validateMessageObjectsForType(\n nextMessageType,\n existingObjects.map((item) => ({\n entityModule: item.entityModule,\n entityType: item.entityType,\n entityId: item.entityId,\n })),\n )\n if (objectValidationError) throw new Error(objectValidationError)\n }\n }\n\n if (input.type !== undefined) message.type = input.type\n if (input.visibility !== undefined) message.visibility = input.visibility\n if (input.sourceEntityType !== undefined) message.sourceEntityType = input.sourceEntityType\n if (input.sourceEntityId !== undefined) message.sourceEntityId = input.sourceEntityId\n if (input.externalEmail !== undefined) message.externalEmail = input.externalEmail\n if (input.externalName !== undefined) message.externalName = input.externalName\n if (input.subject !== undefined) message.subject = input.subject\n if (input.body !== undefined) message.body = input.body\n if (input.bodyFormat !== undefined) message.bodyFormat = input.bodyFormat\n if (input.priority !== undefined) message.priority = input.priority\n if (input.actionData !== undefined) message.actionData = input.actionData\n if (input.sendViaEmail !== undefined) message.sendViaEmail = input.sendViaEmail\n\n if (input.recipients) {\n await em.nativeDelete(MessageRecipient, { messageId: message.id })\n for (const recipient of input.recipients) {\n em.persist(em.create(MessageRecipient, {\n messageId: message.id,\n recipientUserId: recipient.userId,\n recipientType: recipient.type,\n status: 'unread',\n }))\n }\n }\n\n if (input.objects) {\n await em.nativeDelete(MessageObject, { messageId: message.id })\n for (const object of input.objects) {\n em.persist(em.create(MessageObject, {\n messageId: message.id,\n entityModule: object.entityModule,\n entityType: object.entityType,\n entityId: object.entityId,\n actionRequired: object.actionRequired,\n actionType: object.actionType,\n actionLabel: object.actionLabel,\n }))\n }\n }\n\n if (input.attachmentIds) {\n const { Attachment } = await import('@open-mercato/core/modules/attachments/data/entities')\n if (input.attachmentIds.length === 0) {\n await em.nativeDelete(Attachment, {\n entityId: MESSAGE_ATTACHMENT_ENTITY_ID,\n recordId: message.id,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n } else {\n await em.nativeDelete(Attachment, {\n entityId: MESSAGE_ATTACHMENT_ENTITY_ID,\n recordId: message.id,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n id: { $nin: input.attachmentIds },\n })\n }\n await linkAttachmentsToMessage(\n em,\n message.id,\n input.attachmentIds,\n input.organizationId,\n input.tenantId,\n )\n }\n\n if (isSending) {\n const finalVisibility = input.visibility ?? message.visibility\n const finalSubject = input.subject ?? message.subject\n const finalBody = input.body ?? message.body\n const finalRecipientCount = input.recipients\n ? input.recipients.length\n : (preloadedRecipients?.length ?? 0)\n\n if (finalVisibility !== 'public' && finalRecipientCount === 0) {\n throw new Error('at least one recipient is required')\n }\n if (!finalSubject?.trim()) throw new Error('subject is required')\n if (!finalBody?.trim()) throw new Error('body is required')\n\n message.isDraft = false\n message.status = 'sent'\n message.sentAt = new Date()\n if (!message.threadId) message.threadId = message.id\n }\n\n await em.flush()\n await emitMessageIndexUpsert(ctx.container, {\n messageId: message.id,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n\n if (isSending) {\n const recipientUserIds = input.recipients\n ? input.recipients.map((r) => r.userId)\n : (preloadedRecipients ?? []).map((r) => r.recipientUserId)\n const resolvedVisibility = input.visibility ?? message.visibility\n const resolvedSendViaEmail = input.sendViaEmail ?? message.sendViaEmail\n await emitMessageSentEvent(ctx.container, {\n messageId: message.id,\n senderUserId: input.userId,\n recipientUserIds,\n sendViaEmail: resolvedVisibility === 'public' ? true : resolvedSendViaEmail,\n externalEmail: message.externalEmail ?? null,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n }\n\n return { ok: true, id: message.id }\n },\n async captureAfter(rawInput, _result, ctx) {\n const input = updateDraftCommandSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return loadMessageAggregateSnapshot(em, input.messageId, {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n },\n buildLog: async ({ input, snapshots }) => {\n const parsed = updateDraftCommandSchema.parse(input)\n return {\n actionLabel: parsed.isDraft === false ? 'Send draft message' : 'Update draft message',\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 MessageAggregateSnapshot | undefined) ?? null,\n after: (snapshots.after as MessageAggregateSnapshot | undefined) ?? null,\n } satisfies UndoPayload<MessageAggregateSnapshot>,\n },\n snapshotBefore: snapshots.before ?? null,\n snapshotAfter: snapshots.after ?? null,\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const undo = extractUndoPayload<UndoPayload<MessageAggregateSnapshot>>(logEntry)\n const before = undo?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n await restoreMessageAggregateSnapshot(em, before)\n },\n}\n\nconst replyMessageCommand: CommandHandler<unknown, { id: string; externalEmail: string | null; recipientUserIds: string[] }> = {\n id: 'messages.messages.reply',\n async execute(rawInput, ctx) {\n const input = replyCommandSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const original = await requireMessageById(em, input, input.messageId)\n const ownRecipient = await em.findOne(MessageRecipient, {\n messageId: original.id,\n recipientUserId: input.userId,\n deletedAt: null,\n })\n if (original.senderUserId !== input.userId && !ownRecipient) throw new Error('Access denied')\n\n const messageType = getMessageTypeOrDefault(original.type)\n if (messageType.allowReply === false) throw new Error('Reply is not allowed for this message type')\n\n const recipientIds = new Set(\n (input.recipients ?? [])\n .map((recipient) => recipient.userId)\n .filter((recipientUserId) => recipientUserId !== input.userId),\n )\n\n if (recipientIds.size === 0) {\n const originalRecipients = await em.find(MessageRecipient, { messageId: original.id, deletedAt: null })\n if (input.replyAll) {\n if (original.senderUserId !== input.userId) recipientIds.add(original.senderUserId)\n for (const recipient of originalRecipients) {\n if (recipient.recipientUserId !== input.userId) recipientIds.add(recipient.recipientUserId)\n }\n } else if (original.senderUserId !== input.userId) {\n recipientIds.add(original.senderUserId)\n } else {\n for (const recipient of originalRecipients) {\n if (recipient.recipientUserId !== input.userId) {\n recipientIds.add(recipient.recipientUserId)\n break\n }\n }\n }\n\n if (recipientIds.size === 0 && original.senderUserId === input.userId) {\n recipientIds.add(input.userId)\n }\n }\n if (recipientIds.size === 0) throw new Error('No recipients available for reply')\n\n let messageId = ''\n let responseExternalEmail: string | null = null\n await em.transactional(async (trx) => {\n const message = trx.create(Message, {\n type: original.type,\n visibility: original.visibility ?? null,\n sourceEntityType: original.sourceEntityType,\n sourceEntityId: original.sourceEntityId,\n externalEmail: original.externalEmail,\n externalName: original.externalName,\n threadId: original.threadId ?? original.id,\n parentMessageId: original.id,\n senderUserId: input.userId,\n subject: buildReplySubject(original.subject),\n body: input.body,\n bodyFormat: input.bodyFormat,\n priority: original.priority,\n status: 'sent',\n isDraft: false,\n sentAt: new Date(),\n sendViaEmail: input.sendViaEmail,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n await trx.persist(message).flush()\n for (const recipientUserId of recipientIds) {\n trx.persist(trx.create(MessageRecipient, {\n messageId: message.id,\n recipientUserId,\n recipientType: 'to',\n status: 'unread',\n }))\n }\n await trx.flush()\n if (input.attachmentIds?.length) {\n await linkAttachmentsToMessage(\n trx,\n message.id,\n input.attachmentIds,\n input.organizationId,\n input.tenantId,\n )\n }\n if (input.attachmentRecordId) {\n await linkLibraryAttachmentsToMessage(\n trx,\n message.id,\n input.attachmentRecordId,\n input.organizationId,\n input.tenantId,\n )\n }\n messageId = message.id\n responseExternalEmail = message.externalEmail ?? null\n })\n\n await emitMessageSentEvent(ctx.container, {\n messageId,\n senderUserId: input.userId,\n recipientUserIds: Array.from(recipientIds),\n sendViaEmail: input.sendViaEmail,\n externalEmail: responseExternalEmail,\n replyTo: original.id,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n await emitMessageIndexUpsert(ctx.container, {\n messageId,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n\n return {\n id: messageId,\n externalEmail: responseExternalEmail,\n recipientUserIds: Array.from(recipientIds),\n }\n },\n async captureAfter(_input, result, ctx) {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return loadMessageAggregateSnapshot(em, result.id)\n },\n buildLog: async ({ input, result, snapshots }) => {\n const parsed = replyCommandSchema.parse(input)\n return {\n actionLabel: 'Reply to message',\n resourceKind: 'messages.message',\n resourceId: result.id,\n parentResourceKind: 'messages.message',\n parentResourceId: parsed.messageId,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n payload: {\n undo: {\n after: (snapshots.after as MessageAggregateSnapshot | undefined) ?? null,\n } satisfies UndoPayload<MessageAggregateSnapshot>,\n },\n snapshotAfter: snapshots.after ?? null,\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const undo = extractUndoPayload<UndoPayload<MessageAggregateSnapshot>>(logEntry)\n const after = undo?.after\n if (!after) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await em.findOne(Message, { id: after.message.id })\n if (!message) return\n message.deletedAt = new Date()\n await em.flush()\n await emitMessageGloballyDeletedEvent(ctx.container, {\n messageId: after.message.id,\n actorUserId: after.message.senderUserId,\n recipientUserIds: after.recipients.map((recipient) => recipient.recipientUserId),\n tenantId: after.message.tenantId,\n organizationId: after.message.organizationId,\n })\n },\n}\n\nconst forwardMessageCommand: CommandHandler<unknown, { id: string; externalEmail: string | null; recipientUserIds: string[] }> = {\n id: 'messages.messages.forward',\n async execute(rawInput, ctx) {\n const input = forwardCommandSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const original = await requireMessageById(em, input, input.messageId)\n const isRecipient = await em.findOne(MessageRecipient, {\n messageId: input.messageId,\n recipientUserId: input.userId,\n deletedAt: null,\n })\n if (original.senderUserId !== input.userId && !isRecipient) throw new Error('Access denied')\n\n const messageType = getMessageTypeOrDefault(original.type)\n if (messageType.allowForward === false) throw new Error('Forward is not allowed for this message type')\n\n const originalObjects = await em.find(MessageObject, { messageId: input.messageId })\n const forwardThreadSlice = await buildForwardThreadSlice(em, {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n userId: input.userId,\n }, original)\n const generatedPreview = await buildForwardPreviewFromThreadSlice(em, {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n userId: input.userId,\n }, original, forwardThreadSlice)\n const forwardedBody = typeof input.body === 'string'\n ? input.body\n : buildForwardBodyFromLegacyInput(generatedPreview.body, input.additionalBody)\n let newMessageId = ''\n let responseExternalEmail: string | null = null\n await em.transactional(async (trx) => {\n const newMessage = trx.create(Message, {\n type: original.type,\n visibility: original.visibility ?? null,\n sourceEntityType: original.sourceEntityType,\n sourceEntityId: original.sourceEntityId,\n externalEmail: original.externalEmail,\n externalName: original.externalName,\n threadId: original.threadId ?? original.id,\n parentMessageId: original.id,\n senderUserId: input.userId,\n subject: `Fwd: ${original.subject}`,\n body: forwardedBody,\n bodyFormat: original.bodyFormat,\n priority: original.priority,\n status: 'sent',\n isDraft: false,\n sentAt: new Date(),\n sendViaEmail: input.sendViaEmail,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n await trx.persist(newMessage).flush()\n for (const recipient of input.recipients) {\n trx.persist(trx.create(MessageRecipient, {\n messageId: newMessage.id,\n recipientUserId: recipient.userId,\n recipientType: recipient.type,\n status: 'unread',\n }))\n }\n for (const obj of originalObjects) {\n trx.persist(trx.create(MessageObject, {\n messageId: newMessage.id,\n entityModule: obj.entityModule,\n entityType: obj.entityType,\n entityId: obj.entityId,\n actionRequired: obj.actionRequired,\n actionType: obj.actionType,\n actionLabel: obj.actionLabel,\n entitySnapshot: obj.entitySnapshot,\n }))\n }\n await trx.flush()\n if (input.includeAttachments !== false) {\n await copyAttachmentsForForwardMessages(\n trx,\n forwardThreadSlice.map((item) => item.id),\n newMessage.id,\n input.organizationId,\n input.tenantId,\n )\n }\n newMessageId = newMessage.id\n responseExternalEmail = newMessage.externalEmail ?? null\n })\n\n await emitMessageSentEvent(ctx.container, {\n messageId: newMessageId,\n senderUserId: input.userId,\n recipientUserIds: input.recipients.map((item) => item.userId),\n sendViaEmail: input.sendViaEmail,\n externalEmail: responseExternalEmail,\n forwardedFrom: original.id,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n await emitMessageIndexUpsert(ctx.container, {\n messageId: newMessageId,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n\n return {\n id: newMessageId,\n externalEmail: responseExternalEmail,\n recipientUserIds: input.recipients.map((item) => item.userId),\n }\n },\n async captureAfter(_input, result, ctx) {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return loadMessageAggregateSnapshot(em, result.id)\n },\n buildLog: async ({ input, result, snapshots }) => {\n const parsed = forwardCommandSchema.parse(input)\n return {\n actionLabel: 'Forward message',\n resourceKind: 'messages.message',\n resourceId: result.id,\n parentResourceKind: 'messages.message',\n parentResourceId: parsed.messageId,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n payload: {\n undo: {\n after: (snapshots.after as MessageAggregateSnapshot | undefined) ?? null,\n } satisfies UndoPayload<MessageAggregateSnapshot>,\n },\n snapshotAfter: snapshots.after ?? null,\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const undo = extractUndoPayload<UndoPayload<MessageAggregateSnapshot>>(logEntry)\n const after = undo?.after\n if (!after) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await em.findOne(Message, { id: after.message.id })\n if (!message) return\n message.deletedAt = new Date()\n await em.flush()\n await emitMessageGloballyDeletedEvent(ctx.container, {\n messageId: after.message.id,\n actorUserId: after.message.senderUserId,\n recipientUserIds: after.recipients.map((recipient) => recipient.recipientUserId),\n tenantId: after.message.tenantId,\n organizationId: after.message.organizationId,\n })\n },\n}\n\nconst deleteForActorCommand: CommandHandler<unknown, { ok: true }> = {\n id: 'messages.messages.delete_for_actor',\n async prepare(rawInput, ctx) {\n const input = deleteForActorCommandSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await requireMessageById(em, input, input.messageId)\n const recipient = await em.findOne(MessageRecipient, {\n messageId: input.messageId,\n recipientUserId: input.userId,\n deletedAt: null,\n })\n return {\n before: {\n messageId: message.id,\n messageDeletedAt: toIso(message.deletedAt),\n recipientId: recipient?.id ?? null,\n recipientStatus: recipient?.status ?? null,\n recipientDeletedAt: toIso(recipient?.deletedAt),\n } satisfies MessageDeleteUndoState,\n }\n },\n async execute(rawInput, ctx) {\n const input = deleteForActorCommandSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await requireMessageById(em, input, input.messageId)\n const recipient = await em.findOne(MessageRecipient, {\n messageId: input.messageId,\n recipientUserId: input.userId,\n deletedAt: null,\n })\n if (recipient) {\n recipient.status = 'deleted'\n recipient.deletedAt = new Date()\n await em.flush()\n await emitMessageDeletedEvent(ctx.container, {\n messageId: input.messageId,\n actorUserId: input.userId,\n target: 'recipient',\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n return { ok: true }\n }\n if (message.senderUserId === input.userId) {\n const recipientRows = await em.find(MessageRecipient, { messageId: input.messageId })\n message.deletedAt = new Date()\n await em.flush()\n const recipientUserIds = recipientRows\n .map((row) => row.recipientUserId)\n .filter((value): value is string => typeof value === 'string' && value.length > 0)\n await emitMessageGloballyDeletedEvent(ctx.container, {\n messageId: input.messageId,\n actorUserId: input.userId,\n recipientUserIds,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n return { ok: true }\n }\n throw new Error('Access denied')\n },\n async captureAfter(rawInput, _result, ctx) {\n const input = deleteForActorCommandSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await em.findOne(Message, { id: input.messageId, tenantId: input.tenantId })\n const recipient = await em.findOne(MessageRecipient, {\n messageId: input.messageId,\n recipientUserId: input.userId,\n })\n return {\n messageId: input.messageId,\n messageDeletedAt: toIso(message?.deletedAt),\n recipientId: recipient?.id ?? null,\n recipientStatus: recipient?.status ?? null,\n recipientDeletedAt: toIso(recipient?.deletedAt),\n } satisfies MessageDeleteUndoState\n },\n buildLog: async ({ input, snapshots }) => {\n const parsed = deleteForActorCommandSchema.parse(input)\n return {\n actionLabel: 'Delete message for actor',\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 MessageDeleteUndoState | undefined) ?? null,\n after: (snapshots.after as MessageDeleteUndoState | undefined) ?? null,\n } satisfies UndoPayload<MessageDeleteUndoState>,\n },\n snapshotBefore: snapshots.before ?? null,\n snapshotAfter: snapshots.after ?? null,\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const undo = extractUndoPayload<UndoPayload<MessageDeleteUndoState>>(logEntry)\n const before = undo?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await em.findOne(Message, { id: before.messageId })\n if (message) {\n message.deletedAt = toDate(before.messageDeletedAt)\n }\n if (before.recipientId) {\n const recipient = await em.findOne(MessageRecipient, { id: before.recipientId })\n if (recipient) {\n recipient.status = (before.recipientStatus ?? 'unread') as MessageRecipient['status']\n recipient.deletedAt = toDate(before.recipientDeletedAt)\n }\n }\n await em.flush()\n },\n}\n\nregisterCommand(composeMessageCommand)\nregisterCommand(updateDraftCommand)\nregisterCommand(replyMessageCommand)\nregisterCommand(forwardMessageCommand)\nregisterCommand(deleteForActorCommand)\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/messages/components/message-detail/hooks/useMessageDetailsActions.ts"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport type { UseQueryResult } from '@tanstack/react-query'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport type { MessageActionsProps, MessageContentProps } from '@open-mercato/shared/modules/messages/types'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport type {\n ActionResult,\n MessageAction,\n MessageAttachment,\n MessageDetail,\n PendingActionConfirmation,\n} from '../types'\nimport { parseObjectActionId, toErrorMessage } from '../utils'\n\ntype RequestAndRefreshOptions = {\n skipDetailAutoMarkRead?: boolean\n}\n\ntype ConversationActionKind = 'archiveConversation' | 'deleteConversation' | 'markAllUnread'\n\ntype UseMessageDetailsActionsInput = {\n id: string\n t: TranslateFn\n detail: MessageDetail | null\n detailQuery: UseQueryResult<MessageDetail, Error>\n attachments: MessageAttachment[] | undefined\n isArchived: boolean\n onDeleted: () => void\n refreshDetailWithoutAutoMarkRead: () => Promise<MessageDetail>\n}\n\nexport function useMessageDetailsActions({\n id,\n t,\n detail,\n detailQuery,\n attachments,\n isArchived,\n onDeleted,\n refreshDetailWithoutAutoMarkRead,\n}: UseMessageDetailsActionsInput) {\n const [replyOpen, setReplyOpen] = React.useState(false)\n const [forwardOpen, setForwardOpen] = React.useState(false)\n const [editOpen, setEditOpen] = React.useState(false)\n const [updatingState, setUpdatingState] = React.useState(false)\n const [executingActionId, setExecutingActionId] = React.useState<string | null>(null)\n const [pendingActionConfirmation, setPendingActionConfirmation] = React.useState<PendingActionConfirmation | null>(null)\n const [deleteConfirmationOpen, setDeleteConfirmationOpen] = React.useState(false)\n const [activeConversationAction, setActiveConversationAction] = React.useState<ConversationActionKind | null>(null)\n\n const requestAndRefresh = React.useCallback(async (\n url: string,\n method: 'PUT' | 'DELETE',\n options?: RequestAndRefreshOptions,\n ) => {\n setUpdatingState(true)\n try {\n const call = await apiCall<{ ok?: boolean }>(url, { method })\n if (!call.ok) {\n throw new Error(\n toErrorMessage(call.result)\n ?? t('messages.errors.stateChangeFailed', 'Failed to update message state.'),\n )\n }\n if (options?.skipDetailAutoMarkRead) {\n await refreshDetailWithoutAutoMarkRead()\n } else {\n await detailQuery.refetch()\n }\n } catch (err) {\n flash(\n err instanceof Error\n ? err.message\n : t('messages.errors.stateChangeFailed', 'Failed to update message state.'),\n 'error',\n )\n } finally {\n setUpdatingState(false)\n }\n }, [detailQuery, refreshDetailWithoutAutoMarkRead, t])\n\n const handleDelete = React.useCallback(async () => {\n setUpdatingState(true)\n try {\n const call = await apiCall<{ ok?: boolean }>(`/api/messages/${encodeURIComponent(id)}`, {\n method: 'DELETE',\n })\n if (!call.ok) {\n throw new Error(toErrorMessage(call.result) ?? t('messages.errors.deleteFailed', 'Failed to delete message.'))\n }\n flash(t('messages.flash.deleted', 'Message deleted.'), 'success')\n onDeleted()\n } catch (err) {\n flash(\n err instanceof Error\n ? err.message\n : t('messages.errors.deleteFailed', 'Failed to delete message.'),\n 'error',\n )\n } finally {\n setUpdatingState(false)\n }\n }, [id, onDeleted, t])\n\n const runConversationAction = React.useCallback(async (\n action: ConversationActionKind,\n options: {\n url: string\n method: 'PUT' | 'DELETE'\n successMessage: string\n skipDetailAutoMarkRead?: boolean\n onSuccess?: () => void\n },\n ) => {\n setActiveConversationAction(action)\n try {\n const call = await apiCall<{ ok?: boolean; affectedCount?: number }>(options.url, { method: options.method })\n if (!call.ok) {\n throw new Error(\n toErrorMessage(call.result)\n ?? t('messages.errors.conversationActionFailed', 'Failed to update conversation.'),\n )\n }\n\n flash(options.successMessage, 'success')\n\n if (options.onSuccess) {\n options.onSuccess()\n return\n }\n\n if (options.skipDetailAutoMarkRead) {\n await refreshDetailWithoutAutoMarkRead()\n } else {\n await detailQuery.refetch()\n }\n } catch (err) {\n flash(\n err instanceof Error\n ? err.message\n : t('messages.errors.conversationActionFailed', 'Failed to update conversation.'),\n 'error',\n )\n } finally {\n setActiveConversationAction(null)\n }\n }, [detailQuery, refreshDetailWithoutAutoMarkRead, t])\n\n const archiveConversation = React.useCallback(async (messageId?: string) => {\n const targetMessageId = messageId ?? id\n await runConversationAction('archiveConversation', {\n url: `/api/messages/${encodeURIComponent(targetMessageId)}/conversation/archive`,\n method: 'PUT',\n successMessage: t('messages.flash.conversationArchived', 'Conversation archived.'),\n })\n }, [id, runConversationAction, t])\n\n const markConversationUnread = React.useCallback(async (messageId?: string) => {\n const targetMessageId = messageId ?? id\n await runConversationAction('markAllUnread', {\n url: `/api/messages/${encodeURIComponent(targetMessageId)}/conversation/read`,\n method: 'DELETE',\n successMessage: t('messages.flash.conversationMarkedUnread', 'Conversation marked unread.'),\n skipDetailAutoMarkRead: true,\n })\n }, [id, runConversationAction, t])\n\n const deleteConversation = React.useCallback(async (messageId?: string) => {\n const targetMessageId = messageId ?? id\n await runConversationAction('deleteConversation', {\n url: `/api/messages/${encodeURIComponent(targetMessageId)}/conversation`,\n method: 'DELETE',\n successMessage: t('messages.flash.conversationDeleted', 'Conversation deleted.'),\n onSuccess: onDeleted,\n })\n }, [id, onDeleted, runConversationAction, t])\n\n const handleDeleteDialogKeyDown = React.useCallback((event: React.KeyboardEvent<HTMLDivElement>) => {\n if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {\n event.preventDefault()\n void handleDelete()\n return\n }\n\n if (event.key === 'Escape') {\n event.preventDefault()\n setDeleteConfirmationOpen(false)\n }\n }, [handleDelete])\n\n const executeAction = React.useCallback(async (action: MessageAction, payload?: Record<string, unknown>) => {\n setExecutingActionId(action.id)\n try {\n const call = await apiCall<ActionResult>(\n `/api/messages/${encodeURIComponent(id)}/actions/${encodeURIComponent(action.id)}`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload ?? {}),\n },\n )\n\n if (!call.ok) {\n throw new Error(\n toErrorMessage(call.result)\n ?? t('messages.errors.actionFailed', 'Failed to execute action.'),\n )\n }\n\n flash(t('messages.flash.actionSuccess', 'Action completed.'), 'success')\n\n const redirectTarget = call.result?.result?.redirect\n if (typeof redirectTarget === 'string' && redirectTarget.trim().length > 0) {\n window.location.href = redirectTarget\n return\n }\n\n await detailQuery.refetch()\n } catch (err) {\n flash(\n err instanceof Error\n ? err.message\n : t('messages.errors.actionFailed', 'Failed to execute action.'),\n 'error',\n )\n } finally {\n setExecutingActionId(null)\n }\n }, [detailQuery, id, t])\n\n const handleExecuteAction = React.useCallback(async (action: MessageAction, payload?: Record<string, unknown>) => {\n if (executingActionId || detail?.actionTaken) return\n\n if (action.confirmRequired) {\n setPendingActionConfirmation({ action, payload })\n return\n }\n\n await executeAction(action, payload)\n }, [detail?.actionTaken, executeAction, executingActionId])\n\n const handleConfirmPendingAction = React.useCallback(async () => {\n if (!pendingActionConfirmation || executingActionId || detail?.actionTaken) return\n const { action, payload } = pendingActionConfirmation\n setPendingActionConfirmation(null)\n await executeAction(action, payload)\n }, [detail?.actionTaken, executeAction, executingActionId, pendingActionConfirmation])\n\n const handleActionConfirmDialogKeyDown = React.useCallback((event: React.KeyboardEvent<HTMLDivElement>) => {\n if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {\n event.preventDefault()\n void handleConfirmPendingAction()\n return\n }\n\n if (event.key === 'Escape') {\n event.preventDefault()\n setPendingActionConfirmation(null)\n }\n }, [handleConfirmPendingAction])\n\n const contentProps = React.useMemo<MessageContentProps>(() => ({\n message: {\n id: detail?.id ?? '',\n type: detail?.type ?? 'default',\n subject: detail?.subject ?? '',\n body: detail?.body ?? '',\n bodyFormat: detail?.bodyFormat ?? 'text',\n priority: (detail?.priority ?? 'normal') as 'low' | 'normal' | 'high' | 'urgent',\n sentAt: detail?.sentAt ? new Date(detail.sentAt) : null,\n senderName: detail?.senderName ?? undefined,\n senderUserId: detail?.senderUserId ?? '',\n actionData: detail?.actionData ?? null,\n actionTaken: detail?.actionTaken ?? null,\n actionTakenAt: detail?.actionTakenAt ? new Date(detail.actionTakenAt) : null,\n },\n objects: (detail?.objects ?? []).map((item) => ({\n id: item.id,\n entityModule: item.entityModule,\n entityType: item.entityType,\n entityId: item.entityId,\n actionRequired: item.actionRequired,\n snapshot: item.snapshot ?? undefined,\n })),\n attachments: (attachments ?? []).map((item) => ({\n id: item.id,\n fileName: item.fileName,\n fileSize: item.fileSize,\n mimeType: item.mimeType,\n url: item.url,\n })),\n }), [attachments, detail])\n\n const handleExecuteActionById = React.useCallback<MessageActionsProps['onExecuteAction']>(async (actionId, payload) => {\n const action = detail?.actionData?.actions?.find((entry) => {\n if (parseObjectActionId(entry.id)) return false\n return entry.id === actionId\n })\n if (!action) return\n await handleExecuteAction(action, payload)\n }, [detail?.actionData?.actions, handleExecuteAction])\n\n const messageActions = React.useMemo(() => {\n return (detail?.actionData?.actions ?? []).filter((action) => !parseObjectActionId(action.id))\n }, [detail?.actionData?.actions])\n\n const objectActionsByObjectId = React.useMemo(() => {\n const byObjectId = new Map<string, Map<string, MessageAction>>()\n for (const action of detail?.actionData?.actions ?? []) {\n const parsed = parseObjectActionId(action.id)\n if (!parsed) continue\n const current = byObjectId.get(parsed.objectId) ?? new Map<string, MessageAction>()\n current.set(parsed.actionId, action)\n byObjectId.set(parsed.objectId, current)\n }\n return byObjectId\n }, [detail?.actionData?.actions])\n\n const toggleRead = React.useCallback(async () => {\n await requestAndRefresh(\n `/api/messages/${encodeURIComponent(id)}/read`,\n detail?.isRead ? 'DELETE' : 'PUT',\n detail?.isRead ? { skipDetailAutoMarkRead: true } : undefined,\n )\n }, [detail?.isRead, id, requestAndRefresh])\n\n const toggleArchive = React.useCallback(async () => {\n await requestAndRefresh(\n `/api/messages/${encodeURIComponent(id)}/archive`,\n isArchived ? 'DELETE' : 'PUT',\n )\n }, [id, isArchived, requestAndRefresh])\n\n return {\n replyOpen,\n setReplyOpen,\n forwardOpen,\n setForwardOpen,\n editOpen,\n setEditOpen,\n updatingState,\n executingActionId,\n pendingActionConfirmation,\n setPendingActionConfirmation,\n deleteConfirmationOpen,\n setDeleteConfirmationOpen,\n activeConversationAction,\n toggleRead,\n toggleArchive,\n archiveConversation,\n deleteConversation,\n markConversationUnread,\n requestAndRefresh,\n handleDelete,\n handleDeleteDialogKeyDown,\n handleExecuteAction,\n handleConfirmPendingAction,\n handleActionConfirmDialogKeyDown,\n contentProps,\n handleExecuteActionById,\n messageActions,\n objectActionsByObjectId,\n }\n}\n"],
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport type { UseQueryResult } from '@tanstack/react-query'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport type { MessageActionsProps, MessageContentProps } from '@open-mercato/shared/modules/messages/types'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport type {\n ActionResult,\n MessageAction,\n MessageAttachment,\n MessageDetail,\n PendingActionConfirmation,\n} from '../types'\nimport { parseObjectActionId, toErrorMessage } from '../utils'\n\ntype RequestAndRefreshOptions = {\n skipDetailAutoMarkRead?: boolean\n}\n\ntype ConversationActionKind = 'archiveConversation' | 'deleteConversation' | 'markAllUnread'\n\ntype UseMessageDetailsActionsInput = {\n id: string\n t: TranslateFn\n detail: MessageDetail | null\n detailQuery: UseQueryResult<MessageDetail | null, Error>\n attachments: MessageAttachment[] | undefined\n isArchived: boolean\n onDeleted: () => void\n refreshDetailWithoutAutoMarkRead: () => Promise<MessageDetail | null>\n}\n\nexport function useMessageDetailsActions({\n id,\n t,\n detail,\n detailQuery,\n attachments,\n isArchived,\n onDeleted,\n refreshDetailWithoutAutoMarkRead,\n}: UseMessageDetailsActionsInput) {\n const [replyOpen, setReplyOpen] = React.useState(false)\n const [forwardOpen, setForwardOpen] = React.useState(false)\n const [editOpen, setEditOpen] = React.useState(false)\n const [updatingState, setUpdatingState] = React.useState(false)\n const [executingActionId, setExecutingActionId] = React.useState<string | null>(null)\n const [pendingActionConfirmation, setPendingActionConfirmation] = React.useState<PendingActionConfirmation | null>(null)\n const [deleteConfirmationOpen, setDeleteConfirmationOpen] = React.useState(false)\n const [activeConversationAction, setActiveConversationAction] = React.useState<ConversationActionKind | null>(null)\n\n const requestAndRefresh = React.useCallback(async (\n url: string,\n method: 'PUT' | 'DELETE',\n options?: RequestAndRefreshOptions,\n ) => {\n setUpdatingState(true)\n try {\n const call = await apiCall<{ ok?: boolean }>(url, { method })\n if (!call.ok) {\n throw new Error(\n toErrorMessage(call.result)\n ?? t('messages.errors.stateChangeFailed', 'Failed to update message state.'),\n )\n }\n if (options?.skipDetailAutoMarkRead) {\n await refreshDetailWithoutAutoMarkRead()\n } else {\n await detailQuery.refetch()\n }\n } catch (err) {\n flash(\n err instanceof Error\n ? err.message\n : t('messages.errors.stateChangeFailed', 'Failed to update message state.'),\n 'error',\n )\n } finally {\n setUpdatingState(false)\n }\n }, [detailQuery, refreshDetailWithoutAutoMarkRead, t])\n\n const handleDelete = React.useCallback(async () => {\n setUpdatingState(true)\n try {\n const call = await apiCall<{ ok?: boolean }>(`/api/messages/${encodeURIComponent(id)}`, {\n method: 'DELETE',\n })\n if (!call.ok) {\n throw new Error(toErrorMessage(call.result) ?? t('messages.errors.deleteFailed', 'Failed to delete message.'))\n }\n flash(t('messages.flash.deleted', 'Message deleted.'), 'success')\n onDeleted()\n } catch (err) {\n flash(\n err instanceof Error\n ? err.message\n : t('messages.errors.deleteFailed', 'Failed to delete message.'),\n 'error',\n )\n } finally {\n setUpdatingState(false)\n }\n }, [id, onDeleted, t])\n\n const runConversationAction = React.useCallback(async (\n action: ConversationActionKind,\n options: {\n url: string\n method: 'PUT' | 'DELETE'\n successMessage: string\n skipDetailAutoMarkRead?: boolean\n onSuccess?: () => void\n },\n ) => {\n setActiveConversationAction(action)\n try {\n const call = await apiCall<{ ok?: boolean; affectedCount?: number }>(options.url, { method: options.method })\n if (!call.ok) {\n throw new Error(\n toErrorMessage(call.result)\n ?? t('messages.errors.conversationActionFailed', 'Failed to update conversation.'),\n )\n }\n\n flash(options.successMessage, 'success')\n\n if (options.onSuccess) {\n options.onSuccess()\n return\n }\n\n if (options.skipDetailAutoMarkRead) {\n await refreshDetailWithoutAutoMarkRead()\n } else {\n await detailQuery.refetch()\n }\n } catch (err) {\n flash(\n err instanceof Error\n ? err.message\n : t('messages.errors.conversationActionFailed', 'Failed to update conversation.'),\n 'error',\n )\n } finally {\n setActiveConversationAction(null)\n }\n }, [detailQuery, refreshDetailWithoutAutoMarkRead, t])\n\n const archiveConversation = React.useCallback(async (messageId?: string) => {\n const targetMessageId = messageId ?? id\n await runConversationAction('archiveConversation', {\n url: `/api/messages/${encodeURIComponent(targetMessageId)}/conversation/archive`,\n method: 'PUT',\n successMessage: t('messages.flash.conversationArchived', 'Conversation archived.'),\n })\n }, [id, runConversationAction, t])\n\n const markConversationUnread = React.useCallback(async (messageId?: string) => {\n const targetMessageId = messageId ?? id\n await runConversationAction('markAllUnread', {\n url: `/api/messages/${encodeURIComponent(targetMessageId)}/conversation/read`,\n method: 'DELETE',\n successMessage: t('messages.flash.conversationMarkedUnread', 'Conversation marked unread.'),\n skipDetailAutoMarkRead: true,\n })\n }, [id, runConversationAction, t])\n\n const deleteConversation = React.useCallback(async (messageId?: string) => {\n const targetMessageId = messageId ?? id\n await runConversationAction('deleteConversation', {\n url: `/api/messages/${encodeURIComponent(targetMessageId)}/conversation`,\n method: 'DELETE',\n successMessage: t('messages.flash.conversationDeleted', 'Conversation deleted.'),\n onSuccess: onDeleted,\n })\n }, [id, onDeleted, runConversationAction, t])\n\n const handleDeleteDialogKeyDown = React.useCallback((event: React.KeyboardEvent<HTMLDivElement>) => {\n if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {\n event.preventDefault()\n void handleDelete()\n return\n }\n\n if (event.key === 'Escape') {\n event.preventDefault()\n setDeleteConfirmationOpen(false)\n }\n }, [handleDelete])\n\n const executeAction = React.useCallback(async (action: MessageAction, payload?: Record<string, unknown>) => {\n setExecutingActionId(action.id)\n try {\n const call = await apiCall<ActionResult>(\n `/api/messages/${encodeURIComponent(id)}/actions/${encodeURIComponent(action.id)}`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload ?? {}),\n },\n )\n\n if (!call.ok) {\n throw new Error(\n toErrorMessage(call.result)\n ?? t('messages.errors.actionFailed', 'Failed to execute action.'),\n )\n }\n\n flash(t('messages.flash.actionSuccess', 'Action completed.'), 'success')\n\n const redirectTarget = call.result?.result?.redirect\n if (typeof redirectTarget === 'string' && redirectTarget.trim().length > 0) {\n window.location.href = redirectTarget\n return\n }\n\n await detailQuery.refetch()\n } catch (err) {\n flash(\n err instanceof Error\n ? err.message\n : t('messages.errors.actionFailed', 'Failed to execute action.'),\n 'error',\n )\n } finally {\n setExecutingActionId(null)\n }\n }, [detailQuery, id, t])\n\n const handleExecuteAction = React.useCallback(async (action: MessageAction, payload?: Record<string, unknown>) => {\n if (executingActionId || detail?.actionTaken) return\n\n if (action.confirmRequired) {\n setPendingActionConfirmation({ action, payload })\n return\n }\n\n await executeAction(action, payload)\n }, [detail?.actionTaken, executeAction, executingActionId])\n\n const handleConfirmPendingAction = React.useCallback(async () => {\n if (!pendingActionConfirmation || executingActionId || detail?.actionTaken) return\n const { action, payload } = pendingActionConfirmation\n setPendingActionConfirmation(null)\n await executeAction(action, payload)\n }, [detail?.actionTaken, executeAction, executingActionId, pendingActionConfirmation])\n\n const handleActionConfirmDialogKeyDown = React.useCallback((event: React.KeyboardEvent<HTMLDivElement>) => {\n if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {\n event.preventDefault()\n void handleConfirmPendingAction()\n return\n }\n\n if (event.key === 'Escape') {\n event.preventDefault()\n setPendingActionConfirmation(null)\n }\n }, [handleConfirmPendingAction])\n\n const contentProps = React.useMemo<MessageContentProps>(() => ({\n message: {\n id: detail?.id ?? '',\n type: detail?.type ?? 'default',\n subject: detail?.subject ?? '',\n body: detail?.body ?? '',\n bodyFormat: detail?.bodyFormat ?? 'text',\n priority: (detail?.priority ?? 'normal') as 'low' | 'normal' | 'high' | 'urgent',\n sentAt: detail?.sentAt ? new Date(detail.sentAt) : null,\n senderName: detail?.senderName ?? undefined,\n senderUserId: detail?.senderUserId ?? '',\n actionData: detail?.actionData ?? null,\n actionTaken: detail?.actionTaken ?? null,\n actionTakenAt: detail?.actionTakenAt ? new Date(detail.actionTakenAt) : null,\n },\n objects: (detail?.objects ?? []).map((item) => ({\n id: item.id,\n entityModule: item.entityModule,\n entityType: item.entityType,\n entityId: item.entityId,\n actionRequired: item.actionRequired,\n snapshot: item.snapshot ?? undefined,\n })),\n attachments: (attachments ?? []).map((item) => ({\n id: item.id,\n fileName: item.fileName,\n fileSize: item.fileSize,\n mimeType: item.mimeType,\n url: item.url,\n })),\n }), [attachments, detail])\n\n const handleExecuteActionById = React.useCallback<MessageActionsProps['onExecuteAction']>(async (actionId, payload) => {\n const action = detail?.actionData?.actions?.find((entry) => {\n if (parseObjectActionId(entry.id)) return false\n return entry.id === actionId\n })\n if (!action) return\n await handleExecuteAction(action, payload)\n }, [detail?.actionData?.actions, handleExecuteAction])\n\n const messageActions = React.useMemo(() => {\n return (detail?.actionData?.actions ?? []).filter((action) => !parseObjectActionId(action.id))\n }, [detail?.actionData?.actions])\n\n const objectActionsByObjectId = React.useMemo(() => {\n const byObjectId = new Map<string, Map<string, MessageAction>>()\n for (const action of detail?.actionData?.actions ?? []) {\n const parsed = parseObjectActionId(action.id)\n if (!parsed) continue\n const current = byObjectId.get(parsed.objectId) ?? new Map<string, MessageAction>()\n current.set(parsed.actionId, action)\n byObjectId.set(parsed.objectId, current)\n }\n return byObjectId\n }, [detail?.actionData?.actions])\n\n const toggleRead = React.useCallback(async () => {\n await requestAndRefresh(\n `/api/messages/${encodeURIComponent(id)}/read`,\n detail?.isRead ? 'DELETE' : 'PUT',\n detail?.isRead ? { skipDetailAutoMarkRead: true } : undefined,\n )\n }, [detail?.isRead, id, requestAndRefresh])\n\n const toggleArchive = React.useCallback(async () => {\n await requestAndRefresh(\n `/api/messages/${encodeURIComponent(id)}/archive`,\n isArchived ? 'DELETE' : 'PUT',\n )\n }, [id, isArchived, requestAndRefresh])\n\n return {\n replyOpen,\n setReplyOpen,\n forwardOpen,\n setForwardOpen,\n editOpen,\n setEditOpen,\n updatingState,\n executingActionId,\n pendingActionConfirmation,\n setPendingActionConfirmation,\n deleteConfirmationOpen,\n setDeleteConfirmationOpen,\n activeConversationAction,\n toggleRead,\n toggleArchive,\n archiveConversation,\n deleteConversation,\n markConversationUnread,\n requestAndRefresh,\n handleDelete,\n handleDeleteDialogKeyDown,\n handleExecuteAction,\n handleConfirmPendingAction,\n handleActionConfirmDialogKeyDown,\n contentProps,\n handleExecuteActionById,\n messageActions,\n objectActionsByObjectId,\n }\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -17,6 +17,9 @@ function useMessageDetailsQueries({
17
17
  queryKey: detailQueryKey,
18
18
  queryFn: async () => {
19
19
  const call = await apiCall(`/api/messages/${encodeURIComponent(id)}`);
20
+ if (call.status === 404) {
21
+ return null;
22
+ }
20
23
  if (!call.ok || !call.result) {
21
24
  throw new Error(
22
25
  toErrorMessage(call.result) ?? t("messages.errors.loadDetailFailed", "Failed to load message details.")
@@ -27,13 +30,17 @@ function useMessageDetailsQueries({
27
30
  });
28
31
  const detail = detailQuery.data ?? null;
29
32
  const isLoadingDetail = detailQuery.isLoading;
30
- const loadErrorMessage = detailQuery.error instanceof Error ? detailQuery.error.message : t("messages.errors.loadDetailFailed", "Failed to load message details.");
33
+ const isDetailMissing = detailQuery.isSuccess && detailQuery.data === null;
34
+ const loadErrorMessage = isDetailMissing ? t("messages.errors.messageDeleted", "This message is no longer available.") : detailQuery.error instanceof Error ? detailQuery.error.message : t("messages.errors.loadDetailFailed", "Failed to load message details.");
31
35
  const attachmentsQuery = useQuery({
32
36
  queryKey: ["messages", "detail", id, "attachments", scopeVersion],
33
37
  queryFn: async () => {
34
38
  const call = await apiCall(
35
39
  `/api/messages/${encodeURIComponent(id)}/attachments`
36
40
  );
41
+ if (call.status === 404) {
42
+ return [];
43
+ }
37
44
  if (!call.ok) {
38
45
  throw new Error(
39
46
  toErrorMessage(call.result) ?? t("messages.errors.loadDetailFailed", "Failed to load message details.")
@@ -47,6 +54,10 @@ function useMessageDetailsQueries({
47
54
  const call = await apiCall(
48
55
  `/api/messages/${encodeURIComponent(id)}?skipMarkRead=1`
49
56
  );
57
+ if (call.status === 404) {
58
+ queryClient.setQueryData(detailQueryKey, null);
59
+ return null;
60
+ }
50
61
  if (!call.ok || !call.result) {
51
62
  throw new Error(
52
63
  toErrorMessage(call.result) ?? t("messages.errors.stateChangeFailed", "Failed to update message state.")
@@ -63,6 +74,7 @@ function useMessageDetailsQueries({
63
74
  detailQuery,
64
75
  detail,
65
76
  isLoadingDetail,
77
+ isDetailMissing,
66
78
  loadErrorMessage,
67
79
  attachmentsQuery,
68
80
  attachments,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/messages/components/message-detail/hooks/useMessageDetailsQueries.ts"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { useQuery } from '@tanstack/react-query'\nimport type { QueryClient } from '@tanstack/react-query'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport type { MessageAttachment, MessageDetail } from '../types'\nimport { toErrorMessage } from '../utils'\n\ntype UseMessageDetailsQueriesInput = {\n id: string\n t: TranslateFn\n scopeVersion: unknown\n queryClient: QueryClient\n}\n\nexport function useMessageDetailsQueries({\n id,\n t,\n scopeVersion,\n queryClient,\n}: UseMessageDetailsQueriesInput) {\n const detailQueryKey = React.useMemo(\n () => ['messages', 'detail', id, scopeVersion],\n [id, scopeVersion],\n )\n\n const detailQuery = useQuery({\n queryKey: detailQueryKey,\n queryFn: async () => {\n const call = await apiCall<MessageDetail>(`/api/messages/${encodeURIComponent(id)}`)\n if (!call.ok || !call.result) {\n throw new Error(\n toErrorMessage(call.result)\n ?? t('messages.errors.loadDetailFailed', 'Failed to load message details.'),\n )\n }\n return call.result\n },\n })\n\n const detail = detailQuery.data ?? null\n const isLoadingDetail = detailQuery.isLoading\n const loadErrorMessage = detailQuery.error instanceof Error\n ? detailQuery.error.message\n : t('messages.errors.loadDetailFailed', 'Failed to load message details.')\n\n const attachmentsQuery = useQuery({\n queryKey: ['messages', 'detail', id, 'attachments', scopeVersion],\n queryFn: async () => {\n const call = await apiCall<{ attachments?: MessageAttachment[] }>(\n `/api/messages/${encodeURIComponent(id)}/attachments`,\n )\n\n if (!call.ok) {\n throw new Error(\n toErrorMessage(call.result)\n ?? t('messages.errors.loadDetailFailed', 'Failed to load message details.'),\n )\n }\n\n return call.result?.attachments ?? []\n },\n })\n\n const attachments = attachmentsQuery.data\n\n const refreshDetailWithoutAutoMarkRead = React.useCallback(async () => {\n const call = await apiCall<MessageDetail>(\n `/api/messages/${encodeURIComponent(id)}?skipMarkRead=1`,\n )\n\n if (!call.ok || !call.result) {\n throw new Error(\n toErrorMessage(call.result)\n ?? t('messages.errors.stateChangeFailed', 'Failed to update message state.'),\n )\n }\n\n queryClient.setQueryData(detailQueryKey, call.result)\n return call.result\n }, [detailQueryKey, id, queryClient, t])\n\n const listItemComponentKey = detail?.typeDefinition.ui?.listItemComponent ?? null\n const contentComponentKey = detail?.typeDefinition.ui?.contentComponent ?? null\n const actionsComponentKey = detail?.typeDefinition.ui?.actionsComponent ?? null\n\n return {\n detailQueryKey,\n detailQuery,\n detail,\n isLoadingDetail,\n loadErrorMessage,\n attachmentsQuery,\n attachments,\n refreshDetailWithoutAutoMarkRead,\n listItemComponentKey,\n contentComponentKey,\n actionsComponentKey,\n }\n}\n"],
5
- "mappings": ";AAEA,YAAY,WAAW;AACvB,SAAS,gBAAgB;AAGzB,SAAS,eAAe;AAExB,SAAS,sBAAsB;AASxB,SAAS,yBAAyB;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAkC;AAChC,QAAM,iBAAiB,MAAM;AAAA,IAC3B,MAAM,CAAC,YAAY,UAAU,IAAI,YAAY;AAAA,IAC7C,CAAC,IAAI,YAAY;AAAA,EACnB;AAEA,QAAM,cAAc,SAAS;AAAA,IAC3B,UAAU;AAAA,IACV,SAAS,YAAY;AACnB,YAAM,OAAO,MAAM,QAAuB,iBAAiB,mBAAmB,EAAE,CAAC,EAAE;AACnF,UAAI,CAAC,KAAK,MAAM,CAAC,KAAK,QAAQ;AAC5B,cAAM,IAAI;AAAA,UACR,eAAe,KAAK,MAAM,KACvB,EAAE,oCAAoC,iCAAiC;AAAA,QAC5E;AAAA,MACF;AACA,aAAO,KAAK;AAAA,IACd;AAAA,EACF,CAAC;AAED,QAAM,SAAS,YAAY,QAAQ;AACnC,QAAM,kBAAkB,YAAY;AACpC,QAAM,mBAAmB,YAAY,iBAAiB,QAClD,YAAY,MAAM,UAClB,EAAE,oCAAoC,iCAAiC;AAE3E,QAAM,mBAAmB,SAAS;AAAA,IAChC,UAAU,CAAC,YAAY,UAAU,IAAI,eAAe,YAAY;AAAA,IAChE,SAAS,YAAY;AACnB,YAAM,OAAO,MAAM;AAAA,QACjB,iBAAiB,mBAAmB,EAAE,CAAC;AAAA,MACzC;AAEA,UAAI,CAAC,KAAK,IAAI;AACZ,cAAM,IAAI;AAAA,UACR,eAAe,KAAK,MAAM,KACvB,EAAE,oCAAoC,iCAAiC;AAAA,QAC5E;AAAA,MACF;AAEA,aAAO,KAAK,QAAQ,eAAe,CAAC;AAAA,IACtC;AAAA,EACF,CAAC;AAED,QAAM,cAAc,iBAAiB;AAErC,QAAM,mCAAmC,MAAM,YAAY,YAAY;AACrE,UAAM,OAAO,MAAM;AAAA,MACjB,iBAAiB,mBAAmB,EAAE,CAAC;AAAA,IACzC;AAEA,QAAI,CAAC,KAAK,MAAM,CAAC,KAAK,QAAQ;AAC5B,YAAM,IAAI;AAAA,QACR,eAAe,KAAK,MAAM,KACvB,EAAE,qCAAqC,iCAAiC;AAAA,MAC7E;AAAA,IACF;AAEA,gBAAY,aAAa,gBAAgB,KAAK,MAAM;AACpD,WAAO,KAAK;AAAA,EACd,GAAG,CAAC,gBAAgB,IAAI,aAAa,CAAC,CAAC;AAEvC,QAAM,uBAAuB,QAAQ,eAAe,IAAI,qBAAqB;AAC7E,QAAM,sBAAsB,QAAQ,eAAe,IAAI,oBAAoB;AAC3E,QAAM,sBAAsB,QAAQ,eAAe,IAAI,oBAAoB;AAE3E,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { useQuery } from '@tanstack/react-query'\nimport type { QueryClient } from '@tanstack/react-query'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport type { MessageAttachment, MessageDetail } from '../types'\nimport { toErrorMessage } from '../utils'\n\ntype UseMessageDetailsQueriesInput = {\n id: string\n t: TranslateFn\n scopeVersion: unknown\n queryClient: QueryClient\n}\n\nexport function useMessageDetailsQueries({\n id,\n t,\n scopeVersion,\n queryClient,\n}: UseMessageDetailsQueriesInput) {\n const detailQueryKey = React.useMemo(\n () => ['messages', 'detail', id, scopeVersion],\n [id, scopeVersion],\n )\n\n const detailQuery = useQuery<MessageDetail | null>({\n queryKey: detailQueryKey,\n queryFn: async () => {\n const call = await apiCall<MessageDetail>(`/api/messages/${encodeURIComponent(id)}`)\n if (call.status === 404) {\n return null\n }\n if (!call.ok || !call.result) {\n throw new Error(\n toErrorMessage(call.result)\n ?? t('messages.errors.loadDetailFailed', 'Failed to load message details.'),\n )\n }\n return call.result\n },\n })\n\n const detail = detailQuery.data ?? null\n const isLoadingDetail = detailQuery.isLoading\n const isDetailMissing = detailQuery.isSuccess && detailQuery.data === null\n const loadErrorMessage = isDetailMissing\n ? t('messages.errors.messageDeleted', 'This message is no longer available.')\n : detailQuery.error instanceof Error\n ? detailQuery.error.message\n : t('messages.errors.loadDetailFailed', 'Failed to load message details.')\n\n const attachmentsQuery = useQuery<MessageAttachment[]>({\n queryKey: ['messages', 'detail', id, 'attachments', scopeVersion],\n queryFn: async () => {\n const call = await apiCall<{ attachments?: MessageAttachment[] }>(\n `/api/messages/${encodeURIComponent(id)}/attachments`,\n )\n\n if (call.status === 404) {\n return []\n }\n\n if (!call.ok) {\n throw new Error(\n toErrorMessage(call.result)\n ?? t('messages.errors.loadDetailFailed', 'Failed to load message details.'),\n )\n }\n\n return call.result?.attachments ?? []\n },\n })\n\n const attachments = attachmentsQuery.data\n\n const refreshDetailWithoutAutoMarkRead = React.useCallback(async () => {\n const call = await apiCall<MessageDetail>(\n `/api/messages/${encodeURIComponent(id)}?skipMarkRead=1`,\n )\n\n if (call.status === 404) {\n queryClient.setQueryData(detailQueryKey, null)\n return null\n }\n\n if (!call.ok || !call.result) {\n throw new Error(\n toErrorMessage(call.result)\n ?? t('messages.errors.stateChangeFailed', 'Failed to update message state.'),\n )\n }\n\n queryClient.setQueryData(detailQueryKey, call.result)\n return call.result\n }, [detailQueryKey, id, queryClient, t])\n\n const listItemComponentKey = detail?.typeDefinition.ui?.listItemComponent ?? null\n const contentComponentKey = detail?.typeDefinition.ui?.contentComponent ?? null\n const actionsComponentKey = detail?.typeDefinition.ui?.actionsComponent ?? null\n\n return {\n detailQueryKey,\n detailQuery,\n detail,\n isLoadingDetail,\n isDetailMissing,\n loadErrorMessage,\n attachmentsQuery,\n attachments,\n refreshDetailWithoutAutoMarkRead,\n listItemComponentKey,\n contentComponentKey,\n actionsComponentKey,\n }\n}\n"],
5
+ "mappings": ";AAEA,YAAY,WAAW;AACvB,SAAS,gBAAgB;AAGzB,SAAS,eAAe;AAExB,SAAS,sBAAsB;AASxB,SAAS,yBAAyB;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAkC;AAChC,QAAM,iBAAiB,MAAM;AAAA,IAC3B,MAAM,CAAC,YAAY,UAAU,IAAI,YAAY;AAAA,IAC7C,CAAC,IAAI,YAAY;AAAA,EACnB;AAEA,QAAM,cAAc,SAA+B;AAAA,IACjD,UAAU;AAAA,IACV,SAAS,YAAY;AACnB,YAAM,OAAO,MAAM,QAAuB,iBAAiB,mBAAmB,EAAE,CAAC,EAAE;AACnF,UAAI,KAAK,WAAW,KAAK;AACvB,eAAO;AAAA,MACT;AACA,UAAI,CAAC,KAAK,MAAM,CAAC,KAAK,QAAQ;AAC5B,cAAM,IAAI;AAAA,UACR,eAAe,KAAK,MAAM,KACvB,EAAE,oCAAoC,iCAAiC;AAAA,QAC5E;AAAA,MACF;AACA,aAAO,KAAK;AAAA,IACd;AAAA,EACF,CAAC;AAED,QAAM,SAAS,YAAY,QAAQ;AACnC,QAAM,kBAAkB,YAAY;AACpC,QAAM,kBAAkB,YAAY,aAAa,YAAY,SAAS;AACtE,QAAM,mBAAmB,kBACrB,EAAE,kCAAkC,sCAAsC,IAC1E,YAAY,iBAAiB,QAC3B,YAAY,MAAM,UAClB,EAAE,oCAAoC,iCAAiC;AAE7E,QAAM,mBAAmB,SAA8B;AAAA,IACrD,UAAU,CAAC,YAAY,UAAU,IAAI,eAAe,YAAY;AAAA,IAChE,SAAS,YAAY;AACnB,YAAM,OAAO,MAAM;AAAA,QACjB,iBAAiB,mBAAmB,EAAE,CAAC;AAAA,MACzC;AAEA,UAAI,KAAK,WAAW,KAAK;AACvB,eAAO,CAAC;AAAA,MACV;AAEA,UAAI,CAAC,KAAK,IAAI;AACZ,cAAM,IAAI;AAAA,UACR,eAAe,KAAK,MAAM,KACvB,EAAE,oCAAoC,iCAAiC;AAAA,QAC5E;AAAA,MACF;AAEA,aAAO,KAAK,QAAQ,eAAe,CAAC;AAAA,IACtC;AAAA,EACF,CAAC;AAED,QAAM,cAAc,iBAAiB;AAErC,QAAM,mCAAmC,MAAM,YAAY,YAAY;AACrE,UAAM,OAAO,MAAM;AAAA,MACjB,iBAAiB,mBAAmB,EAAE,CAAC;AAAA,IACzC;AAEA,QAAI,KAAK,WAAW,KAAK;AACvB,kBAAY,aAAa,gBAAgB,IAAI;AAC7C,aAAO;AAAA,IACT;AAEA,QAAI,CAAC,KAAK,MAAM,CAAC,KAAK,QAAQ;AAC5B,YAAM,IAAI;AAAA,QACR,eAAe,KAAK,MAAM,KACvB,EAAE,qCAAqC,iCAAiC;AAAA,MAC7E;AAAA,IACF;AAEA,gBAAY,aAAa,gBAAgB,KAAK,MAAM;AACpD,WAAO,KAAK;AAAA,EACd,GAAG,CAAC,gBAAgB,IAAI,aAAa,CAAC,CAAC;AAEvC,QAAM,uBAAuB,QAAQ,eAAe,IAAI,qBAAqB;AAC7E,QAAM,sBAAsB,QAAQ,eAAe,IAAI,oBAAoB;AAC3E,QAAM,sBAAsB,QAAQ,eAAe,IAAI,oBAAoB;AAE3E,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/core",
3
- "version": "0.6.3-develop.3609.1.01983ef87a",
3
+ "version": "0.6.3-develop.3635.1.e4a05c16e8",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "scripts": {
@@ -242,16 +242,16 @@
242
242
  "zod": "^4.4.3"
243
243
  },
244
244
  "peerDependencies": {
245
- "@open-mercato/ai-assistant": "0.6.3-develop.3609.1.01983ef87a",
246
- "@open-mercato/shared": "0.6.3-develop.3609.1.01983ef87a",
247
- "@open-mercato/ui": "0.6.3-develop.3609.1.01983ef87a",
245
+ "@open-mercato/ai-assistant": "0.6.3-develop.3635.1.e4a05c16e8",
246
+ "@open-mercato/shared": "0.6.3-develop.3635.1.e4a05c16e8",
247
+ "@open-mercato/ui": "0.6.3-develop.3635.1.e4a05c16e8",
248
248
  "react": "^19.0.0",
249
249
  "react-dom": "^19.0.0"
250
250
  },
251
251
  "devDependencies": {
252
- "@open-mercato/ai-assistant": "0.6.3-develop.3609.1.01983ef87a",
253
- "@open-mercato/shared": "0.6.3-develop.3609.1.01983ef87a",
254
- "@open-mercato/ui": "0.6.3-develop.3609.1.01983ef87a",
252
+ "@open-mercato/ai-assistant": "0.6.3-develop.3635.1.e4a05c16e8",
253
+ "@open-mercato/shared": "0.6.3-develop.3635.1.e4a05c16e8",
254
+ "@open-mercato/ui": "0.6.3-develop.3635.1.e4a05c16e8",
255
255
  "@testing-library/dom": "^10.4.1",
256
256
  "@testing-library/jest-dom": "^6.9.1",
257
257
  "@testing-library/react": "^16.3.1",