diff --git a/.changeset/young-deserts-behave.md b/.changeset/young-deserts-behave.md new file mode 100644 index 0000000..08181da --- /dev/null +++ b/.changeset/young-deserts-behave.md @@ -0,0 +1,5 @@ +--- +"@opencoredev/email-sdk": minor +--- + +Allow CommonJS applications on Node.js 20.19+ to load every SDK entry point with `require()`. diff --git a/apps/fumadocs/content/docs/getting-started/install.mdx b/apps/fumadocs/content/docs/getting-started/install.mdx index 790bc3b..95faab5 100644 --- a/apps/fumadocs/content/docs/getting-started/install.mdx +++ b/apps/fumadocs/content/docs/getting-started/install.mdx @@ -1,6 +1,6 @@ --- title: Install -description: Install the ESM-only SDK for Node.js 20+ or Bun 1.1+. +description: Install Email SDK for Node.js or Bun using ESM imports or CommonJS require. --- @@ -19,12 +19,11 @@ The public package is `@opencoredev/email-sdk`. The unscoped `email-sdk` package ### Confirm your runtime -Use Node.js 20+ or Bun 1.1+. The package is ESM-only, so use `import` syntax or dynamic `import()` from a CommonJS application. +Use Node.js 20+ or Bun 1.1+. ESM imports work across the supported range. CommonJS applications running Node.js 20.19+ can use `require()` for the main package and every adapter entry point. -```json title="package.json" -{ - "type": "module" -} +```js title="email.cjs" +const { createEmailClient } = require("@opencoredev/email-sdk"); +const { resend } = require("@opencoredev/email-sdk/resend"); ``` diff --git a/apps/fumadocs/content/docs/guides/migrate/v0-to-v1.mdx b/apps/fumadocs/content/docs/guides/migrate/v0-to-v1.mdx index 921d019..7d5018f 100644 --- a/apps/fumadocs/content/docs/guides/migrate/v0-to-v1.mdx +++ b/apps/fumadocs/content/docs/guides/migrate/v0-to-v1.mdx @@ -218,9 +218,9 @@ v1 has a closed error-code union: `validation_error`, `adapter_not_found`, `adap `EmailRouteError.failures` replaces arbitrary route details. Middleware exceptions become `EmailMiddlewareError`. -## 14. Confirm ESM and telemetry +## 14. Confirm runtime and telemetry -v1 is ESM-only on Node.js 20+ or Bun 1.1+. Telemetry remains enabled by default with the existing opt-outs: `telemetry: false`, `EMAIL_SDK_TELEMETRY=0`, or `DO_NOT_TRACK=1`. +v1 supports ESM imports on Node.js 20+ or Bun 1.1+, plus `require()` on Node.js 20.19+. Telemetry remains enabled by default with the existing opt-outs: `telemetry: false`, `EMAIL_SDK_TELEMETRY=0`, or `DO_NOT_TRACK=1`. ## 15. Use the compat bridge only temporarily diff --git a/apps/fumadocs/content/docs/index.mdx b/apps/fumadocs/content/docs/index.mdx index ff4e754..d10787c 100644 --- a/apps/fumadocs/content/docs/index.mdx +++ b/apps/fumadocs/content/docs/index.mdx @@ -33,7 +33,7 @@ Now call `email.send({ from, to, subject, text })`. Add retries, fallback, plugi ## Runtime boundary -Email SDK is ESM-only and server-side. It supports Node.js 20+ and Bun 1.1+. Keep API keys and SMTP credentials out of browser bundles. +Email SDK is server-side and supports Node.js 20+ or Bun 1.1+. Use ESM imports on any supported runtime, or `require()` from CommonJS applications on Node.js 20.19+. Keep API keys and SMTP credentials out of browser bundles. diff --git a/apps/fumadocs/src/lib/docs-lastmod.generated.json b/apps/fumadocs/src/lib/docs-lastmod.generated.json index 8f4baa9..e198519 100644 --- a/apps/fumadocs/src/lib/docs-lastmod.generated.json +++ b/apps/fumadocs/src/lib/docs-lastmod.generated.json @@ -35,7 +35,7 @@ "concepts/sending-modes.mdx": "2026-07-22", "getting-started/agent-skill.mdx": "2026-07-22", "getting-started/credentials.mdx": "2026-07-22", - "getting-started/install.mdx": "2026-07-22", + "getting-started/install.mdx": "2026-07-30", "getting-started/quickstart.mdx": "2026-07-22", "guides/authoring/create-adapter.mdx": "2026-07-22", "guides/authoring/create-first-plugin.mdx": "2026-07-22", @@ -44,12 +44,12 @@ "guides/migrate/nodemailer.mdx": "2026-07-22", "guides/migrate/resend.mdx": "2026-07-22", "guides/migrate/sendgrid.mdx": "2026-07-22", - "guides/migrate/v0-to-v1.mdx": "2026-07-22", + "guides/migrate/v0-to-v1.mdx": "2026-07-30", "guides/production-send-pipeline.mdx": "2026-07-22", "guides/schedule-email.mdx": "2026-07-22", "guides/test-email-behavior.mdx": "2026-07-22", "guides/troubleshoot-failed-sends.mdx": "2026-07-22", - "index.mdx": "2026-07-22", + "index.mdx": "2026-07-30", "integrations/ai-sdk.mdx": "2026-07-22", "integrations/chat-sdk.mdx": "2026-07-22", "integrations/convex/index.mdx": "2026-07-22", diff --git a/packages/email-sdk/README.md b/packages/email-sdk/README.md index b8f4a54..b7c8b9a 100644 --- a/packages/email-sdk/README.md +++ b/packages/email-sdk/README.md @@ -16,7 +16,7 @@ pnpm add @opencoredev/email-sdk bun add @opencoredev/email-sdk ``` -The public npm package is `@opencoredev/email-sdk`. The CLI binary it installs is `email-sdk`. Use both from server-side runtimes such as Node.js 20+ or Bun 1.1+, and never expose provider API keys in browser code. +The public npm package is `@opencoredev/email-sdk`. The CLI binary it installs is `email-sdk`. Use both from server-side runtimes such as Node.js 20+ or Bun 1.1+, and never expose provider API keys in browser code. CommonJS applications running Node.js 20.19+ can load the package and its adapter entry points with `require()`. ## Quickstart diff --git a/packages/email-sdk/package.json b/packages/email-sdk/package.json index 101b9ed..f0a0fe7 100644 --- a/packages/email-sdk/package.json +++ b/packages/email-sdk/package.json @@ -43,139 +43,139 @@ "exports": { ".": { "types": "./dist/index.d.ts", - "import": "./dist/index.js" + "default": "./dist/index.js" }, "./resend": { "types": "./dist/resend.d.ts", - "import": "./dist/resend.js" + "default": "./dist/resend.js" }, "./postmark": { "types": "./dist/postmark.d.ts", - "import": "./dist/postmark.js" + "default": "./dist/postmark.js" }, "./sendgrid": { "types": "./dist/sendgrid.d.ts", - "import": "./dist/sendgrid.js" + "default": "./dist/sendgrid.js" }, "./cloudflare": { "types": "./dist/cloudflare.d.ts", - "import": "./dist/cloudflare.js" + "default": "./dist/cloudflare.js" }, "./unosend": { "types": "./dist/unosend.d.ts", - "import": "./dist/unosend.js" + "default": "./dist/unosend.js" }, "./iterable": { "types": "./dist/iterable.d.ts", - "import": "./dist/iterable.js" + "default": "./dist/iterable.js" }, "./ses": { "types": "./dist/ses.d.ts", - "import": "./dist/ses.js" + "default": "./dist/ses.js" }, "./mailgun": { "types": "./dist/mailgun.d.ts", - "import": "./dist/mailgun.js" + "default": "./dist/mailgun.js" }, "./mailersend": { "types": "./dist/mailersend.d.ts", - "import": "./dist/mailersend.js" + "default": "./dist/mailersend.js" }, "./brevo": { "types": "./dist/brevo.d.ts", - "import": "./dist/brevo.js" + "default": "./dist/brevo.js" }, "./mailchimp": { "types": "./dist/mailchimp.d.ts", - "import": "./dist/mailchimp.js" + "default": "./dist/mailchimp.js" }, "./sparkpost": { "types": "./dist/sparkpost.d.ts", - "import": "./dist/sparkpost.js" + "default": "./dist/sparkpost.js" }, "./loops": { "types": "./dist/loops.d.ts", - "import": "./dist/loops.js" + "default": "./dist/loops.js" }, "./sequenzy": { "types": "./dist/sequenzy.d.ts", - "import": "./dist/sequenzy.js" + "default": "./dist/sequenzy.js" }, "./jetemail": { "types": "./dist/jetemail.d.ts", - "import": "./dist/jetemail.js" + "default": "./dist/jetemail.js" }, "./lettermint": { "types": "./dist/lettermint.d.ts", - "import": "./dist/lettermint.js" + "default": "./dist/lettermint.js" }, "./primitive": { "types": "./dist/primitive.d.ts", - "import": "./dist/primitive.js" + "default": "./dist/primitive.js" }, "./plunk": { "types": "./dist/plunk.d.ts", - "import": "./dist/plunk.js" + "default": "./dist/plunk.js" }, "./mailtrap": { "types": "./dist/mailtrap.d.ts", - "import": "./dist/mailtrap.js" + "default": "./dist/mailtrap.js" }, "./scaleway": { "types": "./dist/scaleway.d.ts", - "import": "./dist/scaleway.js" + "default": "./dist/scaleway.js" }, "./zeptomail": { "types": "./dist/zeptomail.d.ts", - "import": "./dist/zeptomail.js" + "default": "./dist/zeptomail.js" }, "./mailpace": { "types": "./dist/mailpace.d.ts", - "import": "./dist/mailpace.js" + "default": "./dist/mailpace.js" }, "./smtp": { "types": "./dist/smtp.d.ts", - "import": "./dist/smtp.js" + "default": "./dist/smtp.js" }, "./testing": { "types": "./dist/testing.d.ts", - "import": "./dist/testing.js" + "default": "./dist/testing.js" }, "./compat": { "types": "./dist/compat.d.ts", - "import": "./dist/compat.js" + "default": "./dist/compat.js" }, "./agent-tools": { "types": "./dist/agent-tools.d.ts", - "import": "./dist/agent-tools.js" + "default": "./dist/agent-tools.js" }, "./ai": { "types": "./dist/ai.d.ts", - "import": "./dist/ai.js" + "default": "./dist/ai.js" }, "./react": { "types": "./dist/react.d.ts", - "import": "./dist/react.js" + "default": "./dist/react.js" }, "./plugins/defaults": { "types": "./dist/plugins-defaults.d.ts", - "import": "./dist/plugins-defaults.js" + "default": "./dist/plugins-defaults.js" }, "./plugins/observability": { "types": "./dist/plugins-observability.d.ts", - "import": "./dist/plugins-observability.js" + "default": "./dist/plugins-observability.js" }, "./plugins/capture": { "types": "./dist/plugins-capture.d.ts", - "import": "./dist/plugins-capture.js" + "default": "./dist/plugins-capture.js" }, "./plugins/routing": { "types": "./dist/plugins-routing.d.ts", - "import": "./dist/plugins-routing.js" + "default": "./dist/plugins-routing.js" }, "./plugins/timeout": { "types": "./dist/plugins-timeout.d.ts", - "import": "./dist/plugins-timeout.js" + "default": "./dist/plugins-timeout.js" } }, "publishConfig": { diff --git a/scripts/check-package-tarballs.ts b/scripts/check-package-tarballs.ts index 8dab7da..3454592 100644 --- a/scripts/check-package-tarballs.ts +++ b/scripts/check-package-tarballs.ts @@ -49,11 +49,15 @@ try { const smoke = join(install, "smoke.mjs"); await writeFile(smoke, smokeProgram()); + const commonJsSmoke = join(install, "smoke.cjs"); + await writeFile(commonJsSmoke, commonJsSmokeProgram()); console.log("Running installed-package smoke tests under Node..."); await run(["node", smoke], install); + await run(["node", commonJsSmoke], install); console.log("Running installed-package smoke tests under Bun..."); await run(["bun", smoke], install); + await run(["bun", commonJsSmoke], install); console.log("Installed package smoke tests passed."); } finally { await rm(scratch, { recursive: true, force: true }); @@ -196,3 +200,17 @@ async function declarationMaps(directory) { } `; } + +function commonJsSmokeProgram(): string { + return String.raw` +const { readFileSync } = require("node:fs"); +const { join } = require("node:path"); + +const coreDir = join(__dirname, "node_modules/@opencoredev/email-sdk"); +const manifest = JSON.parse(readFileSync(join(coreDir, "package.json"), "utf8")); + +for (const subpath of Object.keys(manifest.exports ?? {})) { + require(subpath === "." ? manifest.name : manifest.name + subpath.slice(1)); +} +`; +}