upthing-sdk 1.0.1 → 1.0.3
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.
- package/README.md +84 -21
- package/dist/index.d.ts +41 -6
- package/dist/index.js +45 -16
- package/dist/node.d.ts +9 -0
- package/dist/node.js +22 -0
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -8,38 +8,64 @@ TypeScript SDK for [upthing.2klabs.xyz](https://upthing.2klabs.xyz) — upload f
|
|
|
8
8
|
npm install upthing-sdk
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Two entry points
|
|
12
|
+
|
|
13
|
+
| Import | Environment | Has `uploadFile`? |
|
|
14
|
+
| ------ | ----------- | ----------------- |
|
|
15
|
+
| `upthing-sdk` | Browser + Node.js | No (`fs` would break bundlers) |
|
|
16
|
+
| `upthing-sdk/node` | Node.js only | Yes |
|
|
17
|
+
|
|
18
|
+
Use the default import for browser/edge/client-side code (Next.js `"use client"`, React, etc.).
|
|
19
|
+
Use `upthing-sdk/node` in server-only code when you need `uploadFile()`.
|
|
20
|
+
|
|
21
|
+
## Quick start (Node.js)
|
|
12
22
|
|
|
13
23
|
```typescript
|
|
14
|
-
import {
|
|
24
|
+
import { UpThingNodeClient } from "upthing-sdk/node";
|
|
15
25
|
|
|
16
|
-
const upthing = new
|
|
26
|
+
const upthing = new UpThingNodeClient({
|
|
17
27
|
apiKey: process.env.UPTHING_API_KEY!,
|
|
18
28
|
});
|
|
19
29
|
|
|
20
|
-
// Upload a file
|
|
30
|
+
// Upload a file from disk
|
|
21
31
|
const file = await upthing.uploadFile("./photo.jpg");
|
|
22
32
|
console.log(file.url);
|
|
23
33
|
// https://upthing.2klabs.xyz/f/UgjIzXI3ZolZ
|
|
24
34
|
|
|
25
|
-
// Proxy an external image
|
|
35
|
+
// Proxy an external image
|
|
26
36
|
const src = upthing.proxyUrl("https://example.com/banner.jpg");
|
|
27
|
-
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Quick start (Browser / Next.js client)
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
"use client";
|
|
43
|
+
import { UpThingClient } from "upthing-sdk";
|
|
44
|
+
|
|
45
|
+
// No API key needed for domain-auth proxy
|
|
46
|
+
const upthing = new UpThingClient();
|
|
47
|
+
|
|
48
|
+
// Use directly in JSX
|
|
49
|
+
<img src={upthing.proxyUrl("https://example.com/photo.jpg", {
|
|
50
|
+
projectUuid: "07595179-..."
|
|
51
|
+
})} />
|
|
28
52
|
```
|
|
29
53
|
|
|
30
54
|
## API
|
|
31
55
|
|
|
32
|
-
### `new UpThingClient(options)`
|
|
56
|
+
### `new UpThingClient(options?)`
|
|
33
57
|
|
|
34
|
-
| Option | Type | Default
|
|
35
|
-
| --------- | ------ |
|
|
36
|
-
| `apiKey` | string |
|
|
37
|
-
| `baseUrl` | string | `https://upthing.2klabs.xyz`
|
|
58
|
+
| Option | Type | Default |
|
|
59
|
+
| --------- | ------ | ----------------------------- |
|
|
60
|
+
| `apiKey` | string | `""` (optional for proxy URL builders) |
|
|
61
|
+
| `baseUrl` | string | `https://upthing.2klabs.xyz` |
|
|
62
|
+
|
|
63
|
+
`UpThingNodeClient` (from `upthing-sdk/node`) extends `UpThingClient` and adds `uploadFile()`.
|
|
38
64
|
|
|
39
65
|
### Upload methods
|
|
40
66
|
|
|
41
67
|
```typescript
|
|
42
|
-
// From a file path (Node.js)
|
|
68
|
+
// From a file path (Node.js only — use UpThingNodeClient)
|
|
43
69
|
await upthing.uploadFile("./photo.jpg");
|
|
44
70
|
await upthing.uploadFile("./photo.jpg", { ttlSeconds: 3600 });
|
|
45
71
|
|
|
@@ -61,17 +87,48 @@ await upthing.uploadBase64(base64String, "avatar.png");
|
|
|
61
87
|
| `projectUuid` | string | Target project (if key isn't pinned) |
|
|
62
88
|
| `ttlSeconds` | number | Auto-delete after N seconds |
|
|
63
89
|
|
|
90
|
+
### File management
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
// List files (paginated)
|
|
94
|
+
const { data, pagination } = await upthing.listFiles({ limit: 20, offset: 0 });
|
|
95
|
+
console.log(`${pagination.total} files total`);
|
|
96
|
+
|
|
97
|
+
// Filter by project
|
|
98
|
+
const { data: projectFiles } = await upthing.listFiles({
|
|
99
|
+
projectUuid: "07595179-...",
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// Get a single file
|
|
103
|
+
const file = await upthing.getFile("d98b6a92-...");
|
|
104
|
+
console.log(file.url, file.mime_type, file.size_bytes);
|
|
105
|
+
|
|
106
|
+
// Delete a file (removes S3 object + soft-deletes DB row)
|
|
107
|
+
await upthing.deleteFile("d98b6a92-...");
|
|
108
|
+
|
|
109
|
+
// Generate a signed URL (for files with url_mode: "signed")
|
|
110
|
+
const { url, expires_in } = await upthing.getSignedUrl("d98b6a92-...", 7200);
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
#### List files options
|
|
114
|
+
|
|
115
|
+
| Option | Type | Default | Description |
|
|
116
|
+
| ------------- | ------ | ------- | ------------------------------------ |
|
|
117
|
+
| `projectUuid` | string | — | Filter by project |
|
|
118
|
+
| `limit` | number | 50 | Results per page (1–200) |
|
|
119
|
+
| `offset` | number | 0 | Pagination offset |
|
|
120
|
+
|
|
64
121
|
### Proxy
|
|
65
122
|
|
|
66
123
|
```typescript
|
|
67
|
-
// Build a URL
|
|
124
|
+
// Build a URL for domain-auth proxy (no API key needed)
|
|
68
125
|
const src = upthing.proxyUrl("https://example.com/image.jpg");
|
|
69
126
|
const src = upthing.proxyUrl("https://example.com/image.jpg", {
|
|
70
127
|
projectUuid: "07595179-...",
|
|
71
128
|
ttlSeconds: 3600,
|
|
72
129
|
});
|
|
73
130
|
|
|
74
|
-
// Fetch the image bytes server-side
|
|
131
|
+
// Fetch the image bytes server-side (requires API key)
|
|
75
132
|
const response = await upthing.proxyFetch("https://example.com/image.jpg");
|
|
76
133
|
const buffer = await response.arrayBuffer();
|
|
77
134
|
```
|
|
@@ -90,7 +147,7 @@ upthing.permanentUrl("UgjIzXI3ZolZ");
|
|
|
90
147
|
import { UpThingSDKError } from "upthing-sdk";
|
|
91
148
|
|
|
92
149
|
try {
|
|
93
|
-
await upthing.
|
|
150
|
+
await upthing.uploadBlob(file, "huge.mp4");
|
|
94
151
|
} catch (err) {
|
|
95
152
|
if (err instanceof UpThingSDKError) {
|
|
96
153
|
console.error(err.status, err.message);
|
|
@@ -99,20 +156,26 @@ try {
|
|
|
99
156
|
}
|
|
100
157
|
```
|
|
101
158
|
|
|
102
|
-
|
|
159
|
+
All methods except `proxyUrl()` and `permanentUrl()` require an API key and throw immediately with a helpful message if none was provided.
|
|
160
|
+
|
|
161
|
+
## Browser / React / Next.js usage
|
|
103
162
|
|
|
104
163
|
```typescript
|
|
105
|
-
|
|
164
|
+
"use client";
|
|
165
|
+
import { UpThingClient } from "upthing-sdk";
|
|
166
|
+
|
|
167
|
+
const upthing = new UpThingClient();
|
|
106
168
|
|
|
107
|
-
// Proxy images directly in HTML — no
|
|
108
|
-
|
|
169
|
+
// Proxy images directly in HTML — no API key needed with domain auth
|
|
170
|
+
<img src={upthing.proxyUrl("https://example.com/photo.jpg")} />
|
|
109
171
|
|
|
110
|
-
// Upload from a file input
|
|
172
|
+
// Upload from a file input (requires API key)
|
|
173
|
+
const uploader = new UpThingClient({ apiKey: "ak_..." });
|
|
111
174
|
const input = document.querySelector<HTMLInputElement>("#file-input")!;
|
|
112
175
|
input.addEventListener("change", async () => {
|
|
113
176
|
const file = input.files?.[0];
|
|
114
177
|
if (!file) return;
|
|
115
|
-
const result = await
|
|
178
|
+
const result = await uploader.uploadBlob(file, file.name);
|
|
116
179
|
console.log("Uploaded:", result.url);
|
|
117
180
|
});
|
|
118
181
|
```
|
package/dist/index.d.ts
CHANGED
|
@@ -20,6 +20,23 @@ export interface UploadOptions {
|
|
|
20
20
|
projectUuid?: string;
|
|
21
21
|
ttlSeconds?: number;
|
|
22
22
|
}
|
|
23
|
+
export interface ListFilesOptions {
|
|
24
|
+
projectUuid?: string;
|
|
25
|
+
limit?: number;
|
|
26
|
+
offset?: number;
|
|
27
|
+
}
|
|
28
|
+
export interface ListFilesResponse {
|
|
29
|
+
data: UpThingFile[];
|
|
30
|
+
pagination: {
|
|
31
|
+
limit: number;
|
|
32
|
+
offset: number;
|
|
33
|
+
total: number;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export interface SignedUrlResponse {
|
|
37
|
+
url: string;
|
|
38
|
+
expires_in: number;
|
|
39
|
+
}
|
|
23
40
|
export interface ProxyOptions {
|
|
24
41
|
projectUuid?: string;
|
|
25
42
|
ttlSeconds?: number;
|
|
@@ -41,10 +58,6 @@ export declare class UpThingClient {
|
|
|
41
58
|
private readonly apiKey;
|
|
42
59
|
private readonly baseUrl;
|
|
43
60
|
constructor(options?: UpThingClientOptions);
|
|
44
|
-
/**
|
|
45
|
-
* Upload a file from a local path (Node.js only).
|
|
46
|
-
*/
|
|
47
|
-
uploadFile(filePath: string, options?: UploadOptions): Promise<UpThingFile>;
|
|
48
61
|
/**
|
|
49
62
|
* Upload a Blob/File (works in Node.js and browsers).
|
|
50
63
|
*/
|
|
@@ -57,6 +70,26 @@ export declare class UpThingClient {
|
|
|
57
70
|
* Upload base64-encoded data.
|
|
58
71
|
*/
|
|
59
72
|
uploadBase64(base64Data: string, filename: string, options?: UploadOptions): Promise<UpThingFile>;
|
|
73
|
+
/**
|
|
74
|
+
* List files owned by the authenticated user.
|
|
75
|
+
* Requires the `read` scope if the API key uses scoped permissions.
|
|
76
|
+
*/
|
|
77
|
+
listFiles(options?: ListFilesOptions): Promise<ListFilesResponse>;
|
|
78
|
+
/**
|
|
79
|
+
* Get a single file's metadata by UUID.
|
|
80
|
+
* Requires the `read` scope if the API key uses scoped permissions.
|
|
81
|
+
*/
|
|
82
|
+
getFile(uuid: string): Promise<UpThingFile>;
|
|
83
|
+
/**
|
|
84
|
+
* Delete a file by UUID. Removes the S3 object and soft-deletes the DB row.
|
|
85
|
+
* Requires the `delete` scope if the API key uses scoped permissions.
|
|
86
|
+
*/
|
|
87
|
+
deleteFile(uuid: string): Promise<void>;
|
|
88
|
+
/**
|
|
89
|
+
* Generate a time-limited signed delivery URL for a file.
|
|
90
|
+
* Requires the `read` scope if the API key uses scoped permissions.
|
|
91
|
+
*/
|
|
92
|
+
getSignedUrl(uuid: string, ttlSeconds?: number): Promise<SignedUrlResponse>;
|
|
60
93
|
/**
|
|
61
94
|
* Build a proxy query-string URL (without auth). Useful when the
|
|
62
95
|
* project uses `domain` auth mode and no API key is needed in the
|
|
@@ -73,7 +106,9 @@ export declare class UpThingClient {
|
|
|
73
106
|
* Build a permanent delivery URL for a public_id.
|
|
74
107
|
*/
|
|
75
108
|
permanentUrl(publicId: string): string;
|
|
76
|
-
|
|
77
|
-
|
|
109
|
+
/** @internal */
|
|
110
|
+
requireKey(method: string): void;
|
|
111
|
+
/** @internal */
|
|
112
|
+
request<T>(method: string, path: string, body?: FormData | Record<string, unknown>): Promise<T>;
|
|
78
113
|
}
|
|
79
114
|
export default UpThingClient;
|
package/dist/index.js
CHANGED
|
@@ -16,22 +16,6 @@ export class UpThingClient {
|
|
|
16
16
|
this.baseUrl = (options.baseUrl ?? "https://upthing.2klabs.xyz").replace(/\/$/, "");
|
|
17
17
|
}
|
|
18
18
|
// ── Upload ──────────────────────────────────────────────────────────
|
|
19
|
-
/**
|
|
20
|
-
* Upload a file from a local path (Node.js only).
|
|
21
|
-
*/
|
|
22
|
-
async uploadFile(filePath, options) {
|
|
23
|
-
const fs = await import("fs");
|
|
24
|
-
const path = await import("path");
|
|
25
|
-
const form = new FormData();
|
|
26
|
-
const blob = new Blob([fs.readFileSync(filePath)]);
|
|
27
|
-
const name = options?.filename ?? path.basename(filePath);
|
|
28
|
-
form.append("file", blob, name);
|
|
29
|
-
if (options?.projectUuid)
|
|
30
|
-
form.append("project_uuid", options.projectUuid);
|
|
31
|
-
if (options?.ttlSeconds != null)
|
|
32
|
-
form.append("ttl_seconds", String(options.ttlSeconds));
|
|
33
|
-
return this.request("POST", "/api/upload", form).then((r) => r.file);
|
|
34
|
-
}
|
|
35
19
|
/**
|
|
36
20
|
* Upload a Blob/File (works in Node.js and browsers).
|
|
37
21
|
*/
|
|
@@ -62,6 +46,47 @@ export class UpThingClient {
|
|
|
62
46
|
ttl_seconds: options?.ttlSeconds,
|
|
63
47
|
}).then((r) => r.file);
|
|
64
48
|
}
|
|
49
|
+
// ── Files ───────────────────────────────────────────────────────────
|
|
50
|
+
/**
|
|
51
|
+
* List files owned by the authenticated user.
|
|
52
|
+
* Requires the `read` scope if the API key uses scoped permissions.
|
|
53
|
+
*/
|
|
54
|
+
async listFiles(options) {
|
|
55
|
+
const params = new URLSearchParams();
|
|
56
|
+
if (options?.projectUuid)
|
|
57
|
+
params.set("project_uuid", options.projectUuid);
|
|
58
|
+
if (options?.limit != null)
|
|
59
|
+
params.set("limit", String(options.limit));
|
|
60
|
+
if (options?.offset != null)
|
|
61
|
+
params.set("offset", String(options.offset));
|
|
62
|
+
const qs = params.toString();
|
|
63
|
+
return this.request("GET", `/api/files${qs ? `?${qs}` : ""}`);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Get a single file's metadata by UUID.
|
|
67
|
+
* Requires the `read` scope if the API key uses scoped permissions.
|
|
68
|
+
*/
|
|
69
|
+
async getFile(uuid) {
|
|
70
|
+
return this.request("GET", `/api/files/${uuid}`).then((r) => r.file);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Delete a file by UUID. Removes the S3 object and soft-deletes the DB row.
|
|
74
|
+
* Requires the `delete` scope if the API key uses scoped permissions.
|
|
75
|
+
*/
|
|
76
|
+
async deleteFile(uuid) {
|
|
77
|
+
await this.request("DELETE", `/api/files/${uuid}`);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Generate a time-limited signed delivery URL for a file.
|
|
81
|
+
* Requires the `read` scope if the API key uses scoped permissions.
|
|
82
|
+
*/
|
|
83
|
+
async getSignedUrl(uuid, ttlSeconds) {
|
|
84
|
+
const params = new URLSearchParams();
|
|
85
|
+
if (ttlSeconds != null)
|
|
86
|
+
params.set("ttl_seconds", String(ttlSeconds));
|
|
87
|
+
const qs = params.toString();
|
|
88
|
+
return this.request("GET", `/api/files/${uuid}/signed-url${qs ? `?${qs}` : ""}`);
|
|
89
|
+
}
|
|
65
90
|
// ── Proxy ───────────────────────────────────────────────────────────
|
|
66
91
|
/**
|
|
67
92
|
* Build a proxy query-string URL (without auth). Useful when the
|
|
@@ -101,12 +126,14 @@ export class UpThingClient {
|
|
|
101
126
|
return `${this.baseUrl}/f/${publicId}`;
|
|
102
127
|
}
|
|
103
128
|
// ── Internal ────────────────────────────────────────────────────────
|
|
129
|
+
/** @internal */
|
|
104
130
|
requireKey(method) {
|
|
105
131
|
if (!this.apiKey) {
|
|
106
132
|
throw new Error(`UpThingClient.${method}() requires an apiKey. ` +
|
|
107
133
|
`Pass one via new UpThingClient({ apiKey: "ak_..." }).`);
|
|
108
134
|
}
|
|
109
135
|
}
|
|
136
|
+
/** @internal */
|
|
110
137
|
async request(method, path, body) {
|
|
111
138
|
this.requireKey("request");
|
|
112
139
|
const headers = {
|
|
@@ -125,6 +152,8 @@ export class UpThingClient {
|
|
|
125
152
|
headers,
|
|
126
153
|
body: requestBody,
|
|
127
154
|
});
|
|
155
|
+
if (res.status === 204)
|
|
156
|
+
return undefined;
|
|
128
157
|
if (!res.ok) {
|
|
129
158
|
const err = await res.json().catch(() => ({ error: `HTTP ${res.status}`, code: 0 }));
|
|
130
159
|
throw new UpThingSDKError(res.status, err);
|
package/dist/node.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { UpThingClient, type UploadOptions, type UpThingFile } from "./index.js";
|
|
2
|
+
export declare class UpThingNodeClient extends UpThingClient {
|
|
3
|
+
/**
|
|
4
|
+
* Upload a file from a local path (Node.js only).
|
|
5
|
+
*/
|
|
6
|
+
uploadFile(filePath: string, options?: UploadOptions): Promise<UpThingFile>;
|
|
7
|
+
}
|
|
8
|
+
export * from "./index.js";
|
|
9
|
+
export default UpThingNodeClient;
|
package/dist/node.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { UpThingClient } from "./index.js";
|
|
2
|
+
import { readFileSync } from "fs";
|
|
3
|
+
import { basename } from "path";
|
|
4
|
+
export class UpThingNodeClient extends UpThingClient {
|
|
5
|
+
/**
|
|
6
|
+
* Upload a file from a local path (Node.js only).
|
|
7
|
+
*/
|
|
8
|
+
async uploadFile(filePath, options) {
|
|
9
|
+
const form = new FormData();
|
|
10
|
+
const blob = new Blob([readFileSync(filePath)]);
|
|
11
|
+
const name = options?.filename ?? basename(filePath);
|
|
12
|
+
form.append("file", blob, name);
|
|
13
|
+
if (options?.projectUuid)
|
|
14
|
+
form.append("project_uuid", options.projectUuid);
|
|
15
|
+
if (options?.ttlSeconds != null)
|
|
16
|
+
form.append("ttl_seconds", String(options.ttlSeconds));
|
|
17
|
+
this.requireKey("uploadFile");
|
|
18
|
+
return this.request("POST", "/api/upload", form).then((r) => r.file);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export * from "./index.js";
|
|
22
|
+
export default UpThingNodeClient;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "upthing-sdk",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "TypeScript SDK for upthing.2klabs.xyz — upload
|
|
3
|
+
"version": "1.0.3",
|
|
4
|
+
"description": "TypeScript SDK for upthing.2klabs.xyz — upload, manage, and proxy files",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -12,6 +12,10 @@
|
|
|
12
12
|
".": {
|
|
13
13
|
"import": "./dist/index.js",
|
|
14
14
|
"types": "./dist/index.d.ts"
|
|
15
|
+
},
|
|
16
|
+
"./node": {
|
|
17
|
+
"import": "./dist/node.js",
|
|
18
|
+
"types": "./dist/node.d.ts"
|
|
15
19
|
}
|
|
16
20
|
},
|
|
17
21
|
"scripts": {
|