@howells/stow-server 2.2.1 → 2.3.1
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 +21 -0
- package/README.md +3 -5
- package/dist/index.d.mts +373 -56
- package/dist/index.d.ts +373 -56
- package/dist/index.js +303 -105
- package/dist/index.mjs +303 -105
- package/package.json +24 -24
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/README.md
CHANGED
|
@@ -67,10 +67,7 @@ const result = await stow.uploadFile(buffer, {
|
|
|
67
67
|
Upload a file from a URL (server-side fetch + upload).
|
|
68
68
|
|
|
69
69
|
```typescript
|
|
70
|
-
const result = await stow.uploadFromUrl(
|
|
71
|
-
"https://example.com/image.jpg",
|
|
72
|
-
"downloaded-image.jpg"
|
|
73
|
-
);
|
|
70
|
+
const result = await stow.uploadFromUrl("https://example.com/image.jpg", "downloaded-image.jpg");
|
|
74
71
|
```
|
|
75
72
|
|
|
76
73
|
### `getPresignedUrl(filename, contentType, route?)`
|
|
@@ -81,7 +78,7 @@ Get a presigned URL for client-side upload.
|
|
|
81
78
|
const { uploadUrl, fileKey, fileUrl } = await stow.getPresignedUrl(
|
|
82
79
|
"photo.jpg",
|
|
83
80
|
"image/jpeg",
|
|
84
|
-
"avatars"
|
|
81
|
+
"avatars",
|
|
85
82
|
);
|
|
86
83
|
|
|
87
84
|
// Client can now PUT directly to uploadUrl
|
|
@@ -122,6 +119,7 @@ const transformedUrl = stow.getTransformUrl("https://photos.stow.sh/image.jpg",
|
|
|
122
119
|
```
|
|
123
120
|
|
|
124
121
|
Transform options:
|
|
122
|
+
|
|
125
123
|
- `width` — Max width in pixels (clamped to 4096)
|
|
126
124
|
- `height` — Max height in pixels (clamped to 4096)
|
|
127
125
|
- `quality` — 1–100, quantized to nearest 5 (default: 80)
|
package/dist/index.d.mts
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/** Error thrown when the Stow API returns a non-success response. */
|
|
2
|
+
declare class StowError extends Error {
|
|
3
|
+
readonly status: number;
|
|
4
|
+
readonly code?: string;
|
|
5
|
+
constructor(message: string, status: number, code?: string);
|
|
6
|
+
}
|
|
7
|
+
|
|
1
8
|
/**
|
|
2
9
|
* Stow Server SDK
|
|
3
10
|
*
|
|
@@ -21,12 +28,6 @@
|
|
|
21
28
|
* console.log(result.url);
|
|
22
29
|
* ```
|
|
23
30
|
*/
|
|
24
|
-
/** Error thrown when the Stow API returns a non-success response. */
|
|
25
|
-
declare class StowError extends Error {
|
|
26
|
-
readonly status: number;
|
|
27
|
-
readonly code?: string;
|
|
28
|
-
constructor(message: string, status: number, code?: string);
|
|
29
|
-
}
|
|
30
31
|
/** Configuration for creating a {@link StowServer} instance. */
|
|
31
32
|
interface StowServerConfig {
|
|
32
33
|
apiKey: string;
|
|
@@ -257,10 +258,21 @@ interface FileResult {
|
|
|
257
258
|
url: string | null;
|
|
258
259
|
width: number | null;
|
|
259
260
|
}
|
|
260
|
-
/**
|
|
261
|
+
/**
|
|
262
|
+
* Input for creating a taste profile.
|
|
263
|
+
*
|
|
264
|
+
* Profiles are the right abstraction when you want a reusable preference vector
|
|
265
|
+
* that can evolve over time through file membership and weighted interaction
|
|
266
|
+
* signals such as `like`, `save`, or `purchase`.
|
|
267
|
+
*
|
|
268
|
+
* Use {@link ClusterCreateRequest} instead when you want to group a fixed,
|
|
269
|
+
* curated subset of files without behavioral weighting.
|
|
270
|
+
*/
|
|
261
271
|
interface ProfileCreateRequest {
|
|
262
272
|
bucket?: string;
|
|
273
|
+
/** Initial files to seed into the profile before any interaction signals exist. */
|
|
263
274
|
fileKeys?: string[];
|
|
275
|
+
/** Optional display name for dashboards, logs, or search integrations. */
|
|
264
276
|
name?: string;
|
|
265
277
|
}
|
|
266
278
|
/** Cluster summary within a taste profile. */
|
|
@@ -275,13 +287,13 @@ interface ProfileClusterResult {
|
|
|
275
287
|
* Optional taxonomy terms inferred for the cluster centroid.
|
|
276
288
|
* Absent when taxonomy data is unavailable for the bucket/profile.
|
|
277
289
|
*/
|
|
278
|
-
tags?:
|
|
290
|
+
tags?: {
|
|
279
291
|
group: string;
|
|
280
292
|
groupSlug: string;
|
|
281
293
|
similarity: number;
|
|
282
294
|
tag: string;
|
|
283
295
|
tagSlug: string;
|
|
284
|
-
}
|
|
296
|
+
}[];
|
|
285
297
|
totalWeight: number;
|
|
286
298
|
}
|
|
287
299
|
/** Taste profile detail payload. */
|
|
@@ -295,8 +307,118 @@ interface ProfileResult {
|
|
|
295
307
|
updatedAt: string;
|
|
296
308
|
vector: number[] | null;
|
|
297
309
|
}
|
|
298
|
-
/**
|
|
310
|
+
/**
|
|
311
|
+
* Input for creating a curated clustering resource from an explicit file set.
|
|
312
|
+
*
|
|
313
|
+
* This resource is designed for cases like "cluster these 200 featured images
|
|
314
|
+
* into 12 visual groups" where every listed file should be treated equally.
|
|
315
|
+
* No behavioral signals or master preference vector are involved.
|
|
316
|
+
*
|
|
317
|
+
* The API returns immediately with the persisted resource. Clustering and
|
|
318
|
+
* cluster naming complete asynchronously, so call `stow.clusters.get(id)` to
|
|
319
|
+
* observe progress.
|
|
320
|
+
*
|
|
321
|
+
* @example
|
|
322
|
+
* ```typescript
|
|
323
|
+
* const resource = await stow.clusters.create({
|
|
324
|
+
* bucket: "inspiration",
|
|
325
|
+
* name: "Spring navigator",
|
|
326
|
+
* fileKeys: featuredKeys,
|
|
327
|
+
* clusterCount: 12,
|
|
328
|
+
* });
|
|
329
|
+
* ```
|
|
330
|
+
*/
|
|
331
|
+
interface ClusterCreateRequest {
|
|
332
|
+
/** Bucket name or ID. Optional when the {@link StowServer} instance already has a default bucket. */
|
|
333
|
+
bucket?: string;
|
|
334
|
+
/**
|
|
335
|
+
* Number of K-means clusters to produce.
|
|
336
|
+
*
|
|
337
|
+
* When omitted, the API auto-selects a value using
|
|
338
|
+
* `max(3, min(15, round(sqrt(fileCount / 10))))`.
|
|
339
|
+
*/
|
|
340
|
+
clusterCount?: number;
|
|
341
|
+
/** Exact file keys to cluster. Files without embeddings cannot participate. */
|
|
342
|
+
fileKeys: string[];
|
|
343
|
+
/** Optional human-friendly resource name. */
|
|
344
|
+
name?: string;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* One group within a curated clustering resource.
|
|
348
|
+
*
|
|
349
|
+
* Group names and descriptions are generated asynchronously. Immediately after
|
|
350
|
+
* creation or reclustering, `name` and `description` may be `null` until the
|
|
351
|
+
* naming worker completes or a human renames the cluster manually.
|
|
352
|
+
*/
|
|
353
|
+
interface ClusterGroupResult {
|
|
354
|
+
description: string | null;
|
|
355
|
+
/** Number of files currently assigned to this group. */
|
|
356
|
+
fileCount: number;
|
|
357
|
+
id: string;
|
|
358
|
+
/** Zero-based index produced by the clustering run. */
|
|
359
|
+
index: number;
|
|
360
|
+
name: string | null;
|
|
361
|
+
/** Timestamp for the most recent generated or manual naming pass. */
|
|
362
|
+
nameGeneratedAt: string | null;
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Persisted curated clustering resource.
|
|
366
|
+
*
|
|
367
|
+
* `clusterCount` is the requested or auto-selected target. `clusters.length`
|
|
368
|
+
* represents the current persisted groups for the latest clustering run.
|
|
369
|
+
* `clusteredAt` stays `null` until the worker has written assignments.
|
|
370
|
+
*/
|
|
371
|
+
interface ClusterResourceResult {
|
|
372
|
+
clusterCount: number;
|
|
373
|
+
/** Timestamp of the last completed clustering pass. Null while work is still pending. */
|
|
374
|
+
clusteredAt: string | null;
|
|
375
|
+
clusters: ClusterGroupResult[];
|
|
376
|
+
createdAt: string;
|
|
377
|
+
/** Number of source files included in the resource. */
|
|
378
|
+
fileCount: number;
|
|
379
|
+
id: string;
|
|
380
|
+
name: string | null;
|
|
381
|
+
updatedAt: string;
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* One file assigned to a curated cluster group.
|
|
385
|
+
*
|
|
386
|
+
* When returned from `stow.clusters.files(...)`, items are ordered by ascending
|
|
387
|
+
* distance to the group centroid so the first files are usually the best
|
|
388
|
+
* representatives for labeling, previews, or inspiration navigators.
|
|
389
|
+
*/
|
|
390
|
+
interface ClusterFileResult {
|
|
391
|
+
bucketId: string;
|
|
392
|
+
contentType: string;
|
|
393
|
+
createdAt: string;
|
|
394
|
+
/** Euclidean distance from the cluster centroid. Lower means more representative. */
|
|
395
|
+
distance: number | null;
|
|
396
|
+
id: string;
|
|
397
|
+
key: string;
|
|
398
|
+
metadata: Record<string, string> | null;
|
|
399
|
+
originalFilename: string | null;
|
|
400
|
+
size: number;
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Paginated files assigned to one curated cluster group.
|
|
404
|
+
*
|
|
405
|
+
* Results are stable within a clustering run and ordered by distance to the
|
|
406
|
+
* centroid, making page 1 suitable for "representative examples".
|
|
407
|
+
*/
|
|
408
|
+
interface ClusterFilesResult {
|
|
409
|
+
clusterId: string;
|
|
410
|
+
files: ClusterFileResult[];
|
|
411
|
+
limit: number;
|
|
412
|
+
offset: number;
|
|
413
|
+
total: number;
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Input for recomputing clusters.
|
|
417
|
+
*
|
|
418
|
+
* Used by both `profiles.recluster(...)` and `clusters.recluster(...)`.
|
|
419
|
+
*/
|
|
299
420
|
interface ReclusterRequest {
|
|
421
|
+
/** Override the existing cluster count for the next clustering pass. */
|
|
300
422
|
clusterCount?: number;
|
|
301
423
|
}
|
|
302
424
|
/** Result payload from cluster recomputation. */
|
|
@@ -306,7 +428,12 @@ interface ReclusterResult {
|
|
|
306
428
|
profileId: string;
|
|
307
429
|
totalSignals: number;
|
|
308
430
|
}
|
|
309
|
-
/**
|
|
431
|
+
/**
|
|
432
|
+
* Input for manually naming a cluster.
|
|
433
|
+
*
|
|
434
|
+
* This is intended for the final editorial pass after generated names are
|
|
435
|
+
* available. You can send just `name`, just `description`, or both.
|
|
436
|
+
*/
|
|
310
437
|
interface RenameClusterRequest {
|
|
311
438
|
description?: string;
|
|
312
439
|
name?: string;
|
|
@@ -451,15 +578,39 @@ interface ConfirmUploadRequest {
|
|
|
451
578
|
/** Request AI-generated title for images */
|
|
452
579
|
title?: boolean;
|
|
453
580
|
}
|
|
454
|
-
/**
|
|
581
|
+
/**
|
|
582
|
+
* Input payload for similarity search.
|
|
583
|
+
*
|
|
584
|
+
* Provide exactly one semantic seed:
|
|
585
|
+
* - `fileKey`
|
|
586
|
+
* - `anchorId`
|
|
587
|
+
* - `profileId`
|
|
588
|
+
* - `clusterId`
|
|
589
|
+
* - `clusterIds`
|
|
590
|
+
* - `vector`
|
|
591
|
+
*
|
|
592
|
+
* Cluster seeds follow the same shape as profile clustering:
|
|
593
|
+
* - with `profileId`, `clusterId` or `clusterIds` reference profile clusters
|
|
594
|
+
* - without `profileId`, they reference curated clusters created via `/clusters`
|
|
595
|
+
*/
|
|
455
596
|
interface SimilarSearchRequest {
|
|
456
597
|
/** Use an anchor's embedding as the query vector */
|
|
457
598
|
anchorId?: string;
|
|
458
599
|
/** Bucket name or ID to scope search */
|
|
459
600
|
bucket?: string;
|
|
460
|
-
/**
|
|
601
|
+
/**
|
|
602
|
+
* Use a specific cluster centroid as the query vector.
|
|
603
|
+
*
|
|
604
|
+
* With `profileId`, this resolves a profile cluster. Without `profileId`, it
|
|
605
|
+
* resolves a curated cluster group from `stow.clusters`.
|
|
606
|
+
*/
|
|
461
607
|
clusterId?: string;
|
|
462
|
-
/**
|
|
608
|
+
/**
|
|
609
|
+
* Blend multiple cluster centroids into one query vector.
|
|
610
|
+
*
|
|
611
|
+
* With `profileId`, these resolve profile clusters. Without `profileId`, they
|
|
612
|
+
* resolve curated cluster groups from `stow.clusters`.
|
|
613
|
+
*/
|
|
463
614
|
clusterIds?: string[];
|
|
464
615
|
/** File keys to exclude from results (e.g. already-seen items). Max 500. */
|
|
465
616
|
excludeKeys?: string[];
|
|
@@ -471,20 +622,35 @@ interface SimilarSearchRequest {
|
|
|
471
622
|
include?: SearchIncludeField[];
|
|
472
623
|
/** Max results (default 10, max 50) */
|
|
473
624
|
limit?: number;
|
|
474
|
-
/** Search using a taste profile's vector */
|
|
625
|
+
/** Search using a taste profile's master vector. */
|
|
475
626
|
profileId?: string;
|
|
476
627
|
/** Search directly with a vector (1024 dimensions) */
|
|
477
628
|
vector?: number[];
|
|
478
629
|
}
|
|
479
|
-
/**
|
|
630
|
+
/**
|
|
631
|
+
* Input payload for diversity-aware search.
|
|
632
|
+
*
|
|
633
|
+
* This uses the same seed rules as {@link SimilarSearchRequest} but balances
|
|
634
|
+
* relevance against diversity using `lambda`.
|
|
635
|
+
*/
|
|
480
636
|
interface DiverseSearchRequest {
|
|
481
637
|
/** Use an anchor's embedding as the query vector */
|
|
482
638
|
anchorId?: string;
|
|
483
639
|
/** Bucket name or ID to scope search */
|
|
484
640
|
bucket?: string;
|
|
485
|
-
/**
|
|
641
|
+
/**
|
|
642
|
+
* Use a specific cluster centroid as the seed vector.
|
|
643
|
+
*
|
|
644
|
+
* With `profileId`, this resolves a profile cluster. Without `profileId`, it
|
|
645
|
+
* resolves a curated cluster group from `stow.clusters`.
|
|
646
|
+
*/
|
|
486
647
|
clusterId?: string;
|
|
487
|
-
/**
|
|
648
|
+
/**
|
|
649
|
+
* Blend multiple cluster centroids into one seed vector.
|
|
650
|
+
*
|
|
651
|
+
* With `profileId`, these resolve profile clusters. Without `profileId`, they
|
|
652
|
+
* resolve curated cluster groups from `stow.clusters`.
|
|
653
|
+
*/
|
|
488
654
|
clusterIds?: string[];
|
|
489
655
|
/** File keys to exclude from results (e.g. already-seen items). Max 500. */
|
|
490
656
|
excludeKeys?: string[];
|
|
@@ -519,18 +685,18 @@ interface SearchResultItem {
|
|
|
519
685
|
originalFilename: string | null;
|
|
520
686
|
similarity: number;
|
|
521
687
|
size: number;
|
|
522
|
-
tags?:
|
|
688
|
+
tags?: {
|
|
523
689
|
slug: string;
|
|
524
690
|
name: string;
|
|
525
|
-
}
|
|
526
|
-
taxonomies?:
|
|
691
|
+
}[];
|
|
692
|
+
taxonomies?: {
|
|
527
693
|
externalUri: string | null;
|
|
528
694
|
group: string;
|
|
529
695
|
name: string;
|
|
530
696
|
similarity: number;
|
|
531
697
|
slug: string;
|
|
532
698
|
source: string;
|
|
533
|
-
}
|
|
699
|
+
}[];
|
|
534
700
|
width?: number | null;
|
|
535
701
|
}
|
|
536
702
|
/** A text anchor — a named semantic reference point in a bucket's vector space. */
|
|
@@ -683,17 +849,57 @@ interface TaxonomyGroup {
|
|
|
683
849
|
interface TaxonomyListResult {
|
|
684
850
|
groups: TaxonomyGroup[];
|
|
685
851
|
}
|
|
686
|
-
/**
|
|
852
|
+
/**
|
|
853
|
+
* Server-side SDK client for Stow's HTTP API.
|
|
854
|
+
*
|
|
855
|
+
* Use this package from trusted environments only: Next.js route handlers,
|
|
856
|
+
* server actions, workers, backend services, CLIs, or scripts. It owns API-key
|
|
857
|
+
* auth and exposes the full bucket/file/search/profile/cluster surface.
|
|
858
|
+
*
|
|
859
|
+
* Bucket scoping rules:
|
|
860
|
+
* - pass `bucket` to the constructor to set a default for the instance
|
|
861
|
+
* - pass `bucket` to a method to override that default for one call
|
|
862
|
+
* - omit both only when the API key itself is bucket-scoped
|
|
863
|
+
*
|
|
864
|
+
* @example
|
|
865
|
+
* ```typescript
|
|
866
|
+
* const stow = new StowServer({
|
|
867
|
+
* apiKey: process.env.STOW_API_KEY!,
|
|
868
|
+
* bucket: "brand-assets",
|
|
869
|
+
* });
|
|
870
|
+
*
|
|
871
|
+
* const upload = await stow.uploadFile(buffer, {
|
|
872
|
+
* filename: "hero.jpg",
|
|
873
|
+
* contentType: "image/jpeg",
|
|
874
|
+
* title: true,
|
|
875
|
+
* altText: true,
|
|
876
|
+
* });
|
|
877
|
+
*
|
|
878
|
+
* const { results } = await stow.search.similar({ fileKey: upload.key, limit: 8 });
|
|
879
|
+
* ```
|
|
880
|
+
*/
|
|
687
881
|
declare class StowServer {
|
|
688
882
|
private readonly apiKey;
|
|
689
883
|
private readonly baseUrl;
|
|
690
884
|
private readonly bucket?;
|
|
691
885
|
private readonly timeout;
|
|
692
886
|
private readonly retries;
|
|
693
|
-
constructor(config: StowServerConfig | string);
|
|
694
887
|
/**
|
|
695
|
-
*
|
|
888
|
+
* Pure helper for building signed transform URLs from an existing public file URL.
|
|
889
|
+
*
|
|
890
|
+
* This does not perform any network I/O and is safe to pass around as a plain
|
|
891
|
+
* function, for example to view-layer code that needs responsive image URLs.
|
|
892
|
+
*/
|
|
893
|
+
readonly getTransformUrl: (url: string, options?: TransformOptions) => string;
|
|
894
|
+
/**
|
|
895
|
+
* Create a server SDK instance.
|
|
896
|
+
*
|
|
897
|
+
* Pass a bare string when you only need the API key and want default values
|
|
898
|
+
* for `baseUrl`, `timeout`, and retries. Pass an object when you want a
|
|
899
|
+
* default bucket, a non-production API origin, or custom transport settings.
|
|
696
900
|
*/
|
|
901
|
+
constructor(config: StowServerConfig | string);
|
|
902
|
+
/** Return the configured API origin, mainly for adapter packages such as `stow-next`. */
|
|
697
903
|
getBaseUrl(): string;
|
|
698
904
|
/**
|
|
699
905
|
* Return account usage and API key info for the current credential.
|
|
@@ -744,9 +950,30 @@ declare class StowServer {
|
|
|
744
950
|
* - Consumer can pass `signal` in options to cancel.
|
|
745
951
|
*/
|
|
746
952
|
private request;
|
|
747
|
-
private sleep;
|
|
748
953
|
/**
|
|
749
|
-
* Upload
|
|
954
|
+
* Upload bytes from a trusted server environment.
|
|
955
|
+
*
|
|
956
|
+
* This is the highest-level server upload helper:
|
|
957
|
+
* 1. compute a SHA-256 hash for dedupe
|
|
958
|
+
* 2. request a presigned upload URL
|
|
959
|
+
* 3. PUT bytes to storage
|
|
960
|
+
* 4. confirm the upload with optional AI metadata generation
|
|
961
|
+
*
|
|
962
|
+
* Prefer this method when your code already has the file bytes in memory.
|
|
963
|
+
* Use `getPresignedUrl()` + `confirmUpload()` for direct browser uploads
|
|
964
|
+
* instead, and `uploadFromUrl()` when the source is an external URL.
|
|
965
|
+
*
|
|
966
|
+
* @example
|
|
967
|
+
* ```typescript
|
|
968
|
+
* await stow.uploadFile(buffer, {
|
|
969
|
+
* filename: "product.jpg",
|
|
970
|
+
* contentType: "image/jpeg",
|
|
971
|
+
* bucket: "catalog",
|
|
972
|
+
* metadata: { sku: "SKU-123" },
|
|
973
|
+
* title: true,
|
|
974
|
+
* altText: true,
|
|
975
|
+
* });
|
|
976
|
+
* ```
|
|
750
977
|
*/
|
|
751
978
|
uploadFile(file: Buffer | Blob, options?: {
|
|
752
979
|
filename?: string;
|
|
@@ -764,7 +991,12 @@ declare class StowServer {
|
|
|
764
991
|
altText?: boolean;
|
|
765
992
|
}): Promise<UploadResult>;
|
|
766
993
|
/**
|
|
767
|
-
*
|
|
994
|
+
* Import a remote asset by URL.
|
|
995
|
+
*
|
|
996
|
+
* Stow fetches the remote URL server-side, stores the resulting bytes, and
|
|
997
|
+
* persists the file as if it had been uploaded normally. This is useful for
|
|
998
|
+
* migrations, ingestion pipelines, or bringing third-party assets into Stow
|
|
999
|
+
* without downloading them into your own process first.
|
|
768
1000
|
*/
|
|
769
1001
|
uploadFromUrl(url: string, filename: string, options?: {
|
|
770
1002
|
bucket?: string;
|
|
@@ -798,24 +1030,36 @@ declare class StowServer {
|
|
|
798
1030
|
altText?: boolean;
|
|
799
1031
|
}): Promise<QueuedResult>;
|
|
800
1032
|
/**
|
|
801
|
-
* Get a presigned URL for direct client
|
|
1033
|
+
* Get a presigned URL for a direct client upload.
|
|
802
1034
|
*
|
|
803
|
-
* This
|
|
804
|
-
*
|
|
805
|
-
*
|
|
806
|
-
*
|
|
807
|
-
*
|
|
1035
|
+
* This is the server-side half of the browser upload flow used by
|
|
1036
|
+
* `@howells/stow-client` and `@howells/stow-next`:
|
|
1037
|
+
* 1. browser calls your app
|
|
1038
|
+
* 2. your app calls `getPresignedUrl()`
|
|
1039
|
+
* 3. browser PUTs bytes to `uploadUrl`
|
|
1040
|
+
* 4. browser or your app calls `confirmUpload()`
|
|
1041
|
+
*
|
|
1042
|
+
* If `contentHash` matches an existing file in the target bucket, the API
|
|
1043
|
+
* short-circuits with `{ dedupe: true, ... }` and no upload is required.
|
|
808
1044
|
*/
|
|
809
1045
|
getPresignedUrl(request: PresignRequest): Promise<PresignResult>;
|
|
810
1046
|
/**
|
|
811
|
-
* Confirm a
|
|
812
|
-
*
|
|
1047
|
+
* Confirm a direct upload after the client has finished the storage PUT.
|
|
1048
|
+
*
|
|
1049
|
+
* This finalizes the file record in the database and optionally triggers
|
|
1050
|
+
* post-processing such as AI-generated title/description/alt text.
|
|
1051
|
+
*
|
|
1052
|
+
* Call this exactly once per successful presigned upload.
|
|
813
1053
|
*/
|
|
814
1054
|
confirmUpload(request: ConfirmUploadRequest): Promise<UploadResult>;
|
|
815
1055
|
/**
|
|
816
|
-
* List files in
|
|
1056
|
+
* List files in a bucket with optional prefix filtering and enrichment blocks.
|
|
1057
|
+
*
|
|
1058
|
+
* Use `cursor` to continue pagination from a previous page. When requesting
|
|
1059
|
+
* `include`, Stow expands those relationships inline so you can avoid follow-up
|
|
1060
|
+
* per-file lookups.
|
|
817
1061
|
*
|
|
818
|
-
* @param options.include
|
|
1062
|
+
* @param options.include Optional enrichment fields: `"tags"`, `"taxonomies"`
|
|
819
1063
|
*/
|
|
820
1064
|
listFiles(options?: {
|
|
821
1065
|
prefix?: string;
|
|
@@ -843,9 +1087,12 @@ declare class StowServer {
|
|
|
843
1087
|
metadata: Record<string, string>;
|
|
844
1088
|
}>;
|
|
845
1089
|
/**
|
|
846
|
-
* Get
|
|
1090
|
+
* Get one file by key.
|
|
1091
|
+
*
|
|
1092
|
+
* This is the detailed file view and includes dimensions, embeddings status,
|
|
1093
|
+
* extracted colors, and AI metadata fields when available.
|
|
847
1094
|
*
|
|
848
|
-
* @param options.include
|
|
1095
|
+
* @param options.include Optional enrichment fields: `"tags"`, `"taxonomies"`
|
|
849
1096
|
*/
|
|
850
1097
|
getFile(key: string, options?: {
|
|
851
1098
|
bucket?: string;
|
|
@@ -904,29 +1151,18 @@ declare class StowServer {
|
|
|
904
1151
|
/** Headers to forward when fetching the URL (e.g. User-Agent, Referer) */
|
|
905
1152
|
headers?: Record<string, string>;
|
|
906
1153
|
}): Promise<ReplaceResult>;
|
|
907
|
-
/**
|
|
908
|
-
* Get a transform URL for an image.
|
|
909
|
-
*
|
|
910
|
-
* Appends transform query params (?w=, ?h=, ?q=, ?f=) to a file URL.
|
|
911
|
-
* Transforms are applied at the edge by the Cloudflare Worker — no
|
|
912
|
-
* server round-trip needed.
|
|
913
|
-
*
|
|
914
|
-
* @param url - Full file URL (e.g. from upload result's fileUrl)
|
|
915
|
-
* @param options - Transform options (width, height, quality, format)
|
|
916
|
-
*/
|
|
917
|
-
getTransformUrl(url: string, options?: TransformOptions): string;
|
|
918
1154
|
/**
|
|
919
1155
|
* Tags namespace for creating, listing, and deleting tags
|
|
920
1156
|
*/
|
|
921
1157
|
get tags(): {
|
|
922
1158
|
list: () => Promise<{
|
|
923
|
-
tags:
|
|
1159
|
+
tags: {
|
|
924
1160
|
id: string;
|
|
925
1161
|
name: string;
|
|
926
1162
|
slug: string;
|
|
927
1163
|
color: string | null;
|
|
928
1164
|
createdAt: string;
|
|
929
|
-
}
|
|
1165
|
+
}[];
|
|
930
1166
|
}>;
|
|
931
1167
|
create: (params: {
|
|
932
1168
|
name: string;
|
|
@@ -971,7 +1207,34 @@ declare class StowServer {
|
|
|
971
1207
|
};
|
|
972
1208
|
private listTaxonomies;
|
|
973
1209
|
/**
|
|
974
|
-
*
|
|
1210
|
+
* Semantic search namespace.
|
|
1211
|
+
*
|
|
1212
|
+
* Methods:
|
|
1213
|
+
* - `text(...)` embeds text and finds matching files
|
|
1214
|
+
* - `similar(...)` finds nearest neighbors for a file, anchor, profile, or cluster
|
|
1215
|
+
* - `diverse(...)` balances similarity against result spread
|
|
1216
|
+
* - `color(...)` performs palette similarity search
|
|
1217
|
+
* - `image(...)` searches using an existing file or an external image URL
|
|
1218
|
+
*
|
|
1219
|
+
* Cluster-aware search examples:
|
|
1220
|
+
*
|
|
1221
|
+
* @example
|
|
1222
|
+
* ```typescript
|
|
1223
|
+
* const cluster = await stow.clusters.create({
|
|
1224
|
+
* bucket: "inspiration",
|
|
1225
|
+
* fileKeys,
|
|
1226
|
+
* clusterCount: 12,
|
|
1227
|
+
* });
|
|
1228
|
+
*
|
|
1229
|
+
* const firstGroup = cluster.clusters[0];
|
|
1230
|
+
* if (firstGroup) {
|
|
1231
|
+
* const related = await stow.search.similar({
|
|
1232
|
+
* bucket: "inspiration",
|
|
1233
|
+
* clusterId: firstGroup.id,
|
|
1234
|
+
* limit: 20,
|
|
1235
|
+
* });
|
|
1236
|
+
* }
|
|
1237
|
+
* ```
|
|
975
1238
|
*/
|
|
976
1239
|
get search(): {
|
|
977
1240
|
similar: (params: SimilarSearchRequest) => Promise<SimilarSearchResult>;
|
|
@@ -1010,7 +1273,11 @@ declare class StowServer {
|
|
|
1010
1273
|
*/
|
|
1011
1274
|
deleteDrop(id: string): Promise<void>;
|
|
1012
1275
|
/**
|
|
1013
|
-
*
|
|
1276
|
+
* Taste-profile namespace.
|
|
1277
|
+
*
|
|
1278
|
+
* Profiles are long-lived preference objects. They can be seeded from files,
|
|
1279
|
+
* updated through weighted signals, clustered into interpretable segments, and
|
|
1280
|
+
* then reused as semantic search seeds.
|
|
1014
1281
|
*/
|
|
1015
1282
|
get profiles(): {
|
|
1016
1283
|
create: (params?: ProfileCreateRequest) => Promise<ProfileResult>;
|
|
@@ -1028,6 +1295,50 @@ declare class StowServer {
|
|
|
1028
1295
|
recluster: (id: string, params?: ReclusterRequest, bucket?: string) => Promise<ReclusterResult>;
|
|
1029
1296
|
renameCluster: (profileId: string, clusterId: string, params: RenameClusterRequest, bucket?: string) => Promise<ProfileClusterResult>;
|
|
1030
1297
|
};
|
|
1298
|
+
/**
|
|
1299
|
+
* Curated cluster namespace.
|
|
1300
|
+
*
|
|
1301
|
+
* Use this when you have an explicit file set that should be grouped by visual
|
|
1302
|
+
* similarity, but should not be modeled as a behavioral profile.
|
|
1303
|
+
*
|
|
1304
|
+
* Typical workflow:
|
|
1305
|
+
* 1. `create({ fileKeys, clusterCount })`
|
|
1306
|
+
* 2. poll `get(id)` until `clusteredAt` is non-null
|
|
1307
|
+
* 3. inspect `clusters`
|
|
1308
|
+
* 4. fetch representative files with `files(id, clusterId)`
|
|
1309
|
+
* 5. optionally `renameCluster(...)`
|
|
1310
|
+
* 6. use `clusterId` with `search.similar(...)` or `search.diverse(...)`
|
|
1311
|
+
*
|
|
1312
|
+
* @example
|
|
1313
|
+
* ```typescript
|
|
1314
|
+
* const resource = await stow.clusters.create({
|
|
1315
|
+
* bucket: "featured-products",
|
|
1316
|
+
* fileKeys: featuredKeys,
|
|
1317
|
+
* clusterCount: 12,
|
|
1318
|
+
* name: "Navigator groups",
|
|
1319
|
+
* });
|
|
1320
|
+
*
|
|
1321
|
+
* const latest = await stow.clusters.get(resource.id, "featured-products");
|
|
1322
|
+
* const group = latest.clusters[0];
|
|
1323
|
+
* if (group) {
|
|
1324
|
+
* const representatives = await stow.clusters.files(resource.id, group.id, {
|
|
1325
|
+
* limit: 12,
|
|
1326
|
+
* offset: 0,
|
|
1327
|
+
* });
|
|
1328
|
+
* }
|
|
1329
|
+
* ```
|
|
1330
|
+
*/
|
|
1331
|
+
get clusters(): {
|
|
1332
|
+
create: (params: ClusterCreateRequest) => Promise<ClusterResourceResult>;
|
|
1333
|
+
get: (id: string, bucket?: string) => Promise<ClusterResourceResult>;
|
|
1334
|
+
recluster: (id: string, params?: ReclusterRequest, bucket?: string) => Promise<ClusterResourceResult>;
|
|
1335
|
+
files: (id: string, clusterId: string, params?: {
|
|
1336
|
+
limit?: number;
|
|
1337
|
+
offset?: number;
|
|
1338
|
+
}, bucket?: string) => Promise<ClusterFilesResult>;
|
|
1339
|
+
renameCluster: (id: string, clusterId: string, params: RenameClusterRequest, bucket?: string) => Promise<ClusterGroupResult>;
|
|
1340
|
+
delete: (id: string, bucket?: string) => Promise<void>;
|
|
1341
|
+
};
|
|
1031
1342
|
private createProfile;
|
|
1032
1343
|
private getProfile;
|
|
1033
1344
|
private deleteProfile;
|
|
@@ -1038,6 +1349,12 @@ declare class StowServer {
|
|
|
1038
1349
|
private getProfileClusters;
|
|
1039
1350
|
private reclusterProfile;
|
|
1040
1351
|
private renameProfileCluster;
|
|
1352
|
+
private createClustersResource;
|
|
1353
|
+
private getClustersResource;
|
|
1354
|
+
private reclusterClustersResource;
|
|
1355
|
+
private getClusterFiles;
|
|
1356
|
+
private renameClusterGroup;
|
|
1357
|
+
private deleteClustersResource;
|
|
1041
1358
|
/**
|
|
1042
1359
|
* Anchors namespace for creating, listing, updating, and deleting text anchors.
|
|
1043
1360
|
*
|
|
@@ -1069,4 +1386,4 @@ declare class StowServer {
|
|
|
1069
1386
|
private deleteAnchor;
|
|
1070
1387
|
}
|
|
1071
1388
|
|
|
1072
|
-
export { type Anchor, type AnchorSearchResult, type AppliedFilters, type BucketResult, type ColorSearchRequest, type ColorSearchResult, type ColorSearchResultItem, type ConfirmUploadRequest, type CreateAnchorRequest, type CreateBucketRequest, type DeleteProfileSignalsResult, type DiverseSearchRequest, type Drop, type DropResult, type FileColor, type FileColorProfile, type FileIncludeField, type FileResult, type FileTag, type FileTaxonomy, type FilteredMetadata, type ListBucketsResult, type ListDropsResult, type ListFilesItem, type ListFilesResult, type PresignDedupeResult, type PresignNewResult, type PresignRequest, type PresignResult, type ProfileClusterResult, type ProfileCreateRequest, type ProfileFilesResult, type ProfileResult, type ProfileSignalInput, type ProfileSignalResult, type ProfileSignalType, type ProfileSignalsResponse, type QueuedResult, type ReclusterRequest, type ReclusterResult, type RenameClusterRequest, type ReplaceResult, type SearchByImageInput, type SearchByImageOptions, type SearchByImageResult, type SearchByImageSource, type SearchFilters, type SearchIncludeField, type SearchResultItem, type SimilarSearchRequest, type SimilarSearchResult, StowError, StowServer, type StowServerConfig, type TaskTriggerResult, type TaxonomyGroup, type TaxonomyListResult, type TaxonomyTerm, type TextSearchRequest, type TransformOptions, type UpdateAnchorRequest, type UpdateBucketRequest, type UploadResult, type WhoamiResult };
|
|
1389
|
+
export { type Anchor, type AnchorSearchResult, type AppliedFilters, type BucketResult, type ClusterCreateRequest, type ClusterFileResult, type ClusterFilesResult, type ClusterGroupResult, type ClusterResourceResult, type ColorSearchRequest, type ColorSearchResult, type ColorSearchResultItem, type ConfirmUploadRequest, type CreateAnchorRequest, type CreateBucketRequest, type DeleteProfileSignalsResult, type DiverseSearchRequest, type Drop, type DropResult, type FileColor, type FileColorProfile, type FileIncludeField, type FileResult, type FileTag, type FileTaxonomy, type FilteredMetadata, type ListBucketsResult, type ListDropsResult, type ListFilesItem, type ListFilesResult, type PresignDedupeResult, type PresignNewResult, type PresignRequest, type PresignResult, type ProfileClusterResult, type ProfileCreateRequest, type ProfileFilesResult, type ProfileResult, type ProfileSignalInput, type ProfileSignalResult, type ProfileSignalType, type ProfileSignalsResponse, type QueuedResult, type ReclusterRequest, type ReclusterResult, type RenameClusterRequest, type ReplaceResult, type SearchByImageInput, type SearchByImageOptions, type SearchByImageResult, type SearchByImageSource, type SearchFilters, type SearchIncludeField, type SearchResultItem, type SimilarSearchRequest, type SimilarSearchResult, StowError, StowServer, type StowServerConfig, type TaskTriggerResult, type TaxonomyGroup, type TaxonomyListResult, type TaxonomyTerm, type TextSearchRequest, type TransformOptions, type UpdateAnchorRequest, type UpdateBucketRequest, type UploadResult, type WhoamiResult };
|