@howells/stow-server 0.3.0 → 0.3.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Stow
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/index.d.mts CHANGED
@@ -21,11 +21,13 @@
21
21
  * console.log(result.url);
22
22
  * ```
23
23
  */
24
+ /** Error thrown when the Stow API returns a non-success response. */
24
25
  declare class StowError extends Error {
25
26
  readonly status: number;
26
27
  readonly code?: string;
27
28
  constructor(message: string, status: number, code?: string);
28
29
  }
30
+ /** Configuration for creating a {@link StowServer} instance. */
29
31
  interface StowServerConfig {
30
32
  apiKey: string;
31
33
  baseUrl?: string;
@@ -36,6 +38,7 @@ interface StowServerConfig {
36
38
  /** Request timeout in ms (default 30000) */
37
39
  timeout?: number;
38
40
  }
41
+ /** Response returned after an upload, confirm, or replace operation. */
39
42
  interface UploadResult {
40
43
  contentType: string;
41
44
  /** True when upload short-circuited to an existing file by content hash dedupe. */
@@ -45,6 +48,7 @@ interface UploadResult {
45
48
  size: number;
46
49
  url: string | null;
47
50
  }
51
+ /** Bucket metadata returned by bucket APIs. */
48
52
  interface BucketResult {
49
53
  allowedTypes?: string[] | null;
50
54
  createdAt?: string;
@@ -59,9 +63,11 @@ interface BucketResult {
59
63
  storageQuota?: number | null;
60
64
  usageBytes?: number;
61
65
  }
66
+ /** Result payload from `listBuckets()`. */
62
67
  interface ListBucketsResult {
63
68
  buckets: BucketResult[];
64
69
  }
70
+ /** Input payload for `createBucket()`. */
65
71
  interface CreateBucketRequest {
66
72
  allowedTypes?: string[];
67
73
  description?: string;
@@ -73,6 +79,7 @@ interface CreateBucketRequest {
73
79
  storageQuota?: number;
74
80
  webhookUrl?: string;
75
81
  }
82
+ /** Partial update payload for `updateBucket()`. */
76
83
  interface UpdateBucketRequest {
77
84
  allowedTypes?: string[] | null;
78
85
  description?: string | null;
@@ -84,6 +91,7 @@ interface UpdateBucketRequest {
84
91
  storageQuota?: number | null;
85
92
  webhookUrl?: string | null;
86
93
  }
94
+ /** Account and credential details for the active API key. */
87
95
  interface WhoamiResult {
88
96
  key?: {
89
97
  name: string;
@@ -99,16 +107,19 @@ interface WhoamiResult {
99
107
  email: string;
100
108
  };
101
109
  }
110
+ /** Query parameters for signed image transform URLs. */
102
111
  interface TransformOptions {
103
112
  format?: "webp" | "avif" | "jpeg" | "png";
104
113
  height?: number;
105
114
  quality?: number;
106
115
  width?: number;
107
116
  }
117
+ /** Paginated file listing payload. */
108
118
  interface ListFilesResult {
109
119
  files: ListFilesItem[];
110
120
  nextCursor: string | null;
111
121
  }
122
+ /** One extracted palette color for a file. */
112
123
  interface FileColor {
113
124
  hex: string;
114
125
  hsl: {
@@ -130,6 +141,7 @@ interface FileColor {
130
141
  position: number;
131
142
  proportion: number;
132
143
  }
144
+ /** Aggregated color profile metadata extracted from a file. */
133
145
  interface FileColorProfile {
134
146
  accent: {
135
147
  hex: string;
@@ -157,6 +169,7 @@ interface FileColorProfile {
157
169
  dominantFamily: string | null;
158
170
  };
159
171
  }
172
+ /** File item returned from list/search APIs. */
160
173
  interface ListFilesItem {
161
174
  colorProfile?: FileColorProfile | null;
162
175
  colors?: FileColor[];
@@ -169,6 +182,7 @@ interface ListFilesItem {
169
182
  url: string | null;
170
183
  width?: number | null;
171
184
  }
185
+ /** Result payload returned from `drop()`. */
172
186
  interface DropResult {
173
187
  contentType: string;
174
188
  filename: string;
@@ -176,6 +190,7 @@ interface DropResult {
176
190
  size: number;
177
191
  url: string;
178
192
  }
193
+ /** Drop entity returned from drop listing APIs. */
179
194
  interface Drop {
180
195
  contentType: string;
181
196
  createdAt: string;
@@ -185,6 +200,7 @@ interface Drop {
185
200
  size: number;
186
201
  url: string;
187
202
  }
203
+ /** Result payload from `listDrops()`. */
188
204
  interface ListDropsResult {
189
205
  drops: Drop[];
190
206
  usage: {
@@ -192,6 +208,7 @@ interface ListDropsResult {
192
208
  limit: number;
193
209
  };
194
210
  }
211
+ /** Full file detail payload returned by `getFile()`. */
195
212
  interface FileResult {
196
213
  colorProfile: FileColorProfile | null;
197
214
  colors: FileColor[];
@@ -206,11 +223,13 @@ interface FileResult {
206
223
  url: string | null;
207
224
  width: number | null;
208
225
  }
226
+ /** Input for creating a taste profile. */
209
227
  interface ProfileCreateRequest {
210
228
  bucket?: string;
211
229
  fileKeys?: string[];
212
230
  name?: string;
213
231
  }
232
+ /** Cluster summary within a taste profile. */
214
233
  interface ProfileClusterResult {
215
234
  description: string | null;
216
235
  id: string;
@@ -218,8 +237,20 @@ interface ProfileClusterResult {
218
237
  name: string | null;
219
238
  nameGeneratedAt: string | null;
220
239
  signalCount: number;
240
+ /**
241
+ * Optional taxonomy terms inferred for the cluster centroid.
242
+ * Absent when taxonomy data is unavailable for the bucket/profile.
243
+ */
244
+ tags?: Array<{
245
+ group: string;
246
+ groupSlug: string;
247
+ similarity: number;
248
+ tag: string;
249
+ tagSlug: string;
250
+ }>;
221
251
  totalWeight: number;
222
252
  }
253
+ /** Taste profile detail payload. */
223
254
  interface ProfileResult {
224
255
  clusters?: ProfileClusterResult[];
225
256
  createdAt: string;
@@ -230,58 +261,70 @@ interface ProfileResult {
230
261
  updatedAt: string;
231
262
  vector: number[] | null;
232
263
  }
264
+ /** Input for recomputing profile clusters. */
233
265
  interface ReclusterRequest {
234
266
  clusterCount?: number;
235
267
  }
268
+ /** Result payload from cluster recomputation. */
236
269
  interface ReclusterResult {
237
270
  clustered: boolean;
238
271
  clusters: ProfileClusterResult[];
239
272
  profileId: string;
240
273
  totalSignals: number;
241
274
  }
275
+ /** Input for updating cluster display metadata. */
242
276
  interface RenameClusterRequest {
243
277
  description?: string;
244
278
  name?: string;
245
279
  }
280
+ /** Result payload when adding/removing files from a profile. */
246
281
  interface ProfileFilesResult {
247
282
  fileCount: number;
248
283
  id: string;
249
284
  }
285
+ /** Supported signal types used to tune taste profiles. */
250
286
  type ProfileSignalType = "view" | "view_long" | "click" | "like" | "save" | "choose" | "purchase" | "share" | "dismiss" | "skip" | "reject" | "report" | "custom";
287
+ /** One signal item submitted to profile signal APIs. */
251
288
  interface ProfileSignalInput {
252
289
  context?: Record<string, unknown>;
253
290
  fileKey: string;
254
291
  type: ProfileSignalType;
255
292
  weight?: number;
256
293
  }
294
+ /** Persisted profile signal entry returned by the API. */
257
295
  interface ProfileSignalResult {
258
296
  fileKey: string;
259
297
  id: string;
260
298
  type: ProfileSignalType;
261
299
  weight: number;
262
300
  }
301
+ /** Result payload when listing or appending profile signals. */
263
302
  interface ProfileSignalsResponse {
264
303
  profileId: string;
265
304
  signals: ProfileSignalResult[];
266
305
  totalSignals: number;
267
306
  vectorUpdated: boolean;
268
307
  }
308
+ /** Result payload after removing profile signals. */
269
309
  interface DeleteProfileSignalsResult {
270
310
  profileId: string;
271
311
  removed: number;
272
312
  totalSignals: number;
273
313
  vectorUpdated: boolean;
274
314
  }
315
+ /** Result payload from task trigger endpoints. */
275
316
  interface TaskTriggerResult {
276
317
  key: string;
277
318
  triggered: string;
278
319
  }
320
+ /** Result payload from replace operations. */
279
321
  interface ReplaceResult {
280
322
  contentType: string;
281
323
  key: string;
282
324
  size: number;
283
325
  triggered: string[];
284
326
  }
327
+ /** Shared structured filters for semantic search endpoints. */
285
328
  interface SearchFilters {
286
329
  color?: {
287
330
  dominantFamily?: string[];
@@ -305,7 +348,9 @@ interface SearchFilters {
305
348
  taxonomies?: string[];
306
349
  taxonomyGroups?: string[];
307
350
  }
351
+ /** Optional enrichment blocks that can be included in search responses. */
308
352
  type SearchIncludeField = "tags" | "taxonomies" | "colors" | "colorProfile";
353
+ /** Input payload for text-based semantic search. */
309
354
  interface TextSearchRequest {
310
355
  bucket?: string;
311
356
  filters?: SearchFilters;
@@ -333,6 +378,7 @@ interface PresignDedupeResult {
333
378
  }
334
379
  /** Presign response is either a new upload or a dedup hit. Check `result.dedupe` to differentiate. */
335
380
  type PresignResult = PresignNewResult | PresignDedupeResult;
381
+ /** Input payload for requesting presigned upload URLs. */
336
382
  interface PresignRequest {
337
383
  /** Override the default bucket */
338
384
  bucket?: string;
@@ -347,6 +393,7 @@ interface PresignRequest {
347
393
  /** File size in bytes */
348
394
  size: number;
349
395
  }
396
+ /** Input payload for confirming a direct upload. */
350
397
  interface ConfirmUploadRequest {
351
398
  /** Request AI-generated alt text for images */
352
399
  altText?: boolean;
@@ -355,8 +402,6 @@ interface ConfirmUploadRequest {
355
402
  /** SHA-256 hex digest of file content. Stored with the file record for future dedup lookups. */
356
403
  contentHash?: string;
357
404
  contentType: string;
358
- /** Fire KV sync in background instead of blocking. Saves ~100ms per upload. */
359
- deferKvSync?: boolean;
360
405
  /** Request AI-generated description for images */
361
406
  describe?: boolean;
362
407
  fileKey: string;
@@ -368,6 +413,7 @@ interface ConfirmUploadRequest {
368
413
  /** Request AI-generated title for images */
369
414
  title?: boolean;
370
415
  }
416
+ /** Input payload for similarity search. */
371
417
  interface SimilarSearchRequest {
372
418
  /** Bucket name or ID to scope search */
373
419
  bucket?: string;
@@ -390,6 +436,7 @@ interface SimilarSearchRequest {
390
436
  /** Search directly with a vector (1024 dimensions) */
391
437
  vector?: number[];
392
438
  }
439
+ /** Input payload for diversity-aware search. */
393
440
  interface DiverseSearchRequest {
394
441
  /** Bucket name or ID to scope search */
395
442
  bucket?: string;
@@ -414,6 +461,7 @@ interface DiverseSearchRequest {
414
461
  /** Search directly with a vector (1024 dimensions) as the relevance seed */
415
462
  vector?: number[];
416
463
  }
464
+ /** One semantic search result item. */
417
465
  interface SearchResultItem {
418
466
  bucketId: string;
419
467
  colorProfile?: FileColorProfile | null;
@@ -441,15 +489,18 @@ interface SearchResultItem {
441
489
  }>;
442
490
  width?: number | null;
443
491
  }
492
+ /** Metadata describing server-side filter pruning. */
444
493
  interface FilteredMetadata {
445
494
  candidatesScanned: number;
446
495
  requested: number;
447
496
  returned: number;
448
497
  }
498
+ /** Result payload returned by similarity/diversity search endpoints. */
449
499
  interface SimilarSearchResult {
450
500
  filtered?: FilteredMetadata;
451
501
  results: SearchResultItem[];
452
502
  }
503
+ /** Input payload for color similarity search. */
453
504
  interface ColorSearchRequest {
454
505
  /** Bucket name or ID to scope search */
455
506
  bucket?: string;
@@ -468,6 +519,7 @@ interface ColorSearchRequest {
468
519
  b: number;
469
520
  };
470
521
  }
522
+ /** One color search result item. */
471
523
  interface ColorSearchResultItem {
472
524
  bucketId: string;
473
525
  colorDistance: number;
@@ -486,9 +538,11 @@ interface ColorSearchResultItem {
486
538
  proportion: number;
487
539
  };
488
540
  }
541
+ /** Result payload for color similarity search. */
489
542
  interface ColorSearchResult {
490
543
  results: ColorSearchResultItem[];
491
544
  }
545
+ /** Server-side SDK client for Stow's API. */
492
546
  declare class StowServer {
493
547
  private readonly apiKey;
494
548
  private readonly baseUrl;
@@ -634,16 +688,22 @@ declare class StowServer {
634
688
  * Extract color palette from an image file.
635
689
  * Requires a searchable bucket.
636
690
  */
637
- extractColors(key: string): Promise<TaskTriggerResult>;
691
+ extractColors(key: string, options?: {
692
+ bucket?: string;
693
+ }): Promise<TaskTriggerResult>;
638
694
  /**
639
695
  * Extract dimensions (width/height) from an image or video file.
640
696
  */
641
- extractDimensions(key: string): Promise<TaskTriggerResult>;
697
+ extractDimensions(key: string, options?: {
698
+ bucket?: string;
699
+ }): Promise<TaskTriggerResult>;
642
700
  /**
643
701
  * Generate a vector embedding for an image file.
644
702
  * Requires a searchable bucket.
645
703
  */
646
- embed(key: string): Promise<TaskTriggerResult>;
704
+ embed(key: string, options?: {
705
+ bucket?: string;
706
+ }): Promise<TaskTriggerResult>;
647
707
  /**
648
708
  * Replace a file's content by fetching from a new URL.
649
709
  *
package/dist/index.d.ts CHANGED
@@ -21,11 +21,13 @@
21
21
  * console.log(result.url);
22
22
  * ```
23
23
  */
24
+ /** Error thrown when the Stow API returns a non-success response. */
24
25
  declare class StowError extends Error {
25
26
  readonly status: number;
26
27
  readonly code?: string;
27
28
  constructor(message: string, status: number, code?: string);
28
29
  }
30
+ /** Configuration for creating a {@link StowServer} instance. */
29
31
  interface StowServerConfig {
30
32
  apiKey: string;
31
33
  baseUrl?: string;
@@ -36,6 +38,7 @@ interface StowServerConfig {
36
38
  /** Request timeout in ms (default 30000) */
37
39
  timeout?: number;
38
40
  }
41
+ /** Response returned after an upload, confirm, or replace operation. */
39
42
  interface UploadResult {
40
43
  contentType: string;
41
44
  /** True when upload short-circuited to an existing file by content hash dedupe. */
@@ -45,6 +48,7 @@ interface UploadResult {
45
48
  size: number;
46
49
  url: string | null;
47
50
  }
51
+ /** Bucket metadata returned by bucket APIs. */
48
52
  interface BucketResult {
49
53
  allowedTypes?: string[] | null;
50
54
  createdAt?: string;
@@ -59,9 +63,11 @@ interface BucketResult {
59
63
  storageQuota?: number | null;
60
64
  usageBytes?: number;
61
65
  }
66
+ /** Result payload from `listBuckets()`. */
62
67
  interface ListBucketsResult {
63
68
  buckets: BucketResult[];
64
69
  }
70
+ /** Input payload for `createBucket()`. */
65
71
  interface CreateBucketRequest {
66
72
  allowedTypes?: string[];
67
73
  description?: string;
@@ -73,6 +79,7 @@ interface CreateBucketRequest {
73
79
  storageQuota?: number;
74
80
  webhookUrl?: string;
75
81
  }
82
+ /** Partial update payload for `updateBucket()`. */
76
83
  interface UpdateBucketRequest {
77
84
  allowedTypes?: string[] | null;
78
85
  description?: string | null;
@@ -84,6 +91,7 @@ interface UpdateBucketRequest {
84
91
  storageQuota?: number | null;
85
92
  webhookUrl?: string | null;
86
93
  }
94
+ /** Account and credential details for the active API key. */
87
95
  interface WhoamiResult {
88
96
  key?: {
89
97
  name: string;
@@ -99,16 +107,19 @@ interface WhoamiResult {
99
107
  email: string;
100
108
  };
101
109
  }
110
+ /** Query parameters for signed image transform URLs. */
102
111
  interface TransformOptions {
103
112
  format?: "webp" | "avif" | "jpeg" | "png";
104
113
  height?: number;
105
114
  quality?: number;
106
115
  width?: number;
107
116
  }
117
+ /** Paginated file listing payload. */
108
118
  interface ListFilesResult {
109
119
  files: ListFilesItem[];
110
120
  nextCursor: string | null;
111
121
  }
122
+ /** One extracted palette color for a file. */
112
123
  interface FileColor {
113
124
  hex: string;
114
125
  hsl: {
@@ -130,6 +141,7 @@ interface FileColor {
130
141
  position: number;
131
142
  proportion: number;
132
143
  }
144
+ /** Aggregated color profile metadata extracted from a file. */
133
145
  interface FileColorProfile {
134
146
  accent: {
135
147
  hex: string;
@@ -157,6 +169,7 @@ interface FileColorProfile {
157
169
  dominantFamily: string | null;
158
170
  };
159
171
  }
172
+ /** File item returned from list/search APIs. */
160
173
  interface ListFilesItem {
161
174
  colorProfile?: FileColorProfile | null;
162
175
  colors?: FileColor[];
@@ -169,6 +182,7 @@ interface ListFilesItem {
169
182
  url: string | null;
170
183
  width?: number | null;
171
184
  }
185
+ /** Result payload returned from `drop()`. */
172
186
  interface DropResult {
173
187
  contentType: string;
174
188
  filename: string;
@@ -176,6 +190,7 @@ interface DropResult {
176
190
  size: number;
177
191
  url: string;
178
192
  }
193
+ /** Drop entity returned from drop listing APIs. */
179
194
  interface Drop {
180
195
  contentType: string;
181
196
  createdAt: string;
@@ -185,6 +200,7 @@ interface Drop {
185
200
  size: number;
186
201
  url: string;
187
202
  }
203
+ /** Result payload from `listDrops()`. */
188
204
  interface ListDropsResult {
189
205
  drops: Drop[];
190
206
  usage: {
@@ -192,6 +208,7 @@ interface ListDropsResult {
192
208
  limit: number;
193
209
  };
194
210
  }
211
+ /** Full file detail payload returned by `getFile()`. */
195
212
  interface FileResult {
196
213
  colorProfile: FileColorProfile | null;
197
214
  colors: FileColor[];
@@ -206,11 +223,13 @@ interface FileResult {
206
223
  url: string | null;
207
224
  width: number | null;
208
225
  }
226
+ /** Input for creating a taste profile. */
209
227
  interface ProfileCreateRequest {
210
228
  bucket?: string;
211
229
  fileKeys?: string[];
212
230
  name?: string;
213
231
  }
232
+ /** Cluster summary within a taste profile. */
214
233
  interface ProfileClusterResult {
215
234
  description: string | null;
216
235
  id: string;
@@ -218,8 +237,20 @@ interface ProfileClusterResult {
218
237
  name: string | null;
219
238
  nameGeneratedAt: string | null;
220
239
  signalCount: number;
240
+ /**
241
+ * Optional taxonomy terms inferred for the cluster centroid.
242
+ * Absent when taxonomy data is unavailable for the bucket/profile.
243
+ */
244
+ tags?: Array<{
245
+ group: string;
246
+ groupSlug: string;
247
+ similarity: number;
248
+ tag: string;
249
+ tagSlug: string;
250
+ }>;
221
251
  totalWeight: number;
222
252
  }
253
+ /** Taste profile detail payload. */
223
254
  interface ProfileResult {
224
255
  clusters?: ProfileClusterResult[];
225
256
  createdAt: string;
@@ -230,58 +261,70 @@ interface ProfileResult {
230
261
  updatedAt: string;
231
262
  vector: number[] | null;
232
263
  }
264
+ /** Input for recomputing profile clusters. */
233
265
  interface ReclusterRequest {
234
266
  clusterCount?: number;
235
267
  }
268
+ /** Result payload from cluster recomputation. */
236
269
  interface ReclusterResult {
237
270
  clustered: boolean;
238
271
  clusters: ProfileClusterResult[];
239
272
  profileId: string;
240
273
  totalSignals: number;
241
274
  }
275
+ /** Input for updating cluster display metadata. */
242
276
  interface RenameClusterRequest {
243
277
  description?: string;
244
278
  name?: string;
245
279
  }
280
+ /** Result payload when adding/removing files from a profile. */
246
281
  interface ProfileFilesResult {
247
282
  fileCount: number;
248
283
  id: string;
249
284
  }
285
+ /** Supported signal types used to tune taste profiles. */
250
286
  type ProfileSignalType = "view" | "view_long" | "click" | "like" | "save" | "choose" | "purchase" | "share" | "dismiss" | "skip" | "reject" | "report" | "custom";
287
+ /** One signal item submitted to profile signal APIs. */
251
288
  interface ProfileSignalInput {
252
289
  context?: Record<string, unknown>;
253
290
  fileKey: string;
254
291
  type: ProfileSignalType;
255
292
  weight?: number;
256
293
  }
294
+ /** Persisted profile signal entry returned by the API. */
257
295
  interface ProfileSignalResult {
258
296
  fileKey: string;
259
297
  id: string;
260
298
  type: ProfileSignalType;
261
299
  weight: number;
262
300
  }
301
+ /** Result payload when listing or appending profile signals. */
263
302
  interface ProfileSignalsResponse {
264
303
  profileId: string;
265
304
  signals: ProfileSignalResult[];
266
305
  totalSignals: number;
267
306
  vectorUpdated: boolean;
268
307
  }
308
+ /** Result payload after removing profile signals. */
269
309
  interface DeleteProfileSignalsResult {
270
310
  profileId: string;
271
311
  removed: number;
272
312
  totalSignals: number;
273
313
  vectorUpdated: boolean;
274
314
  }
315
+ /** Result payload from task trigger endpoints. */
275
316
  interface TaskTriggerResult {
276
317
  key: string;
277
318
  triggered: string;
278
319
  }
320
+ /** Result payload from replace operations. */
279
321
  interface ReplaceResult {
280
322
  contentType: string;
281
323
  key: string;
282
324
  size: number;
283
325
  triggered: string[];
284
326
  }
327
+ /** Shared structured filters for semantic search endpoints. */
285
328
  interface SearchFilters {
286
329
  color?: {
287
330
  dominantFamily?: string[];
@@ -305,7 +348,9 @@ interface SearchFilters {
305
348
  taxonomies?: string[];
306
349
  taxonomyGroups?: string[];
307
350
  }
351
+ /** Optional enrichment blocks that can be included in search responses. */
308
352
  type SearchIncludeField = "tags" | "taxonomies" | "colors" | "colorProfile";
353
+ /** Input payload for text-based semantic search. */
309
354
  interface TextSearchRequest {
310
355
  bucket?: string;
311
356
  filters?: SearchFilters;
@@ -333,6 +378,7 @@ interface PresignDedupeResult {
333
378
  }
334
379
  /** Presign response is either a new upload or a dedup hit. Check `result.dedupe` to differentiate. */
335
380
  type PresignResult = PresignNewResult | PresignDedupeResult;
381
+ /** Input payload for requesting presigned upload URLs. */
336
382
  interface PresignRequest {
337
383
  /** Override the default bucket */
338
384
  bucket?: string;
@@ -347,6 +393,7 @@ interface PresignRequest {
347
393
  /** File size in bytes */
348
394
  size: number;
349
395
  }
396
+ /** Input payload for confirming a direct upload. */
350
397
  interface ConfirmUploadRequest {
351
398
  /** Request AI-generated alt text for images */
352
399
  altText?: boolean;
@@ -355,8 +402,6 @@ interface ConfirmUploadRequest {
355
402
  /** SHA-256 hex digest of file content. Stored with the file record for future dedup lookups. */
356
403
  contentHash?: string;
357
404
  contentType: string;
358
- /** Fire KV sync in background instead of blocking. Saves ~100ms per upload. */
359
- deferKvSync?: boolean;
360
405
  /** Request AI-generated description for images */
361
406
  describe?: boolean;
362
407
  fileKey: string;
@@ -368,6 +413,7 @@ interface ConfirmUploadRequest {
368
413
  /** Request AI-generated title for images */
369
414
  title?: boolean;
370
415
  }
416
+ /** Input payload for similarity search. */
371
417
  interface SimilarSearchRequest {
372
418
  /** Bucket name or ID to scope search */
373
419
  bucket?: string;
@@ -390,6 +436,7 @@ interface SimilarSearchRequest {
390
436
  /** Search directly with a vector (1024 dimensions) */
391
437
  vector?: number[];
392
438
  }
439
+ /** Input payload for diversity-aware search. */
393
440
  interface DiverseSearchRequest {
394
441
  /** Bucket name or ID to scope search */
395
442
  bucket?: string;
@@ -414,6 +461,7 @@ interface DiverseSearchRequest {
414
461
  /** Search directly with a vector (1024 dimensions) as the relevance seed */
415
462
  vector?: number[];
416
463
  }
464
+ /** One semantic search result item. */
417
465
  interface SearchResultItem {
418
466
  bucketId: string;
419
467
  colorProfile?: FileColorProfile | null;
@@ -441,15 +489,18 @@ interface SearchResultItem {
441
489
  }>;
442
490
  width?: number | null;
443
491
  }
492
+ /** Metadata describing server-side filter pruning. */
444
493
  interface FilteredMetadata {
445
494
  candidatesScanned: number;
446
495
  requested: number;
447
496
  returned: number;
448
497
  }
498
+ /** Result payload returned by similarity/diversity search endpoints. */
449
499
  interface SimilarSearchResult {
450
500
  filtered?: FilteredMetadata;
451
501
  results: SearchResultItem[];
452
502
  }
503
+ /** Input payload for color similarity search. */
453
504
  interface ColorSearchRequest {
454
505
  /** Bucket name or ID to scope search */
455
506
  bucket?: string;
@@ -468,6 +519,7 @@ interface ColorSearchRequest {
468
519
  b: number;
469
520
  };
470
521
  }
522
+ /** One color search result item. */
471
523
  interface ColorSearchResultItem {
472
524
  bucketId: string;
473
525
  colorDistance: number;
@@ -486,9 +538,11 @@ interface ColorSearchResultItem {
486
538
  proportion: number;
487
539
  };
488
540
  }
541
+ /** Result payload for color similarity search. */
489
542
  interface ColorSearchResult {
490
543
  results: ColorSearchResultItem[];
491
544
  }
545
+ /** Server-side SDK client for Stow's API. */
492
546
  declare class StowServer {
493
547
  private readonly apiKey;
494
548
  private readonly baseUrl;
@@ -634,16 +688,22 @@ declare class StowServer {
634
688
  * Extract color palette from an image file.
635
689
  * Requires a searchable bucket.
636
690
  */
637
- extractColors(key: string): Promise<TaskTriggerResult>;
691
+ extractColors(key: string, options?: {
692
+ bucket?: string;
693
+ }): Promise<TaskTriggerResult>;
638
694
  /**
639
695
  * Extract dimensions (width/height) from an image or video file.
640
696
  */
641
- extractDimensions(key: string): Promise<TaskTriggerResult>;
697
+ extractDimensions(key: string, options?: {
698
+ bucket?: string;
699
+ }): Promise<TaskTriggerResult>;
642
700
  /**
643
701
  * Generate a vector embedding for an image file.
644
702
  * Requires a searchable bucket.
645
703
  */
646
- embed(key: string): Promise<TaskTriggerResult>;
704
+ embed(key: string, options?: {
705
+ bucket?: string;
706
+ }): Promise<TaskTriggerResult>;
647
707
  /**
648
708
  * Replace a file's content by fetching from a new URL.
649
709
  *
package/dist/index.js CHANGED
@@ -201,7 +201,16 @@ var profileClusterResultSchema = import_zod.z.object({
201
201
  description: import_zod.z.string().nullable(),
202
202
  signalCount: import_zod.z.number().int(),
203
203
  totalWeight: import_zod.z.number(),
204
- nameGeneratedAt: import_zod.z.string().nullable()
204
+ nameGeneratedAt: import_zod.z.string().nullable(),
205
+ tags: import_zod.z.array(
206
+ import_zod.z.object({
207
+ tag: import_zod.z.string(),
208
+ tagSlug: import_zod.z.string(),
209
+ group: import_zod.z.string(),
210
+ groupSlug: import_zod.z.string(),
211
+ similarity: import_zod.z.number()
212
+ })
213
+ ).optional()
205
214
  });
206
215
  var profileResultSchema = import_zod.z.object({
207
216
  id: import_zod.z.string(),
@@ -579,7 +588,6 @@ var StowServer = class {
579
588
  bucket,
580
589
  metadata,
581
590
  skipVerify,
582
- deferKvSync,
583
591
  contentHash,
584
592
  title,
585
593
  describe,
@@ -596,7 +604,6 @@ var StowServer = class {
596
604
  contentType,
597
605
  ...metadata ? { metadata } : {},
598
606
  ...skipVerify ? { skipVerify } : {},
599
- ...deferKvSync ? { deferKvSync } : {},
600
607
  ...contentHash ? { contentHash } : {},
601
608
  ...title ? { title } : {},
602
609
  ...describe ? { describe } : {},
@@ -665,9 +672,10 @@ var StowServer = class {
665
672
  * Extract color palette from an image file.
666
673
  * Requires a searchable bucket.
667
674
  */
668
- extractColors(key) {
675
+ extractColors(key, options) {
676
+ const path = `/api/files/${encodeURIComponent(key)}/extract-colors`;
669
677
  return this.request(
670
- `/api/files/${encodeURIComponent(key)}/extract-colors`,
678
+ this.withBucket(path, options?.bucket),
671
679
  { method: "POST" },
672
680
  taskTriggerResultSchema
673
681
  );
@@ -675,9 +683,10 @@ var StowServer = class {
675
683
  /**
676
684
  * Extract dimensions (width/height) from an image or video file.
677
685
  */
678
- extractDimensions(key) {
686
+ extractDimensions(key, options) {
687
+ const path = `/api/files/${encodeURIComponent(key)}/extract-dimensions`;
679
688
  return this.request(
680
- `/api/files/${encodeURIComponent(key)}/extract-dimensions`,
689
+ this.withBucket(path, options?.bucket),
681
690
  { method: "POST" },
682
691
  taskTriggerResultSchema
683
692
  );
@@ -686,9 +695,10 @@ var StowServer = class {
686
695
  * Generate a vector embedding for an image file.
687
696
  * Requires a searchable bucket.
688
697
  */
689
- embed(key) {
698
+ embed(key, options) {
699
+ const path = `/api/files/${encodeURIComponent(key)}/embed`;
690
700
  return this.request(
691
- `/api/files/${encodeURIComponent(key)}/embed`,
701
+ this.withBucket(path, options?.bucket),
692
702
  { method: "POST" },
693
703
  taskTriggerResultSchema
694
704
  );
package/dist/index.mjs CHANGED
@@ -176,7 +176,16 @@ var profileClusterResultSchema = z.object({
176
176
  description: z.string().nullable(),
177
177
  signalCount: z.number().int(),
178
178
  totalWeight: z.number(),
179
- nameGeneratedAt: z.string().nullable()
179
+ nameGeneratedAt: z.string().nullable(),
180
+ tags: z.array(
181
+ z.object({
182
+ tag: z.string(),
183
+ tagSlug: z.string(),
184
+ group: z.string(),
185
+ groupSlug: z.string(),
186
+ similarity: z.number()
187
+ })
188
+ ).optional()
180
189
  });
181
190
  var profileResultSchema = z.object({
182
191
  id: z.string(),
@@ -554,7 +563,6 @@ var StowServer = class {
554
563
  bucket,
555
564
  metadata,
556
565
  skipVerify,
557
- deferKvSync,
558
566
  contentHash,
559
567
  title,
560
568
  describe,
@@ -571,7 +579,6 @@ var StowServer = class {
571
579
  contentType,
572
580
  ...metadata ? { metadata } : {},
573
581
  ...skipVerify ? { skipVerify } : {},
574
- ...deferKvSync ? { deferKvSync } : {},
575
582
  ...contentHash ? { contentHash } : {},
576
583
  ...title ? { title } : {},
577
584
  ...describe ? { describe } : {},
@@ -640,9 +647,10 @@ var StowServer = class {
640
647
  * Extract color palette from an image file.
641
648
  * Requires a searchable bucket.
642
649
  */
643
- extractColors(key) {
650
+ extractColors(key, options) {
651
+ const path = `/api/files/${encodeURIComponent(key)}/extract-colors`;
644
652
  return this.request(
645
- `/api/files/${encodeURIComponent(key)}/extract-colors`,
653
+ this.withBucket(path, options?.bucket),
646
654
  { method: "POST" },
647
655
  taskTriggerResultSchema
648
656
  );
@@ -650,9 +658,10 @@ var StowServer = class {
650
658
  /**
651
659
  * Extract dimensions (width/height) from an image or video file.
652
660
  */
653
- extractDimensions(key) {
661
+ extractDimensions(key, options) {
662
+ const path = `/api/files/${encodeURIComponent(key)}/extract-dimensions`;
654
663
  return this.request(
655
- `/api/files/${encodeURIComponent(key)}/extract-dimensions`,
664
+ this.withBucket(path, options?.bucket),
656
665
  { method: "POST" },
657
666
  taskTriggerResultSchema
658
667
  );
@@ -661,9 +670,10 @@ var StowServer = class {
661
670
  * Generate a vector embedding for an image file.
662
671
  * Requires a searchable bucket.
663
672
  */
664
- embed(key) {
673
+ embed(key, options) {
674
+ const path = `/api/files/${encodeURIComponent(key)}/embed`;
665
675
  return this.request(
666
- `/api/files/${encodeURIComponent(key)}/embed`,
676
+ this.withBucket(path, options?.bucket),
667
677
  { method: "POST" },
668
678
  taskTriggerResultSchema
669
679
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@howells/stow-server",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "Server-side SDK for Stow file storage",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -29,21 +29,21 @@
29
29
  "files": [
30
30
  "dist"
31
31
  ],
32
- "scripts": {
33
- "build": "tsup src/index.ts --format cjs,esm --dts",
34
- "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
35
- "test": "vitest run",
36
- "test:watch": "vitest"
37
- },
38
32
  "peerDependencies": {
39
33
  "zod": "^3.0.0 || ^4.0.0"
40
34
  },
41
35
  "devDependencies": {
42
- "@stow/typescript-config": "workspace:*",
43
36
  "@types/node": "^25.3.0",
44
37
  "tsup": "^8.5.1",
45
38
  "typescript": "^5.9.3",
46
39
  "vitest": "^4.0.18",
47
- "zod": "^4.3.6"
40
+ "zod": "^4.3.6",
41
+ "@stow/typescript-config": "0.0.0"
42
+ },
43
+ "scripts": {
44
+ "build": "tsup src/index.ts --format cjs,esm --dts",
45
+ "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
46
+ "test": "vitest run",
47
+ "test:watch": "vitest"
48
48
  }
49
- }
49
+ }