Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@base44/sdk",
"version": "0.8.44",
"version": "0.8.45",
"description": "JavaScript SDK for Base44 API",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export type {
GenerateImageResult,
UploadFileParams,
UploadFileResult,
EmailAttachment,
SendEmailParams,
SendEmailResult,
ExtractDataFromUploadedFileParams,
Expand Down
55 changes: 51 additions & 4 deletions src/modules/integrations.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,20 +87,67 @@ export interface UploadFileResult {
file_url: string;
}

/** Requires at least one key from Keys to be present. */
type RequireAtLeastOne<T, Keys extends keyof T = keyof T> =
Pick<T, Exclude<keyof T, Keys>> &
{ [K in Keys]-?: Required<Pick<T, K>> & Partial<Pick<T, Exclude<Keys, K>>> }[Keys];

/**
* Parameters for the SendEmail function.
* A file to attach to a `SendEmail` call.
*
* Provide exactly one content source per attachment:
* - `content` — base64-encoded bytes generated at runtime (e.g. a PDF built in the function).
* - `file_url` — a URL returned by `UploadFile` or `UploadPrivateFile` for a file already in storage.
*
* Allowed extensions: `pdf`, `png`, `jpg`/`jpeg`, `gif`, `webp`, `csv`, `txt`, `md`, `ics`, `xlsx`, `docx`.
* Limits: up to **5 attachments**, **5 MB each**, **10 MB total**.
*/
export interface SendEmailParams {
export type EmailAttachment =
| { /** Attachment filename, including extension. */ filename: string; /** Base64-encoded file content. */ content: string; file_url?: never }
| { /** Attachment filename, including extension. */ filename: string; /** URL from `UploadFile` or `UploadPrivateFile`. */ file_url: string; content?: never };

interface SendEmailParamsBase {
/** Recipient email address. */
to: string;
/** Email subject line. */
subject: string;
/** Plain text email body content. */
body: string;
/** HTML email body content. Alias of `html` — set one or the other, never both. */
body?: string;
/** HTML email body content. The same thing as `body` under an explicit name. */
html?: string;
/**
* Plain-text email body content.
*
* On its own, sends a plain-text (`text/plain`) email. Alongside `body`/`html`,
* both parts go out as a single `multipart/alternative` email and the recipient's
* mail client renders whichever it prefers — so the two must say the same thing.
*/
text?: string;
/** The name of the sender. If omitted, the app's name will be used. */
from_name?: string;
/**
* Files to attach to the email. Up to 5 attachments, 5 MB each, 10 MB total.
*
* Each item must have a `filename` and exactly one content source:
* `content` (inline base64) or `file_url` (storage reference).
*/
attachments?: EmailAttachment[];
}

/**
* Parameters for the SendEmail function.
*
* At least one of `body`, `html`, or `text` is required; the backend returns 422 otherwise.
*
* | Fields set | Result |
* |---|---|
* | `body` or `html` alone | `text/html` email |
* | `text` alone | `text/plain` email |
* | `body`/`html` + `text` | `multipart/alternative` — one email, two representations; recipient sees whichever their client prefers — both parts must say the same thing |
* | `body` + `html` | **422** — same slot, set one not both |
*/
export type SendEmailParams = RequireAtLeastOne<SendEmailParamsBase, 'body' | 'html' | 'text'>;

export type SendEmailResult = any;

/**
Expand Down
81 changes: 81 additions & 0 deletions tests/types/integrations.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import type { SendEmailParams, EmailAttachment } from "../../src/index.js";

// body-only (existing callers must still compile — backward compat)
const bodyOnly = {
to: "user@example.com",
subject: "Hello",
body: "<p>Hello</p>",
} satisfies SendEmailParams;

// html-only
const htmlOnly = {
to: "user@example.com",
subject: "Hello",
html: "<p>Hello</p>",
} satisfies SendEmailParams;

// text-only
const textOnly = {
to: "user@example.com",
subject: "Hello",
text: "Hello",
} satisfies SendEmailParams;

// html + text → multipart/alternative
const htmlAndText = {
to: "user@example.com",
subject: "Hello",
html: "<p>Hello</p>",
text: "Hello",
} satisfies SendEmailParams;

// body + text → multipart/alternative
const bodyAndText = {
to: "user@example.com",
subject: "Hello",
body: "<p>Hello</p>",
text: "Hello",
} satisfies SendEmailParams;

// optional from_name
const withFromName = {
to: "user@example.com",
subject: "Hello",
body: "<p>Hello</p>",
from_name: "My App",
} satisfies SendEmailParams;

// attachments: inline base64
const inlineAttachment = {
filename: "receipt.pdf",
content: "JVBERi0x",
} satisfies EmailAttachment;

// attachments: storage reference
const storedAttachment = {
filename: "logo.png",
file_url: "https://storage.example.com/logo.png",
} satisfies EmailAttachment;

// with attachments on a full params object
const withAttachments = {
to: "user@example.com",
subject: "Invoice",
body: "<p>See attached.</p>",
attachments: [inlineAttachment, storedAttachment],
} satisfies SendEmailParams;

// omitting all three content fields must be a compile error
// @ts-expect-error At least one of body/html/text is required.
const missingContent: SendEmailParams = { to: "user@example.com", subject: "Hello" };

void bodyOnly;
void htmlOnly;
void textOnly;
void htmlAndText;
void bodyAndText;
void withFromName;
void inlineAttachment;
void storedAttachment;
void withAttachments;
void missingContent;