@howells/stow-server 0.1.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.
@@ -0,0 +1,302 @@
1
+ /**
2
+ * Stow Server SDK
3
+ *
4
+ * Server-side SDK for Node.js environments.
5
+ * Use this to upload files, generate presigned URLs, and manage files from your server.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { StowServer } from "@howells/stow-server";
10
+ *
11
+ * // Scoped API key — bucket is implicit
12
+ * const stow = new StowServer(process.env.STOW_API_KEY!);
13
+ *
14
+ * // Global API key — specify bucket
15
+ * const stow = new StowServer({
16
+ * apiKey: process.env.STOW_API_KEY!,
17
+ * bucket: "my-blog",
18
+ * });
19
+ *
20
+ * const result = await stow.uploadFromUrl("https://example.com/image.jpg", "image.jpg");
21
+ * console.log(result.url);
22
+ * ```
23
+ */
24
+ declare class StowError extends Error {
25
+ readonly status: number;
26
+ readonly code?: string;
27
+ constructor(message: string, status: number, code?: string);
28
+ }
29
+ interface StowServerConfig {
30
+ apiKey: string;
31
+ baseUrl?: string;
32
+ /** Default bucket name or ID. Required for global API keys. */
33
+ bucket?: string;
34
+ }
35
+ interface UploadResult {
36
+ key: string;
37
+ url: string | null;
38
+ size: number;
39
+ contentType: string;
40
+ metadata?: Record<string, string>;
41
+ }
42
+ interface TransformOptions {
43
+ width?: number;
44
+ height?: number;
45
+ quality?: number;
46
+ format?: "webp" | "avif" | "jpeg" | "png";
47
+ }
48
+ interface ListFilesResult {
49
+ files: Array<{
50
+ key: string;
51
+ size: number;
52
+ lastModified: string;
53
+ url: string | null;
54
+ metadata?: Record<string, string>;
55
+ }>;
56
+ nextCursor: string | null;
57
+ }
58
+ interface DropResult {
59
+ shortId: string;
60
+ url: string;
61
+ filename: string;
62
+ size: number;
63
+ contentType: string;
64
+ }
65
+ interface Drop {
66
+ id: string;
67
+ shortId: string;
68
+ url: string;
69
+ filename: string;
70
+ size: number;
71
+ contentType: string;
72
+ createdAt: string;
73
+ }
74
+ interface ListDropsResult {
75
+ drops: Drop[];
76
+ usage: {
77
+ bytes: number;
78
+ limit: number;
79
+ };
80
+ }
81
+ interface PresignResult {
82
+ /** The file key that will be created */
83
+ fileKey: string;
84
+ /** URL to PUT the file to */
85
+ uploadUrl: string;
86
+ /** The R2 key for the file */
87
+ r2Key: string;
88
+ /** URL to call to confirm the upload */
89
+ confirmUrl: string;
90
+ }
91
+ interface PresignRequest {
92
+ filename: string;
93
+ contentType: string;
94
+ /** File size in bytes */
95
+ size: number;
96
+ /** Optional route/folder */
97
+ route?: string;
98
+ /** Override the default bucket */
99
+ bucket?: string;
100
+ /** Custom metadata to attach to the file */
101
+ metadata?: Record<string, string>;
102
+ }
103
+ interface ConfirmUploadRequest {
104
+ fileKey: string;
105
+ size: number;
106
+ contentType: string;
107
+ /** Override the default bucket */
108
+ bucket?: string;
109
+ /** Custom metadata to attach to the file */
110
+ metadata?: Record<string, string>;
111
+ }
112
+ interface SimilarSearchRequest {
113
+ /** Find files similar to this file key */
114
+ fileKey?: string;
115
+ /** Search directly with a vector (1024 dimensions) */
116
+ vector?: number[];
117
+ /** Bucket name or ID to scope search */
118
+ bucket?: string;
119
+ /** Max results (default 10, max 50) */
120
+ limit?: number;
121
+ }
122
+ interface SimilarSearchResult {
123
+ results: Array<{
124
+ id: string;
125
+ key: string;
126
+ bucketId: string;
127
+ originalFilename: string | null;
128
+ size: number;
129
+ contentType: string;
130
+ metadata: Record<string, string> | null;
131
+ embeddingStatus: string | null;
132
+ similarity: number;
133
+ createdAt: string;
134
+ }>;
135
+ }
136
+ declare class StowServer {
137
+ private readonly apiKey;
138
+ private readonly baseUrl;
139
+ private readonly bucket?;
140
+ constructor(config: StowServerConfig | string);
141
+ /**
142
+ * Get the base URL for this instance (used by client SDK)
143
+ */
144
+ getBaseUrl(): string;
145
+ /**
146
+ * Resolve the effective bucket for this request.
147
+ * Per-call override > constructor default.
148
+ */
149
+ private resolveBucket;
150
+ /**
151
+ * Append bucket query param to a URL path if set.
152
+ */
153
+ private withBucket;
154
+ /**
155
+ * Make an API request with proper error handling
156
+ */
157
+ private request;
158
+ /**
159
+ * Upload a file directly from the server
160
+ */
161
+ uploadFile(file: Buffer | Blob, options?: {
162
+ filename?: string;
163
+ contentType?: string;
164
+ route?: string;
165
+ /** Override the default bucket for this request */
166
+ bucket?: string;
167
+ /** Custom metadata to attach to the file */
168
+ metadata?: Record<string, string>;
169
+ }): Promise<UploadResult>;
170
+ /**
171
+ * Upload a file from a URL (server-side fetch + upload)
172
+ */
173
+ uploadFromUrl(url: string, filename: string, options?: {
174
+ bucket?: string;
175
+ metadata?: Record<string, string>;
176
+ }): Promise<UploadResult>;
177
+ /**
178
+ * Get a presigned URL for direct client-side upload.
179
+ *
180
+ * This enables uploads that bypass your server entirely:
181
+ * 1. Client calls your endpoint
182
+ * 2. Your endpoint calls this method
183
+ * 3. Client PUTs directly to the returned uploadUrl
184
+ * 4. Client calls confirmUpload to finalize
185
+ */
186
+ getPresignedUrl(request: PresignRequest): Promise<PresignResult>;
187
+ /**
188
+ * Confirm a presigned upload after the client has uploaded to R2.
189
+ * This creates the file record in the database.
190
+ */
191
+ confirmUpload(request: ConfirmUploadRequest): Promise<UploadResult>;
192
+ /**
193
+ * List files in the bucket
194
+ */
195
+ listFiles(options?: {
196
+ prefix?: string;
197
+ limit?: number;
198
+ cursor?: string;
199
+ bucket?: string;
200
+ /** Filter by tag slug */
201
+ tag?: string;
202
+ }): Promise<ListFilesResult>;
203
+ /**
204
+ * Delete a file by key
205
+ */
206
+ deleteFile(key: string, options?: {
207
+ bucket?: string;
208
+ }): Promise<void>;
209
+ /**
210
+ * Update metadata on an existing file
211
+ */
212
+ updateFileMetadata(key: string, metadata: Record<string, string>, options?: {
213
+ bucket?: string;
214
+ }): Promise<{
215
+ key: string;
216
+ metadata: Record<string, string>;
217
+ }>;
218
+ /**
219
+ * Get a transform URL for an image.
220
+ *
221
+ * Appends transform query params (?w=, ?h=, ?q=, ?f=) to a file URL.
222
+ * Transforms are applied at the edge by the Cloudflare Worker — no
223
+ * server round-trip needed.
224
+ *
225
+ * @param url - Full file URL (e.g. from upload result's fileUrl)
226
+ * @param options - Transform options (width, height, quality, format)
227
+ */
228
+ getTransformUrl(url: string, options?: TransformOptions): string;
229
+ /**
230
+ * Tags namespace for creating, listing, and deleting tags
231
+ */
232
+ get tags(): {
233
+ list: () => Promise<{
234
+ tags: Array<{
235
+ id: string;
236
+ name: string;
237
+ slug: string;
238
+ color: string | null;
239
+ createdAt: string;
240
+ }>;
241
+ }>;
242
+ create: (params: {
243
+ name: string;
244
+ color?: string;
245
+ }) => Promise<{
246
+ id: string;
247
+ name: string;
248
+ slug: string;
249
+ color: string | null;
250
+ createdAt: string;
251
+ }>;
252
+ delete: (id: string) => Promise<void>;
253
+ };
254
+ private listTags;
255
+ private createTag;
256
+ private deleteTag;
257
+ /**
258
+ * Add tags to a file
259
+ */
260
+ addTags(key: string, tagIds: string[], options?: {
261
+ bucket?: string;
262
+ }): Promise<void>;
263
+ /**
264
+ * Remove a tag from a file
265
+ */
266
+ removeTag(key: string, tagId: string, options?: {
267
+ bucket?: string;
268
+ }): Promise<void>;
269
+ /**
270
+ * Search namespace for vector similarity search
271
+ */
272
+ get search(): {
273
+ similar: (params: SimilarSearchRequest) => Promise<SimilarSearchResult>;
274
+ };
275
+ private searchSimilar;
276
+ /**
277
+ * Upload a file as a drop (quick share)
278
+ *
279
+ * Drops are simpler than bucket uploads - just upload and get a URL.
280
+ * No bucket setup required. 1GB storage limit per user.
281
+ *
282
+ * @example
283
+ * ```typescript
284
+ * const drop = await stow.drop(buffer, { filename: "screenshot.png" });
285
+ * console.log(drop.url); // https://d.stow.sh/x7kQ3m
286
+ * ```
287
+ */
288
+ drop(file: Buffer | Blob, options?: {
289
+ filename?: string;
290
+ contentType?: string;
291
+ }): Promise<DropResult>;
292
+ /**
293
+ * List all drops for the authenticated user
294
+ */
295
+ listDrops(): Promise<ListDropsResult>;
296
+ /**
297
+ * Delete a drop by ID
298
+ */
299
+ deleteDrop(id: string): Promise<void>;
300
+ }
301
+
302
+ export { type ConfirmUploadRequest, type Drop, type DropResult, type ListDropsResult, type ListFilesResult, type PresignRequest, type PresignResult, type SimilarSearchRequest, type SimilarSearchResult, StowError, StowServer, type StowServerConfig, type TransformOptions, type UploadResult };