@open-mercato/channel-imap 0.10.1-develop.7770.1.970b396ebb → 0.10.1-develop.7772.1.9d3d6ce261

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/channel_imap/lib/normalize-inbound.ts"],
4
- "sourcesContent": ["import type { NormalizedInboundMessage } from '@open-mercato/core/modules/communication_channels/lib/adapter'\nimport {\n normalizeMimeInbound,\n type ParsedMail,\n} from '@open-mercato/core/modules/communication_channels/lib/email-mime'\n\n/**\n * Convert a raw RFC2822 MIME buffer (delivered by IMAP fetch) to the hub's\n * canonical `NormalizedInboundMessage`. Parses with `mailparser`, then delegates\n * threading / attachments / headers to the shared `normalizeMimeInbound` helper.\n *\n * Threading:\n * - `externalMessageId` := MIME `Message-ID` header (RFC2822). Required by\n * IMAP/SMTP; if missing we fall back to `imap:<uid>@<account>` so downstream\n * idempotency still has a deterministic key.\n * - `replyToExternalId` := `In-Reply-To` header (single value).\n * - `externalConversationId` := the root of the References chain when present,\n * otherwise the message id itself (single-message thread).\n */\n\nexport interface NormalizeInboundOptions {\n rawMessage: Buffer\n /** UID from the IMAP fetch \u2014 embedded into `channelMetadata.uid` for diagnostics. */\n uid?: number\n /** External identifier of the receiving channel (typically the account's email). */\n accountIdentifier: string\n /** IMAP `INTERNALDATE`: when the server received the message. Wins over the MIME Date header. */\n receivedAt?: Date\n /** Used only when neither `receivedAt` nor a usable Date header is available. */\n fallbackDate?: Date\n}\n\nexport async function normalizeInboundImapMessage(\n options: NormalizeInboundOptions,\n): Promise<NormalizedInboundMessage> {\n const mailparser = (await import('mailparser')) as unknown as {\n simpleParser: (buf: Buffer | string) => Promise<ParsedMail>\n }\n const parsed = await mailparser.simpleParser(options.rawMessage)\n\n return normalizeMimeInbound({\n parsed,\n accountIdentifier: options.accountIdentifier,\n fallbackMessageId: `imap:${options.uid ?? 'unknown'}@${options.accountIdentifier}`,\n resolveConversationId: ({ messageId, references }) => references[0] ?? messageId,\n receivedAt: options.receivedAt,\n fallbackDate: options.fallbackDate,\n channelMetadata: () => ({ uid: options.uid }),\n })\n}\n"],
4
+ "sourcesContent": ["import type { NormalizedInboundMessage } from '@open-mercato/core/modules/communication_channels/lib/adapter'\nimport {\n normalizeMimeInbound,\n type ParsedMail,\n} from '@open-mercato/core/modules/communication_channels/lib/email-mime'\n\n/**\n * Convert a raw RFC2822 MIME buffer (delivered by IMAP fetch) to the hub's\n * canonical `NormalizedInboundMessage`. Parses with `mailparser`, then delegates\n * threading / attachments / headers to the shared `normalizeMimeInbound` helper.\n *\n * Threading:\n * - `externalMessageId` := MIME `Message-ID` header (RFC2822). Required by\n * IMAP/SMTP; if missing we fall back to `imap:<uid>@<account>` so downstream\n * idempotency still has a deterministic key.\n * - `replyToExternalId` := `In-Reply-To` header (single value).\n * - `externalConversationId` := the root of the References chain when present,\n * otherwise the message id itself (single-message thread).\n */\n\nexport interface NormalizeInboundOptions {\n rawMessage: Buffer\n /** UID from the IMAP fetch \u2014 embedded into `channelMetadata.uid` for diagnostics. */\n uid?: number\n /** External identifier of the receiving channel (typically the account's email). */\n accountIdentifier: string\n /** IMAP `INTERNALDATE`: when the server received the message. Wins over the MIME Date header. */\n receivedAt?: Date\n /** Used only when neither `receivedAt` nor a usable Date header is available. */\n fallbackDate?: Date | null\n}\n\nexport async function normalizeInboundImapMessage(\n options: NormalizeInboundOptions,\n): Promise<NormalizedInboundMessage> {\n const mailparser = (await import('mailparser')) as unknown as {\n simpleParser: (buf: Buffer | string) => Promise<ParsedMail>\n }\n const parsed = await mailparser.simpleParser(options.rawMessage)\n\n return normalizeMimeInbound({\n parsed,\n accountIdentifier: options.accountIdentifier,\n fallbackMessageId: `imap:${options.uid ?? 'unknown'}@${options.accountIdentifier}`,\n resolveConversationId: ({ messageId, references }) => references[0] ?? messageId,\n receivedAt: options.receivedAt,\n fallbackDate: options.fallbackDate,\n channelMetadata: () => ({ uid: options.uid }),\n })\n}\n"],
5
5
  "mappings": "AACA;AAAA,EACE;AAAA,OAEK;AA4BP,eAAsB,4BACpB,SACmC;AACnC,QAAM,aAAc,MAAM,OAAO,YAAY;AAG7C,QAAM,SAAS,MAAM,WAAW,aAAa,QAAQ,UAAU;AAE/D,SAAO,qBAAqB;AAAA,IAC1B;AAAA,IACA,mBAAmB,QAAQ;AAAA,IAC3B,mBAAmB,QAAQ,QAAQ,OAAO,SAAS,IAAI,QAAQ,iBAAiB;AAAA,IAChF,uBAAuB,CAAC,EAAE,WAAW,WAAW,MAAM,WAAW,CAAC,KAAK;AAAA,IACvE,YAAY,QAAQ;AAAA,IACpB,cAAc,QAAQ;AAAA,IACtB,iBAAiB,OAAO,EAAE,KAAK,QAAQ,IAAI;AAAA,EAC7C,CAAC;AACH;",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/channel-imap",
3
- "version": "0.10.1-develop.7770.1.970b396ebb",
3
+ "version": "0.10.1-develop.7772.1.9d3d6ce261",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -62,9 +62,9 @@
62
62
  }
63
63
  },
64
64
  "dependencies": {
65
- "@open-mercato/core": "0.10.1-develop.7770.1.970b396ebb",
66
- "@open-mercato/queue": "0.10.1-develop.7770.1.970b396ebb",
67
- "@open-mercato/ui": "0.10.1-develop.7770.1.970b396ebb",
65
+ "@open-mercato/core": "0.10.1-develop.7772.1.9d3d6ce261",
66
+ "@open-mercato/queue": "0.10.1-develop.7772.1.9d3d6ce261",
67
+ "@open-mercato/ui": "0.10.1-develop.7772.1.9d3d6ce261",
68
68
  "@types/mailparser": "^3.4.5",
69
69
  "@types/nodemailer": "^8.0.1",
70
70
  "imapflow": "^1.7.6",
@@ -73,12 +73,12 @@
73
73
  },
74
74
  "peerDependencies": {
75
75
  "@mikro-orm/postgresql": "^7.0.14",
76
- "@open-mercato/shared": "0.10.1-develop.7770.1.970b396ebb",
76
+ "@open-mercato/shared": "0.10.1-develop.7772.1.9d3d6ce261",
77
77
  "react": "^19.0.0",
78
78
  "react-dom": "^19.0.0"
79
79
  },
80
80
  "devDependencies": {
81
- "@open-mercato/shared": "0.10.1-develop.7770.1.970b396ebb",
81
+ "@open-mercato/shared": "0.10.1-develop.7772.1.9d3d6ce261",
82
82
  "@types/jest": "^30.0.0",
83
83
  "@types/react": "^19.2.18",
84
84
  "@types/react-dom": "^19.2.5",
@@ -141,4 +141,21 @@ describe('normalizeInboundImapMessage', () => {
141
141
  expect(result.bodyFormat).toBe('html')
142
142
  expect(result.body).toContain('<b>rich</b>')
143
143
  })
144
+
145
+ it('uses IMAP INTERNALDATE when the MIME Date header is missing', async () => {
146
+ const fallbackDate = new Date('2026-05-29T10:00:00.000Z')
147
+ const result = await normalizeInboundImapMessage({
148
+ rawMessage: buildMimeMessage({
149
+ messageId: '<fallback-date@example.com>',
150
+ from: 'alice@example.com',
151
+ to: 'bob@example.com',
152
+ text: 'hi',
153
+ }),
154
+ uid: 101,
155
+ accountIdentifier: 'bob@example.com',
156
+ fallbackDate,
157
+ })
158
+ expect(result.timestamp).toEqual(fallbackDate)
159
+ expect(result.providerTimestamp).toEqual(fallbackDate)
160
+ })
144
161
  })
@@ -27,7 +27,7 @@ export interface NormalizeInboundOptions {
27
27
  /** IMAP `INTERNALDATE`: when the server received the message. Wins over the MIME Date header. */
28
28
  receivedAt?: Date
29
29
  /** Used only when neither `receivedAt` nor a usable Date header is available. */
30
- fallbackDate?: Date
30
+ fallbackDate?: Date | null
31
31
  }
32
32
 
33
33
  export async function normalizeInboundImapMessage(