@oncely/express 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +74 -19
  2. package/package.json +4 -4
package/README.md CHANGED
@@ -1,48 +1,103 @@
1
1
  # @oncely/express
2
2
 
3
- Express middleware for oncely idempotency.
3
+ Express middleware for HTTP idempotency.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@oncely/express.svg)](https://www.npmjs.com/package/@oncely/express)
4
6
 
5
7
  ## Installation
6
8
 
9
+ ```bash
7
10
  npm install @oncely/core @oncely/express
11
+ ```
8
12
 
9
- ## Usage
13
+ ## Quick Start
10
14
 
15
+ ```typescript
11
16
  import express from 'express';
12
- import { express as idempotent, configure } from '@oncely/express';
17
+ import { express as idempotent } from '@oncely/express';
13
18
 
14
19
  const app = express();
20
+ app.use(express.json());
15
21
 
16
- // Zero-config (uses memory storage)
22
+ // Zero-config: memory storage, 24h TTL
17
23
  app.post('/orders', idempotent(), async (req, res) => {
18
- res.status(201).json(await createOrder(req.body));
24
+ const order = await createOrder(req.body);
25
+ res.status(201).json(order);
19
26
  });
20
-
21
- // With options
22
- app.post('/payments', idempotent({
23
- required: true,
24
- ttl: '1h',
25
- }), paymentHandler);
26
-
27
- // Pre-configured factory
27
+ ```
28
+
29
+ ## Configuration
30
+
31
+ ```typescript
32
+ app.post(
33
+ '/payments',
34
+ idempotent({
35
+ storage: redis(), // Storage adapter
36
+ ttl: '1h', // Cache duration
37
+ required: true, // Require Idempotency-Key header
38
+ methods: ['POST', 'PUT'], // HTTP methods to protect
39
+ failOpen: true, // Continue if storage fails
40
+ getKey: (req) => req.headers['x-request-id'], // Custom key extraction
41
+ getHash: (req) => hashObject(req.body), // Custom hash function
42
+ onHit: (key, response) => {}, // Cache hit callback
43
+ onMiss: (key) => {}, // Cache miss callback
44
+ onError: (key, error) => {}, // Error callback
45
+ }),
46
+ handler
47
+ );
48
+ ```
49
+
50
+ ## Pre-configured Factory
51
+
52
+ Share configuration across routes:
53
+
54
+ ```typescript
55
+ import { configure } from '@oncely/express';
28
56
  import { redis } from '@oncely/redis';
29
57
 
30
58
  const idempotent = configure({
31
- storage: redis(),
32
- ttl: '1h',
59
+ storage: redis(),
60
+ ttl: '1h',
33
61
  });
34
62
 
35
63
  app.post('/orders', idempotent(), orderHandler);
36
64
  app.post('/payments', idempotent({ required: true }), paymentHandler);
65
+ ```
37
66
 
38
67
  ## Headers
39
68
 
40
- Request: Idempotency-Key
41
- Response: Idempotency-Key, Idempotency-Replay (on cache hit)
69
+ | Header | Direction | Description |
70
+ | -------------------- | --------- | ------------------------------------- |
71
+ | `Idempotency-Key` | Request | Client-provided unique key |
72
+ | `Idempotency-Key` | Response | Echo of the key used |
73
+ | `Idempotency-Replay` | Response | `true` when returning cached response |
42
74
 
43
- ## License
75
+ ## Error Responses
44
76
 
45
- MIT
77
+ All errors follow [RFC 7807 Problem Details](https://tools.ietf.org/html/rfc7807):
78
+
79
+ | Status | Type | Cause |
80
+ | ------ | -------------- | ----------------------------------- |
81
+ | 400 | `key-required` | Missing key when `required: true` |
82
+ | 409 | `conflict` | Request with same key in progress |
83
+ | 422 | `mismatch` | Same key reused with different body |
84
+
85
+ ```json
86
+ {
87
+ "type": "https://oncely.dev/errors/conflict",
88
+ "title": "Conflict",
89
+ "status": 409,
90
+ "detail": "A request with this idempotency key is already being processed"
91
+ }
92
+ ```
93
+
94
+ ## With Redis
95
+
96
+ ```typescript
97
+ import { redis } from '@oncely/redis';
98
+
99
+ app.post('/orders', idempotent({ storage: redis() }), handler);
100
+ ```
46
101
 
47
102
  ## License
48
103
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oncely/express",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Express middleware for oncely idempotency",
5
5
  "author": "stacks0x",
6
6
  "license": "MIT",
@@ -33,20 +33,20 @@
33
33
  ],
34
34
  "peerDependencies": {
35
35
  "express": "^4.18.0 || ^5.0.0",
36
- "@oncely/core": "0.2.1"
36
+ "@oncely/core": "0.2.2"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@types/express": "^5.0.6",
40
40
  "express": "^5.2.1",
41
41
  "tsup": "^8.0.1",
42
42
  "typescript": "^5.3.3",
43
- "@oncely/core": "0.2.1"
43
+ "@oncely/core": "0.2.2"
44
44
  },
45
45
  "publishConfig": {
46
46
  "access": "public"
47
47
  },
48
48
  "engines": {
49
- "node": ">=18.0.0"
49
+ "node": ">=20.0.0"
50
50
  },
51
51
  "scripts": {
52
52
  "build": "tsup",