Edge runtimes
Run better-payment on Vercel Edge, Cloudflare Workers, Deno and Bun.
better-payment has no runtime dependencies and uses only web-standard APIs: fetch, WebCrypto (crypto.subtle), TextEncoder and atob/btoa. The same package runs on:
- Node.js 20+
- Vercel Edge Functions and Next.js routes with
runtime = 'edge' - Cloudflare Workers
- Deno and Deno Deploy
- Bun
Every release is tested in the Vercel Edge Runtime VM. That VM has no Buffer, process or require. The test signs requests and verifies callbacks for all four providers there, and compares the results with values computed in Node.js.
Next.js (edge)
The Next.js route handler works unchanged. Only switch the runtime:
// app/api/pay/[...path]/route.ts
export const runtime = 'edge'; // or 'nodejs'Cloudflare Workers
import { betterPayment, iyzico, toFetchHandler } from 'better-payment';
interface Env {
IYZICO_API_KEY: string;
IYZICO_SECRET_KEY: string;
}
export default {
fetch(request: Request, env: Env): Promise<Response> {
const payment = betterPayment({
mode: 'sandbox',
providers: {
iyzico: iyzico({ apiKey: env.IYZICO_API_KEY, secretKey: env.IYZICO_SECRET_KEY }),
},
});
return toFetchHandler(payment)(request);
},
};Deno and Bun
import { betterPayment, toFetchHandler } from 'npm:better-payment';
const payment = betterPayment({ /* ... */ });
Deno.serve(toFetchHandler(payment)); // Deno
// Bun.serve({ fetch: toFetchHandler(payment) }); // BuntoFetchHandler turns the handler into a (request: Request) => Promise<Response> function. Hono has its own adapter.
Idempotency on edge and serverless
The default idempotency store keeps duplicate-callback and Idempotency-Key records in memory. On edge and serverless platforms, every isolate or instance has its own memory, so it only deduplicates requests that reach the same isolate. Pass a shared store in production:
- Upstash Redis (HTTP-based, works on every edge runtime):
SET key value EX ttl NXforsetIfAbsent. - Cloudflare: Durable Objects or D1 (
INSERT ... ON CONFLICT DO NOTHING). Workers KV is eventually consistent and cannot implement the atomicsetIfAbsent.
Custom fetch
Provider API calls use globalThis.fetch. Pass your own implementation, for example to route requests through a proxy or to stub them in tests:
betterPayment({
fetch: (input, init) => fetch(input, { ...init, keepalive: true }),
providers: { /* ... */ },
});