@oncely/upstash 1.0.0 → 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 (3) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +71 -114
  3. package/package.json +13 -13
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 stacks0x
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
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.0",
3
+ "version": "1.0.2",
4
4
  "description": "Upstash Redis adapter for oncely idempotency",
5
5
  "author": "stacks0x",
6
6
  "license": "MIT",
@@ -35,26 +35,26 @@
35
35
  "README.md",
36
36
  "LICENSE"
37
37
  ],
38
- "scripts": {
39
- "build": "tsup",
40
- "dev": "tsup --watch",
41
- "typecheck": "tsc --noEmit",
42
- "clean": "rm -rf dist"
43
- },
44
38
  "peerDependencies": {
45
- "@oncely/core": "workspace:*",
46
- "@upstash/redis": "^1.28.0"
39
+ "@upstash/redis": "^1.28.0",
40
+ "@oncely/core": "0.2.2"
47
41
  },
48
42
  "devDependencies": {
49
- "@oncely/core": "workspace:*",
50
43
  "@upstash/redis": "^1.28.0",
51
44
  "tsup": "^8.0.1",
52
- "typescript": "^5.3.3"
45
+ "typescript": "^5.3.3",
46
+ "@oncely/core": "0.2.2"
53
47
  },
54
48
  "publishConfig": {
55
49
  "access": "public"
56
50
  },
57
51
  "engines": {
58
- "node": ">=18.0.0"
52
+ "node": ">=20.0.0"
53
+ },
54
+ "scripts": {
55
+ "build": "tsup",
56
+ "dev": "tsup --watch",
57
+ "typecheck": "tsc --noEmit",
58
+ "clean": "rm -rf dist"
59
59
  }
60
- }
60
+ }