@venizia/ignis 0.3.8 → 0.4.1
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/LICENSE.md +1 -1
- package/dist/base/applications/base.js +1 -1
- package/dist/base/applications/base.js.map +1 -1
- package/dist/base/applications/server.js +4 -4
- package/dist/base/applications/server.js.map +1 -1
- package/dist/base/middlewares/app-error/app-error.middleware.js +1 -1
- package/dist/base/middlewares/app-error/app-error.middleware.js.map +1 -1
- package/dist/components/auth/authenticate/controllers/factory.js +1 -1
- package/dist/components/auth/authenticate/controllers/factory.js.map +1 -1
- package/dist/components/auth/authenticate/controllers/jwks/controller.js.map +1 -1
- package/dist/components/auth/authenticate/controllers/service-certs/controller.js.map +1 -1
- package/dist/components/auth/authenticate/services/bearer/jwks/abstract.service.js +1 -1
- package/dist/components/auth/authenticate/services/bearer/jwks/abstract.service.js.map +1 -1
- package/dist/components/auth/authenticate/services/bearer/jwks/issuer.service.js +1 -1
- package/dist/components/auth/authenticate/services/bearer/jwks/issuer.service.js.map +1 -1
- package/dist/components/auth/authorize/adapters/custom-grant-expander.js +3 -3
- package/dist/components/auth/authorize/adapters/custom-grant-expander.js.map +1 -1
- package/dist/components/auth/authorize/adapters/scoped-casbin/adapter.d.ts.map +1 -1
- package/dist/components/auth/authorize/adapters/scoped-casbin/adapter.js +3 -3
- package/dist/components/auth/authorize/adapters/scoped-casbin/adapter.js.map +1 -1
- package/dist/components/auth/authorize/enforcers/casbin.enforcer.js +2 -2
- package/dist/components/auth/authorize/enforcers/casbin.enforcer.js.map +1 -1
- package/dist/components/auth/authorize/enforcers/user-policy-line-cache.js +1 -1
- package/dist/components/auth/authorize/enforcers/user-policy-line-cache.js.map +1 -1
- package/dist/components/health-check/controller.js +2 -2
- package/dist/components/health-check/controller.js.map +1 -1
- package/dist/components/mail/helpers/executors/bull-mq-executor.helper.js +2 -2
- package/dist/components/mail/helpers/executors/bull-mq-executor.helper.js.map +1 -1
- package/dist/components/mail/helpers/executors/internal-queue-executor.helper.js +2 -2
- package/dist/components/mail/helpers/executors/internal-queue-executor.helper.js.map +1 -1
- package/dist/components/mail/helpers/transporters/mailgun-transporter.helper.js +1 -1
- package/dist/components/mail/helpers/transporters/mailgun-transporter.helper.js.map +1 -1
- package/dist/components/mail/services/mail.service.js +2 -2
- package/dist/components/mail/services/mail.service.js.map +1 -1
- package/dist/components/mail/utilities/attachment.utility.js +2 -2
- package/dist/components/mail/utilities/attachment.utility.js.map +1 -1
- package/dist/components/mail/utilities/mime.utility.js +3 -3
- package/dist/components/mail/utilities/mime.utility.js.map +1 -1
- package/dist/components/static-asset/component.js +1 -1
- package/dist/components/static-asset/component.js.map +1 -1
- package/dist/components/static-asset/controller/factory.d.ts.map +1 -1
- package/dist/components/static-asset/controller/factory.js +9 -9
- package/dist/components/static-asset/controller/factory.js.map +1 -1
- package/dist/components/static-asset/controller/key-scope.js +1 -1
- package/dist/components/static-asset/controller/key-scope.js.map +1 -1
- package/dist/components/static-asset/controller/meta-link.js +2 -2
- package/dist/components/static-asset/controller/meta-link.js.map +1 -1
- package/dist/components/static-asset/models/base.model.js +1 -1
- package/dist/components/static-asset/models/base.model.js.map +1 -1
- package/dist/presets/app/files/.configs/formatters/.ignore +2 -2
- package/dist/presets/app/files/src/smoke.test.ts +1 -1
- package/dist/presets/app/files/tsconfig.json +2 -8
- package/dist/presets/app/preset.json +4 -5
- package/dist/presets/lib/files/.configs/formatters/.ignore +2 -2
- package/dist/presets/lib/files/tsconfig.json +2 -7
- package/dist/presets/lib/preset.json +3 -4
- package/package.json +51 -52
- package/dist/presets/app/files/.configs/formatters/oxfmt.config.mts +0 -4
- package/dist/presets/lib/files/.configs/formatters/oxfmt.config.mts +0 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mime.utility.js","sourceRoot":"","sources":["../../../../src/components/mail/utilities/mime.utility.ts"],"names":[],"mappings":"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","sourcesContent":["import { HTTP } from '@venizia/ignis-helpers/common';\nimport { randomBytes } from 'node:crypto';\nimport { getError } from '@venizia/ignis-helpers/core';\nimport { MailErrorCodes, type IMailAttachment, type IMailMessage } from '../common';\nimport { splitAddressList } from './address.utility';\nimport { readAttachmentContent } from './attachment.utility';\n\nconst CRLF = '\\r\\n';\nconst BASE64_LINE_LENGTH = 76;\n/** RFC 5322 recommends folding well under its own 998-byte hard limit; 78 matches common MTA\n * practice. This is a *soft* preferred width, not a hard requirement - {@link foldHeaderLine}\n * only forces a line break past it when a natural whitespace break point exists nearby. */\nconst MAX_HEADER_LINE_LENGTH = 78;\n/** The real hard requirement: SES rejects any raw-message physical line at or over 1000 bytes.\n * A 10-byte margin below that, and comfortably under RFC 5322's own 998-octet hard limit. Only\n * an unbroken token that would itself cross this line forces {@link foldHeaderLine}'s\n * content-altering hard-wrap fallback - below it, one long line is safer than corrupting an\n * atomic value (a single very long address, an unbroken encoded-word) by splitting it. */\nconst MAX_HEADER_HARD_LIMIT = 990;\n/** RFC 2047 caps one encoded-word (`=?charset?B?...?=` included) at 75 characters. */\nconst ENCODED_WORD_MAX_LENGTH = 75;\n\nfunction isAscii(value: string): boolean {\n for (let index = 0; index < value.length; index++) {\n if (value.charCodeAt(index) > 127) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * RFC 2047 §5(3) requires each encoded-word to carry whole characters - a multi-byte UTF-8\n * sequence split across two encoded-words decodes to mojibake or invalid UTF-8 on either side of\n * the cut. `bytesPerChunk` is a fixed byte budget, not a character-aligned one, so after slicing\n * at that budget we walk the boundary back over any UTF-8 continuation bytes (`10xxxxxx`, i.e.\n * `byte & 0xC0 === 0x80`) until it lands on the leading byte of a character. `bytesPerChunk` is\n * always far larger than the longest UTF-8 sequence (4 bytes), so this walk-back can never\n * consume the whole chunk. Words are joined with a single space - the required separator between\n * adjacent encoded-words, and also a valid header-folding point.\n */\nfunction encodeWord(text: string): string {\n const prefix = '=?UTF-8?B?';\n const suffix = '?=';\n const maxPayloadChars = ENCODED_WORD_MAX_LENGTH - prefix.length - suffix.length;\n const bytesPerChunk = Math.floor(maxPayloadChars / 4) * 3;\n const bytes = Buffer.from(text, 'utf-8');\n const words: string[] = [];\n let offset = 0;\n\n while (offset < bytes.length) {\n let end = Math.min(offset + bytesPerChunk, bytes.length);\n\n while (end < bytes.length && (bytes[end] & 0xc0) === 0x80) {\n end--;\n }\n\n const chunk = bytes.subarray(offset, end);\n words.push(`${prefix}${chunk.toString('base64')}${suffix}`);\n offset = end;\n }\n\n return words.join(' ');\n}\n\n/** Only non-ASCII values pay for RFC 2047 encoding, so a plain-English subject or custom header\n * stays byte-for-byte readable. */\nfunction encodeHeaderValue(value: string): string {\n return isAscii(value) ? value : encodeWord(value);\n}\n\n/**\n * Encodes only the *display-name* portion of `\"Name\" <addr@x.com>` (or bare `Name <addr@x.com>`).\n * The `<addr-spec>` must stay 7-bit ASCII per RFC 5321/5322 and per the SES raw-message\n * requirements - only the free-text name may become an RFC 2047 encoded-word. A bare address with\n * no display name is returned unchanged.\n */\nfunction encodeAddress(address: string): string {\n const match = /^(.*)<([^<>]+)>\\s*$/.exec(address);\n\n if (!match) {\n return address;\n }\n\n const [, rawName, addr] = match;\n const name = rawName.trim().replace(/^\"|\"$/g, '');\n\n if (name.length === 0 || isAscii(name)) {\n return rawName.trim().length > 0 ? `${rawName.trim()} <${addr}>` : `<${addr}>`;\n }\n\n return `${encodeWord(name)} <${addr}>`;\n}\n\n/** Formats a `to`/`cc`/`from`/`replyTo` field as one RFC 5322 address list: splits a\n * comma-separated string or array into individual mailboxes, RFC 2047-encodes each display name,\n * and rejoins with `, ` - the same shape whether the caller passed a string or an array. */\nexport function formatAddressHeader(value: string | string[]): string {\n return splitAddressList(value).map(encodeAddress).join(', ');\n}\n\n/**\n * RFC 5322 §2.2.3 header folding: inserting CRLF immediately before an existing whitespace\n * character splits one logical header value across physical lines without changing its content\n * (the folded whitespace is still there, just after a line break). SES enforces a 1000-byte\n * ceiling per raw-message line; folding at {@link MAX_HEADER_LINE_LENGTH} keeps arbitrarily long\n * recipient lists, subjects, or encoded display names deliverable regardless of how many\n * addresses or how much non-ASCII text a caller supplies - purely by adding more physical\n * lines, never by dropping or truncating anything (verified: rejoining every folded line always\n * reproduces the original value exactly).\n *\n * The one value-altering fallback is deliberately gated on the *hard* limit, not the soft one:\n * an unbroken token (a single very long address, an encoded-word with no adjacent break) that\n * fits under {@link MAX_HEADER_HARD_LIMIT} is left on one long physical line rather than\n * force-broken at the soft width - forcing a break through the middle of an atomic token (an\n * email address has no internal whitespace) would insert a space that was never there,\n * corrupting it. Only a token that would itself violate the real transport limit gets the\n * content-altering hard-wrap - a case that essentially never occurs with real-world input.\n */\nfunction foldHeaderLine(line: string): string {\n const lines: string[] = [];\n let remaining = line;\n\n while (remaining.length > MAX_HEADER_LINE_LENGTH) {\n let breakAt = remaining.lastIndexOf(' ', MAX_HEADER_LINE_LENGTH);\n\n if (breakAt <= 0) {\n // No break within the soft width - look further ahead instead of forcing one through an\n // atomic token. Still bounded by the hard limit, so the physical line this produces can\n // never violate the real transport constraint.\n const nextBreak = remaining.indexOf(' ', MAX_HEADER_LINE_LENGTH);\n breakAt = nextBreak > 0 && nextBreak <= MAX_HEADER_HARD_LIMIT ? nextBreak : -1;\n }\n\n if (breakAt > 0) {\n lines.push(remaining.slice(0, breakAt));\n remaining = remaining.slice(breakAt);\n continue;\n }\n\n if (remaining.length <= MAX_HEADER_HARD_LIMIT) {\n break;\n }\n\n // Truly no natural break within the hard limit - an unbroken token that would itself\n // violate the transport line cap. This is the only path that can alter the value.\n lines.push(remaining.slice(0, MAX_HEADER_HARD_LIMIT));\n remaining = ` ${remaining.slice(MAX_HEADER_HARD_LIMIT)}`;\n }\n\n lines.push(remaining);\n return lines.join(CRLF);\n}\n\n/** MIME requires encoded body lines capped well under the RFC 5322 998-byte hard limit. */\nfunction foldBase64(base64: string): string {\n const lines: string[] = [];\n\n for (let index = 0; index < base64.length; index += BASE64_LINE_LENGTH) {\n lines.push(base64.slice(index, index + BASE64_LINE_LENGTH));\n }\n\n return lines.join(CRLF);\n}\n\n/** UTF-8 text (`text`/`html` bodies) must be encoded before folding - unlike {@link encodeBufferBase64}, which folds bytes that are already final. Two names instead of one so the caller can never feed raw bytes through the wrong path and silently double-encode them. */\nfunction encodeTextBase64(text: string): string {\n return foldBase64(Buffer.from(text, 'utf-8').toString('base64'));\n}\n\n/** Attachment bytes are already final binary content - only folding applies, no UTF-8 re-encode. */\nfunction encodeBufferBase64(buffer: Buffer): string {\n return foldBase64(buffer.toString('base64'));\n}\n\n/** A literal CR/LF/NUL inside a header-bound value would let it break out of its own header line and forge additional headers or smuggle body content - classic email header injection. Every value spliced into a raw header line is checked here first, so an attempt fails loudly instead of silently reaching the wire.\n *\n * `value` is `unknown`, not `string`: `IMailMessage`/`IMailAttachment` both end in\n * `[key: string]: any`, so nothing at the type layer stops a caller (e.g. a controller\n * forwarding a request body) from putting a non-string - notably an array - where a string is\n * declared. `Array.prototype.includes('\\r')` checks element *equality*, not substring, so\n * `['x\\r\\nBcc: evil'].includes('\\r')` is `false` and a naive string-only check would wave a\n * forged header straight through once it is later stringified by a template literal. Requiring\n * `typeof value === 'string'` up front closes that gap for every field that flows through here. */\nfunction assertNoHeaderInjection(opts: { field: string; value: unknown }): void {\n const { field, value } = opts;\n\n if (typeof value !== 'string') {\n throw getError({\n statusCode: HTTP.ResultCodes.RS_5.InternalServerError,\n messageCode: MailErrorCodes.INVALID_CONFIGURATION,\n message: `Invalid Amazon SES message | ${field} must be a string`,\n });\n }\n\n if (!value.includes('\\r') && !value.includes('\\n') && !value.includes('\\0')) {\n return;\n }\n\n throw getError({\n statusCode: HTTP.ResultCodes.RS_5.InternalServerError,\n messageCode: MailErrorCodes.INVALID_CONFIGURATION,\n message: `Invalid Amazon SES message | ${field} contains illegal control characters`,\n });\n}\n\n/** Same guard as {@link assertNoHeaderInjection}, applied to every address in a `to`/`cc`/`bcc`\n * field individually - a string field only, not `[key: string]: any`; validating the raw\n * caller-provided value (before splitting/joining) both types and content-checks each entry. */\nfunction assertNoAddressListInjection(opts: { field: string; value: string | string[] }): void {\n const { field, value } = opts;\n const list = Array.isArray(value) ? value : [value];\n\n for (const item of list) {\n assertNoHeaderInjection({ field, value: item });\n }\n}\n\nfunction extractDomain(address: string | undefined): string {\n const match = address ? /@([^@>\\s]+)>?\\s*$/.exec(address) : null;\n return match ? match[1] : 'localhost';\n}\n\nfunction buildHeaders(message: IMailMessage): string[] {\n const headers: string[] = [];\n\n if (message.from) {\n assertNoAddressListInjection({ field: 'from', value: message.from });\n headers.push(foldHeaderLine(`From: ${formatAddressHeader(message.from)}`));\n }\n\n if (message.to) {\n assertNoAddressListInjection({ field: 'to', value: message.to });\n headers.push(foldHeaderLine(`To: ${formatAddressHeader(message.to)}`));\n }\n\n if (message.cc) {\n assertNoAddressListInjection({ field: 'cc', value: message.cc });\n headers.push(foldHeaderLine(`Cc: ${formatAddressHeader(message.cc)}`));\n }\n\n if (message.replyTo) {\n assertNoAddressListInjection({ field: 'replyTo', value: message.replyTo });\n headers.push(foldHeaderLine(`Reply-To: ${formatAddressHeader(message.replyTo)}`));\n }\n\n // Checked, never emitted: a `Bcc:` header would disclose the blind recipients, so they travel as\n // `Destination.BccAddresses`. Without this, `bcc` is the one address field that fails at AWS.\n if (message.bcc) {\n assertNoAddressListInjection({ field: 'bcc', value: message.bcc });\n }\n\n assertNoHeaderInjection({ field: 'subject', value: message.subject });\n headers.push(foldHeaderLine(`Subject: ${encodeHeaderValue(message.subject)}`));\n // RFC 5322 requires both on every message; SES's raw-message parser does not synthesize them,\n // so an omission here is an omission on the wire (some receiving MTAs reject a `Date`-less\n // message outright, and a missing `Message-ID` breaks threading and dedup).\n headers.push(`Date: ${new Date().toUTCString()}`);\n headers.push(`Message-ID: <${randomBytes(16).toString('hex')}@${extractDomain(message.from)}>`);\n headers.push('MIME-Version: 1.0');\n\n if (message.headers) {\n const messageHeadersEntries = Object.entries(message.headers);\n for (const [key, value] of messageHeadersEntries) {\n assertNoHeaderInjection({ field: `headers.${key}`, value: key });\n assertNoHeaderInjection({ field: `headers.${key}`, value });\n headers.push(foldHeaderLine(`${key}: ${encodeHeaderValue(value)}`));\n }\n }\n\n return headers;\n}\n\n/** One text/plain or text/html MIME part. `boundary` omitted only for the single-part, no-attachment case, where the content type belongs on the top-level headers instead of a nested part. */\nfunction textPart(\n boundary: string,\n contentType: 'text/plain' | 'text/html',\n content: string,\n): string {\n return [\n `--${boundary}`,\n `Content-Type: ${contentType}; charset=UTF-8`,\n 'Content-Transfer-Encoding: base64',\n '',\n encodeTextBase64(content),\n ].join(CRLF);\n}\n\nfunction escapeQuotedString(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"');\n}\n\n/** RFC 2231 percent-encoding for the `filename*=`/`name*=` extended parameter form. */\nfunction encodeRfc2231(value: string): string {\n return encodeURIComponent(value).replace(\n /[!'()*]/g,\n char => `%${char.charCodeAt(0).toString(16).toUpperCase()}`,\n );\n}\n\n/**\n * Builds the `; name=\"...\"`/`; filename=\"...\"` (and, for non-ASCII names, the RFC 2231\n * `; filename*=UTF-8''...` extended form) suffix for a Content-Type/Content-Disposition line.\n * ASCII names are still quoted-string escaped - an unescaped `\"` or `\\` in a filename would\n * terminate the quoted string early and let the rest of the value merge into a sibling MIME\n * parameter, corrupting the part header for every downstream reader.\n */\nfunction attachmentNameParams(attribute: 'name' | 'filename', value: string): string {\n if (isAscii(value)) {\n return `; ${attribute}=\"${escapeQuotedString(value)}\"`;\n }\n\n const asciiFallback = value.replace(/[^\\x20-\\x7E]/g, '_');\n return (\n `; ${attribute}=\"${escapeQuotedString(asciiFallback)}\"` +\n `; ${attribute}*=UTF-8''${encodeRfc2231(value)}`\n );\n}\n\nasync function attachmentPart(attachment: IMailAttachment, boundary: string): Promise<string> {\n // No root here: a `path` that did not go through `resolveMailAttachments` is refused, never read.\n const content = await readAttachmentContent({ attachment });\n const contentType = attachment.contentType ?? 'application/octet-stream';\n assertNoHeaderInjection({ field: 'attachment.contentType', value: contentType });\n\n if (attachment.filename) {\n assertNoHeaderInjection({ field: 'attachment.filename', value: attachment.filename });\n }\n\n if (attachment.cid) {\n assertNoHeaderInjection({ field: 'attachment.cid', value: attachment.cid });\n }\n\n const nameAttribute = attachment.filename\n ? attachmentNameParams('name', attachment.filename)\n : '';\n const filenameAttribute = attachment.filename\n ? attachmentNameParams('filename', attachment.filename)\n : '';\n const disposition = attachment.cid ? 'inline' : 'attachment';\n\n const headerLines = [\n `--${boundary}`,\n foldHeaderLine(`Content-Type: ${contentType}${nameAttribute}`),\n 'Content-Transfer-Encoding: base64',\n foldHeaderLine(`Content-Disposition: ${disposition}${filenameAttribute}`),\n ];\n\n if (attachment.cid) {\n headerLines.push(`Content-ID: <${attachment.cid}>`);\n }\n\n return [...headerLines, '', encodeBufferBase64(content)].join(CRLF);\n}\n\n/** Every boundary is generated the same way - a fixed prefix plus random hex - so no two nested multipart sections in one message can ever collide. */\nfunction newBoundary(label: string): string {\n return `----=_${label}_${randomBytes(12).toString('hex')}`;\n}\n\n/**\n * Builds a raw RFC 822 message with zero external dependencies - Amazon SES's `SendEmailCommand`\n * `Content.Simple` shape has no attachment field, so attachments require a raw MIME body. Written\n * by hand instead of depending on `nodemailer`'s `MailComposer` so the `ses` provider never needs\n * the `nodemailer` peer installed at all.\n *\n * Inline (`cid`) attachments nest under `multipart/related` next to the body - a mail client\n * only renders `cid:` references inline when they share a `multipart/related` parent with the\n * body; under `multipart/mixed` they show up as ordinary downloadable attachments instead. Plain\n * file attachments (no `cid`) stay under `multipart/mixed`, alongside the body or the\n * `multipart/related` group when both kinds are present.\n */\nexport async function buildRawMimeMessage(message: IMailMessage): Promise<Buffer> {\n const headers = buildHeaders(message);\n const attachments = message.attachments ?? [];\n const inlineAttachments = attachments.filter(attachment => Boolean(attachment.cid));\n const fileAttachments = attachments.filter(attachment => !attachment.cid);\n const hasBothBodies = Boolean(message.text) && Boolean(message.html);\n const singleContentType = message.html ? ('text/html' as const) : ('text/plain' as const);\n const singleContent = message.html ?? message.text ?? '';\n\n const bodyPart = (boundary: string): string => {\n if (!hasBothBodies) {\n return textPart(boundary, singleContentType, singleContent);\n }\n\n const altBoundary = newBoundary('Alt');\n return [\n `--${boundary}`,\n `Content-Type: multipart/alternative; boundary=\"${altBoundary}\"`,\n '',\n [\n textPart(altBoundary, 'text/plain', message.text ?? ''),\n textPart(altBoundary, 'text/html', message.html ?? ''),\n `--${altBoundary}--`,\n ].join(CRLF),\n ].join(CRLF);\n };\n\n if (attachments.length === 0 && !hasBothBodies) {\n headers.push(`Content-Type: ${singleContentType}; charset=UTF-8`);\n headers.push('Content-Transfer-Encoding: base64');\n return Buffer.from([...headers, '', encodeTextBase64(singleContent)].join(CRLF), 'utf-8');\n }\n\n if (attachments.length === 0) {\n const boundary = newBoundary('Alt');\n headers.push(`Content-Type: multipart/alternative; boundary=\"${boundary}\"`);\n const parts = [\n textPart(boundary, 'text/plain', message.text ?? ''),\n textPart(boundary, 'text/html', message.html ?? ''),\n `--${boundary}--`,\n ];\n return Buffer.from([...headers, '', parts.join(CRLF)].join(CRLF), 'utf-8');\n }\n\n const buildRelatedPart = async (parentBoundary: string): Promise<string> => {\n const relatedBoundary = newBoundary('Related');\n const parts = [bodyPart(relatedBoundary)];\n\n for (const attachment of inlineAttachments) {\n parts.push(await attachmentPart(attachment, relatedBoundary));\n }\n\n parts.push(`--${relatedBoundary}--`);\n\n return [\n `--${parentBoundary}`,\n `Content-Type: multipart/related; boundary=\"${relatedBoundary}\"`,\n '',\n parts.join(CRLF),\n ].join(CRLF);\n };\n\n if (inlineAttachments.length > 0 && fileAttachments.length === 0) {\n const relatedBoundary = newBoundary('Related');\n const parts = [bodyPart(relatedBoundary)];\n\n for (const attachment of inlineAttachments) {\n parts.push(await attachmentPart(attachment, relatedBoundary));\n }\n\n parts.push(`--${relatedBoundary}--`);\n headers.push(`Content-Type: multipart/related; boundary=\"${relatedBoundary}\"`);\n return Buffer.from([...headers, '', parts.join(CRLF)].join(CRLF), 'utf-8');\n }\n\n const mixedBoundary = newBoundary('Mixed');\n headers.push(`Content-Type: multipart/mixed; boundary=\"${mixedBoundary}\"`);\n\n const bodyParts: string[] = [];\n\n if (inlineAttachments.length > 0) {\n bodyParts.push(await buildRelatedPart(mixedBoundary));\n } else {\n bodyParts.push(bodyPart(mixedBoundary));\n }\n\n for (const attachment of fileAttachments) {\n bodyParts.push(await attachmentPart(attachment, mixedBoundary));\n }\n\n bodyParts.push(`--${mixedBoundary}--`);\n\n return Buffer.from([...headers, '', bodyParts.join(CRLF)].join(CRLF), 'utf-8');\n}\n"]}
|
|
1
|
+
{"version":3,"file":"mime.utility.js","sourceRoot":"","sources":["../../../../src/components/mail/utilities/mime.utility.ts"],"names":[],"mappings":"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","sourcesContent":["import { HTTP } from '@venizia/ignis-helpers/common';\nimport { randomBytes } from 'node:crypto';\nimport { getError } from '@venizia/ignis-helpers/core';\nimport { MailErrorCodes, type IMailAttachment, type IMailMessage } from '../common';\nimport { splitAddressList } from './address.utility';\nimport { readAttachmentContent } from './attachment.utility';\n\nconst CRLF = '\\r\\n';\nconst BASE64_LINE_LENGTH = 76;\n/** RFC 5322 recommends folding well under its own 998-byte hard limit; 78 matches common MTA\n * practice. This is a *soft* preferred width, not a hard requirement - {@link foldHeaderLine}\n * only forces a line break past it when a natural whitespace break point exists nearby. */\nconst MAX_HEADER_LINE_LENGTH = 78;\n/** The real hard requirement: SES rejects any raw-message physical line at or over 1000 bytes.\n * A 10-byte margin below that, and comfortably under RFC 5322's own 998-octet hard limit. Only\n * an unbroken token that would itself cross this line forces {@link foldHeaderLine}'s\n * content-altering hard-wrap fallback - below it, one long line is safer than corrupting an\n * atomic value (a single very long address, an unbroken encoded-word) by splitting it. */\nconst MAX_HEADER_HARD_LIMIT = 990;\n/** RFC 2047 caps one encoded-word (`=?charset?B?...?=` included) at 75 characters. */\nconst ENCODED_WORD_MAX_LENGTH = 75;\n\nfunction isAscii(value: string): boolean {\n for (let index = 0; index < value.length; index++) {\n if (value.charCodeAt(index) > 127) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * RFC 2047 §5(3) requires each encoded-word to carry whole characters - a multi-byte UTF-8\n * sequence split across two encoded-words decodes to mojibake or invalid UTF-8 on either side of\n * the cut. `bytesPerChunk` is a fixed byte budget, not a character-aligned one, so after slicing\n * at that budget we walk the boundary back over any UTF-8 continuation bytes (`10xxxxxx`, i.e.\n * `byte & 0xC0 === 0x80`) until it lands on the leading byte of a character. `bytesPerChunk` is\n * always far larger than the longest UTF-8 sequence (4 bytes), so this walk-back can never\n * consume the whole chunk. Words are joined with a single space - the required separator between\n * adjacent encoded-words, and also a valid header-folding point.\n */\nfunction encodeWord(text: string): string {\n const prefix = '=?UTF-8?B?';\n const suffix = '?=';\n const maxPayloadChars = ENCODED_WORD_MAX_LENGTH - prefix.length - suffix.length;\n const bytesPerChunk = Math.floor(maxPayloadChars / 4) * 3;\n const bytes = Buffer.from(text, 'utf-8');\n const words: string[] = [];\n let offset = 0;\n\n while (offset < bytes.length) {\n let end = Math.min(offset + bytesPerChunk, bytes.length);\n\n while (end < bytes.length && (bytes[end] & 0xc0) === 0x80) {\n end--;\n }\n\n const chunk = bytes.subarray(offset, end);\n words.push(`${prefix}${chunk.toString('base64')}${suffix}`);\n offset = end;\n }\n\n return words.join(' ');\n}\n\n/** Only non-ASCII values pay for RFC 2047 encoding, so a plain-English subject or custom header\n * stays byte-for-byte readable. */\nfunction encodeHeaderValue(value: string): string {\n return isAscii(value) ? value : encodeWord(value);\n}\n\n/**\n * Encodes only the *display-name* portion of `\"Name\" <addr@x.com>` (or bare `Name <addr@x.com>`).\n * The `<addr-spec>` must stay 7-bit ASCII per RFC 5321/5322 and per the SES raw-message\n * requirements - only the free-text name may become an RFC 2047 encoded-word. A bare address with\n * no display name is returned unchanged.\n */\nfunction encodeAddress(address: string): string {\n const match = /^(.*)<([^<>]+)>\\s*$/.exec(address);\n\n if (!match) {\n return address;\n }\n\n const [, rawName, addr] = match;\n const name = rawName.trim().replace(/^\"|\"$/g, '');\n\n if (name.length === 0 || isAscii(name)) {\n return rawName.trim().length > 0 ? `${rawName.trim()} <${addr}>` : `<${addr}>`;\n }\n\n return `${encodeWord(name)} <${addr}>`;\n}\n\n/** Formats a `to`/`cc`/`from`/`replyTo` field as one RFC 5322 address list: splits a\n * comma-separated string or array into individual mailboxes, RFC 2047-encodes each display name,\n * and rejoins with `, ` - the same shape whether the caller passed a string or an array. */\nexport function formatAddressHeader(value: string | string[]): string {\n return splitAddressList(value).map(encodeAddress).join(', ');\n}\n\n/**\n * RFC 5322 §2.2.3 header folding: inserting CRLF immediately before an existing whitespace\n * character splits one logical header value across physical lines without changing its content\n * (the folded whitespace is still there, just after a line break). SES enforces a 1000-byte\n * ceiling per raw-message line; folding at {@link MAX_HEADER_LINE_LENGTH} keeps arbitrarily long\n * recipient lists, subjects, or encoded display names deliverable regardless of how many\n * addresses or how much non-ASCII text a caller supplies - purely by adding more physical\n * lines, never by dropping or truncating anything (verified: rejoining every folded line always\n * reproduces the original value exactly).\n *\n * The one value-altering fallback is deliberately gated on the *hard* limit, not the soft one:\n * an unbroken token (a single very long address, an encoded-word with no adjacent break) that\n * fits under {@link MAX_HEADER_HARD_LIMIT} is left on one long physical line rather than\n * force-broken at the soft width - forcing a break through the middle of an atomic token (an\n * email address has no internal whitespace) would insert a space that was never there,\n * corrupting it. Only a token that would itself violate the real transport limit gets the\n * content-altering hard-wrap - a case that essentially never occurs with real-world input.\n */\nfunction foldHeaderLine(line: string): string {\n const lines: string[] = [];\n let remaining = line;\n\n while (remaining.length > MAX_HEADER_LINE_LENGTH) {\n let breakAt = remaining.lastIndexOf(' ', MAX_HEADER_LINE_LENGTH);\n\n if (breakAt <= 0) {\n // No break within the soft width - look further ahead instead of forcing one through an\n // atomic token. Still bounded by the hard limit, so the physical line this produces can\n // never violate the real transport constraint.\n const nextBreak = remaining.indexOf(' ', MAX_HEADER_LINE_LENGTH);\n breakAt = nextBreak > 0 && nextBreak <= MAX_HEADER_HARD_LIMIT ? nextBreak : -1;\n }\n\n if (breakAt > 0) {\n lines.push(remaining.slice(0, breakAt));\n remaining = remaining.slice(breakAt);\n continue;\n }\n\n if (remaining.length <= MAX_HEADER_HARD_LIMIT) {\n break;\n }\n\n // Truly no natural break within the hard limit - an unbroken token that would itself\n // violate the transport line cap. This is the only path that can alter the value.\n lines.push(remaining.slice(0, MAX_HEADER_HARD_LIMIT));\n remaining = ` ${remaining.slice(MAX_HEADER_HARD_LIMIT)}`;\n }\n\n lines.push(remaining);\n return lines.join(CRLF);\n}\n\n/** MIME requires encoded body lines capped well under the RFC 5322 998-byte hard limit. */\nfunction foldBase64(base64: string): string {\n const lines: string[] = [];\n\n for (let index = 0; index < base64.length; index += BASE64_LINE_LENGTH) {\n lines.push(base64.slice(index, index + BASE64_LINE_LENGTH));\n }\n\n return lines.join(CRLF);\n}\n\n/** UTF-8 text (`text`/`html` bodies) must be encoded before folding - unlike {@link encodeBufferBase64}, which folds bytes that are already final. Two names instead of one so the caller can never feed raw bytes through the wrong path and silently double-encode them. */\nfunction encodeTextBase64(text: string): string {\n return foldBase64(Buffer.from(text, 'utf-8').toString('base64'));\n}\n\n/** Attachment bytes are already final binary content - only folding applies, no UTF-8 re-encode. */\nfunction encodeBufferBase64(buffer: Buffer): string {\n return foldBase64(buffer.toString('base64'));\n}\n\n/** A literal CR/LF/NUL inside a header-bound value would let it break out of its own header line and forge additional headers or smuggle body content - classic email header injection. Every value spliced into a raw header line is checked here first, so an attempt fails loudly instead of silently reaching the wire.\n *\n * `value` is `unknown`, not `string`: `IMailMessage`/`IMailAttachment` both end in\n * `[key: string]: any`, so nothing at the type layer stops a caller (e.g. a controller\n * forwarding a request body) from putting a non-string - notably an array - where a string is\n * declared. `Array.prototype.includes('\\r')` checks element *equality*, not substring, so\n * `['x\\r\\nBcc: evil'].includes('\\r')` is `false` and a naive string-only check would wave a\n * forged header straight through once it is later stringified by a template literal. Requiring\n * `typeof value === 'string'` up front closes that gap for every field that flows through here. */\nfunction assertNoHeaderInjection(opts: { field: string; value: unknown }): void {\n const { field, value } = opts;\n\n if (typeof value !== 'string') {\n throw getError({\n statusCode: HTTP.ResultCodes.RS_5.InternalServerError,\n messageCode: MailErrorCodes.INVALID_CONFIGURATION,\n message: `Invalid Amazon SES message | ${field} must be a string`,\n });\n }\n\n if (!value.includes('\\r') && !value.includes('\\n') && !value.includes('\\0')) {\n return;\n }\n\n throw getError({\n statusCode: HTTP.ResultCodes.RS_5.InternalServerError,\n messageCode: MailErrorCodes.INVALID_CONFIGURATION,\n message: `Invalid Amazon SES message | ${field} contains illegal control characters`,\n });\n}\n\n/** Same guard as {@link assertNoHeaderInjection}, applied to every address in a `to`/`cc`/`bcc`\n * field individually - a string field only, not `[key: string]: any`; validating the raw\n * caller-provided value (before splitting/joining) both types and content-checks each entry. */\nfunction assertNoAddressListInjection(opts: { field: string; value: string | string[] }): void {\n const { field, value } = opts;\n const list = Array.isArray(value) ? value : [value];\n\n for (const item of list) {\n assertNoHeaderInjection({ field, value: item });\n }\n}\n\nfunction extractDomain(address: string | undefined): string {\n const match = address ? /@([^@>\\s]+)>?\\s*$/.exec(address) : null;\n return match ? match[1] : 'localhost';\n}\n\nfunction buildHeaders(message: IMailMessage): string[] {\n const headers: string[] = [];\n\n if (message.from) {\n assertNoAddressListInjection({ field: 'from', value: message.from });\n headers.push(foldHeaderLine(`From: ${formatAddressHeader(message.from)}`));\n }\n\n if (message.to) {\n assertNoAddressListInjection({ field: 'to', value: message.to });\n headers.push(foldHeaderLine(`To: ${formatAddressHeader(message.to)}`));\n }\n\n if (message.cc) {\n assertNoAddressListInjection({ field: 'cc', value: message.cc });\n headers.push(foldHeaderLine(`Cc: ${formatAddressHeader(message.cc)}`));\n }\n\n if (message.replyTo) {\n assertNoAddressListInjection({ field: 'replyTo', value: message.replyTo });\n headers.push(foldHeaderLine(`Reply-To: ${formatAddressHeader(message.replyTo)}`));\n }\n\n // Checked, never emitted: a `Bcc:` header would disclose the blind recipients, so they travel as\n // `Destination.BccAddresses`. Without this, `bcc` is the one address field that fails at AWS.\n if (message.bcc) {\n assertNoAddressListInjection({ field: 'bcc', value: message.bcc });\n }\n\n assertNoHeaderInjection({ field: 'subject', value: message.subject });\n headers.push(foldHeaderLine(`Subject: ${encodeHeaderValue(message.subject)}`));\n // RFC 5322 requires both on every message; SES's raw-message parser does not synthesize them,\n // so an omission here is an omission on the wire (some receiving MTAs reject a `Date`-less\n // message outright, and a missing `Message-ID` breaks threading and dedup).\n headers.push(`Date: ${new Date().toUTCString()}`);\n headers.push(`Message-ID: <${randomBytes(16).toString('hex')}@${extractDomain(message.from)}>`);\n headers.push('MIME-Version: 1.0');\n\n if (message.headers) {\n const messageHeadersEntries = Object.entries(message.headers);\n for (const [key, value] of messageHeadersEntries) {\n assertNoHeaderInjection({ field: `headers.${key}`, value: key });\n assertNoHeaderInjection({ field: `headers.${key}`, value });\n headers.push(foldHeaderLine(`${key}: ${encodeHeaderValue(value)}`));\n }\n }\n\n return headers;\n}\n\n/** One text/plain or text/html MIME part. `boundary` omitted only for the single-part, no-attachment case, where the content type belongs on the top-level headers instead of a nested part. */\nfunction textPart(\n boundary: string,\n contentType: 'text/plain' | 'text/html',\n content: string,\n): string {\n return [\n `--${boundary}`,\n `Content-Type: ${contentType}; charset=UTF-8`,\n 'Content-Transfer-Encoding: base64',\n '',\n encodeTextBase64(content),\n ].join(CRLF);\n}\n\nfunction escapeQuotedString(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"');\n}\n\n/** RFC 2231 percent-encoding for the `filename*=`/`name*=` extended parameter form. */\nfunction encodeRfc2231(value: string): string {\n return encodeURIComponent(value).replace(\n /[!'()*]/g,\n (char) => `%${char.charCodeAt(0).toString(16).toUpperCase()}`,\n );\n}\n\n/**\n * Builds the `; name=\"...\"`/`; filename=\"...\"` (and, for non-ASCII names, the RFC 2231\n * `; filename*=UTF-8''...` extended form) suffix for a Content-Type/Content-Disposition line.\n * ASCII names are still quoted-string escaped - an unescaped `\"` or `\\` in a filename would\n * terminate the quoted string early and let the rest of the value merge into a sibling MIME\n * parameter, corrupting the part header for every downstream reader.\n */\nfunction attachmentNameParams(attribute: 'name' | 'filename', value: string): string {\n if (isAscii(value)) {\n return `; ${attribute}=\"${escapeQuotedString(value)}\"`;\n }\n\n const asciiFallback = value.replace(/[^\\x20-\\x7E]/g, '_');\n return (\n `; ${attribute}=\"${escapeQuotedString(asciiFallback)}\"` +\n `; ${attribute}*=UTF-8''${encodeRfc2231(value)}`\n );\n}\n\nasync function attachmentPart(attachment: IMailAttachment, boundary: string): Promise<string> {\n // No root here: a `path` that did not go through `resolveMailAttachments` is refused, never read.\n const content = await readAttachmentContent({ attachment });\n const contentType = attachment.contentType ?? 'application/octet-stream';\n assertNoHeaderInjection({ field: 'attachment.contentType', value: contentType });\n\n if (attachment.filename) {\n assertNoHeaderInjection({ field: 'attachment.filename', value: attachment.filename });\n }\n\n if (attachment.cid) {\n assertNoHeaderInjection({ field: 'attachment.cid', value: attachment.cid });\n }\n\n const nameAttribute = attachment.filename\n ? attachmentNameParams('name', attachment.filename)\n : '';\n const filenameAttribute = attachment.filename\n ? attachmentNameParams('filename', attachment.filename)\n : '';\n const disposition = attachment.cid ? 'inline' : 'attachment';\n\n const headerLines = [\n `--${boundary}`,\n foldHeaderLine(`Content-Type: ${contentType}${nameAttribute}`),\n 'Content-Transfer-Encoding: base64',\n foldHeaderLine(`Content-Disposition: ${disposition}${filenameAttribute}`),\n ];\n\n if (attachment.cid) {\n headerLines.push(`Content-ID: <${attachment.cid}>`);\n }\n\n return [...headerLines, '', encodeBufferBase64(content)].join(CRLF);\n}\n\n/** Every boundary is generated the same way - a fixed prefix plus random hex - so no two nested multipart sections in one message can ever collide. */\nfunction newBoundary(label: string): string {\n return `----=_${label}_${randomBytes(12).toString('hex')}`;\n}\n\n/**\n * Builds a raw RFC 822 message with zero external dependencies - Amazon SES's `SendEmailCommand`\n * `Content.Simple` shape has no attachment field, so attachments require a raw MIME body. Written\n * by hand instead of depending on `nodemailer`'s `MailComposer` so the `ses` provider never needs\n * the `nodemailer` peer installed at all.\n *\n * Inline (`cid`) attachments nest under `multipart/related` next to the body - a mail client\n * only renders `cid:` references inline when they share a `multipart/related` parent with the\n * body; under `multipart/mixed` they show up as ordinary downloadable attachments instead. Plain\n * file attachments (no `cid`) stay under `multipart/mixed`, alongside the body or the\n * `multipart/related` group when both kinds are present.\n */\nexport async function buildRawMimeMessage(message: IMailMessage): Promise<Buffer> {\n const headers = buildHeaders(message);\n const attachments = message.attachments ?? [];\n const inlineAttachments = attachments.filter((attachment) => Boolean(attachment.cid));\n const fileAttachments = attachments.filter((attachment) => !attachment.cid);\n const hasBothBodies = Boolean(message.text) && Boolean(message.html);\n const singleContentType = message.html ? ('text/html' as const) : ('text/plain' as const);\n const singleContent = message.html ?? message.text ?? '';\n\n const bodyPart = (boundary: string): string => {\n if (!hasBothBodies) {\n return textPart(boundary, singleContentType, singleContent);\n }\n\n const altBoundary = newBoundary('Alt');\n return [\n `--${boundary}`,\n `Content-Type: multipart/alternative; boundary=\"${altBoundary}\"`,\n '',\n [\n textPart(altBoundary, 'text/plain', message.text ?? ''),\n textPart(altBoundary, 'text/html', message.html ?? ''),\n `--${altBoundary}--`,\n ].join(CRLF),\n ].join(CRLF);\n };\n\n if (attachments.length === 0 && !hasBothBodies) {\n headers.push(`Content-Type: ${singleContentType}; charset=UTF-8`);\n headers.push('Content-Transfer-Encoding: base64');\n return Buffer.from([...headers, '', encodeTextBase64(singleContent)].join(CRLF), 'utf-8');\n }\n\n if (attachments.length === 0) {\n const boundary = newBoundary('Alt');\n headers.push(`Content-Type: multipart/alternative; boundary=\"${boundary}\"`);\n const parts = [\n textPart(boundary, 'text/plain', message.text ?? ''),\n textPart(boundary, 'text/html', message.html ?? ''),\n `--${boundary}--`,\n ];\n return Buffer.from([...headers, '', parts.join(CRLF)].join(CRLF), 'utf-8');\n }\n\n const buildRelatedPart = async (parentBoundary: string): Promise<string> => {\n const relatedBoundary = newBoundary('Related');\n const parts = [bodyPart(relatedBoundary)];\n\n for (const attachment of inlineAttachments) {\n parts.push(await attachmentPart(attachment, relatedBoundary));\n }\n\n parts.push(`--${relatedBoundary}--`);\n\n return [\n `--${parentBoundary}`,\n `Content-Type: multipart/related; boundary=\"${relatedBoundary}\"`,\n '',\n parts.join(CRLF),\n ].join(CRLF);\n };\n\n if (inlineAttachments.length > 0 && fileAttachments.length === 0) {\n const relatedBoundary = newBoundary('Related');\n const parts = [bodyPart(relatedBoundary)];\n\n for (const attachment of inlineAttachments) {\n parts.push(await attachmentPart(attachment, relatedBoundary));\n }\n\n parts.push(`--${relatedBoundary}--`);\n headers.push(`Content-Type: multipart/related; boundary=\"${relatedBoundary}\"`);\n return Buffer.from([...headers, '', parts.join(CRLF)].join(CRLF), 'utf-8');\n }\n\n const mixedBoundary = newBoundary('Mixed');\n headers.push(`Content-Type: multipart/mixed; boundary=\"${mixedBoundary}\"`);\n\n const bodyParts: string[] = [];\n\n if (inlineAttachments.length > 0) {\n bodyParts.push(await buildRelatedPart(mixedBoundary));\n } else {\n bodyParts.push(bodyPart(mixedBoundary));\n }\n\n for (const attachment of fileAttachments) {\n bodyParts.push(await attachmentPart(attachment, mixedBoundary));\n }\n\n bodyParts.push(`--${mixedBoundary}--`);\n\n return Buffer.from([...headers, '', bodyParts.join(CRLF)].join(CRLF), 'utf-8');\n}\n"]}
|
|
@@ -57,7 +57,7 @@ let StaticAssetComponent = StaticAssetComponent_1 = class StaticAssetComponent e
|
|
|
57
57
|
...extra,
|
|
58
58
|
normalizeLinkFn: extra?.normalizeLinkFn ??
|
|
59
59
|
// The link follows the URL shape the controller serves: `{objectName}` is one Hono path segment unless `rawObjectPath` widens it, and a configured bucket leaves the path.
|
|
60
|
-
(linkOptions => (0, controller_1.buildObjectLink)({
|
|
60
|
+
((linkOptions) => (0, controller_1.buildObjectLink)({
|
|
61
61
|
basePath: controller.basePath,
|
|
62
62
|
bucket: linkOptions.bucket,
|
|
63
63
|
object: linkOptions.object,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component.js","sourceRoot":"","sources":["../../../src/components/static-asset/component.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AACA,wDAAsD;AACtD,8CAAyC;AACzC,wDAAqD;AACrD,wDAAgD;AAEhD,qCAA+F;AAE/F,6CAAuE;AAEvE,kQAAkQ;AAClQ,IAAa,oBAAoB,4BAAjC,MAAa,oBAEX,SAAQ,4BAAoD;IAC5D,YAC8D,WAA4B;QAExF,KAAK,CAAC;YACJ,KAAK,EAAE,sBAAoB,CAAC,IAAI;YAChC,WAAW,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE;YACrD,QAAQ,EAAE;gBACR,CAAC,wCAA+B,CAAC,8BAA8B,CAAC,EAC9D,sBAAO,CAAC,IAAI,CAAgC;oBAC1C,GAAG,EAAE,wCAA+B,CAAC,8BAA8B;iBACpE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;aACjB;SACF,CAAC,CAAC;QAXyD,gBAAW,GAAX,WAAW,CAAiB;IAY1F,CAAC;IAEQ,OAAO;QACd,2FAA2F;QAC3F,8EAA8E;QAC9E,MAAM,gBAAgB,GACpB,IAAI,CAAC,OAAO;YACZ,IAAI,CAAC,WAAW,CAAC,GAAG,CAAwC;gBAC1D,GAAG,EAAE,wCAA+B,CAAC,8BAA8B;aACpE,CAAC,CAAC;QAEL,MAAM,uBAAuB,GAAG,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QACjE,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,uBAAuB,EAAE,CAAC;YACjD,MAAM,EACJ,OAAO,EACP,UAAU,EACV,MAAM,EACN,KAAK,EACL,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,GAClB,GAAG,GAAG,CAAC;YAER,IAAI,CAAC,WAAW,CAAC,UAAU,CACzB,mCAAsB,CAAC,qBAAqB,CAAC;gBAC3C,UAAU;gBACV,OAAO;gBACP,MAAM;gBACN,WAAW,EAAE,GAAG,CAAC,WAAW;gBAC5B,QAAQ,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;gBACpD,iBAAiB;gBACjB,kBAAkB;gBAClB,iBAAiB;gBACjB,OAAO,EAAE;oBACP,GAAG,KAAK;oBACR,eAAe,EACb,KAAK,EAAE,eAAe;wBACtB,2KAA2K;wBAC3K,CAAC,WAAW,
|
|
1
|
+
{"version":3,"file":"component.js","sourceRoot":"","sources":["../../../src/components/static-asset/component.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AACA,wDAAsD;AACtD,8CAAyC;AACzC,wDAAqD;AACrD,wDAAgD;AAEhD,qCAA+F;AAE/F,6CAAuE;AAEvE,kQAAkQ;AAClQ,IAAa,oBAAoB,4BAAjC,MAAa,oBAEX,SAAQ,4BAAoD;IAC5D,YAC8D,WAA4B;QAExF,KAAK,CAAC;YACJ,KAAK,EAAE,sBAAoB,CAAC,IAAI;YAChC,WAAW,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE;YACrD,QAAQ,EAAE;gBACR,CAAC,wCAA+B,CAAC,8BAA8B,CAAC,EAC9D,sBAAO,CAAC,IAAI,CAAgC;oBAC1C,GAAG,EAAE,wCAA+B,CAAC,8BAA8B;iBACpE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;aACjB;SACF,CAAC,CAAC;QAXyD,gBAAW,GAAX,WAAW,CAAiB;IAY1F,CAAC;IAEQ,OAAO;QACd,2FAA2F;QAC3F,8EAA8E;QAC9E,MAAM,gBAAgB,GACpB,IAAI,CAAC,OAAO;YACZ,IAAI,CAAC,WAAW,CAAC,GAAG,CAAwC;gBAC1D,GAAG,EAAE,wCAA+B,CAAC,8BAA8B;aACpE,CAAC,CAAC;QAEL,MAAM,uBAAuB,GAAG,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QACjE,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,uBAAuB,EAAE,CAAC;YACjD,MAAM,EACJ,OAAO,EACP,UAAU,EACV,MAAM,EACN,KAAK,EACL,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,GAClB,GAAG,GAAG,CAAC;YAER,IAAI,CAAC,WAAW,CAAC,UAAU,CACzB,mCAAsB,CAAC,qBAAqB,CAAC;gBAC3C,UAAU;gBACV,OAAO;gBACP,MAAM;gBACN,WAAW,EAAE,GAAG,CAAC,WAAW;gBAC5B,QAAQ,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;gBACpD,iBAAiB;gBACjB,kBAAkB;gBAClB,iBAAiB;gBACjB,OAAO,EAAE;oBACP,GAAG,KAAK;oBACR,eAAe,EACb,KAAK,EAAE,eAAe;wBACtB,2KAA2K;wBAC3K,CAAC,CAAC,WAAW,EAAE,EAAE,CACf,IAAA,4BAAe,EAAC;4BACd,QAAQ,EAAE,UAAU,CAAC,QAAQ;4BAC7B,MAAM,EAAE,WAAW,CAAC,MAAM;4BAC1B,MAAM,EAAE,WAAW,CAAC,MAAM;4BAC1B,mBAAmB,EAAE,UAAU,CAAC,MAAM,KAAK,SAAS;4BACpD,aAAa,EAAE,UAAU,CAAC,aAAa;yBACxC,CAAC,CAAC;iBACR;aACF,CAAC,CACH,CAAC;YAEF,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAC1B,iFAAiF,EACjF,GAAG,EACH,OAAO,EACP,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CACzB,CAAC;QACJ,CAAC;IACH,CAAC;CACF,CAAA;AA1EY,oDAAoB;+BAApB,oBAAoB;IAI5B,WAAA,IAAA,iBAAM,EAAC,EAAE,GAAG,EAAE,2BAAY,CAAC,oBAAoB,EAAE,CAAC,CAAA;;GAJ1C,oBAAoB,CA0EhC","sourcesContent":["import { type BaseApplication } from '@/base/applications';\nimport { BaseComponent } from '@venizia/ignis-kernel';\nimport { inject } from '@/base/metadata';\nimport { CoreBindings } from '@venizia/ignis-kernel';\nimport { Binding } from '@venizia/ignis-kernel';\nimport { type ValueOrPromise } from '@venizia/ignis-helpers/common';\nimport { StaticAssetComponentBindingKeys, type TStaticAssetsComponentOptions } from './common';\nimport type { TMetaLinkCompatibleSchema, TMetaLinkSchema } from './models';\nimport { AssetControllerFactory, buildObjectLink } from './controller';\n\n/** `Schema` is the MetaLink table the application binds. It has to live on the CLASS, not only on the options: `component(Ctor, { options })` infers the options from the class, so a class pinned to the shipped table can only carry options for that table. */\nexport class StaticAssetComponent<\n Schema extends TMetaLinkCompatibleSchema = TMetaLinkSchema,\n> extends BaseComponent<TStaticAssetsComponentOptions<Schema>> {\n constructor(\n @inject({ key: CoreBindings.APPLICATION_INSTANCE }) private application: BaseApplication,\n ) {\n super({\n scope: StaticAssetComponent.name,\n initDefault: { enable: true, container: application },\n bindings: {\n [StaticAssetComponentBindingKeys.STATIC_ASSET_COMPONENT_OPTIONS]:\n Binding.bind<TStaticAssetsComponentOptions>({\n key: StaticAssetComponentBindingKeys.STATIC_ASSET_COMPONENT_OPTIONS,\n }).toValue({}),\n },\n });\n }\n\n override binding(): ValueOrPromise<void> {\n // Direct options win. The key is the path for an application that registers this component\n // through `configs.artifacts`, where an index carries classes and no options.\n const componentOptions =\n this.options ??\n this.application.get<TStaticAssetsComponentOptions<Schema>>({\n key: StaticAssetComponentBindingKeys.STATIC_ASSET_COMPONENT_OPTIONS,\n });\n\n const componentOptionsEntries = Object.entries(componentOptions);\n for (const [key, opt] of componentOptionsEntries) {\n const {\n storage,\n controller,\n helper,\n extra,\n resolveObjectName,\n defineRoutesBefore,\n defineExtraRoutes,\n } = opt;\n\n this.application.controller(\n AssetControllerFactory.defineAssetController({\n controller,\n storage,\n helper,\n useMetaLink: opt.useMetaLink,\n metaLink: opt.useMetaLink ? opt.metaLink : undefined,\n resolveObjectName,\n defineRoutesBefore,\n defineExtraRoutes,\n options: {\n ...extra,\n normalizeLinkFn:\n extra?.normalizeLinkFn ??\n // The link follows the URL shape the controller serves: `{objectName}` is one Hono path segment unless `rawObjectPath` widens it, and a configured bucket leaves the path.\n ((linkOptions) =>\n buildObjectLink({\n basePath: controller.basePath,\n bucket: linkOptions.bucket,\n object: linkOptions.object,\n hasConfiguredBucket: controller.bucket !== undefined,\n rawObjectPath: controller.rawObjectPath,\n })),\n },\n }),\n );\n\n this.application.logger.info(\n `[binding] Asset storage is bound | Key: %s | Storage type: %s | UseMetaLink: %s`,\n key,\n storage,\n Boolean(opt.useMetaLink),\n );\n }\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../../src/components/static-asset/controller/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAE5E,OAAO,EAGL,KAAK,eAAe,EAEpB,KAAK,UAAU,EAEf,KAAK,cAAc,EAMpB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAA2B,KAAK,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC7F,OAAO,KAAK,EAAE,OAAO,EAAyB,MAAM,+BAA+B,CAAC;AACpF,OAAO,EAAE,UAAU,EAAwB,MAAM,6BAA6B,CAAC;AAC/E,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,MAAM,CAAC;AAEhC,OAAO,EAIL,KAAK,kBAAkB,EAEvB,KAAK,eAAe,EAKpB,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAC7B,KAAK,6BAA6B,EAClC,KAAK,uBAAuB,EAG7B,MAAM,WAAW,CAAC;AAYnB,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,6BAA6B,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IAChE,OAAO,EAAE,uBAAuB,CAAC;IACjC,MAAM,EAAE,cAAc,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,iRAAiR;IACjR,QAAQ,CAAC,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;IACpC,OAAO,CAAC,EAAE,wBAAwB,CAAC;IAEnC,qHAAqH;IACrH,iBAAiB,CAAC,EAAE,mBAAmB,CAAC;IAExC,oGAAoG;IACpG,4IAA4I;IAC5I,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC,iBAAiB,CAAC,EAAE,kBAAkB,CAAC;CACxC;AAED,6OAA6O;AAC7O,mIAAmI;AACnI,0EAA0E;AAC1E,QAAA,MAAM,kBAAkB,gFAMd,CAAC;AAEX,qFAAqF;AACrF,eAAO,MAAM,iBAAiB,GAAI,MAAM;IACtC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,KAAK,CAAC,EAAE,aAAa,CAAC,CAAC,OAAO,kBAAkB,EAAE,MAAM,CAAC,CAAC,CAAC;CAC5D,KAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../../src/components/static-asset/controller/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAE5E,OAAO,EAGL,KAAK,eAAe,EAEpB,KAAK,UAAU,EAEf,KAAK,cAAc,EAMpB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAA2B,KAAK,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC7F,OAAO,KAAK,EAAE,OAAO,EAAyB,MAAM,+BAA+B,CAAC;AACpF,OAAO,EAAE,UAAU,EAAwB,MAAM,6BAA6B,CAAC;AAC/E,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,MAAM,CAAC;AAEhC,OAAO,EAIL,KAAK,kBAAkB,EAEvB,KAAK,eAAe,EAKpB,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAC7B,KAAK,6BAA6B,EAClC,KAAK,uBAAuB,EAG7B,MAAM,WAAW,CAAC;AAYnB,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,6BAA6B,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IAChE,OAAO,EAAE,uBAAuB,CAAC;IACjC,MAAM,EAAE,cAAc,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,iRAAiR;IACjR,QAAQ,CAAC,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;IACpC,OAAO,CAAC,EAAE,wBAAwB,CAAC;IAEnC,qHAAqH;IACrH,iBAAiB,CAAC,EAAE,mBAAmB,CAAC;IAExC,oGAAoG;IACpG,4IAA4I;IAC5I,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC,iBAAiB,CAAC,EAAE,kBAAkB,CAAC;CACxC;AAED,6OAA6O;AAC7O,mIAAmI;AACnI,0EAA0E;AAC1E,QAAA,MAAM,kBAAkB,gFAMd,CAAC;AAEX,qFAAqF;AACrF,eAAO,MAAM,iBAAiB,GAAI,MAAM;IACtC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,KAAK,CAAC,EAAE,aAAa,CAAC,CAAC,OAAO,kBAAkB,EAAE,MAAM,CAAC,CAAC,CAAC;CAC5D,KAAG,MAAM,EAAyF,CAAC;AA8DpG,qJAAqJ;AACrJ,eAAO,MAAM,eAAe,GAC1B,MAAM,eAAe,GAAG;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,KACA,MAQF,CAAC;AAcF;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,GAAI,MAAM;IAC7C,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,UAAU,CAAC;CACpB,KAAG;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,OAAO,CAAA;CAS/C,CAAC;AAyDF,qBAAa,sBAAuB,SAAQ,UAAU;;IAKpD,MAAM,CAAC,qBAAqB,CAAC,IAAI,EAAE,uBAAuB;;YAwDtD,6FAA6F;2CAC9D;gBAAE,KAAK,EAAE,MAAM,EAAE,CAAA;aAAE,GAAG,IAAI;uBAYrC,cAAc,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAxRnC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAymCX"}
|
|
@@ -33,7 +33,7 @@ const UPLOAD_LABEL_NAMES = [
|
|
|
33
33
|
'folderPath',
|
|
34
34
|
];
|
|
35
35
|
/** Names any label a caller put in the query - where the upload routes refuse it. */
|
|
36
|
-
const findLabelsInQuery = (opts) => (opts.names ?? UPLOAD_LABEL_NAMES).filter(name => opts.query[name] !== undefined);
|
|
36
|
+
const findLabelsInQuery = (opts) => (opts.names ?? UPLOAD_LABEL_NAMES).filter((name) => opts.query[name] !== undefined);
|
|
37
37
|
exports.findLabelsInQuery = findLabelsInQuery;
|
|
38
38
|
/** Refused before the body is read: a route that ignored them would store an unlabelled row. */
|
|
39
39
|
const refuseLabelsInQuery = (opts) => {
|
|
@@ -46,7 +46,7 @@ const refuseLabelsInQuery = (opts) => {
|
|
|
46
46
|
}
|
|
47
47
|
};
|
|
48
48
|
/** The commit body carries four of the five: the object key - and so `folderPath` - was fixed when the policy was issued. */
|
|
49
|
-
const COMMIT_LABEL_NAMES = UPLOAD_LABEL_NAMES.filter(name => name !== 'folderPath');
|
|
49
|
+
const COMMIT_LABEL_NAMES = UPLOAD_LABEL_NAMES.filter((name) => name !== 'folderPath');
|
|
50
50
|
// A multipart form hands strings; a JSON commit body may hand `sequence` as a number.
|
|
51
51
|
const readUploadLabels = (opts) => {
|
|
52
52
|
const { fields } = opts;
|
|
@@ -63,9 +63,9 @@ const readUploadLabels = (opts) => {
|
|
|
63
63
|
folderPath: read('folderPath'),
|
|
64
64
|
};
|
|
65
65
|
};
|
|
66
|
-
const readObjectName = rawObjectName => rawObjectName;
|
|
66
|
+
const readObjectName = (rawObjectName) => rawObjectName;
|
|
67
67
|
/** Encodes an object path into a SINGLE url segment: `{objectName}` matches one segment only, so `/` must be percent-encoded too (Hono decodes it back before the handler reads the param). */
|
|
68
|
-
const encodeObjectPath = objectPath => {
|
|
68
|
+
const encodeObjectPath = (objectPath) => {
|
|
69
69
|
return encodeURIComponent(objectPath);
|
|
70
70
|
};
|
|
71
71
|
/** The bucket one request works on: a configured value wins - called on every request, so an application may read an environment variable lazily - else the path param, which is only registered when there is no configured bucket. */
|
|
@@ -437,7 +437,7 @@ class AssetControllerFactory extends core_1.BaseHelper {
|
|
|
437
437
|
message: `Folder path exceeds max depth of ${maxFolderDepth}`,
|
|
438
438
|
});
|
|
439
439
|
}
|
|
440
|
-
const invalidSegmentIndex = folderSegments.findIndex(segment => !helper.isValidSegment({ segment }));
|
|
440
|
+
const invalidSegmentIndex = folderSegments.findIndex((segment) => !helper.isValidSegment({ segment }));
|
|
441
441
|
if (invalidSegmentIndex !== -1) {
|
|
442
442
|
throw (0, core_1.getError)({
|
|
443
443
|
error: common_2.StaticAssetErrors.FOLDER_SEGMENT_INVALID,
|
|
@@ -458,12 +458,12 @@ class AssetControllerFactory extends core_1.BaseHelper {
|
|
|
458
458
|
validateFolderPath(folderPath);
|
|
459
459
|
}
|
|
460
460
|
const spoolPaths = filesArray
|
|
461
|
-
.map(file => file.path)
|
|
461
|
+
.map((file) => file.path)
|
|
462
462
|
.filter((filePath) => Boolean(filePath));
|
|
463
463
|
let uploaded;
|
|
464
464
|
try {
|
|
465
465
|
// `storage: 'disk'` spools the payload to `uploadDir` and returns `path` instead of `buffer`; the storage helpers only ever write `buffer`, so it must be read back.
|
|
466
|
-
const modifiedFiles = filesArray.map(file => {
|
|
466
|
+
const modifiedFiles = filesArray.map((file) => {
|
|
467
467
|
const buffer = file.buffer ?? (file.path ? (0, node_fs_1.readFileSync)(file.path) : undefined);
|
|
468
468
|
if (!buffer?.length) {
|
|
469
469
|
throw (0, core_1.getError)({
|
|
@@ -618,7 +618,7 @@ class AssetControllerFactory extends core_1.BaseHelper {
|
|
|
618
618
|
.for('DELETE_OBJECT')
|
|
619
619
|
.info('Successfully to delete MetaLink for %s/%s', bucketName, objectName);
|
|
620
620
|
})
|
|
621
|
-
.catch(error => {
|
|
621
|
+
.catch((error) => {
|
|
622
622
|
this.logger
|
|
623
623
|
.for('DELETE_OBJECT')
|
|
624
624
|
.error('Failed to delete MetaLink | bucket: %s | objectName: %s | Error: %s', bucketName, objectName, error);
|
|
@@ -763,7 +763,7 @@ class AssetControllerFactory extends core_1.BaseHelper {
|
|
|
763
763
|
// caller their upload did not work when it did.
|
|
764
764
|
await helper
|
|
765
765
|
.removeObject({ bucket: bucketRef, object: pendingObject })
|
|
766
|
-
.catch(error => {
|
|
766
|
+
.catch((error) => {
|
|
767
767
|
this.logger
|
|
768
768
|
.for('UPLOAD_COMMIT')
|
|
769
769
|
.warn('Committed, but the pending object remains | key: %s | error: %s', pendingObject.key, error);
|