diff --git a/README.md b/README.md index 6729272..54d1a4f 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,14 @@ const mailerlite = new MailerLite({ }); ``` +### Edge & serverless runtimes + +The SDK works in edge/serverless runtimes that don't ship Node's `http` +module — such as Vercel Edge Functions, Cloudflare Workers, Next.js edge +routes and Deno. Requests automatically fall back to the `fetch` adapter +in those environments, while Node and browsers keep using their existing +adapters unchanged. + - [Subscribers](src/modules/subscribers/README.md) * [List all subscribers](src/modules/subscribers/README.md#list-all-subscribers) * [Create/update subscriber](src/modules/subscribers/README.md#createupdate-subscriber) diff --git a/src/utils/fetch.test.ts b/src/utils/fetch.test.ts new file mode 100644 index 0000000..8b4e0a1 --- /dev/null +++ b/src/utils/fetch.test.ts @@ -0,0 +1,30 @@ +import { describe, it, expect, vi, beforeEach } from "vitest"; + +// `vi.mock` is hoisted to the top of the file, so the mock fn has to be +// created with `vi.hoisted` to be available inside the factory. +const axiosMock = vi.hoisted(() => vi.fn(() => Promise.resolve({ data: {} }))); +vi.mock("axios", () => ({ default: axiosMock })); + +import request from "./fetch"; +import { Config } from "./types"; + +const config: Config = { + api_key: "test-key", + basePath: "https://connect.mailerlite.com", +}; + +describe("request adapter selection", () => { + beforeEach(() => { + axiosMock.mockClear(); + }); + + it("asks axios to fall back through http -> xhr -> fetch", async () => { + await request("/api/subscribers", { method: "GET" }, config); + + expect(axiosMock).toHaveBeenCalledTimes(1); + const passedConfig = axiosMock.mock.calls[0][0] as { adapter: unknown }; + // Ordering matters: Node/browser keep their existing adapter, while + // edge/serverless runtimes fall back to `fetch`. See issue #31. + expect(passedConfig.adapter).toEqual(["http", "xhr", "fetch"]); + }); +}); diff --git a/src/utils/fetch.ts b/src/utils/fetch.ts index 2af676d..df854cd 100644 --- a/src/utils/fetch.ts +++ b/src/utils/fetch.ts @@ -25,7 +25,12 @@ export default function request(endpoint: string = "", options: Options, config: "Content-type": "application/json", "accept-encoding": "null" // needed for axios }, - data: body && JSON.stringify(body) + data: body && JSON.stringify(body), + // Let axios pick the first adapter supported by the current runtime. + // Node keeps using `http` and browsers keep using `xhr` (no behaviour + // change), while edge/serverless runtimes (Vercel Edge, Cloudflare + // Workers, Deno, Next.js edge) that ship neither fall back to `fetch`. + adapter: ["http", "xhr", "fetch"] }) }