upthing-sdk 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.
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
- ## Quick start
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 { UpThingClient } from "upthing-sdk";
24
+ import { UpThingNodeClient } from "upthing-sdk/node";
15
25
 
16
- const upthing = new UpThingClient({
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 — get a URL you can use directly
35
+ // Proxy an external image
26
36
  const src = upthing.proxyUrl("https://example.com/banner.jpg");
27
- // <img src={src} />
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?)`
57
+
58
+ | Option | Type | Default |
59
+ | --------- | ------ | ----------------------------- |
60
+ | `apiKey` | string | `""` (optional for proxy URL builders) |
61
+ | `baseUrl` | string | `https://upthing.2klabs.xyz` |
33
62
 
34
- | Option | Type | Default |
35
- | --------- | ------ | -------------------------------- |
36
- | `apiKey` | string | **required** |
37
- | `baseUrl` | string | `https://upthing.2klabs.xyz` |
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
 
@@ -64,14 +90,14 @@ await upthing.uploadBase64(base64String, "avatar.png");
64
90
  ### Proxy
65
91
 
66
92
  ```typescript
67
- // Build a URL that serves the proxied image (use in <img>, fetch, etc.)
93
+ // Build a URL for domain-auth proxy (no API key needed)
68
94
  const src = upthing.proxyUrl("https://example.com/image.jpg");
69
95
  const src = upthing.proxyUrl("https://example.com/image.jpg", {
70
96
  projectUuid: "07595179-...",
71
97
  ttlSeconds: 3600,
72
98
  });
73
99
 
74
- // Fetch the image bytes server-side
100
+ // Fetch the image bytes server-side (requires API key)
75
101
  const response = await upthing.proxyFetch("https://example.com/image.jpg");
76
102
  const buffer = await response.arrayBuffer();
77
103
  ```
@@ -90,7 +116,7 @@ upthing.permanentUrl("UgjIzXI3ZolZ");
90
116
  import { UpThingSDKError } from "upthing-sdk";
91
117
 
92
118
  try {
93
- await upthing.uploadFile("./huge.mp4");
119
+ await upthing.uploadBlob(file, "huge.mp4");
94
120
  } catch (err) {
95
121
  if (err instanceof UpThingSDKError) {
96
122
  console.error(err.status, err.message);
@@ -99,20 +125,26 @@ try {
99
125
  }
100
126
  ```
101
127
 
102
- ## Browser usage
128
+ Methods that require an API key (`uploadBlob`, `uploadBuffer`, `uploadBase64`, `uploadFile`, `proxyFetch`) throw immediately with a helpful message if no key was provided.
129
+
130
+ ## Browser / React / Next.js usage
103
131
 
104
132
  ```typescript
105
- const upthing = new UpThingClient({ apiKey: "ak_..." });
133
+ "use client";
134
+ import { UpThingClient } from "upthing-sdk";
135
+
136
+ const upthing = new UpThingClient();
106
137
 
107
- // Proxy images directly in HTML — no async needed
108
- document.querySelector("img")!.src = upthing.proxyUrl("https://example.com/photo.jpg");
138
+ // Proxy images directly in HTML — no API key needed with domain auth
139
+ <img src={upthing.proxyUrl("https://example.com/photo.jpg")} />
109
140
 
110
- // Upload from a file input
141
+ // Upload from a file input (requires API key)
142
+ const uploader = new UpThingClient({ apiKey: "ak_..." });
111
143
  const input = document.querySelector<HTMLInputElement>("#file-input")!;
112
144
  input.addEventListener("change", async () => {
113
145
  const file = input.files?.[0];
114
146
  if (!file) return;
115
- const result = await upthing.uploadBlob(file, file.name);
147
+ const result = await uploader.uploadBlob(file, file.name);
116
148
  console.log("Uploaded:", result.url);
117
149
  });
118
150
  ```
package/dist/index.d.ts CHANGED
@@ -34,17 +34,13 @@ export declare class UpThingSDKError extends Error {
34
34
  constructor(status: number, body: UpThingError);
35
35
  }
36
36
  export interface UpThingClientOptions {
37
- apiKey: string;
37
+ apiKey?: string;
38
38
  baseUrl?: string;
39
39
  }
40
40
  export declare class UpThingClient {
41
41
  private readonly apiKey;
42
42
  private readonly baseUrl;
43
- constructor(options: UpThingClientOptions);
44
- /**
45
- * Upload a file from a local path (Node.js only).
46
- */
47
- uploadFile(filePath: string, options?: UploadOptions): Promise<UpThingFile>;
43
+ constructor(options?: UpThingClientOptions);
48
44
  /**
49
45
  * Upload a Blob/File (works in Node.js and browsers).
50
46
  */
@@ -66,12 +62,16 @@ export declare class UpThingClient {
66
62
  /**
67
63
  * Fetch a proxied image and return the raw Response.
68
64
  * Sends the API key via header (never exposed in the URL).
65
+ * Requires an API key — use proxyUrl() for domain-auth-only requests.
69
66
  */
70
67
  proxyFetch(url: string, options?: ProxyOptions): Promise<Response>;
71
68
  /**
72
69
  * Build a permanent delivery URL for a public_id.
73
70
  */
74
71
  permanentUrl(publicId: string): string;
75
- private request;
72
+ /** @internal */
73
+ requireKey(method: string): void;
74
+ /** @internal */
75
+ request<T>(method: string, path: string, body?: FormData | Record<string, unknown>): Promise<T>;
76
76
  }
77
77
  export default UpThingClient;
package/dist/index.js CHANGED
@@ -11,27 +11,11 @@ export class UpThingSDKError extends Error {
11
11
  export class UpThingClient {
12
12
  apiKey;
13
13
  baseUrl;
14
- constructor(options) {
15
- this.apiKey = options.apiKey;
14
+ constructor(options = {}) {
15
+ this.apiKey = options.apiKey ?? "";
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
  */
@@ -79,8 +63,10 @@ export class UpThingClient {
79
63
  /**
80
64
  * Fetch a proxied image and return the raw Response.
81
65
  * Sends the API key via header (never exposed in the URL).
66
+ * Requires an API key — use proxyUrl() for domain-auth-only requests.
82
67
  */
83
68
  async proxyFetch(url, options) {
69
+ this.requireKey("proxyFetch");
84
70
  const target = this.proxyUrl(url, options);
85
71
  const res = await fetch(target, {
86
72
  headers: { "X-API-Key": this.apiKey },
@@ -99,7 +85,16 @@ export class UpThingClient {
99
85
  return `${this.baseUrl}/f/${publicId}`;
100
86
  }
101
87
  // ── Internal ────────────────────────────────────────────────────────
88
+ /** @internal */
89
+ requireKey(method) {
90
+ if (!this.apiKey) {
91
+ throw new Error(`UpThingClient.${method}() requires an apiKey. ` +
92
+ `Pass one via new UpThingClient({ apiKey: "ak_..." }).`);
93
+ }
94
+ }
95
+ /** @internal */
102
96
  async request(method, path, body) {
97
+ this.requireKey("request");
103
98
  const headers = {
104
99
  "X-API-Key": this.apiKey,
105
100
  };
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,6 +1,6 @@
1
1
  {
2
2
  "name": "upthing-sdk",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "TypeScript SDK for upthing.2klabs.xyz — upload files, proxy images",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -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": {