80 lines
2.2 KiB
TypeScript
80 lines
2.2 KiB
TypeScript
export type PostalMessageInput = {
|
|
to: string[];
|
|
subject: string;
|
|
plainBody: string;
|
|
htmlBody: string;
|
|
};
|
|
|
|
export type PostalClient = {
|
|
enabled: boolean;
|
|
sendMessage: (input: PostalMessageInput) => Promise<void>;
|
|
};
|
|
|
|
export type CreatePostalClientOptions = {
|
|
baseUrl: string;
|
|
apiKey: string;
|
|
from: string;
|
|
fetchImpl?: typeof fetch;
|
|
};
|
|
|
|
export type CreatePostalClientFromEnvOptions = {
|
|
baseUrlEnv?: string;
|
|
apiKeyEnv?: string;
|
|
fromEnv?: string;
|
|
env?: Record<string, string | undefined>;
|
|
fetchImpl?: typeof fetch;
|
|
};
|
|
|
|
export function createPostalClient(options: CreatePostalClientOptions): PostalClient {
|
|
const baseUrl = options.baseUrl.trim();
|
|
const apiKey = options.apiKey.trim();
|
|
const from = options.from.trim();
|
|
const fetchImpl = options.fetchImpl ?? fetch;
|
|
const enabled = baseUrl.length > 0 && apiKey.length > 0 && from.length > 0;
|
|
|
|
return {
|
|
enabled,
|
|
async sendMessage(input: PostalMessageInput): Promise<void> {
|
|
if (!enabled || input.to.length === 0) {
|
|
return;
|
|
}
|
|
|
|
const endpoint = new URL("/api/v1/send/message", ensureTrailingSlash(baseUrl));
|
|
const response = await fetchImpl(endpoint, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"X-Server-API-Key": apiKey
|
|
},
|
|
body: JSON.stringify({
|
|
from,
|
|
to: input.to,
|
|
subject: input.subject,
|
|
plain_body: input.plainBody,
|
|
html_body: input.htmlBody
|
|
})
|
|
});
|
|
|
|
const payload = (await response.json().catch(() => null)) as { status?: string } | null;
|
|
if (!response.ok || payload?.status !== "success") {
|
|
throw new Error(`postal_send_failed:${response.status}`);
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
export function createPostalClientFromEnv(options: CreatePostalClientFromEnvOptions = {}): PostalClient {
|
|
const env = options.env ?? process.env;
|
|
|
|
return createPostalClient({
|
|
baseUrl: env[options.baseUrlEnv ?? "POSTAL_URL"] ?? "",
|
|
apiKey: env[options.apiKeyEnv ?? "POSTAL_API_KEY"] ?? "",
|
|
from: env[options.fromEnv ?? "POSTAL_MESSAGE_FROM"] ?? "",
|
|
fetchImpl: options.fetchImpl
|
|
});
|
|
}
|
|
|
|
function ensureTrailingSlash(value: string): string {
|
|
return value.endsWith("/") ? value : `${value}/`;
|
|
}
|