@uploadbox/nextjs 0.1.0 → 0.2.0

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 +206 -0
  2. package/package.json +2 -2
package/README.md ADDED
@@ -0,0 +1,206 @@
1
+ # @uploadbox/nextjs
2
+
3
+ Next.js route handler for Uploadbox — presigned URL uploads with your own S3 bucket.
4
+
5
+ [![npm](https://img.shields.io/npm/v/@uploadbox/nextjs)](https://www.npmjs.com/package/@uploadbox/nextjs)
6
+ [![license](https://img.shields.io/npm/l/@uploadbox/nextjs)](./LICENSE)
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ npm i @uploadbox/nextjs @uploadbox/core
12
+ ```
13
+
14
+ **Peer dependency:** Next.js 14, 15, or 16.
15
+
16
+ ## Quick Start
17
+
18
+ ### 1. Define your file router
19
+
20
+ ```ts
21
+ // src/lib/uploadbox.ts
22
+ import { f } from "@uploadbox/core";
23
+
24
+ export const router = {
25
+ imageUploader: f({ image: { maxFileSize: "4MB", maxFileCount: 5 } })
26
+ .middleware(async ({ auth }) => {
27
+ return { userId: auth?.apiKeyId };
28
+ })
29
+ .onUploadComplete(async ({ file, metadata }) => {
30
+ console.log("Upload complete:", file.url);
31
+ return { fileId: file.key };
32
+ }),
33
+ };
34
+
35
+ export type AppRouter = typeof router;
36
+ ```
37
+
38
+ ### 2. Create the route handler
39
+
40
+ ```ts
41
+ // src/app/api/uploadbox/route.ts
42
+ import { createRouteHandler } from "@uploadbox/nextjs";
43
+ import { router } from "@/lib/uploadbox";
44
+
45
+ export const { GET, POST } = createRouteHandler({ router });
46
+ ```
47
+
48
+ S3 credentials are read from environment variables by default (`UPLOADBOX_S3_BUCKET`, `UPLOADBOX_AWS_REGION`, `UPLOADBOX_AWS_ACCESS_KEY_ID`, `UPLOADBOX_AWS_SECRET_ACCESS_KEY`), or pass a `config` object explicitly.
49
+
50
+ ### 3. Add the React components
51
+
52
+ See [`@uploadbox/react`](https://www.npmjs.com/package/@uploadbox/react) for the client-side integration.
53
+
54
+ ## Lifecycle Hooks
55
+
56
+ Lifecycle hooks let you integrate authentication, quotas, and database tracking without coupling your upload logic to a specific database.
57
+
58
+ ```ts
59
+ export const { GET, POST } = createRouteHandler({
60
+ router,
61
+ hooks: {
62
+ onAuthenticate: async (req) => {
63
+ const token = req.headers.get("authorization");
64
+ const user = await verifyToken(token);
65
+ return { apiKeyId: user.id, apiKeyName: user.name };
66
+ },
67
+
68
+ onQuotaCheck: async ({ auth, totalSize, fileCount }) => {
69
+ const usage = await getStorageUsage(auth.apiKeyId);
70
+ if (usage + totalSize > MAX_STORAGE) {
71
+ throw UploadboxError.quotaExceeded();
72
+ }
73
+ },
74
+
75
+ onUploadStarted: async (events) => {
76
+ await db.insert(uploads).values(events.map(toRecord));
77
+ },
78
+
79
+ onUploadCompleted: async (event) => {
80
+ await db.update(uploads)
81
+ .set({ status: "completed" })
82
+ .where(eq(uploads.key, event.file.key));
83
+ },
84
+
85
+ onUploadFailed: async (event) => {
86
+ await db.update(uploads)
87
+ .set({ status: "failed", error: event.error })
88
+ .where(eq(uploads.key, event.fileKey));
89
+ },
90
+
91
+ onFileVerified: async (fileKey) => {
92
+ // Fallback lookup when in-memory state is lost (e.g., multi-instance deploys)
93
+ return db.query.uploads.findFirst({ where: eq(uploads.key, fileKey) });
94
+ },
95
+ },
96
+ });
97
+ ```
98
+
99
+ ### Available Hooks
100
+
101
+ | Hook | When | Purpose |
102
+ |------|------|---------|
103
+ | `onAuthenticate` | Every request | Return `AuthContext` or `undefined` for anonymous |
104
+ | `onQuotaCheck` | Before presigning | Throw `UploadboxError.quotaExceeded()` to deny |
105
+ | `onUploadStarted` | After presigned URLs generated | Track pending uploads |
106
+ | `onFileVerified` | On complete, if in-memory miss | Fallback lookup for file data |
107
+ | `onUploadCompleted` | After `onUploadComplete` succeeds | Update DB, trigger webhooks |
108
+ | `onUploadFailed` | On upload failure | Log errors, clean up |
109
+ | `onMultipartStarted` | Multipart upload created | Track large uploads |
110
+ | `onMultipartCompleted` | Multipart upload finished | Update status |
111
+ | `onMultipartAborted` | Multipart upload cancelled | Clean up |
112
+ | `onResolveConfig` | Every request | Per-tenant S3 config (BYOB) |
113
+
114
+ ## Rate Limiting
115
+
116
+ Built-in sliding window rate limiter, no external dependencies:
117
+
118
+ ```ts
119
+ export const { GET, POST } = createRouteHandler({
120
+ router,
121
+ rateLimit: {
122
+ requestsPerMinute: 60,
123
+ uploadsPerHour: 100,
124
+ },
125
+ });
126
+ ```
127
+
128
+ Limits are applied per API key or client IP.
129
+
130
+ ## Processing Pipeline
131
+
132
+ Run post-upload processing hooks (image resize, virus scan, etc.):
133
+
134
+ ```ts
135
+ import { createImageResizeHook } from "@uploadbox/core/hooks/image-resize";
136
+ import { createVirusScanHook } from "@uploadbox/core/hooks/virus-scan";
137
+
138
+ export const { GET, POST } = createRouteHandler({
139
+ router,
140
+ processing: {
141
+ hooks: [
142
+ createImageResizeHook({ maxWidth: 1920, format: "webp" }),
143
+ createVirusScanHook({ clamavUrl: "http://localhost:3310" }),
144
+ ],
145
+ mode: "sequential", // or "parallel"
146
+ continueOnError: true,
147
+ },
148
+ });
149
+ ```
150
+
151
+ Or use `runProcessingPipeline` directly:
152
+
153
+ ```ts
154
+ import { runProcessingPipeline } from "@uploadbox/nextjs";
155
+
156
+ const results = await runProcessingPipeline(pipelineConfig, file, metadata, s3Client, config);
157
+ ```
158
+
159
+ ## Hosted Mode
160
+
161
+ For the Uploadbox hosted platform, use `createHostedHandler` which adds platform-integrated auth, quotas, and event tracking:
162
+
163
+ ```ts
164
+ import { createHostedHandler } from "@uploadbox/nextjs";
165
+
166
+ export const { GET, POST } = createHostedHandler({
167
+ router,
168
+ platform: {
169
+ platformUrl: "https://uploadbox.dev",
170
+ projectId: "proj_abc123",
171
+ },
172
+ });
173
+ ```
174
+
175
+ ## Configuration
176
+
177
+ Full `createRouteHandler` options:
178
+
179
+ ```ts
180
+ createRouteHandler({
181
+ router, // FileRouter (required)
182
+ config: { // S3 config (or use env vars)
183
+ bucket: "my-bucket",
184
+ region: "us-east-1",
185
+ accessKeyId: "...",
186
+ secretAccessKey: "...",
187
+ endpoint: "...", // MinIO, R2, Wasabi
188
+ forcePathStyle: true,
189
+ cdnBaseUrl: "https://cdn.example.com",
190
+ presignedUrlExpiry: 3600,
191
+ },
192
+ hooks: { ... }, // LifecycleHooks
193
+ rateLimit: { ... }, // RateLimitConfig
194
+ processing: { ... }, // ProcessingPipelineConfig
195
+ s3ClientFactory: (cfg) => createCustomClient(cfg),
196
+ });
197
+ ```
198
+
199
+ ## Related Packages
200
+
201
+ - [`@uploadbox/core`](https://www.npmjs.com/package/@uploadbox/core) — Core utilities, builder pattern, S3 operations
202
+ - [`@uploadbox/react`](https://www.npmjs.com/package/@uploadbox/react) — React components and hooks
203
+
204
+ ## License
205
+
206
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uploadbox/nextjs",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -12,7 +12,7 @@
12
12
  }
13
13
  },
14
14
  "dependencies": {
15
- "@uploadbox/core": "0.1.0"
15
+ "@uploadbox/core": "0.2.0"
16
16
  },
17
17
  "peerDependencies": {
18
18
  "next": "^14.0.0 || ^15.0.0 || ^16.0.0"