Next.js integration for oncely idempotency
npm install @oncely/nextNext.js integration for HTTP idempotency. Supports App Router and Pages Router.

``bash`
npm install @oncely/core @oncely/next
`typescript
// app/api/orders/route.ts
import { next } from '@oncely/next';
export const POST = next()(async (req) => {
const order = await createOrder(await req.json());
return Response.json(order, { status: 201 });
});
`
`typescript
// pages/api/orders.ts
import { pages } from '@oncely/next/pages';
export default pages()(async (req, res) => {
const order = await createOrder(req.body);
res.status(201).json(order);
});
`
Both next() and pages() accept the same options:
`typescript`
export const POST = next({
storage: upstash(), // Storage adapter
ttl: '1h', // Cache duration
required: true, // Require Idempotency-Key header
failOpen: true, // Continue if storage fails
getKey: (req) => req.headers.get('x-request-id'), // Custom key extraction
getHash: async (req) => hashObject(await req.json()), // Custom hash
onHit: (key, response) => {}, // Cache hit callback
onMiss: (key) => {}, // Cache miss callback
onError: (key, error) => {}, // Error callback
})(handler);
Share configuration across routes:
`typescript
// lib/idempotency.ts
import { configure } from '@oncely/next';
import { upstash } from '@oncely/upstash';
export const idempotent = configure({
storage: upstash(),
ttl: '1h',
});
// app/api/orders/route.ts
import { idempotent } from '@/lib/idempotency';
export const POST = idempotent()(handler);
`
Pages Router has its own configure:
`typescript
// lib/idempotency.ts
import { configure } from '@oncely/next/pages';
export const idempotent = configure({
storage: upstash(),
ttl: '1h',
});
// pages/api/orders.ts
import { idempotent } from '@/lib/idempotency';
export default idempotent()(handler);
`
| Header | Direction | Description |
| -------------------- | --------- | ------------------------------------- |
| Idempotency-Key | Request | Client-provided unique key |Idempotency-Key
| | Response | Echo of the key used |Idempotency-Replay
| | Response | true when returning cached response |
All errors follow RFC 7807 Problem Details:
| Status | Type | Cause |
| ------ | -------------- | ----------------------------------- |
| 400 | key-required | Missing key when required: true |conflict
| 409 | | Request with same key in progress |mismatch
| 422 | | Same key reused with different body |
`typescript
import { upstash } from '@oncely/upstash';
export const POST = next({ storage: upstash() })(handler);
``
MIT