@uploadbox/core 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 +228 -0
  2. package/package.json +1 -1
package/README.md ADDED
@@ -0,0 +1,228 @@
1
+ # @uploadbox/core
2
+
3
+ Core utilities for Uploadbox — S3 operations, file validation, and the file-router builder pattern.
4
+
5
+ [![npm](https://img.shields.io/npm/v/@uploadbox/core)](https://www.npmjs.com/package/@uploadbox/core)
6
+ [![license](https://img.shields.io/npm/l/@uploadbox/core)](./LICENSE)
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ npm i @uploadbox/core
12
+ ```
13
+
14
+ ## Quick Start
15
+
16
+ Define upload routes using the `f()` builder pattern:
17
+
18
+ ```ts
19
+ import { f } from "@uploadbox/core";
20
+
21
+ const router = {
22
+ imageUploader: f({ image: { maxFileSize: "4MB", maxFileCount: 5 } })
23
+ .middleware(async ({ files, auth }) => {
24
+ return { userId: auth?.apiKeyId };
25
+ })
26
+ .onUploadComplete(async ({ file, metadata }) => {
27
+ console.log("Upload complete:", file.url);
28
+ return { fileId: file.key };
29
+ }),
30
+
31
+ documentUploader: f({
32
+ pdf: { maxFileSize: "16MB" },
33
+ text: { maxFileSize: "1MB" },
34
+ })
35
+ .middleware(async ({ auth }) => {
36
+ if (!auth) throw new Error("Unauthorized");
37
+ return { userId: auth.apiKeyId };
38
+ })
39
+ .onUploadComplete(async ({ file }) => {
40
+ return { url: file.url };
41
+ }),
42
+ };
43
+
44
+ export type AppRouter = typeof router;
45
+ ```
46
+
47
+ ### File Route Config
48
+
49
+ Each route accepts a map of file types with constraints:
50
+
51
+ ```ts
52
+ f({
53
+ image: {
54
+ maxFileSize: "4MB", // "B" | "KB" | "MB" | "GB"
55
+ maxFileCount: 10,
56
+ minFileCount: 1,
57
+ acl: "public-read", // "public-read" | "private"
58
+ contentDisposition: "inline",
59
+ presignedUrlExpiry: 3600, // seconds
60
+ defaultTtlSeconds: 86400,
61
+ maxTtlSeconds: 604800,
62
+ },
63
+ })
64
+ ```
65
+
66
+ Supported file types: `image`, `video`, `audio`, `pdf`, `text`, `blob` (any file).
67
+
68
+ ## S3 Utilities
69
+
70
+ ### Create an S3 Client
71
+
72
+ ```ts
73
+ import { createS3Client } from "@uploadbox/core";
74
+
75
+ const s3 = createS3Client({
76
+ bucket: "my-bucket",
77
+ region: "us-east-1",
78
+ accessKeyId: "...",
79
+ secretAccessKey: "...",
80
+ // Optional — for MinIO, R2, Wasabi:
81
+ endpoint: "https://s3.example.com",
82
+ forcePathStyle: true,
83
+ });
84
+ ```
85
+
86
+ Or use environment variables (`UPLOADBOX_S3_BUCKET`, `UPLOADBOX_AWS_REGION`, etc.) and let `createUploadbox()` auto-configure.
87
+
88
+ ### Presigned URLs
89
+
90
+ ```ts
91
+ import { generatePresignedPutUrl, generatePresignedGetUrl } from "@uploadbox/core";
92
+
93
+ const putUrl = await generatePresignedPutUrl(s3, "bucket", "key.png", "image/png", 1024);
94
+ const getUrl = await generatePresignedGetUrl(s3, "bucket", "key.png", 3600);
95
+ ```
96
+
97
+ ### Other S3 Operations
98
+
99
+ ```ts
100
+ import { headObject, deleteObject, deleteObjects, listObjects } from "@uploadbox/core";
101
+
102
+ await headObject(s3, "bucket", "key.png"); // verify existence
103
+ await deleteObject(s3, "bucket", "key.png");
104
+ await deleteObjects(s3, "bucket", ["a.png", "b.png"]);
105
+ const { keys, nextToken } = await listObjects(s3, "bucket", "uploads/");
106
+ ```
107
+
108
+ ## Multipart Uploads
109
+
110
+ Files larger than 10 MB are automatically split into parts:
111
+
112
+ ```ts
113
+ import {
114
+ createMultipartUpload,
115
+ generatePresignedPartUrls,
116
+ completeMultipartUpload,
117
+ abortMultipartUpload,
118
+ MULTIPART_THRESHOLD,
119
+ DEFAULT_PART_SIZE,
120
+ } from "@uploadbox/core";
121
+
122
+ const uploadId = await createMultipartUpload(s3, "bucket", "key.mp4", "video/mp4");
123
+ const parts = await generatePresignedPartUrls(s3, "bucket", "key.mp4", uploadId, [1, 2, 3]);
124
+ // ... upload parts ...
125
+ await completeMultipartUpload(s3, "bucket", "key.mp4", uploadId, [
126
+ { partNumber: 1, etag: "..." },
127
+ { partNumber: 2, etag: "..." },
128
+ ]);
129
+ ```
130
+
131
+ ## Processing Hooks
132
+
133
+ Optional post-upload processing via subpath imports. These run server-side after a file is uploaded.
134
+
135
+ ### Image Resize
136
+
137
+ Requires `sharp` as a peer dependency.
138
+
139
+ ```ts
140
+ import { createImageResizeHook } from "@uploadbox/core/hooks/image-resize";
141
+
142
+ const resizeHook = createImageResizeHook({
143
+ maxWidth: 1920,
144
+ maxHeight: 1080,
145
+ quality: 80,
146
+ format: "webp", // "jpeg" | "png" | "webp"
147
+ });
148
+ ```
149
+
150
+ ### Virus Scan
151
+
152
+ Requires a running ClamAV REST service.
153
+
154
+ ```ts
155
+ import { createVirusScanHook } from "@uploadbox/core/hooks/virus-scan";
156
+
157
+ const scanHook = createVirusScanHook({
158
+ clamavUrl: "http://localhost:3310",
159
+ deleteOnDetection: true,
160
+ timeoutMs: 30000,
161
+ });
162
+ ```
163
+
164
+ ## Server-Side Upload
165
+
166
+ Upload files directly from your server (no presigned URL):
167
+
168
+ ```ts
169
+ import { serverUpload, serverUploadMany } from "@uploadbox/core";
170
+
171
+ const result = await serverUpload(s3, config, {
172
+ name: "report.pdf",
173
+ body: buffer,
174
+ contentType: "application/pdf",
175
+ acl: "private",
176
+ });
177
+
178
+ const results = await serverUploadMany(s3, config, files, 3); // concurrency = 3
179
+ ```
180
+
181
+ ### UploadboxApi
182
+
183
+ High-level wrapper combining common operations:
184
+
185
+ ```ts
186
+ import { UploadboxApi } from "@uploadbox/core";
187
+
188
+ const api = new UploadboxApi(s3, config);
189
+
190
+ await api.uploadFile({ name: "photo.jpg", body: buffer });
191
+ await api.deleteFile("uploads/photo.jpg");
192
+ const url = await api.getSignedUrl("uploads/photo.jpg");
193
+ const { keys } = await api.listFiles({ prefix: "uploads/" });
194
+ ```
195
+
196
+ ## Utilities
197
+
198
+ ```ts
199
+ import { parseFileSize, formatFileSize, validateFiles, generateFileKey } from "@uploadbox/core";
200
+
201
+ parseFileSize("4MB"); // 4194304
202
+ formatFileSize(4194304); // "4 MB"
203
+ generateFileKey("my file.png"); // "my-file-a1b2c3d4e5f6.png"
204
+
205
+ // Throws UploadboxError if validation fails
206
+ validateFiles(files, { image: { maxFileSize: "4MB", maxFileCount: 5 } });
207
+ ```
208
+
209
+ ## Key Types
210
+
211
+ | Type | Description |
212
+ |------|-------------|
213
+ | `FileRouter` | `Record<string, FileRoute>` — your upload route definitions |
214
+ | `UploadboxConfig` | S3 config: bucket, region, credentials, endpoint, CDN URL |
215
+ | `UploadedFileData` | Completed upload: key, name, size, type, url, acl, metadata |
216
+ | `AuthContext` | `{ apiKeyId, apiKeyName, projectId? }` |
217
+ | `FileRouteConfig` | Per-type constraints: maxFileSize, maxFileCount, acl, etc. |
218
+ | `ProcessingHook` | `{ name, shouldRun, run, timeoutMs? }` |
219
+ | `UploadboxError` | Structured error with code, statusCode, and static factories |
220
+
221
+ ## Related Packages
222
+
223
+ - [`@uploadbox/nextjs`](https://www.npmjs.com/package/@uploadbox/nextjs) — Next.js route handler adapter
224
+ - [`@uploadbox/react`](https://www.npmjs.com/package/@uploadbox/react) — React components and hooks
225
+
226
+ ## License
227
+
228
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uploadbox/core",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",