added /dist

This commit is contained in:
2026-08-03 12:24:28 +02:00
parent dd97bb67fe
commit 05150e7ece
490 changed files with 6667 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
export { sendEmail } from './sendEmail.js';
//# sourceMappingURL=index.d.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["index.d.ts"],"sourcesContent":["export { sendEmail } from './sendEmail.js';\nexport type { SendEmailArgs, SendEmailResult } from './sendEmail.js';\n"],"names":["sendEmail"],"mappings":"AAAA,SAASA,SAAS,QAAQ,iBAAiB"}
+2
View File
@@ -0,0 +1,2 @@
export { sendEmail } from './sendEmail.js';
export type { SendEmailArgs, SendEmailResult } from './sendEmail.js';
+5
View File
@@ -0,0 +1,5 @@
// Server-only exports. sendEmail imports 'server-only' (SMTP password, nodemailer)
// so this must never be imported from a client component.
export { sendEmail } from './sendEmail.js';
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../../../src/modules/email/index.ts"],"sourcesContent":["// Server-only exports. sendEmail imports 'server-only' (SMTP password, nodemailer)\n// so this must never be imported from a client component.\nexport { sendEmail } from './sendEmail.js'\nexport type { SendEmailArgs, SendEmailResult } from './sendEmail.js'\n"],"names":["sendEmail"],"mappings":"AAAA,mFAAmF;AACnF,0DAA0D;AAC1D,SAASA,SAAS,QAAQ,iBAAgB"}
+23
View File
@@ -0,0 +1,23 @@
/**
* Payload email adapter backed by the SMTP settings in the SiteIntegrations
* global.
*
* Why this exists: Payload builds its email adapter once, at boot, from the
* config — which would normally mean SMTP credentials living in env vars and a
* redeploy to change them. This adapter instead resolves SMTP on every send, so
* an editor can change the mailbox in the admin panel and the next email uses
* it.
*
* Wiring it into the config means `payload.sendEmail` works everywhere — which
* includes the form-builder's own submission emails (the ones an editor
* configures per form under "Emails"). Those go out over the panel's SMTP with
* no extra code.
*
* Boot-time constraints shape two details:
* - `defaultFromAddress` / `defaultFromName` must be returned synchronously, so
* they're placeholders; the real from-address is applied per message below.
* - nodemailer is imported dynamically inside sendEmail, so merely loading the
* Payload config (or running `generate:importmap`) doesn't pull it in.
*/ export { };
//# sourceMappingURL=panelSmtpAdapter.d.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["panelSmtpAdapter.d.ts"],"sourcesContent":["import type { PayloadEmailAdapter } from 'payload';\nexport type PanelSmtpAdapterArgs = {\n /**\n * Used only until the panel is filled in — Payload requires a from-address\n * synchronously at boot, before any global can be read. Once SiteIntegrations\n * has an address, it wins.\n */\n fallbackFromAddress?: string;\n fallbackFromName?: string;\n};\n/**\n * Payload email adapter backed by the SMTP settings in the SiteIntegrations\n * global.\n *\n * Why this exists: Payload builds its email adapter once, at boot, from the\n * config — which would normally mean SMTP credentials living in env vars and a\n * redeploy to change them. This adapter instead resolves SMTP on every send, so\n * an editor can change the mailbox in the admin panel and the next email uses\n * it.\n *\n * Wiring it into the config means `payload.sendEmail` works everywhere — which\n * includes the form-builder's own submission emails (the ones an editor\n * configures per form under \"Emails\"). Those go out over the panel's SMTP with\n * no extra code.\n *\n * Boot-time constraints shape two details:\n * - `defaultFromAddress` / `defaultFromName` must be returned synchronously, so\n * they're placeholders; the real from-address is applied per message below.\n * - nodemailer is imported dynamically inside sendEmail, so merely loading the\n * Payload config (or running `generate:importmap`) doesn't pull it in.\n */\nexport declare const panelSmtpAdapter: (args?: PanelSmtpAdapterArgs) => PayloadEmailAdapter;\n"],"names":[],"mappings":"AAUA;;;;;;;;;;;;;;;;;;;;CAoBC,GACD,WAA4F"}
+32
View File
@@ -0,0 +1,32 @@
import type { PayloadEmailAdapter } from 'payload';
export type PanelSmtpAdapterArgs = {
/**
* Used only until the panel is filled in — Payload requires a from-address
* synchronously at boot, before any global can be read. Once SiteIntegrations
* has an address, it wins.
*/
fallbackFromAddress?: string;
fallbackFromName?: string;
};
/**
* Payload email adapter backed by the SMTP settings in the SiteIntegrations
* global.
*
* Why this exists: Payload builds its email adapter once, at boot, from the
* config — which would normally mean SMTP credentials living in env vars and a
* redeploy to change them. This adapter instead resolves SMTP on every send, so
* an editor can change the mailbox in the admin panel and the next email uses
* it.
*
* Wiring it into the config means `payload.sendEmail` works everywhere — which
* includes the form-builder's own submission emails (the ones an editor
* configures per form under "Emails"). Those go out over the panel's SMTP with
* no extra code.
*
* Boot-time constraints shape two details:
* - `defaultFromAddress` / `defaultFromName` must be returned synchronously, so
* they're placeholders; the real from-address is applied per message below.
* - nodemailer is imported dynamically inside sendEmail, so merely loading the
* Payload config (or running `generate:importmap`) doesn't pull it in.
*/
export declare const panelSmtpAdapter: (args?: PanelSmtpAdapterArgs) => PayloadEmailAdapter;
+83
View File
@@ -0,0 +1,83 @@
import { getSiteIntegrations } from '../payload/index.js';
/**
* Payload email adapter backed by the SMTP settings in the SiteIntegrations
* global.
*
* Why this exists: Payload builds its email adapter once, at boot, from the
* config — which would normally mean SMTP credentials living in env vars and a
* redeploy to change them. This adapter instead resolves SMTP on every send, so
* an editor can change the mailbox in the admin panel and the next email uses
* it.
*
* Wiring it into the config means `payload.sendEmail` works everywhere — which
* includes the form-builder's own submission emails (the ones an editor
* configures per form under "Emails"). Those go out over the panel's SMTP with
* no extra code.
*
* Boot-time constraints shape two details:
* - `defaultFromAddress` / `defaultFromName` must be returned synchronously, so
* they're placeholders; the real from-address is applied per message below.
* - nodemailer is imported dynamically inside sendEmail, so merely loading the
* Payload config (or running `generate:importmap`) doesn't pull it in.
*/ export const panelSmtpAdapter = (args = {})=>({ payload })=>({
name: 'ipal-panel-smtp',
defaultFromAddress: args.fallbackFromAddress ?? 'noreply@localhost',
defaultFromName: args.fallbackFromName ?? 'Website',
sendEmail: async (message)=>{
const smtp = await getSiteIntegrations(payload);
const host = smtp.smtpHost;
const port = smtp.smtpPort ?? 587;
const user = smtp.smtpUser;
const pass = smtp.smtpPassword;
if (!host || !user || !pass) {
payload.logger.error('[ipal] Email not sent: SMTP is not configured in Site Integrations.');
return {
error: 'SMTP is not configured in Site Integrations.',
sent: false
};
}
// The panel is the source of truth for the sender; fall back to whatever
// the caller set (Payload fills in defaultFromAddress when unset).
const fromAddress = smtp.smtpFromAddress;
const fromName = smtp.smtpFromName;
const from = fromAddress ? fromName ? `${fromName} <${fromAddress}>` : fromAddress : message.from;
// Defence in depth against header injection. Modern nodemailer already
// normalises CRLF in standard headers, but the form-builder interpolates
// user data into the subject via {{field}} placeholders, so strip any
// newlines from header-bound values before they reach the transport.
const stripCRLF = (v)=>String(v ?? '').replace(/[\r\n]+/g, ' ').trim();
const { default: nodemailer } = await import('nodemailer');
const transporter = nodemailer.createTransport({
auth: {
pass,
user
},
host,
port,
secure: port === 465
});
try {
const info = await transporter.sendMail({
...message,
from,
...message.subject ? {
subject: stripCRLF(message.subject)
} : {}
});
return {
messageId: info.messageId,
sent: true
};
} catch (err) {
// Never surface SMTP internals to the caller — a form submission
// shouldn't fail loudly because the mailbox is misconfigured.
payload.logger.error(`[ipal] Email send failed: ${err.message}`);
return {
error: 'Failed to send email.',
sent: false
};
}
}
});
//# sourceMappingURL=panelSmtpAdapter.js.map
File diff suppressed because one or more lines are too long
+3
View File
@@ -0,0 +1,3 @@
import 'server-only';
//# sourceMappingURL=sendEmail.d.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["sendEmail.d.ts"],"sourcesContent":["import 'server-only';\nimport type { BasePayload } from 'payload';\nexport type SendEmailArgs = {\n /** Override the configured from-address for this message. */\n from?: string;\n /** HTML body. */\n html: string;\n /** Payload instance — used to read SMTP config from SiteIntegrations. */\n payload: BasePayload;\n replyTo?: string;\n subject: string;\n /** Optional plain-text fallback. */\n text?: string;\n to: string | string[];\n};\nexport type SendEmailResult = {\n error: string;\n sent: false;\n} | {\n messageId: string;\n sent: true;\n};\n/**\n * Sends an email using SMTP settings from the SiteIntegrations global.\n *\n * Reads config at call time (not at boot) so editors can change SMTP in the\n * admin panel without a restart — consistent with the plugin's panel-managed\n * model. `server-only` keeps the SMTP password out of any client bundle.\n *\n * Returns a result object rather than throwing, so callers (e.g. form\n * submission) can handle failure without a try/catch and never leak SMTP\n * details to the client.\n */\nexport declare function sendEmail({ from, html, payload, replyTo, subject, text, to, }: SendEmailArgs): Promise<SendEmailResult>;\n"],"names":[],"mappings":"AAAA,OAAO,cAAc"}
+34
View File
@@ -0,0 +1,34 @@
import 'server-only';
import type { BasePayload } from 'payload';
export type SendEmailArgs = {
/** Override the configured from-address for this message. */
from?: string;
/** HTML body. */
html: string;
/** Payload instance — used to read SMTP config from SiteIntegrations. */
payload: BasePayload;
replyTo?: string;
subject: string;
/** Optional plain-text fallback. */
text?: string;
to: string | string[];
};
export type SendEmailResult = {
error: string;
sent: false;
} | {
messageId: string;
sent: true;
};
/**
* Sends an email using SMTP settings from the SiteIntegrations global.
*
* Reads config at call time (not at boot) so editors can change SMTP in the
* admin panel without a restart — consistent with the plugin's panel-managed
* model. `server-only` keeps the SMTP password out of any client bundle.
*
* Returns a result object rather than throwing, so callers (e.g. form
* submission) can handle failure without a try/catch and never leak SMTP
* details to the client.
*/
export declare function sendEmail({ from, html, payload, replyTo, subject, text, to, }: SendEmailArgs): Promise<SendEmailResult>;
+70
View File
@@ -0,0 +1,70 @@
import 'server-only';
import nodemailer from 'nodemailer';
import { getSiteIntegrations } from '../payload/index.js';
/**
* Sends an email using SMTP settings from the SiteIntegrations global.
*
* Reads config at call time (not at boot) so editors can change SMTP in the
* admin panel without a restart — consistent with the plugin's panel-managed
* model. `server-only` keeps the SMTP password out of any client bundle.
*
* Returns a result object rather than throwing, so callers (e.g. form
* submission) can handle failure without a try/catch and never leak SMTP
* details to the client.
*/ export async function sendEmail({ from, html, payload, replyTo, subject, text, to }) {
const smtp = await getSiteIntegrations(payload);
const host = smtp.smtpHost;
const port = smtp.smtpPort ?? 587;
const user = smtp.smtpUser;
const pass = smtp.smtpPassword;
if (!host || !user || !pass) {
return {
error: 'SMTP is not configured in Site Integrations.',
sent: false
};
}
const fromAddress = from ?? smtp.smtpFromAddress;
if (!fromAddress) {
return {
error: 'No from-address configured.',
sent: false
};
}
const fromName = smtp.smtpFromName;
const fromHeader = fromName ? `${fromName} <${fromAddress}>` : fromAddress;
const transporter = nodemailer.createTransport({
auth: {
pass,
user
},
host,
port,
secure: port === 465
});
try {
const info = await transporter.sendMail({
from: fromHeader,
html,
subject,
to,
...text ? {
text
} : {},
...replyTo ? {
replyTo
} : {}
});
return {
messageId: info.messageId,
sent: true
};
} catch (err) {
payload.logger.error(`[ipal] Email send failed: ${err.message}`);
return {
error: 'Failed to send email.',
sent: false
};
}
}
//# sourceMappingURL=sendEmail.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../../../src/modules/email/sendEmail.ts"],"sourcesContent":["import 'server-only'\n\nimport type { BasePayload } from 'payload'\n\nimport nodemailer from 'nodemailer'\n\nimport { getSiteIntegrations } from '../payload/index.js'\n\n/** SMTP fields the sender reads from SiteIntegrations. */\ntype SmtpIntegrations = {\n smtpFromAddress?: null | string\n smtpFromName?: null | string\n smtpHost?: null | string\n smtpPassword?: null | string\n smtpPort?: null | number\n smtpUser?: null | string\n}\n\nexport type SendEmailArgs = {\n /** Override the configured from-address for this message. */\n from?: string\n /** HTML body. */\n html: string\n /** Payload instance — used to read SMTP config from SiteIntegrations. */\n payload: BasePayload\n replyTo?: string\n subject: string\n /** Optional plain-text fallback. */\n text?: string\n to: string | string[]\n}\n\nexport type SendEmailResult = { error: string; sent: false } | { messageId: string; sent: true }\n\n/**\n * Sends an email using SMTP settings from the SiteIntegrations global.\n *\n * Reads config at call time (not at boot) so editors can change SMTP in the\n * admin panel without a restart — consistent with the plugin's panel-managed\n * model. `server-only` keeps the SMTP password out of any client bundle.\n *\n * Returns a result object rather than throwing, so callers (e.g. form\n * submission) can handle failure without a try/catch and never leak SMTP\n * details to the client.\n */\nexport async function sendEmail({\n from,\n html,\n payload,\n replyTo,\n subject,\n text,\n to,\n}: SendEmailArgs): Promise<SendEmailResult> {\n const smtp = await getSiteIntegrations<SmtpIntegrations>(payload)\n\n const host = smtp.smtpHost\n const port = smtp.smtpPort ?? 587\n const user = smtp.smtpUser\n const pass = smtp.smtpPassword\n\n if (!host || !user || !pass) {\n return { error: 'SMTP is not configured in Site Integrations.', sent: false }\n }\n\n const fromAddress = from ?? smtp.smtpFromAddress\n if (!fromAddress) {\n return { error: 'No from-address configured.', sent: false }\n }\n\n const fromName = smtp.smtpFromName\n const fromHeader = fromName ? `${fromName} <${fromAddress}>` : fromAddress\n\n const transporter = nodemailer.createTransport({\n auth: { pass, user },\n host,\n port,\n secure: port === 465, // implicit TLS on 465, STARTTLS otherwise\n })\n\n try {\n const info = await transporter.sendMail({\n from: fromHeader,\n html,\n subject,\n to,\n ...(text ? { text } : {}),\n ...(replyTo ? { replyTo } : {}),\n })\n return { messageId: info.messageId, sent: true }\n } catch (err) {\n payload.logger.error(`[ipal] Email send failed: ${(err as Error).message}`)\n return { error: 'Failed to send email.', sent: false }\n }\n}\n"],"names":["nodemailer","getSiteIntegrations","sendEmail","from","html","payload","replyTo","subject","text","to","smtp","host","smtpHost","port","smtpPort","user","smtpUser","pass","smtpPassword","error","sent","fromAddress","smtpFromAddress","fromName","smtpFromName","fromHeader","transporter","createTransport","auth","secure","info","sendMail","messageId","err","logger","message"],"mappings":"AAAA,OAAO,cAAa;AAIpB,OAAOA,gBAAgB,aAAY;AAEnC,SAASC,mBAAmB,QAAQ,sBAAqB;AA4BzD;;;;;;;;;;CAUC,GACD,OAAO,eAAeC,UAAU,EAC9BC,IAAI,EACJC,IAAI,EACJC,OAAO,EACPC,OAAO,EACPC,OAAO,EACPC,IAAI,EACJC,EAAE,EACY;IACd,MAAMC,OAAO,MAAMT,oBAAsCI;IAEzD,MAAMM,OAAOD,KAAKE,QAAQ;IAC1B,MAAMC,OAAOH,KAAKI,QAAQ,IAAI;IAC9B,MAAMC,OAAOL,KAAKM,QAAQ;IAC1B,MAAMC,OAAOP,KAAKQ,YAAY;IAE9B,IAAI,CAACP,QAAQ,CAACI,QAAQ,CAACE,MAAM;QAC3B,OAAO;YAAEE,OAAO;YAAgDC,MAAM;QAAM;IAC9E;IAEA,MAAMC,cAAclB,QAAQO,KAAKY,eAAe;IAChD,IAAI,CAACD,aAAa;QAChB,OAAO;YAAEF,OAAO;YAA+BC,MAAM;QAAM;IAC7D;IAEA,MAAMG,WAAWb,KAAKc,YAAY;IAClC,MAAMC,aAAaF,WAAW,GAAGA,SAAS,EAAE,EAAEF,YAAY,CAAC,CAAC,GAAGA;IAE/D,MAAMK,cAAc1B,WAAW2B,eAAe,CAAC;QAC7CC,MAAM;YAAEX;YAAMF;QAAK;QACnBJ;QACAE;QACAgB,QAAQhB,SAAS;IACnB;IAEA,IAAI;QACF,MAAMiB,OAAO,MAAMJ,YAAYK,QAAQ,CAAC;YACtC5B,MAAMsB;YACNrB;YACAG;YACAE;YACA,GAAID,OAAO;gBAAEA;YAAK,IAAI,CAAC,CAAC;YACxB,GAAIF,UAAU;gBAAEA;YAAQ,IAAI,CAAC,CAAC;QAChC;QACA,OAAO;YAAE0B,WAAWF,KAAKE,SAAS;YAAEZ,MAAM;QAAK;IACjD,EAAE,OAAOa,KAAK;QACZ5B,QAAQ6B,MAAM,CAACf,KAAK,CAAC,CAAC,0BAA0B,EAAE,AAACc,IAAcE,OAAO,EAAE;QAC1E,OAAO;YAAEhB,OAAO;YAAyBC,MAAM;QAAM;IACvD;AACF"}