@oncely/upstash 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 +71 -114
  2. package/package.json +4 -4
package/README.md CHANGED
@@ -1,164 +1,121 @@
1
1
  # @oncely/upstash
2
2
 
3
- Upstash storage adapter for oncely (edge/serverless compatible).
3
+ Upstash Redis adapter for oncely. HTTP-based, perfect for serverless and edge.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@oncely/upstash.svg)](https://www.npmjs.com/package/@oncely/upstash)
4
6
 
5
7
  ## Installation
6
8
 
9
+ ```bash
7
10
  npm install @oncely/core @oncely/upstash
11
+ ```
8
12
 
9
- ## Usage
13
+ ## Quick Start
10
14
 
11
- import { upstash, UpstashStorage } from '@oncely/upstash';
15
+ ```typescript
16
+ import { upstash } from '@oncely/upstash';
12
17
  import { next } from '@oncely/next';
13
18
 
14
19
  // From environment variables
15
- const storage = upstash();
20
+ export const POST = next({ storage: upstash() })(handler);
21
+ ```
16
22
 
17
- // With explicit config
18
- const storage = upstash({
19
- url: 'https://...',
20
- token: '...',
21
- });
23
+ ## Configuration
22
24
 
23
- // Use with Next.js
24
- export const POST = next({ storage: upstash() })(handler);
25
+ ```typescript
26
+ import { upstash } from '@oncely/upstash';
25
27
 
26
- ## Environment Variables
28
+ // From environment variables (ONCELY_UPSTASH_REST_URL, ONCELY_UPSTASH_REST_TOKEN)
29
+ const storage = upstash();
27
30
 
28
- ONCELY_UPSTASH_REST_URL - Upstash REST URL
29
- ONCELY_UPSTASH_REST_TOKEN - Upstash REST token
31
+ // With explicit credentials
32
+ const storage = upstash({
33
+ url: 'https://your-redis.upstash.io',
34
+ token: 'your-rest-token',
35
+ });
30
36
 
31
- ## License
37
+ // With options
38
+ const storage = upstash({
39
+ url: process.env.UPSTASH_REDIS_REST_URL,
40
+ token: process.env.UPSTASH_REDIS_REST_TOKEN,
41
+ keyPrefix: 'myapp:idem:',
42
+ });
32
43
 
33
- MIT
34
- await storage.acquire(key, hash, ttl); // AcquireResult
35
- await storage.save(key, response); // void
36
- await storage.release(key); // void
37
- await storage.delete(key); // void
38
- await storage.clear(); // void
44
+ // With existing @upstash/redis client
45
+ import { Redis } from '@upstash/redis';
46
+ const client = new Redis({ url: '...', token: '...' });
47
+ const storage = upstash({ client });
48
+ ```
39
49
 
40
- ````
50
+ ## Environment Variables
41
51
 
42
- ## Usage Examples
52
+ | Variable | Description |
53
+ | --------------------------- | ------------------------------------------------------ |
54
+ | `ONCELY_UPSTASH_REST_URL` | Upstash REST endpoint (e.g., `https://xyz.upstash.io`) |
55
+ | `ONCELY_UPSTASH_REST_TOKEN` | Upstash REST token |
43
56
 
44
- ### Next.js App Router (Edge)
57
+ ## Usage with Next.js App Router
45
58
 
46
59
  ```typescript
47
60
  // app/api/orders/route.ts
48
- import { oncely } from '@oncely/core';
61
+ import { next } from '@oncely/next';
49
62
  import { upstash } from '@oncely/upstash';
50
63
 
51
- export const runtime = 'edge';
52
-
53
- const handler = oncely.handler({
54
- storage: upstash(),
55
- ttl: 60000,
64
+ export const POST = next({ storage: upstash() })(async (req) => {
65
+ const order = await createOrder(await req.json());
66
+ return Response.json(order, { status: 201 });
56
67
  });
68
+ ```
57
69
 
58
- export async function POST(request: Request) {
59
- return handler(request, async (req) => {
60
- const body = await req.json();
61
- const order = await createOrder(body);
62
-
63
- return Response.json(order, { status: 201 });
64
- });
65
- }
66
- ````
67
-
68
- ### Vercel Serverless Function
70
+ ## Usage with Next.js Pages Router
69
71
 
70
72
  ```typescript
71
- // api/checkout.ts
72
- import type { VercelRequest, VercelResponse } from '@vercel/node';
73
- import { oncely } from '@oncely/core';
73
+ // pages/api/orders.ts
74
+ import { pages } from '@oncely/next/pages';
74
75
  import { upstash } from '@oncely/upstash';
75
76
 
76
- const storage = upstash();
77
-
78
- export default async function handler(req: VercelRequest, res: VercelResponse) {
79
- const idempotencyKey = req.headers['idempotency-key'] as string;
80
-
81
- if (!idempotencyKey) {
82
- return res.status(400).json({ error: 'Idempotency-Key required' });
83
- }
84
-
85
- const result = await storage.acquire(idempotencyKey, null, 60000);
86
-
87
- if (result.status === 'hit') {
88
- res.setHeader('Idempotency-Replay', 'true');
89
- return res.json(result.response.data);
90
- }
91
-
92
- if (result.status === 'conflict') {
93
- return res.status(409).json({ error: 'Request in progress' });
94
- }
95
-
96
- try {
97
- const data = await processCheckout(req.body);
98
- await storage.save(idempotencyKey, {
99
- data,
100
- createdAt: Date.now(),
101
- hash: null,
102
- });
103
- return res.json(data);
104
- } catch (error) {
105
- await storage.release(idempotencyKey);
106
- throw error;
107
- }
108
- }
77
+ export default pages({ storage: upstash() })(async (req, res) => {
78
+ const order = await createOrder(req.body);
79
+ res.status(201).json(order);
80
+ });
109
81
  ```
110
82
 
111
- ### Cloudflare Workers
83
+ ## Pre-configured Factory
112
84
 
113
85
  ```typescript
114
- import { oncely } from '@oncely/core';
86
+ // lib/idempotency.ts
87
+ import { configure } from '@oncely/next';
115
88
  import { upstash } from '@oncely/upstash';
116
89
 
117
- export interface Env {
118
- ONCELY_UPSTASH_REST_URL: string;
119
- ONCELY_UPSTASH_REST_TOKEN: string;
120
- }
121
-
122
- export default {
123
- async fetch(request: Request, env: Env): Promise<Response> {
124
- const storage = upstash({
125
- url: env.ONCELY_UPSTASH_REST_URL,
126
- token: env.ONCELY_UPSTASH_REST_TOKEN,
127
- });
128
-
129
- const handler = oncely.handler({
130
- storage,
131
- ttl: 60000,
132
- });
133
-
134
- return handler(request, async (req) => {
135
- // Your handler logic
136
- return new Response(JSON.stringify({ ok: true }));
137
- });
138
- },
139
- };
90
+ export const idempotent = configure({
91
+ storage: upstash(),
92
+ ttl: '1h',
93
+ });
94
+
95
+ // app/api/orders/route.ts
96
+ import { idempotent } from '@/lib/idempotency';
97
+
98
+ export const POST = idempotent()(handler);
140
99
  ```
141
100
 
142
- ### With Regional Endpoints
101
+ ## Vercel KV
143
102
 
144
- For lower latency, use Upstash regional endpoints:
103
+ Vercel KV is compatible with Upstash. Use the Vercel KV environment variables:
145
104
 
146
105
  ```typescript
147
106
  const storage = upstash({
148
- url: process.env.ONCELY_UPSTASH_REST_URL_US_EAST_1,
149
- token: process.env.ONCELY_UPSTASH_REST_TOKEN,
107
+ url: process.env.KV_REST_API_URL,
108
+ token: process.env.KV_REST_API_TOKEN,
150
109
  });
151
110
  ```
152
111
 
153
- ## Why Upstash?
112
+ ## Key Prefix
113
+
114
+ All keys are prefixed with `oncely:` by default. Customize with:
154
115
 
155
- | Feature | Upstash | Self-hosted Redis |
156
- | ------------------ | --------------- | ---------------------- |
157
- | Edge/Serverless | ✅ HTTP-based | ❌ Requires TCP |
158
- | Connection pooling | ✅ Not needed | ⚠️ Required |
159
- | Cold start | ✅ Instant | ⚠️ Connection overhead |
160
- | Scaling | ✅ Auto | Manual |
161
- | Global | ✅ Multi-region | Manual setup |
116
+ ```typescript
117
+ const storage = upstash({ keyPrefix: 'myapp:idem:' });
118
+ ```
162
119
 
163
120
  ## License
164
121
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oncely/upstash",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Upstash Redis adapter for oncely idempotency",
5
5
  "author": "stacks0x",
6
6
  "license": "MIT",
@@ -37,19 +37,19 @@
37
37
  ],
38
38
  "peerDependencies": {
39
39
  "@upstash/redis": "^1.28.0",
40
- "@oncely/core": "0.2.1"
40
+ "@oncely/core": "0.2.2"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@upstash/redis": "^1.28.0",
44
44
  "tsup": "^8.0.1",
45
45
  "typescript": "^5.3.3",
46
- "@oncely/core": "0.2.1"
46
+ "@oncely/core": "0.2.2"
47
47
  },
48
48
  "publishConfig": {
49
49
  "access": "public"
50
50
  },
51
51
  "engines": {
52
- "node": ">=18.0.0"
52
+ "node": ">=20.0.0"
53
53
  },
54
54
  "scripts": {
55
55
  "build": "tsup",