@brightchain/brightchain-lib 0.12.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -3
- package/src/browser.d.ts +1 -1
- package/src/browser.d.ts.map +1 -1
- package/src/browser.js +3 -3
- package/src/browser.js.map +1 -1
- package/src/lib/blocks/cblBase.d.ts.map +1 -1
- package/src/lib/blocks/cblBase.js +8 -1
- package/src/lib/blocks/cblBase.js.map +1 -1
- package/src/lib/blocks/encryptedBlockFactory.d.ts +6 -1
- package/src/lib/blocks/encryptedBlockFactory.d.ts.map +1 -1
- package/src/lib/blocks/encryptedBlockFactory.js +14 -5
- package/src/lib/blocks/encryptedBlockFactory.js.map +1 -1
- package/src/lib/documents/member/memberDocument.d.ts +12 -1
- package/src/lib/documents/member/memberDocument.d.ts.map +1 -1
- package/src/lib/documents/member/memberDocument.js +24 -4
- package/src/lib/documents/member/memberDocument.js.map +1 -1
- package/src/lib/documents/member/memberProfileHydration.d.ts.map +1 -1
- package/src/lib/documents/member/memberProfileHydration.js +23 -23
- package/src/lib/documents/member/memberProfileHydration.js.map +1 -1
- package/src/lib/enumeration-translations/blockSize.d.ts.map +1 -1
- package/src/lib/enumeration-translations/blockSize.js +58 -59
- package/src/lib/enumeration-translations/blockSize.js.map +1 -1
- package/src/lib/enumeration-translations/blockType.d.ts.map +1 -1
- package/src/lib/enumeration-translations/blockType.js +2 -2
- package/src/lib/enumeration-translations/blockType.js.map +1 -1
- package/src/lib/enumeration-translations/index.d.ts +8 -0
- package/src/lib/enumeration-translations/index.d.ts.map +1 -1
- package/src/lib/enumeration-translations/index.js +7 -0
- package/src/lib/enumeration-translations/index.js.map +1 -1
- package/src/lib/enumeration-translations/memberType.d.ts.map +1 -1
- package/src/lib/enumeration-translations/memberType.js +2 -2
- package/src/lib/enumeration-translations/memberType.js.map +1 -1
- package/src/lib/enumeration-translations/quorumDataRecordAction.d.ts.map +1 -1
- package/src/lib/enumeration-translations/quorumDataRecordAction.js +2 -2
- package/src/lib/enumeration-translations/quorumDataRecordAction.js.map +1 -1
- package/src/lib/enumeration-translations/security-event-severity.d.ts.map +1 -1
- package/src/lib/enumeration-translations/security-event-severity.js +2 -2
- package/src/lib/enumeration-translations/security-event-severity.js.map +1 -1
- package/src/lib/enumeration-translations/security-event-type.d.ts.map +1 -1
- package/src/lib/enumeration-translations/security-event-type.js +2 -2
- package/src/lib/enumeration-translations/security-event-type.js.map +1 -1
- package/src/lib/enumerations/blockSize.d.ts.map +1 -1
- package/src/lib/enumerations/brightChainStrings.d.ts +10 -4
- package/src/lib/enumerations/brightChainStrings.d.ts.map +1 -1
- package/src/lib/enumerations/brightChainStrings.js +9 -4
- package/src/lib/enumerations/brightChainStrings.js.map +1 -1
- package/src/lib/enumerations/durabilityLevel.d.ts +4 -0
- package/src/lib/enumerations/durabilityLevel.d.ts.map +1 -1
- package/src/lib/enumerations/durabilityLevel.js +10 -1
- package/src/lib/enumerations/durabilityLevel.js.map +1 -1
- package/src/lib/enumerations/healthStatus.d.ts +10 -0
- package/src/lib/enumerations/healthStatus.d.ts.map +1 -0
- package/src/lib/enumerations/healthStatus.js +14 -0
- package/src/lib/enumerations/healthStatus.js.map +1 -0
- package/src/lib/enumerations/index.d.ts +4 -0
- package/src/lib/enumerations/index.d.ts.map +1 -1
- package/src/lib/enumerations/index.js +4 -0
- package/src/lib/enumerations/index.js.map +1 -1
- package/src/lib/enumerations/memberErrorType.d.ts +5 -1
- package/src/lib/enumerations/memberErrorType.d.ts.map +1 -1
- package/src/lib/enumerations/memberErrorType.js +4 -0
- package/src/lib/enumerations/memberErrorType.js.map +1 -1
- package/src/lib/enumerations/messaging/deliveryStatus.d.ts +50 -0
- package/src/lib/enumerations/messaging/deliveryStatus.d.ts.map +1 -0
- package/src/lib/enumerations/messaging/deliveryStatus.js +68 -0
- package/src/lib/enumerations/messaging/deliveryStatus.js.map +1 -0
- package/src/lib/enumerations/messaging/emailErrorType.d.ts +36 -0
- package/src/lib/enumerations/messaging/emailErrorType.d.ts.map +1 -0
- package/src/lib/enumerations/messaging/emailErrorType.js +46 -0
- package/src/lib/enumerations/messaging/emailErrorType.js.map +1 -0
- package/src/lib/enumerations/messaging/index.d.ts +2 -1
- package/src/lib/enumerations/messaging/index.d.ts.map +1 -1
- package/src/lib/enumerations/messaging/index.js +2 -1
- package/src/lib/enumerations/messaging/index.js.map +1 -1
- package/src/lib/enumerations/messaging/messageEncryptionScheme.d.ts +4 -2
- package/src/lib/enumerations/messaging/messageEncryptionScheme.d.ts.map +1 -1
- package/src/lib/enumerations/messaging/messageEncryptionScheme.js +3 -1
- package/src/lib/enumerations/messaging/messageEncryptionScheme.js.map +1 -1
- package/src/lib/enumerations/nodeCapability.d.ts +12 -0
- package/src/lib/enumerations/nodeCapability.d.ts.map +1 -0
- package/src/lib/enumerations/nodeCapability.js +16 -0
- package/src/lib/enumerations/nodeCapability.js.map +1 -0
- package/src/lib/enumerations/nodeEventType.d.ts +13 -0
- package/src/lib/enumerations/nodeEventType.d.ts.map +1 -0
- package/src/lib/enumerations/nodeEventType.js +17 -0
- package/src/lib/enumerations/nodeEventType.js.map +1 -0
- package/src/lib/enumerations/nodeStatus.d.ts +12 -0
- package/src/lib/enumerations/nodeStatus.d.ts.map +1 -0
- package/src/lib/enumerations/nodeStatus.js +16 -0
- package/src/lib/enumerations/nodeStatus.js.map +1 -0
- package/src/lib/enumerations/votingDerivationErrorType.d.ts.map +1 -1
- package/src/lib/errors/block/blockAccess.d.ts.map +1 -1
- package/src/lib/errors/block/blockAccess.js.map +1 -1
- package/src/lib/errors/block/blockCapacity.d.ts.map +1 -1
- package/src/lib/errors/block/blockCapacity.js.map +1 -1
- package/src/lib/errors/block/blockError.d.ts.map +1 -1
- package/src/lib/errors/block/blockError.js.map +1 -1
- package/src/lib/errors/block/blockMetadata.d.ts.map +1 -1
- package/src/lib/errors/block/blockMetadata.js.map +1 -1
- package/src/lib/errors/block/blockValidation.d.ts.map +1 -1
- package/src/lib/errors/block/blockValidation.js.map +1 -1
- package/src/lib/errors/blockServiceError.d.ts.map +1 -1
- package/src/lib/errors/blockServiceError.js.map +1 -1
- package/src/lib/errors/bufferError.js.map +1 -1
- package/src/lib/errors/cblError.d.ts.map +1 -1
- package/src/lib/errors/cblError.js.map +1 -1
- package/src/lib/errors/disposed.d.ts.map +1 -1
- package/src/lib/errors/disposed.js +1 -1
- package/src/lib/errors/disposed.js.map +1 -1
- package/src/lib/errors/document.d.ts.map +1 -1
- package/src/lib/errors/document.js.map +1 -1
- package/src/lib/errors/eciesError.d.ts.map +1 -1
- package/src/lib/errors/eciesError.js.map +1 -1
- package/src/lib/errors/enhancedValidationError.d.ts.map +1 -1
- package/src/lib/errors/extendedCblError.d.ts.map +1 -1
- package/src/lib/errors/extendedCblError.js.map +1 -1
- package/src/lib/errors/failedToHydrate.js.map +1 -1
- package/src/lib/errors/fecError.d.ts +3 -1
- package/src/lib/errors/fecError.d.ts.map +1 -1
- package/src/lib/errors/fecError.js.map +1 -1
- package/src/lib/errors/handleTupleError.d.ts.map +1 -1
- package/src/lib/errors/handleTupleError.js.map +1 -1
- package/src/lib/errors/invalidIDFormat.js.map +1 -1
- package/src/lib/errors/isolatedKeyError.d.ts.map +1 -1
- package/src/lib/errors/isolatedKeyError.js.map +1 -1
- package/src/lib/errors/memberError.d.ts.map +1 -1
- package/src/lib/errors/memberError.js +1 -0
- package/src/lib/errors/memberError.js.map +1 -1
- package/src/lib/errors/memoryTupleError.d.ts.map +1 -1
- package/src/lib/errors/memoryTupleError.js.map +1 -1
- package/src/lib/errors/messaging/emailError.d.ts +55 -0
- package/src/lib/errors/messaging/emailError.d.ts.map +1 -0
- package/src/lib/errors/messaging/emailError.js +64 -0
- package/src/lib/errors/messaging/emailError.js.map +1 -0
- package/src/lib/errors/messaging/index.d.ts +1 -0
- package/src/lib/errors/messaging/index.d.ts.map +1 -1
- package/src/lib/errors/messaging/index.js +1 -0
- package/src/lib/errors/messaging/index.js.map +1 -1
- package/src/lib/errors/multiEncryptedError.d.ts.map +1 -1
- package/src/lib/errors/multiEncryptedError.js.map +1 -1
- package/src/lib/errors/notImplemented.js.map +1 -1
- package/src/lib/errors/quorumError.d.ts.map +1 -1
- package/src/lib/errors/quorumError.js.map +1 -1
- package/src/lib/errors/sealingError.d.ts.map +1 -1
- package/src/lib/errors/sealingError.js.map +1 -1
- package/src/lib/errors/secureStorage.d.ts.map +1 -1
- package/src/lib/errors/storeError.d.ts +2 -1
- package/src/lib/errors/storeError.d.ts.map +1 -1
- package/src/lib/errors/storeError.js.map +1 -1
- package/src/lib/errors/streamError.d.ts.map +1 -1
- package/src/lib/errors/streamError.js.map +1 -1
- package/src/lib/errors/symmetricError.d.ts.map +1 -1
- package/src/lib/errors/symmetricError.js.map +1 -1
- package/src/lib/errors/systemKeyringError.d.ts.map +1 -1
- package/src/lib/errors/systemKeyringError.js.map +1 -1
- package/src/lib/errors/translatableBrightChainError.d.ts.map +1 -1
- package/src/lib/errors/tupleError.d.ts.map +1 -1
- package/src/lib/errors/tupleError.js.map +1 -1
- package/src/lib/errors/typedError.d.ts +5 -5
- package/src/lib/errors/typedError.d.ts.map +1 -1
- package/src/lib/errors/typedError.js +2 -2
- package/src/lib/errors/typedError.js.map +1 -1
- package/src/lib/errors/typedWithReasonError.d.ts.map +1 -1
- package/src/lib/errors/whitenedError.d.ts.map +1 -1
- package/src/lib/errors/whitenedError.js.map +1 -1
- package/src/lib/i18n/i18n-setup.d.ts +86 -0
- package/src/lib/i18n/i18n-setup.d.ts.map +1 -0
- package/src/lib/i18n/i18n-setup.js +291 -0
- package/src/lib/i18n/i18n-setup.js.map +1 -0
- package/src/lib/i18n/index.d.ts +1 -54
- package/src/lib/i18n/index.d.ts.map +1 -1
- package/src/lib/i18n/index.js +1 -257
- package/src/lib/i18n/index.js.map +1 -1
- package/src/lib/i18n/strings/englishUK.d.ts.map +1 -1
- package/src/lib/i18n/strings/englishUK.js.map +1 -1
- package/src/lib/i18n/strings/englishUs.d.ts.map +1 -1
- package/src/lib/i18n/strings/englishUs.js +4 -0
- package/src/lib/i18n/strings/englishUs.js.map +1 -1
- package/src/lib/i18n/strings/french.d.ts.map +1 -1
- package/src/lib/i18n/strings/french.js +4 -0
- package/src/lib/i18n/strings/french.js.map +1 -1
- package/src/lib/i18n/strings/german.d.ts.map +1 -1
- package/src/lib/i18n/strings/german.js +4 -0
- package/src/lib/i18n/strings/german.js.map +1 -1
- package/src/lib/i18n/strings/japanese.d.ts.map +1 -1
- package/src/lib/i18n/strings/japanese.js +4 -0
- package/src/lib/i18n/strings/japanese.js.map +1 -1
- package/src/lib/i18n/strings/mandarin.d.ts.map +1 -1
- package/src/lib/i18n/strings/mandarin.js +4 -0
- package/src/lib/i18n/strings/mandarin.js.map +1 -1
- package/src/lib/i18n/strings/spanish.d.ts.map +1 -1
- package/src/lib/i18n/strings/spanish.js +4 -0
- package/src/lib/i18n/strings/spanish.js.map +1 -1
- package/src/lib/i18n/strings/ukrainian.d.ts.map +1 -1
- package/src/lib/i18n/strings/ukrainian.js +4 -0
- package/src/lib/i18n/strings/ukrainian.js.map +1 -1
- package/src/lib/interfaces/availability/gossipService.d.ts +171 -4
- package/src/lib/interfaces/availability/gossipService.d.ts.map +1 -1
- package/src/lib/interfaces/availability/gossipService.js +139 -0
- package/src/lib/interfaces/availability/gossipService.js.map +1 -1
- package/src/lib/interfaces/blockLocationInfo.d.ts +10 -0
- package/src/lib/interfaces/blockLocationInfo.d.ts.map +1 -0
- package/src/lib/interfaces/blockLocationInfo.js +3 -0
- package/src/lib/interfaces/blockLocationInfo.js.map +1 -0
- package/src/lib/interfaces/dependencyStatus.d.ts +11 -0
- package/src/lib/interfaces/dependencyStatus.d.ts.map +1 -0
- package/src/lib/interfaces/{network/networkTransport.js → dependencyStatus.js} +1 -1
- package/src/lib/interfaces/dependencyStatus.js.map +1 -0
- package/src/lib/interfaces/index.d.ts +4 -0
- package/src/lib/interfaces/index.d.ts.map +1 -1
- package/src/lib/interfaces/index.js.map +1 -1
- package/src/lib/interfaces/messaging/attachmentMetadata.d.ts +47 -0
- package/src/lib/interfaces/messaging/attachmentMetadata.d.ts.map +1 -0
- package/src/lib/interfaces/messaging/attachmentMetadata.js +3 -0
- package/src/lib/interfaces/messaging/attachmentMetadata.js.map +1 -0
- package/src/lib/interfaces/messaging/emailAddress.d.ts +210 -0
- package/src/lib/interfaces/messaging/emailAddress.d.ts.map +1 -0
- package/src/lib/interfaces/messaging/emailAddress.js +213 -0
- package/src/lib/interfaces/messaging/emailAddress.js.map +1 -0
- package/src/lib/interfaces/messaging/emailDelivery.d.ts +80 -0
- package/src/lib/interfaces/messaging/emailDelivery.d.ts.map +1 -0
- package/src/lib/interfaces/messaging/emailDelivery.js +50 -0
- package/src/lib/interfaces/messaging/emailDelivery.js.map +1 -0
- package/src/lib/interfaces/messaging/emailMetadata.d.ts +269 -0
- package/src/lib/interfaces/messaging/emailMetadata.d.ts.map +1 -0
- package/src/lib/interfaces/messaging/emailMetadata.js +16 -0
- package/src/lib/interfaces/messaging/emailMetadata.js.map +1 -0
- package/src/lib/interfaces/messaging/index.d.ts +5 -1
- package/src/lib/interfaces/messaging/index.d.ts.map +1 -1
- package/src/lib/interfaces/messaging/index.js +5 -1
- package/src/lib/interfaces/messaging/index.js.map +1 -1
- package/src/lib/interfaces/messaging/messageMetadata.d.ts +2 -2
- package/src/lib/interfaces/messaging/messageMetadata.d.ts.map +1 -1
- package/src/lib/interfaces/messaging/messageMetadataStore.d.ts +2 -2
- package/src/lib/interfaces/messaging/messageMetadataStore.d.ts.map +1 -1
- package/src/lib/interfaces/messaging/mimePart.d.ts +214 -0
- package/src/lib/interfaces/messaging/mimePart.d.ts.map +1 -0
- package/src/lib/interfaces/messaging/mimePart.js +71 -0
- package/src/lib/interfaces/messaging/mimePart.js.map +1 -0
- package/src/lib/interfaces/network/index.d.ts +5 -1
- package/src/lib/interfaces/network/index.d.ts.map +1 -1
- package/src/lib/interfaces/network/node.d.ts +5 -107
- package/src/lib/interfaces/network/node.d.ts.map +1 -1
- package/src/lib/interfaces/network/node.js +0 -37
- package/src/lib/interfaces/network/node.js.map +1 -1
- package/src/lib/interfaces/network/nodeAdvertisement.d.ts +22 -0
- package/src/lib/interfaces/network/nodeAdvertisement.d.ts.map +1 -0
- package/src/lib/interfaces/network/nodeAdvertisement.js +3 -0
- package/src/lib/interfaces/network/nodeAdvertisement.js.map +1 -0
- package/src/lib/interfaces/network/nodeConfig.d.ts +14 -0
- package/src/lib/interfaces/network/nodeConfig.d.ts.map +1 -0
- package/src/lib/interfaces/{responses/apiMessage.js → network/nodeConfig.js} +1 -1
- package/src/lib/interfaces/network/nodeConfig.js.map +1 -0
- package/src/lib/interfaces/network/nodeEvent.d.ts +12 -0
- package/src/lib/interfaces/network/nodeEvent.d.ts.map +1 -0
- package/src/lib/interfaces/{messaging/messageRouter.js → network/nodeEvent.js} +1 -1
- package/src/lib/interfaces/network/nodeEvent.js.map +1 -0
- package/src/lib/interfaces/network/nodeLocation.d.ts +15 -0
- package/src/lib/interfaces/network/nodeLocation.d.ts.map +1 -0
- package/src/lib/interfaces/network/nodeLocation.js +3 -0
- package/src/lib/interfaces/network/nodeLocation.js.map +1 -0
- package/src/lib/interfaces/network/nodeResources.d.ts +20 -0
- package/src/lib/interfaces/network/nodeResources.d.ts.map +1 -0
- package/src/lib/interfaces/network/nodeResources.js +3 -0
- package/src/lib/interfaces/network/nodeResources.js.map +1 -0
- package/src/lib/interfaces/nodeInfo.d.ts +13 -0
- package/src/lib/interfaces/nodeInfo.d.ts.map +1 -0
- package/src/lib/interfaces/nodeInfo.js +3 -0
- package/src/lib/interfaces/nodeInfo.js.map +1 -0
- package/src/lib/interfaces/replicationNodeResult.d.ts +9 -0
- package/src/lib/interfaces/replicationNodeResult.d.ts.map +1 -0
- package/src/lib/interfaces/replicationNodeResult.js +3 -0
- package/src/lib/interfaces/replicationNodeResult.js.map +1 -0
- package/src/lib/interfaces/responses/apiError.d.ts +1 -1
- package/src/lib/interfaces/responses/apiError.d.ts.map +1 -1
- package/src/lib/interfaces/responses/apiExpressValidationError.d.ts +1 -1
- package/src/lib/interfaces/responses/apiExpressValidationError.d.ts.map +1 -1
- package/src/lib/interfaces/responses/blockLocationResponse.d.ts +11 -0
- package/src/lib/interfaces/responses/blockLocationResponse.d.ts.map +1 -0
- package/src/lib/interfaces/responses/blockLocationResponse.js +3 -0
- package/src/lib/interfaces/responses/blockLocationResponse.js.map +1 -0
- package/src/lib/interfaces/responses/deleteMessageResponse.d.ts +11 -0
- package/src/lib/interfaces/responses/deleteMessageResponse.d.ts.map +1 -0
- package/src/lib/interfaces/responses/deleteMessageResponse.js +3 -0
- package/src/lib/interfaces/responses/deleteMessageResponse.js.map +1 -0
- package/src/lib/interfaces/responses/detailedHealthResponse.d.ts +14 -0
- package/src/lib/interfaces/responses/detailedHealthResponse.d.ts.map +1 -0
- package/src/lib/interfaces/responses/detailedHealthResponse.js +3 -0
- package/src/lib/interfaces/responses/detailedHealthResponse.js.map +1 -0
- package/src/lib/interfaces/responses/discoverBlockResponse.d.ts +17 -0
- package/src/lib/interfaces/responses/discoverBlockResponse.d.ts.map +1 -0
- package/src/lib/interfaces/responses/discoverBlockResponse.js +3 -0
- package/src/lib/interfaces/responses/discoverBlockResponse.js.map +1 -0
- package/src/lib/interfaces/responses/getBlock.d.ts +1 -1
- package/src/lib/interfaces/responses/getBlock.d.ts.map +1 -1
- package/src/lib/interfaces/responses/getCbl.d.ts +1 -1
- package/src/lib/interfaces/responses/getCbl.d.ts.map +1 -1
- package/src/lib/interfaces/responses/getMessageResponse.d.ts +11 -0
- package/src/lib/interfaces/responses/getMessageResponse.d.ts.map +1 -0
- package/src/lib/interfaces/responses/getMessageResponse.js +3 -0
- package/src/lib/interfaces/responses/getMessageResponse.js.map +1 -0
- package/src/lib/interfaces/responses/getNodeResponse.d.ts +10 -0
- package/src/lib/interfaces/responses/getNodeResponse.d.ts.map +1 -0
- package/src/lib/interfaces/responses/getNodeResponse.js +3 -0
- package/src/lib/interfaces/responses/getNodeResponse.js.map +1 -0
- package/src/lib/interfaces/responses/healthResponse.d.ts +13 -0
- package/src/lib/interfaces/responses/healthResponse.d.ts.map +1 -0
- package/src/lib/interfaces/responses/healthResponse.js +3 -0
- package/src/lib/interfaces/responses/healthResponse.js.map +1 -0
- package/src/lib/interfaces/responses/index.d.ts +16 -1
- package/src/lib/interfaces/responses/index.d.ts.map +1 -1
- package/src/lib/interfaces/responses/listNodesResponse.d.ts +11 -0
- package/src/lib/interfaces/responses/listNodesResponse.d.ts.map +1 -0
- package/src/lib/interfaces/responses/listNodesResponse.js +3 -0
- package/src/lib/interfaces/responses/listNodesResponse.js.map +1 -0
- package/src/lib/interfaces/responses/members.d.ts +4 -2
- package/src/lib/interfaces/responses/members.d.ts.map +1 -1
- package/src/lib/interfaces/responses/queryMessageResponse.d.ts +18 -0
- package/src/lib/interfaces/responses/queryMessageResponse.d.ts.map +1 -0
- package/src/lib/interfaces/responses/queryMessageResponse.js +3 -0
- package/src/lib/interfaces/responses/queryMessageResponse.js.map +1 -0
- package/src/lib/interfaces/responses/reconcileResponse.d.ts +10 -0
- package/src/lib/interfaces/responses/reconcileResponse.d.ts.map +1 -0
- package/src/lib/interfaces/responses/reconcileResponse.js +3 -0
- package/src/lib/interfaces/responses/reconcileResponse.js.map +1 -0
- package/src/lib/interfaces/responses/registerNodeResponse.d.ts +10 -0
- package/src/lib/interfaces/responses/registerNodeResponse.d.ts.map +1 -0
- package/src/lib/interfaces/responses/registerNodeResponse.js +3 -0
- package/src/lib/interfaces/responses/registerNodeResponse.js.map +1 -0
- package/src/lib/interfaces/responses/replicateBlockResponse.d.ts +11 -0
- package/src/lib/interfaces/responses/replicateBlockResponse.d.ts.map +1 -0
- package/src/lib/interfaces/responses/replicateBlockResponse.js +3 -0
- package/src/lib/interfaces/responses/replicateBlockResponse.js.map +1 -0
- package/src/lib/interfaces/responses/retrieveSCBLResponse.d.ts +10 -0
- package/src/lib/interfaces/responses/retrieveSCBLResponse.d.ts.map +1 -0
- package/src/lib/interfaces/responses/retrieveSCBLResponse.js +3 -0
- package/src/lib/interfaces/responses/retrieveSCBLResponse.js.map +1 -0
- package/src/lib/interfaces/responses/sendMessageResponse.d.ts +13 -0
- package/src/lib/interfaces/responses/sendMessageResponse.d.ts.map +1 -0
- package/src/lib/interfaces/responses/sendMessageResponse.js +3 -0
- package/src/lib/interfaces/responses/sendMessageResponse.js.map +1 -0
- package/src/lib/interfaces/responses/storeBlock.d.ts +1 -1
- package/src/lib/interfaces/responses/storeBlock.d.ts.map +1 -1
- package/src/lib/interfaces/responses/storeCbl.d.ts +1 -1
- package/src/lib/interfaces/responses/storeCbl.d.ts.map +1 -1
- package/src/lib/interfaces/responses/storeSCBLResponse.d.ts +15 -0
- package/src/lib/interfaces/responses/storeSCBLResponse.d.ts.map +1 -0
- package/src/lib/interfaces/responses/storeSCBLResponse.js +3 -0
- package/src/lib/interfaces/responses/storeSCBLResponse.js.map +1 -0
- package/src/lib/interfaces/responses/syncRequestResponse.d.ts +11 -0
- package/src/lib/interfaces/responses/syncRequestResponse.d.ts.map +1 -0
- package/src/lib/interfaces/responses/syncRequestResponse.js +3 -0
- package/src/lib/interfaces/responses/syncRequestResponse.js.map +1 -0
- package/src/lib/interfaces/services/quorumService.d.ts +6 -6
- package/src/lib/interfaces/services/quorumService.d.ts.map +1 -1
- package/src/lib/schemas/messaging/messageMetadataSchema.d.ts.map +1 -1
- package/src/lib/schemas/messaging/messageMetadataSchema.js.map +1 -1
- package/src/lib/schemas/network/networkDocumentSchema.js.map +1 -1
- package/src/lib/security/securityAuditLogger.js +1 -1
- package/src/lib/security/securityAuditLogger.js.map +1 -1
- package/src/lib/services/fec.service.js +2 -2
- package/src/lib/services/fec.service.js.map +1 -1
- package/src/lib/services/member/memberCblService.d.ts +7 -1
- package/src/lib/services/member/memberCblService.d.ts.map +1 -1
- package/src/lib/services/member/memberCblService.js +87 -29
- package/src/lib/services/member/memberCblService.js.map +1 -1
- package/src/lib/services/memberStore.d.ts +30 -0
- package/src/lib/services/memberStore.d.ts.map +1 -1
- package/src/lib/services/memberStore.js +446 -39
- package/src/lib/services/memberStore.js.map +1 -1
- package/src/lib/services/messaging/deliveryTimeoutService.js +2 -2
- package/src/lib/services/messaging/deliveryTimeoutService.js.map +1 -1
- package/src/lib/services/messaging/emailEncryptionService.d.ts +250 -0
- package/src/lib/services/messaging/emailEncryptionService.d.ts.map +1 -0
- package/src/lib/services/messaging/emailEncryptionService.js +420 -0
- package/src/lib/services/messaging/emailEncryptionService.js.map +1 -0
- package/src/lib/services/messaging/emailMessageService.d.ts +669 -0
- package/src/lib/services/messaging/emailMessageService.d.ts.map +1 -0
- package/src/lib/services/messaging/emailMessageService.js +1013 -0
- package/src/lib/services/messaging/emailMessageService.js.map +1 -0
- package/src/lib/services/messaging/emailParser.d.ts +458 -0
- package/src/lib/services/messaging/emailParser.d.ts.map +1 -0
- package/src/lib/services/messaging/emailParser.js +1298 -0
- package/src/lib/services/messaging/emailParser.js.map +1 -0
- package/src/lib/services/messaging/emailSerializer.d.ts +403 -0
- package/src/lib/services/messaging/emailSerializer.d.ts.map +1 -0
- package/src/lib/services/messaging/emailSerializer.js +852 -0
- package/src/lib/services/messaging/emailSerializer.js.map +1 -0
- package/src/lib/services/messaging/emailValidator.d.ts +448 -0
- package/src/lib/services/messaging/emailValidator.d.ts.map +1 -0
- package/src/lib/services/messaging/emailValidator.js +810 -0
- package/src/lib/services/messaging/emailValidator.js.map +1 -0
- package/src/lib/services/messaging/gossipRetryService.d.ts +204 -0
- package/src/lib/services/messaging/gossipRetryService.d.ts.map +1 -0
- package/src/lib/services/messaging/gossipRetryService.js +319 -0
- package/src/lib/services/messaging/gossipRetryService.js.map +1 -0
- package/src/lib/services/messaging/inMemoryEmailMetadataStore.d.ts +60 -0
- package/src/lib/services/messaging/inMemoryEmailMetadataStore.d.ts.map +1 -0
- package/src/lib/services/messaging/inMemoryEmailMetadataStore.js +281 -0
- package/src/lib/services/messaging/inMemoryEmailMetadataStore.js.map +1 -0
- package/src/lib/services/messaging/index.d.ts +11 -5
- package/src/lib/services/messaging/index.d.ts.map +1 -1
- package/src/lib/services/messaging/index.js +19 -5
- package/src/lib/services/messaging/index.js.map +1 -1
- package/src/lib/services/messaging/messageCBLService.js +2 -2
- package/src/lib/services/messaging/messageCBLService.js.map +1 -1
- package/src/lib/stores/messaging/memoryMessageMetadataStore.d.ts +2 -2
- package/src/lib/stores/messaging/memoryMessageMetadataStore.d.ts.map +1 -1
- package/src/lib/stores/messaging/memoryMessageMetadataStore.js +2 -2
- package/src/lib/stores/messaging/memoryMessageMetadataStore.js.map +1 -1
- package/src/lib/enumerations/messaging/messageDeliveryStatus.d.ts +0 -18
- package/src/lib/enumerations/messaging/messageDeliveryStatus.d.ts.map +0 -1
- package/src/lib/enumerations/messaging/messageDeliveryStatus.js +0 -22
- package/src/lib/enumerations/messaging/messageDeliveryStatus.js.map +0 -1
- package/src/lib/enumerations/messaging/routingStrategy.d.ts +0 -12
- package/src/lib/enumerations/messaging/routingStrategy.d.ts.map +0 -1
- package/src/lib/enumerations/messaging/routingStrategy.js +0 -16
- package/src/lib/enumerations/messaging/routingStrategy.js.map +0 -1
- package/src/lib/interfaces/messaging/messageRouter.d.ts +0 -48
- package/src/lib/interfaces/messaging/messageRouter.d.ts.map +0 -1
- package/src/lib/interfaces/messaging/messageRouter.js.map +0 -1
- package/src/lib/interfaces/network/networkTransport.d.ts +0 -19
- package/src/lib/interfaces/network/networkTransport.d.ts.map +0 -1
- package/src/lib/interfaces/network/networkTransport.js.map +0 -1
- package/src/lib/interfaces/responses/apiMessage.d.ts +0 -4
- package/src/lib/interfaces/responses/apiMessage.d.ts.map +0 -1
- package/src/lib/interfaces/responses/apiMessage.js.map +0 -1
- package/src/lib/services/messaging/broadcastMessageRouter.d.ts +0 -18
- package/src/lib/services/messaging/broadcastMessageRouter.d.ts.map +0 -1
- package/src/lib/services/messaging/broadcastMessageRouter.js +0 -32
- package/src/lib/services/messaging/broadcastMessageRouter.js.map +0 -1
- package/src/lib/services/messaging/directMessageRouter.d.ts +0 -25
- package/src/lib/services/messaging/directMessageRouter.d.ts.map +0 -1
- package/src/lib/services/messaging/directMessageRouter.js +0 -58
- package/src/lib/services/messaging/directMessageRouter.js.map +0 -1
- package/src/lib/services/messaging/messageForwardingService.d.ts +0 -40
- package/src/lib/services/messaging/messageForwardingService.d.ts.map +0 -1
- package/src/lib/services/messaging/messageForwardingService.js +0 -74
- package/src/lib/services/messaging/messageForwardingService.js.map +0 -1
- package/src/lib/services/messaging/messageRouter.d.ts +0 -24
- package/src/lib/services/messaging/messageRouter.d.ts.map +0 -1
- package/src/lib/services/messaging/messageRouter.js +0 -111
- package/src/lib/services/messaging/messageRouter.js.map +0 -1
- package/src/lib/services/messaging/webSocketTransport.d.ts +0 -34
- package/src/lib/services/messaging/webSocketTransport.d.ts.map +0 -1
- package/src/lib/services/messaging/webSocketTransport.js +0 -115
- package/src/lib/services/messaging/webSocketTransport.js.map +0 -1
|
@@ -0,0 +1,852 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* RFC 5322/MIME Compliant Email Serializer
|
|
4
|
+
*
|
|
5
|
+
* Serializes IEmailMetadata objects into RFC 5322 compliant email format.
|
|
6
|
+
* Provides methods for serializing individual email components (headers,
|
|
7
|
+
* addresses, Message-IDs, dates, content types).
|
|
8
|
+
*
|
|
9
|
+
* Wraps the `mimetext` library for full email serialization.
|
|
10
|
+
*
|
|
11
|
+
* @see RFC 5322 - Internet Message Format
|
|
12
|
+
* @see RFC 2045 - MIME Part One: Format of Internet Message Bodies
|
|
13
|
+
* @see RFC 2046 - MIME Part Two: Media Types
|
|
14
|
+
*
|
|
15
|
+
* @remarks
|
|
16
|
+
* Requirements: 14.1, 14.2, 14.3
|
|
17
|
+
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.EmailSerializer = void 0;
|
|
20
|
+
const emailAddress_1 = require("../../interfaces/messaging/emailAddress");
|
|
21
|
+
const mimePart_1 = require("../../interfaces/messaging/mimePart");
|
|
22
|
+
/** CRLF line ending per RFC 5322 */
|
|
23
|
+
const CRLF = '\r\n';
|
|
24
|
+
/** Default maximum header line length per RFC 5322 Section 2.2.3 */
|
|
25
|
+
const DEFAULT_MAX_LINE_LENGTH = 78;
|
|
26
|
+
/**
|
|
27
|
+
* RFC 5322/MIME compliant email serializer.
|
|
28
|
+
*
|
|
29
|
+
* Provides methods for serializing email headers, addresses, Message-IDs,
|
|
30
|
+
* dates, and content types. The main `serialize()` method (Task 5.7) will
|
|
31
|
+
* use `mimetext` for full email serialization.
|
|
32
|
+
*
|
|
33
|
+
* @see Design Document: EmailSerializer Class
|
|
34
|
+
*/
|
|
35
|
+
class EmailSerializer {
|
|
36
|
+
/**
|
|
37
|
+
* Serializes all headers from an IEmailMetadata object into an RFC 5322
|
|
38
|
+
* compliant header section string.
|
|
39
|
+
*
|
|
40
|
+
* Produces headers with proper CRLF line endings and folds long lines
|
|
41
|
+
* at 78 characters per RFC 5322 Section 2.2.3. The header section is
|
|
42
|
+
* terminated with a blank line (CRLF CRLF) to separate it from the body.
|
|
43
|
+
*
|
|
44
|
+
* @param email - The email metadata to serialize headers from
|
|
45
|
+
* @returns The serialized header section string with CRLF line endings,
|
|
46
|
+
* terminated by a blank line (CRLF CRLF)
|
|
47
|
+
*
|
|
48
|
+
* @see RFC 5322 Section 2.2 - Header Fields
|
|
49
|
+
* @see Requirement 14.1 - RFC 5322 compliant output with proper CRLF line endings
|
|
50
|
+
* @see Requirement 14.2 - Fold header lines exceeding 78 characters
|
|
51
|
+
* @see Requirement 14.3 - Separate header section from body with blank line
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* const serializer = new EmailSerializer();
|
|
56
|
+
* const headers = serializer.serializeHeaders(emailMetadata);
|
|
57
|
+
* // "From: sender@example.com\r\nTo: recipient@example.com\r\n..."
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
serializeHeaders(email) {
|
|
61
|
+
const headerLines = [];
|
|
62
|
+
// Date (required, RFC 5322 Section 3.6.1)
|
|
63
|
+
headerLines.push(`Date: ${this.serializeDate(email.date)}`);
|
|
64
|
+
// From (required, RFC 5322 Section 3.6.2)
|
|
65
|
+
headerLines.push(`From: ${this.serializeMailbox(email.from)}`);
|
|
66
|
+
// Sender (optional, RFC 5322 Section 3.6.2)
|
|
67
|
+
if (email.sender) {
|
|
68
|
+
headerLines.push(`Sender: ${this.serializeMailbox(email.sender)}`);
|
|
69
|
+
}
|
|
70
|
+
// Reply-To (optional, RFC 5322 Section 3.6.2)
|
|
71
|
+
if (email.replyTo && email.replyTo.length > 0) {
|
|
72
|
+
headerLines.push(`Reply-To: ${this.serializeAddressList(email.replyTo)}`);
|
|
73
|
+
}
|
|
74
|
+
// To (RFC 5322 Section 3.6.3)
|
|
75
|
+
if (email.to && email.to.length > 0) {
|
|
76
|
+
headerLines.push(`To: ${this.serializeAddressList(email.to)}`);
|
|
77
|
+
}
|
|
78
|
+
// Cc (optional, RFC 5322 Section 3.6.3)
|
|
79
|
+
if (email.cc && email.cc.length > 0) {
|
|
80
|
+
headerLines.push(`Cc: ${this.serializeAddressList(email.cc)}`);
|
|
81
|
+
}
|
|
82
|
+
// Bcc (optional, RFC 5322 Section 3.6.3)
|
|
83
|
+
if (email.bcc && email.bcc.length > 0) {
|
|
84
|
+
headerLines.push(`Bcc: ${this.serializeAddressList(email.bcc)}`);
|
|
85
|
+
}
|
|
86
|
+
// Message-ID (required, RFC 5322 Section 3.6.4)
|
|
87
|
+
headerLines.push(`Message-ID: ${this.serializeMessageId(email.messageId)}`);
|
|
88
|
+
// In-Reply-To (optional, RFC 5322 Section 3.6.4)
|
|
89
|
+
if (email.inReplyTo) {
|
|
90
|
+
headerLines.push(`In-Reply-To: ${this.serializeMessageId(email.inReplyTo)}`);
|
|
91
|
+
}
|
|
92
|
+
// References (optional, RFC 5322 Section 3.6.4)
|
|
93
|
+
if (email.references && email.references.length > 0) {
|
|
94
|
+
const refs = email.references
|
|
95
|
+
.map((ref) => this.serializeMessageId(ref))
|
|
96
|
+
.join(' ');
|
|
97
|
+
headerLines.push(`References: ${refs}`);
|
|
98
|
+
}
|
|
99
|
+
// Subject (optional, RFC 5322 Section 3.6.5)
|
|
100
|
+
if (email.subject !== undefined && email.subject !== null) {
|
|
101
|
+
headerLines.push(`Subject: ${email.subject}`);
|
|
102
|
+
}
|
|
103
|
+
// Comments (optional, RFC 5322 Section 3.6.5, may appear multiple times)
|
|
104
|
+
if (email.comments) {
|
|
105
|
+
for (const comment of email.comments) {
|
|
106
|
+
headerLines.push(`Comments: ${comment}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// Keywords (optional, RFC 5322 Section 3.6.5)
|
|
110
|
+
if (email.keywords && email.keywords.length > 0) {
|
|
111
|
+
headerLines.push(`Keywords: ${email.keywords.join(', ')}`);
|
|
112
|
+
}
|
|
113
|
+
// MIME-Version (RFC 2045)
|
|
114
|
+
headerLines.push(`MIME-Version: ${email.mimeVersion || '1.0'}`);
|
|
115
|
+
// Content-Type (RFC 2045)
|
|
116
|
+
headerLines.push(`Content-Type: ${this.serializeContentType(email.contentType)}`);
|
|
117
|
+
// Content-Transfer-Encoding (optional, RFC 2045)
|
|
118
|
+
if (email.contentTransferEncoding) {
|
|
119
|
+
headerLines.push(`Content-Transfer-Encoding: ${email.contentTransferEncoding}`);
|
|
120
|
+
}
|
|
121
|
+
// Custom headers (X-* and other extension headers)
|
|
122
|
+
if (email.customHeaders && email.customHeaders.size > 0) {
|
|
123
|
+
for (const [name, values] of email.customHeaders) {
|
|
124
|
+
for (const value of values) {
|
|
125
|
+
headerLines.push(`${name}: ${value}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// Fold each header line and join with CRLF
|
|
130
|
+
const foldedHeaders = headerLines
|
|
131
|
+
.map((line) => this.foldHeader(line))
|
|
132
|
+
.join(CRLF);
|
|
133
|
+
// Terminate with blank line (CRLF CRLF) per Requirement 14.3
|
|
134
|
+
return foldedHeaders + CRLF + CRLF;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Serializes a single IMailbox into an RFC 5322 compliant mailbox string.
|
|
138
|
+
*
|
|
139
|
+
* If a display name is present, formats as name-addr: `"Display Name" <local@domain>`
|
|
140
|
+
* Otherwise, formats as addr-spec: `local@domain`
|
|
141
|
+
*
|
|
142
|
+
* @param mailbox - The mailbox to serialize
|
|
143
|
+
* @returns RFC 5322 formatted mailbox string
|
|
144
|
+
*
|
|
145
|
+
* @see RFC 5322 Section 3.4 - Address Specification
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* ```typescript
|
|
149
|
+
* const serializer = new EmailSerializer();
|
|
150
|
+
* serializer.serializeMailbox({ localPart: 'john', domain: 'example.com', displayName: 'John Doe', address: 'john@example.com' });
|
|
151
|
+
* // => '"John Doe" <john@example.com>'
|
|
152
|
+
*
|
|
153
|
+
* serializer.serializeMailbox({ localPart: 'john', domain: 'example.com', address: 'john@example.com' });
|
|
154
|
+
* // => 'john@example.com'
|
|
155
|
+
* ```
|
|
156
|
+
*/
|
|
157
|
+
serializeMailbox(mailbox) {
|
|
158
|
+
return (0, emailAddress_1.formatMailbox)(mailbox);
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Serializes an array of IAddress objects into a comma-separated
|
|
162
|
+
* RFC 5322 address list string.
|
|
163
|
+
*
|
|
164
|
+
* Supports both individual mailboxes and group addresses.
|
|
165
|
+
*
|
|
166
|
+
* @param addresses - Array of addresses to serialize
|
|
167
|
+
* @returns Comma-separated RFC 5322 formatted address list string
|
|
168
|
+
*
|
|
169
|
+
* @see RFC 5322 Section 3.4 - Address Specification
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* ```typescript
|
|
173
|
+
* const serializer = new EmailSerializer();
|
|
174
|
+
* serializer.serializeAddressList([mailbox1, mailbox2]);
|
|
175
|
+
* // => '"Alice" <alice@example.com>, bob@example.com'
|
|
176
|
+
* ```
|
|
177
|
+
*/
|
|
178
|
+
serializeAddressList(addresses) {
|
|
179
|
+
if (!addresses || addresses.length === 0) {
|
|
180
|
+
return '';
|
|
181
|
+
}
|
|
182
|
+
return addresses
|
|
183
|
+
.map((addr) => {
|
|
184
|
+
if ((0, emailAddress_1.isMailbox)(addr)) {
|
|
185
|
+
return this.serializeMailbox(addr);
|
|
186
|
+
}
|
|
187
|
+
if ((0, emailAddress_1.isAddressGroup)(addr)) {
|
|
188
|
+
return (0, emailAddress_1.formatAddressGroup)(addr);
|
|
189
|
+
}
|
|
190
|
+
return '';
|
|
191
|
+
})
|
|
192
|
+
.filter((s) => s.length > 0)
|
|
193
|
+
.join(', ');
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Serializes a Message-ID string, ensuring it is enclosed in angle brackets.
|
|
197
|
+
*
|
|
198
|
+
* If the Message-ID is already enclosed in angle brackets, it is returned as-is.
|
|
199
|
+
* Otherwise, angle brackets are added.
|
|
200
|
+
*
|
|
201
|
+
* @param messageId - The Message-ID string to serialize
|
|
202
|
+
* @returns The Message-ID enclosed in angle brackets
|
|
203
|
+
*
|
|
204
|
+
* @see RFC 5322 Section 3.6.4 - Identification Fields
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* ```typescript
|
|
208
|
+
* const serializer = new EmailSerializer();
|
|
209
|
+
* serializer.serializeMessageId('<unique-id@example.com>');
|
|
210
|
+
* // => '<unique-id@example.com>'
|
|
211
|
+
*
|
|
212
|
+
* serializer.serializeMessageId('unique-id@example.com');
|
|
213
|
+
* // => '<unique-id@example.com>'
|
|
214
|
+
* ```
|
|
215
|
+
*/
|
|
216
|
+
serializeMessageId(messageId) {
|
|
217
|
+
if (!messageId) {
|
|
218
|
+
return '';
|
|
219
|
+
}
|
|
220
|
+
const trimmed = messageId.trim();
|
|
221
|
+
// If already enclosed in angle brackets, return as-is
|
|
222
|
+
if (trimmed.startsWith('<') && trimmed.endsWith('>')) {
|
|
223
|
+
return trimmed;
|
|
224
|
+
}
|
|
225
|
+
// Add angle brackets
|
|
226
|
+
return `<${trimmed}>`;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Serializes a Date object into an RFC 5322 compliant date-time string.
|
|
230
|
+
*
|
|
231
|
+
* Produces format: "day-of-week, DD Mon YYYY HH:MM:SS +0000"
|
|
232
|
+
* Example: "Thu, 13 Feb 2025 15:30:00 +0000"
|
|
233
|
+
*
|
|
234
|
+
* @param date - The Date object to serialize
|
|
235
|
+
* @returns RFC 5322 formatted date-time string
|
|
236
|
+
*
|
|
237
|
+
* @see RFC 5322 Section 3.3 - Date and Time Specification
|
|
238
|
+
*
|
|
239
|
+
* @example
|
|
240
|
+
* ```typescript
|
|
241
|
+
* const serializer = new EmailSerializer();
|
|
242
|
+
* serializer.serializeDate(new Date('2025-02-13T15:30:00Z'));
|
|
243
|
+
* // => 'Thu, 13 Feb 2025 15:30:00 +0000'
|
|
244
|
+
* ```
|
|
245
|
+
*/
|
|
246
|
+
serializeDate(date) {
|
|
247
|
+
if (!date || isNaN(date.getTime())) {
|
|
248
|
+
return new Date().toUTCString().replace('GMT', '+0000');
|
|
249
|
+
}
|
|
250
|
+
const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
|
251
|
+
const months = [
|
|
252
|
+
'Jan',
|
|
253
|
+
'Feb',
|
|
254
|
+
'Mar',
|
|
255
|
+
'Apr',
|
|
256
|
+
'May',
|
|
257
|
+
'Jun',
|
|
258
|
+
'Jul',
|
|
259
|
+
'Aug',
|
|
260
|
+
'Sep',
|
|
261
|
+
'Oct',
|
|
262
|
+
'Nov',
|
|
263
|
+
'Dec',
|
|
264
|
+
];
|
|
265
|
+
const dayOfWeek = days[date.getUTCDay()];
|
|
266
|
+
const day = date.getUTCDate().toString().padStart(2, '0');
|
|
267
|
+
const month = months[date.getUTCMonth()];
|
|
268
|
+
const year = date.getUTCFullYear();
|
|
269
|
+
const hours = date.getUTCHours().toString().padStart(2, '0');
|
|
270
|
+
const minutes = date.getUTCMinutes().toString().padStart(2, '0');
|
|
271
|
+
const seconds = date.getUTCSeconds().toString().padStart(2, '0');
|
|
272
|
+
return `${dayOfWeek}, ${day} ${month} ${year} ${hours}:${minutes}:${seconds} +0000`;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Serializes an IContentType object into an RFC 2045 Content-Type header value.
|
|
276
|
+
*
|
|
277
|
+
* Produces format: "type/subtype; param1=value1; param2=value2"
|
|
278
|
+
* Parameter values containing special characters are quoted.
|
|
279
|
+
*
|
|
280
|
+
* @param contentType - The content type to serialize
|
|
281
|
+
* @returns RFC 2045 formatted Content-Type header value
|
|
282
|
+
*
|
|
283
|
+
* @see RFC 2045 Section 5 - Content-Type Header Field
|
|
284
|
+
*
|
|
285
|
+
* @example
|
|
286
|
+
* ```typescript
|
|
287
|
+
* const serializer = new EmailSerializer();
|
|
288
|
+
* serializer.serializeContentType(createContentType('text', 'plain', new Map([['charset', 'utf-8']])));
|
|
289
|
+
* // => 'text/plain; charset=utf-8'
|
|
290
|
+
*
|
|
291
|
+
* serializer.serializeContentType(createContentType('multipart', 'mixed', new Map([['boundary', '----=_Part_123']])));
|
|
292
|
+
* // => 'multipart/mixed; boundary="----=_Part_123"'
|
|
293
|
+
* ```
|
|
294
|
+
*/
|
|
295
|
+
serializeContentType(contentType) {
|
|
296
|
+
let result = contentType.mediaType;
|
|
297
|
+
if (contentType.parameters && contentType.parameters.size > 0) {
|
|
298
|
+
for (const [key, value] of contentType.parameters) {
|
|
299
|
+
// Quote parameter values that contain special characters per RFC 2045
|
|
300
|
+
if (this.needsQuoting(value)) {
|
|
301
|
+
result += `; ${key}="${this.escapeQuotedString(value)}"`;
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
result += `; ${key}=${value}`;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return result;
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Serializes an array of IMimePart objects into a multipart body with
|
|
312
|
+
* proper boundary delimiters per RFC 2046 Section 5.1.1.
|
|
313
|
+
*
|
|
314
|
+
* Each part is formatted with its MIME headers (Content-Type,
|
|
315
|
+
* Content-Transfer-Encoding, Content-Disposition, Content-ID,
|
|
316
|
+
* Content-Description) followed by a blank line and the encoded body.
|
|
317
|
+
* Parts are separated by "--boundary" delimiters and the message is
|
|
318
|
+
* terminated with "--boundary--".
|
|
319
|
+
*
|
|
320
|
+
* Handles nested multipart parts recursively.
|
|
321
|
+
*
|
|
322
|
+
* @param parts - Array of IMimePart objects to serialize
|
|
323
|
+
* @param boundary - The boundary string to use as delimiter
|
|
324
|
+
* @returns The serialized multipart body as Uint8Array
|
|
325
|
+
*
|
|
326
|
+
* @see RFC 2046 Section 5.1.1 - Common Syntax
|
|
327
|
+
* @see Requirement 6.5 - Generate unique boundary string
|
|
328
|
+
* @see Requirement 6.6 - Format multipart with proper boundary delimiters
|
|
329
|
+
*
|
|
330
|
+
* @example
|
|
331
|
+
* ```typescript
|
|
332
|
+
* const serializer = new EmailSerializer();
|
|
333
|
+
* const parts: IMimePart[] = [
|
|
334
|
+
* { contentType: createContentType('text', 'plain'), body: new TextEncoder().encode('Hello'), size: 5 },
|
|
335
|
+
* { contentType: createContentType('text', 'html'), body: new TextEncoder().encode('<p>Hello</p>'), size: 12 },
|
|
336
|
+
* ];
|
|
337
|
+
* const boundary = serializer.generateBoundary();
|
|
338
|
+
* const result = serializer.serializeMultipart(parts, boundary);
|
|
339
|
+
* ```
|
|
340
|
+
*/
|
|
341
|
+
serializeMultipart(parts, boundary) {
|
|
342
|
+
const sections = [];
|
|
343
|
+
for (const part of parts) {
|
|
344
|
+
// Start with boundary delimiter
|
|
345
|
+
sections.push(`--${boundary}${CRLF}`);
|
|
346
|
+
// Build part headers
|
|
347
|
+
const partHeaders = [];
|
|
348
|
+
// Content-Type (always present)
|
|
349
|
+
partHeaders.push(`Content-Type: ${this.serializeContentType(part.contentType)}`);
|
|
350
|
+
// Content-Transfer-Encoding (if specified)
|
|
351
|
+
if (part.contentTransferEncoding) {
|
|
352
|
+
partHeaders.push(`Content-Transfer-Encoding: ${part.contentTransferEncoding}`);
|
|
353
|
+
}
|
|
354
|
+
// Content-Disposition (if specified)
|
|
355
|
+
if (part.contentDisposition) {
|
|
356
|
+
let dispositionValue = part.contentDisposition.type;
|
|
357
|
+
if (part.contentDisposition.filename) {
|
|
358
|
+
if (this.needsQuoting(part.contentDisposition.filename)) {
|
|
359
|
+
dispositionValue += `; filename="${this.escapeQuotedString(part.contentDisposition.filename)}"`;
|
|
360
|
+
}
|
|
361
|
+
else {
|
|
362
|
+
dispositionValue += `; filename=${part.contentDisposition.filename}`;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
if (part.contentDisposition.size !== undefined) {
|
|
366
|
+
dispositionValue += `; size=${part.contentDisposition.size}`;
|
|
367
|
+
}
|
|
368
|
+
partHeaders.push(`Content-Disposition: ${dispositionValue}`);
|
|
369
|
+
}
|
|
370
|
+
// Content-ID (if specified)
|
|
371
|
+
if (part.contentId) {
|
|
372
|
+
partHeaders.push(`Content-ID: ${part.contentId}`);
|
|
373
|
+
}
|
|
374
|
+
// Content-Description (if specified)
|
|
375
|
+
if (part.contentDescription) {
|
|
376
|
+
partHeaders.push(`Content-Description: ${part.contentDescription}`);
|
|
377
|
+
}
|
|
378
|
+
// Add headers followed by blank line
|
|
379
|
+
sections.push(partHeaders.join(CRLF) + CRLF + CRLF);
|
|
380
|
+
// Add body content
|
|
381
|
+
if (part.contentType.type === 'multipart' &&
|
|
382
|
+
part.parts &&
|
|
383
|
+
part.parts.length > 0) {
|
|
384
|
+
// Nested multipart - serialize recursively
|
|
385
|
+
const nestedBoundary = part.contentType.parameters.get('boundary');
|
|
386
|
+
if (nestedBoundary) {
|
|
387
|
+
const nestedBody = this.serializeMultipart(part.parts, nestedBoundary);
|
|
388
|
+
sections.push(new TextDecoder().decode(nestedBody));
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
else if (part.body) {
|
|
392
|
+
// Encode body based on Content-Transfer-Encoding
|
|
393
|
+
const encodedBody = this.encodePartBody(part.body, part.contentTransferEncoding);
|
|
394
|
+
sections.push(new TextDecoder().decode(encodedBody));
|
|
395
|
+
}
|
|
396
|
+
// Add CRLF after body content
|
|
397
|
+
sections.push(CRLF);
|
|
398
|
+
}
|
|
399
|
+
// Closing boundary delimiter
|
|
400
|
+
sections.push(`--${boundary}--${CRLF}`);
|
|
401
|
+
return new TextEncoder().encode(sections.join(''));
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Serializes the body of an email message based on its content type.
|
|
405
|
+
*
|
|
406
|
+
* For multipart content types (multipart/*), delegates to serializeMultipart()
|
|
407
|
+
* using the boundary parameter from the content type.
|
|
408
|
+
* For single-part content, encodes the first part's body directly based on
|
|
409
|
+
* its Content-Transfer-Encoding.
|
|
410
|
+
*
|
|
411
|
+
* @param parts - Array of IMimePart objects representing the message body
|
|
412
|
+
* @param contentType - The top-level Content-Type of the message
|
|
413
|
+
* @returns The serialized body as Uint8Array
|
|
414
|
+
*
|
|
415
|
+
* @see Requirement 6.5 - Generate unique boundary for multipart messages
|
|
416
|
+
* @see Requirement 6.6 - Format multipart with proper boundary delimiters
|
|
417
|
+
*
|
|
418
|
+
* @example
|
|
419
|
+
* ```typescript
|
|
420
|
+
* const serializer = new EmailSerializer();
|
|
421
|
+
* // Single part
|
|
422
|
+
* const textPart: IMimePart = {
|
|
423
|
+
* contentType: createContentType('text', 'plain'),
|
|
424
|
+
* body: new TextEncoder().encode('Hello'),
|
|
425
|
+
* size: 5,
|
|
426
|
+
* };
|
|
427
|
+
* const body = serializer.serializeBody([textPart], textPart.contentType);
|
|
428
|
+
* ```
|
|
429
|
+
*/
|
|
430
|
+
serializeBody(parts, contentType) {
|
|
431
|
+
if (contentType.type === 'multipart') {
|
|
432
|
+
// Multipart message - use boundary from content type parameters
|
|
433
|
+
let boundary = contentType.parameters.get('boundary');
|
|
434
|
+
if (!boundary) {
|
|
435
|
+
// Generate a boundary if not provided
|
|
436
|
+
boundary = this.generateBoundary();
|
|
437
|
+
}
|
|
438
|
+
return this.serializeMultipart(parts, boundary);
|
|
439
|
+
}
|
|
440
|
+
// Single part - encode the body directly
|
|
441
|
+
if (parts.length > 0 && parts[0].body) {
|
|
442
|
+
return this.encodePartBody(parts[0].body, parts[0].contentTransferEncoding);
|
|
443
|
+
}
|
|
444
|
+
return new Uint8Array(0);
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Encodes a part's body content based on its Content-Transfer-Encoding.
|
|
448
|
+
*
|
|
449
|
+
* @param body - The raw body content
|
|
450
|
+
* @param encoding - The Content-Transfer-Encoding to apply
|
|
451
|
+
* @returns The encoded body as Uint8Array
|
|
452
|
+
*/
|
|
453
|
+
encodePartBody(body, encoding) {
|
|
454
|
+
if (!encoding) {
|
|
455
|
+
return body;
|
|
456
|
+
}
|
|
457
|
+
switch (encoding) {
|
|
458
|
+
case mimePart_1.ContentTransferEncoding.Base64:
|
|
459
|
+
return this.encodeBase64(body);
|
|
460
|
+
case mimePart_1.ContentTransferEncoding.QuotedPrintable:
|
|
461
|
+
return this.encodeQuotedPrintable(body);
|
|
462
|
+
case mimePart_1.ContentTransferEncoding.SevenBit:
|
|
463
|
+
case mimePart_1.ContentTransferEncoding.EightBit:
|
|
464
|
+
case mimePart_1.ContentTransferEncoding.Binary:
|
|
465
|
+
return body;
|
|
466
|
+
default:
|
|
467
|
+
return body;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Folds a header line at the specified maximum length per RFC 5322 Section 2.2.3.
|
|
472
|
+
*
|
|
473
|
+
* Long header lines are broken at appropriate whitespace boundaries by
|
|
474
|
+
* inserting CRLF followed by a space (folding whitespace). The fold point
|
|
475
|
+
* is chosen at the last whitespace boundary before the maximum length.
|
|
476
|
+
*
|
|
477
|
+
* If no whitespace boundary is found before the maximum length, the line
|
|
478
|
+
* is folded at the first whitespace boundary after the maximum length.
|
|
479
|
+
*
|
|
480
|
+
* @param headerLine - The header line to fold
|
|
481
|
+
* @param maxLength - Maximum line length before folding (default: 78)
|
|
482
|
+
* @returns The folded header line with CRLF + space at fold points
|
|
483
|
+
*
|
|
484
|
+
* @see RFC 5322 Section 2.2.3 - Long Header Fields
|
|
485
|
+
* @see Requirement 14.2 - Fold header lines exceeding 78 characters
|
|
486
|
+
*
|
|
487
|
+
* @example
|
|
488
|
+
* ```typescript
|
|
489
|
+
* const serializer = new EmailSerializer();
|
|
490
|
+
* const long = 'Subject: ' + 'a'.repeat(80);
|
|
491
|
+
* const folded = serializer.foldHeader(long);
|
|
492
|
+
* // Lines are broken at whitespace boundaries, each <= 78 chars
|
|
493
|
+
* ```
|
|
494
|
+
*/
|
|
495
|
+
foldHeader(headerLine, maxLength = DEFAULT_MAX_LINE_LENGTH) {
|
|
496
|
+
// If the line is already within the limit, return as-is
|
|
497
|
+
if (headerLine.length <= maxLength) {
|
|
498
|
+
return headerLine;
|
|
499
|
+
}
|
|
500
|
+
const result = [];
|
|
501
|
+
let remaining = headerLine;
|
|
502
|
+
while (remaining.length > maxLength) {
|
|
503
|
+
// Find the last whitespace boundary before maxLength
|
|
504
|
+
let foldAt = -1;
|
|
505
|
+
// Start searching from maxLength backwards
|
|
506
|
+
// On continuation lines, the leading space counts toward the length
|
|
507
|
+
for (let i = maxLength - 1; i > 0; i--) {
|
|
508
|
+
if (remaining[i] === ' ' || remaining[i] === '\t') {
|
|
509
|
+
foldAt = i;
|
|
510
|
+
break;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
if (foldAt <= 0) {
|
|
514
|
+
// No whitespace found before maxLength - find the first whitespace after
|
|
515
|
+
for (let i = maxLength; i < remaining.length; i++) {
|
|
516
|
+
if (remaining[i] === ' ' || remaining[i] === '\t') {
|
|
517
|
+
foldAt = i;
|
|
518
|
+
break;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
if (foldAt <= 0) {
|
|
523
|
+
// No whitespace found at all - can't fold, emit the rest
|
|
524
|
+
break;
|
|
525
|
+
}
|
|
526
|
+
// Add the portion before the fold point
|
|
527
|
+
result.push(remaining.substring(0, foldAt));
|
|
528
|
+
// Skip the whitespace at the fold point; the continuation line
|
|
529
|
+
// will start with a space (folding whitespace)
|
|
530
|
+
remaining = remaining.substring(foldAt);
|
|
531
|
+
// If the remaining starts with whitespace, keep it as the folding WSP
|
|
532
|
+
// Otherwise, prepend a space
|
|
533
|
+
if (remaining[0] !== ' ' && remaining[0] !== '\t') {
|
|
534
|
+
remaining = ' ' + remaining;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
// Add the remaining portion
|
|
538
|
+
if (remaining.length > 0) {
|
|
539
|
+
result.push(remaining);
|
|
540
|
+
}
|
|
541
|
+
return result.join(CRLF);
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* Generates a unique boundary string for multipart messages.
|
|
545
|
+
*
|
|
546
|
+
* The boundary is designed to be unique and unlikely to appear in
|
|
547
|
+
* any message content. Uses a combination of a fixed prefix,
|
|
548
|
+
* timestamp, and random characters.
|
|
549
|
+
*
|
|
550
|
+
* @returns A unique boundary string
|
|
551
|
+
*
|
|
552
|
+
* @see RFC 2046 Section 5.1.1 - Common Syntax
|
|
553
|
+
*
|
|
554
|
+
* @example
|
|
555
|
+
* ```typescript
|
|
556
|
+
* const serializer = new EmailSerializer();
|
|
557
|
+
* const boundary = serializer.generateBoundary();
|
|
558
|
+
* // => '----=_Part_1707836400000_abc123def456'
|
|
559
|
+
* ```
|
|
560
|
+
*/
|
|
561
|
+
generateBoundary() {
|
|
562
|
+
const timestamp = Date.now();
|
|
563
|
+
const random = Math.random().toString(36).substring(2, 14);
|
|
564
|
+
const random2 = Math.random().toString(36).substring(2, 8);
|
|
565
|
+
return `----=_Part_${timestamp}_${random}${random2}`;
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Encodes a string as an RFC 2047 encoded-word.
|
|
569
|
+
*
|
|
570
|
+
* Encoded-words have the format: =?charset?encoding?encoded-text?=
|
|
571
|
+
* where encoding is either "B" (base64) or "Q" (quoted-printable).
|
|
572
|
+
*
|
|
573
|
+
* For 'B' encoding, the text bytes are base64 encoded.
|
|
574
|
+
* For 'Q' encoding, the text bytes are quoted-printable encoded with
|
|
575
|
+
* underscore for space per RFC 2047 Section 4.2.
|
|
576
|
+
*
|
|
577
|
+
* @param text - The text string to encode
|
|
578
|
+
* @param charset - The character set (e.g., 'UTF-8', 'ISO-8859-1')
|
|
579
|
+
* @param encoding - The encoding type: 'B' for base64, 'Q' for quoted-printable
|
|
580
|
+
* @returns The RFC 2047 encoded-word string
|
|
581
|
+
*
|
|
582
|
+
* @see RFC 2047 - MIME Part Three: Message Header Extensions for Non-ASCII Text
|
|
583
|
+
* @see Requirement 4.2 - Encode non-ASCII subject characters using RFC 2047 encoded-words
|
|
584
|
+
* @see Requirement 4.3 - Support both Base64 (B) and Quoted-Printable (Q) encoding
|
|
585
|
+
*
|
|
586
|
+
* @example
|
|
587
|
+
* ```typescript
|
|
588
|
+
* const serializer = new EmailSerializer();
|
|
589
|
+
* serializer.encodeEncodedWord('Hello World', 'UTF-8', 'B');
|
|
590
|
+
* // => '=?UTF-8?B?SGVsbG8gV29ybGQ=?='
|
|
591
|
+
*
|
|
592
|
+
* serializer.encodeEncodedWord('Hello World', 'UTF-8', 'Q');
|
|
593
|
+
* // => '=?UTF-8?Q?Hello_World?='
|
|
594
|
+
* ```
|
|
595
|
+
*/
|
|
596
|
+
encodeEncodedWord(text, charset, encoding) {
|
|
597
|
+
if (!text) {
|
|
598
|
+
return '';
|
|
599
|
+
}
|
|
600
|
+
// Convert text to bytes using the specified charset
|
|
601
|
+
const textBytes = Buffer.from(text, 'utf-8');
|
|
602
|
+
let encodedText;
|
|
603
|
+
if (encoding === 'B') {
|
|
604
|
+
// Base64 encoding
|
|
605
|
+
encodedText = textBytes.toString('base64');
|
|
606
|
+
}
|
|
607
|
+
else {
|
|
608
|
+
// Quoted-printable encoding for encoded-words (RFC 2047 Section 4.2)
|
|
609
|
+
// In Q encoding:
|
|
610
|
+
// - Underscore represents space
|
|
611
|
+
// - Printable ASCII (33-126) except '=', '?', '_' are literal
|
|
612
|
+
// - Everything else is encoded as =XX
|
|
613
|
+
const result = [];
|
|
614
|
+
for (let i = 0; i < textBytes.length; i++) {
|
|
615
|
+
const byte = textBytes[i];
|
|
616
|
+
if (byte === 0x20) {
|
|
617
|
+
// Space -> underscore per RFC 2047 Section 4.2
|
|
618
|
+
result.push('_');
|
|
619
|
+
}
|
|
620
|
+
else if (byte >= 33 &&
|
|
621
|
+
byte <= 126 &&
|
|
622
|
+
byte !== 0x3d && // '='
|
|
623
|
+
byte !== 0x3f && // '?'
|
|
624
|
+
byte !== 0x5f // '_'
|
|
625
|
+
) {
|
|
626
|
+
// Printable ASCII (except =, ?, _) - literal
|
|
627
|
+
result.push(String.fromCharCode(byte));
|
|
628
|
+
}
|
|
629
|
+
else {
|
|
630
|
+
// Encode as =XX
|
|
631
|
+
result.push('=' + byte.toString(16).toUpperCase().padStart(2, '0'));
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
encodedText = result.join('');
|
|
635
|
+
}
|
|
636
|
+
return `=?${charset}?${encoding}?${encodedText}?=`;
|
|
637
|
+
}
|
|
638
|
+
/**
|
|
639
|
+
* Encodes binary data as quoted-printable per RFC 2045 Section 6.7.
|
|
640
|
+
*
|
|
641
|
+
* Rules:
|
|
642
|
+
* - Bytes in the printable ASCII range (33-126, except '=') are literal
|
|
643
|
+
* - All other bytes are encoded as =XX (uppercase hex)
|
|
644
|
+
* - Lines are limited to 76 characters max; soft line breaks (=\r\n) are
|
|
645
|
+
* inserted when needed
|
|
646
|
+
* - Spaces and tabs before line breaks are encoded
|
|
647
|
+
* - Tab (0x09) and space (0x20) are allowed as literals within a line
|
|
648
|
+
*
|
|
649
|
+
* @param data - The binary data to encode as Uint8Array
|
|
650
|
+
* @returns The quoted-printable encoded data as Uint8Array
|
|
651
|
+
*
|
|
652
|
+
* @see RFC 2045 Section 6.7 - Quoted-Printable Content-Transfer-Encoding
|
|
653
|
+
* @see Requirement 7.7 - Use quoted-printable for text with special characters
|
|
654
|
+
* @see Requirement 14.8 - Encode body according to Content-Transfer-Encoding header
|
|
655
|
+
*
|
|
656
|
+
* @example
|
|
657
|
+
* ```typescript
|
|
658
|
+
* const serializer = new EmailSerializer();
|
|
659
|
+
* const data = new TextEncoder().encode('Hello World!');
|
|
660
|
+
* const encoded = serializer.encodeQuotedPrintable(data);
|
|
661
|
+
* // encoded contains bytes for 'Hello World!'
|
|
662
|
+
*
|
|
663
|
+
* const nonAscii = new Uint8Array([0xC3, 0xA9]); // UTF-8 'é'
|
|
664
|
+
* const encodedNonAscii = serializer.encodeQuotedPrintable(nonAscii);
|
|
665
|
+
* // encoded contains bytes for '=C3=A9'
|
|
666
|
+
* ```
|
|
667
|
+
*/
|
|
668
|
+
encodeQuotedPrintable(data) {
|
|
669
|
+
const MAX_LINE_LENGTH = 76;
|
|
670
|
+
const lines = [];
|
|
671
|
+
let currentLine = '';
|
|
672
|
+
for (let i = 0; i < data.length; i++) {
|
|
673
|
+
const byte = data[i];
|
|
674
|
+
let encoded;
|
|
675
|
+
// Check for CRLF line breaks - pass through as-is
|
|
676
|
+
if (byte === 0x0d && i + 1 < data.length && data[i + 1] === 0x0a) {
|
|
677
|
+
// Before emitting the line break, encode trailing whitespace
|
|
678
|
+
if (currentLine.length > 0) {
|
|
679
|
+
const lastChar = currentLine[currentLine.length - 1];
|
|
680
|
+
if (lastChar === ' ' || lastChar === '\t') {
|
|
681
|
+
// Encode the trailing whitespace
|
|
682
|
+
const wsCode = lastChar.charCodeAt(0);
|
|
683
|
+
currentLine =
|
|
684
|
+
currentLine.substring(0, currentLine.length - 1) +
|
|
685
|
+
'=' +
|
|
686
|
+
wsCode.toString(16).toUpperCase().padStart(2, '0');
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
lines.push(currentLine);
|
|
690
|
+
currentLine = '';
|
|
691
|
+
i++; // Skip the LF
|
|
692
|
+
continue;
|
|
693
|
+
}
|
|
694
|
+
// Check for bare LF line break
|
|
695
|
+
if (byte === 0x0a) {
|
|
696
|
+
if (currentLine.length > 0) {
|
|
697
|
+
const lastChar = currentLine[currentLine.length - 1];
|
|
698
|
+
if (lastChar === ' ' || lastChar === '\t') {
|
|
699
|
+
const wsCode = lastChar.charCodeAt(0);
|
|
700
|
+
currentLine =
|
|
701
|
+
currentLine.substring(0, currentLine.length - 1) +
|
|
702
|
+
'=' +
|
|
703
|
+
wsCode.toString(16).toUpperCase().padStart(2, '0');
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
lines.push(currentLine);
|
|
707
|
+
currentLine = '';
|
|
708
|
+
continue;
|
|
709
|
+
}
|
|
710
|
+
// Determine encoding for this byte
|
|
711
|
+
if (byte === 0x09 || byte === 0x20) {
|
|
712
|
+
// Tab and space are allowed as literals within a line
|
|
713
|
+
encoded = String.fromCharCode(byte);
|
|
714
|
+
}
|
|
715
|
+
else if (byte >= 33 && byte <= 126 && byte !== 0x3d) {
|
|
716
|
+
// Printable ASCII (33-126) except '=' (0x3d) - literal
|
|
717
|
+
encoded = String.fromCharCode(byte);
|
|
718
|
+
}
|
|
719
|
+
else {
|
|
720
|
+
// Encode as =XX
|
|
721
|
+
encoded = '=' + byte.toString(16).toUpperCase().padStart(2, '0');
|
|
722
|
+
}
|
|
723
|
+
// Check if adding this encoded character would exceed line length
|
|
724
|
+
// Need room for soft line break (=) at end if we need to wrap
|
|
725
|
+
if (currentLine.length + encoded.length > MAX_LINE_LENGTH - 1) {
|
|
726
|
+
// Emit soft line break: current line + '='
|
|
727
|
+
lines.push(currentLine + '=');
|
|
728
|
+
currentLine = encoded;
|
|
729
|
+
}
|
|
730
|
+
else {
|
|
731
|
+
currentLine += encoded;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
// Handle trailing whitespace on the last line
|
|
735
|
+
if (currentLine.length > 0) {
|
|
736
|
+
const lastChar = currentLine[currentLine.length - 1];
|
|
737
|
+
if (lastChar === ' ' || lastChar === '\t') {
|
|
738
|
+
const wsCode = lastChar.charCodeAt(0);
|
|
739
|
+
currentLine =
|
|
740
|
+
currentLine.substring(0, currentLine.length - 1) +
|
|
741
|
+
'=' +
|
|
742
|
+
wsCode.toString(16).toUpperCase().padStart(2, '0');
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
// Add the last line
|
|
746
|
+
lines.push(currentLine);
|
|
747
|
+
// Join lines with CRLF
|
|
748
|
+
const result = lines.join('\r\n');
|
|
749
|
+
return new TextEncoder().encode(result);
|
|
750
|
+
}
|
|
751
|
+
/**
|
|
752
|
+
* Encodes binary data as base64 per RFC 2045 Section 6.8.
|
|
753
|
+
*
|
|
754
|
+
* Produces standard base64 encoding with line breaks inserted every
|
|
755
|
+
* 76 characters per RFC 2045.
|
|
756
|
+
*
|
|
757
|
+
* @param data - The binary data to encode as Uint8Array
|
|
758
|
+
* @returns The base64 encoded data as Uint8Array
|
|
759
|
+
*
|
|
760
|
+
* @see RFC 2045 Section 6.8 - Base64 Content-Transfer-Encoding
|
|
761
|
+
* @see Requirement 7.6 - Use base64 for binary content
|
|
762
|
+
* @see Requirement 14.8 - Encode body according to Content-Transfer-Encoding header
|
|
763
|
+
*
|
|
764
|
+
* @example
|
|
765
|
+
* ```typescript
|
|
766
|
+
* const serializer = new EmailSerializer();
|
|
767
|
+
* const data = new TextEncoder().encode('Hello World');
|
|
768
|
+
* const encoded = serializer.encodeBase64(data);
|
|
769
|
+
* // encoded contains bytes for 'SGVsbG8gV29ybGQ='
|
|
770
|
+
* ```
|
|
771
|
+
*/
|
|
772
|
+
encodeBase64(data) {
|
|
773
|
+
const MAX_LINE_LENGTH = 76;
|
|
774
|
+
// Encode to base64 string
|
|
775
|
+
const base64String = Buffer.from(data).toString('base64');
|
|
776
|
+
// Insert CRLF line breaks every 76 characters per RFC 2045
|
|
777
|
+
const lines = [];
|
|
778
|
+
for (let i = 0; i < base64String.length; i += MAX_LINE_LENGTH) {
|
|
779
|
+
lines.push(base64String.substring(i, i + MAX_LINE_LENGTH));
|
|
780
|
+
}
|
|
781
|
+
const result = lines.join('\r\n');
|
|
782
|
+
return new TextEncoder().encode(result);
|
|
783
|
+
}
|
|
784
|
+
/**
|
|
785
|
+
* Determines if a parameter value needs to be quoted per RFC 2045.
|
|
786
|
+
*
|
|
787
|
+
* Values containing special characters (spaces, semicolons, equals signs,
|
|
788
|
+
* quotes, backslashes, parentheses, angle brackets, at signs, commas,
|
|
789
|
+
* or non-printable characters) must be quoted.
|
|
790
|
+
*
|
|
791
|
+
* @param value - The parameter value to check
|
|
792
|
+
* @returns true if the value needs quoting
|
|
793
|
+
*/
|
|
794
|
+
needsQuoting(value) {
|
|
795
|
+
// RFC 2045 tspecials: ()<>@,;:\"/[]?=
|
|
796
|
+
// Also quote if contains spaces or non-printable characters
|
|
797
|
+
return /[()<>@,;:\\"/[\]?=\s]/.test(value);
|
|
798
|
+
}
|
|
799
|
+
/**
|
|
800
|
+
* Escapes special characters in a quoted string per RFC 2045.
|
|
801
|
+
*
|
|
802
|
+
* Backslashes and double quotes are escaped with a preceding backslash.
|
|
803
|
+
*
|
|
804
|
+
* @param value - The string to escape
|
|
805
|
+
* @returns The escaped string (without surrounding quotes)
|
|
806
|
+
*/
|
|
807
|
+
escapeQuotedString(value) {
|
|
808
|
+
return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
809
|
+
}
|
|
810
|
+
/**
|
|
811
|
+
* Serializes a complete IEmailMetadata object into an RFC 5322 compliant
|
|
812
|
+
* email message as a Uint8Array.
|
|
813
|
+
*
|
|
814
|
+
* Composes the existing `serializeHeaders()` and `serializeBody()` methods
|
|
815
|
+
* to produce a complete email message with proper CRLF line endings.
|
|
816
|
+
* The header section is separated from the body by a blank line (CRLF CRLF),
|
|
817
|
+
* which is already included by `serializeHeaders()`.
|
|
818
|
+
*
|
|
819
|
+
* Handles both single-part and multipart emails by delegating to
|
|
820
|
+
* `serializeBody()` which selects the appropriate serialization strategy
|
|
821
|
+
* based on the content type.
|
|
822
|
+
*
|
|
823
|
+
* @param email - The email metadata to serialize
|
|
824
|
+
* @returns The complete RFC 5322 email message as Uint8Array
|
|
825
|
+
*
|
|
826
|
+
* @see RFC 5322 - Internet Message Format
|
|
827
|
+
* @see Requirement 14.1 - RFC 5322 compliant output with proper CRLF line endings
|
|
828
|
+
*
|
|
829
|
+
* @example
|
|
830
|
+
* ```typescript
|
|
831
|
+
* const serializer = new EmailSerializer();
|
|
832
|
+
* const rawEmail = serializer.serialize(emailMetadata);
|
|
833
|
+
* // rawEmail is a Uint8Array containing the full RFC 5322 message
|
|
834
|
+
* ```
|
|
835
|
+
*/
|
|
836
|
+
serialize(email) {
|
|
837
|
+
// 1. Serialize headers (already includes trailing CRLF CRLF)
|
|
838
|
+
const headerSection = this.serializeHeaders(email);
|
|
839
|
+
// 2. Serialize body based on content type and parts
|
|
840
|
+
const bodySection = email.parts && email.parts.length > 0
|
|
841
|
+
? this.serializeBody(email.parts, email.contentType)
|
|
842
|
+
: new Uint8Array(0);
|
|
843
|
+
// 3. Combine header and body sections
|
|
844
|
+
const headerBytes = new TextEncoder().encode(headerSection);
|
|
845
|
+
const result = new Uint8Array(headerBytes.length + bodySection.length);
|
|
846
|
+
result.set(headerBytes, 0);
|
|
847
|
+
result.set(bodySection, headerBytes.length);
|
|
848
|
+
return result;
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
exports.EmailSerializer = EmailSerializer;
|
|
852
|
+
//# sourceMappingURL=emailSerializer.js.map
|