@howells/stow-server 0.6.0 → 2.0.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.
package/dist/index.d.mts CHANGED
@@ -389,6 +389,8 @@ type FileIncludeField = "tags" | "taxonomies";
389
389
  /** Input payload for text-based semantic search. */
390
390
  interface TextSearchRequest {
391
391
  bucket?: string;
392
+ /** File keys to exclude from results (e.g. already-seen items). Max 500. */
393
+ excludeKeys?: string[];
392
394
  filters?: SearchFilters;
393
395
  include?: SearchIncludeField[];
394
396
  limit?: number;
@@ -457,7 +459,7 @@ interface SimilarSearchRequest {
457
459
  clusterId?: string;
458
460
  /** Blend multiple cluster centroids as query vector. Requires profileId. */
459
461
  clusterIds?: string[];
460
- /** File keys to exclude from results (e.g. already-seen items). Max 200. */
462
+ /** File keys to exclude from results (e.g. already-seen items). Max 500. */
461
463
  excludeKeys?: string[];
462
464
  /** Find files similar to this file key */
463
465
  fileKey?: string;
@@ -480,7 +482,7 @@ interface DiverseSearchRequest {
480
482
  clusterId?: string;
481
483
  /** Blend multiple cluster centroids as query vector. Requires profileId. */
482
484
  clusterIds?: string[];
483
- /** File keys to exclude from results (e.g. already-seen items). Max 200. */
485
+ /** File keys to exclude from results (e.g. already-seen items). Max 500. */
484
486
  excludeKeys?: string[];
485
487
  /** Find diverse files seeded by this file key */
486
488
  fileKey?: string;
@@ -525,8 +527,18 @@ interface SearchResultItem {
525
527
  }>;
526
528
  width?: number | null;
527
529
  }
530
+ /** Which filter categories were active in the request. */
531
+ interface AppliedFilters {
532
+ color?: string[];
533
+ contentType?: string[];
534
+ metadata?: string[];
535
+ tags?: string[];
536
+ taxonomies?: string[];
537
+ taxonomyGroups?: string[];
538
+ }
528
539
  /** Metadata describing server-side filter pruning. */
529
540
  interface FilteredMetadata {
541
+ appliedFilters: AppliedFilters;
530
542
  candidatesScanned: number;
531
543
  requested: number;
532
544
  returned: number;
@@ -542,6 +554,8 @@ interface ColorSearchRequest {
542
554
  bucket?: string;
543
555
  /** Only search the dominant (first) color per file */
544
556
  dominantOnly?: boolean;
557
+ /** File keys to exclude from results (e.g. already-seen items). Max 500. */
558
+ excludeKeys?: string[];
545
559
  /** Target color as hex (e.g. "#FF0000") */
546
560
  hex?: string;
547
561
  /** Max results (default 10, max 50) */
@@ -561,6 +575,7 @@ interface ColorSearchResultItem {
561
575
  colorDistance: number;
562
576
  contentType: string;
563
577
  createdAt: string;
578
+ height: number | null;
564
579
  id: string;
565
580
  key: string;
566
581
  matchedColor: {
@@ -573,11 +588,27 @@ interface ColorSearchResultItem {
573
588
  position: number;
574
589
  proportion: number;
575
590
  };
591
+ width: number | null;
576
592
  }
577
593
  /** Result payload for color similarity search. */
578
594
  interface ColorSearchResult {
579
595
  results: ColorSearchResultItem[];
580
596
  }
597
+ /** A taxonomy term within a group. */
598
+ interface TaxonomyTerm {
599
+ name: string;
600
+ slug: string;
601
+ }
602
+ /** A taxonomy group with its terms. */
603
+ interface TaxonomyGroup {
604
+ name: string;
605
+ slug: string;
606
+ taxonomies: TaxonomyTerm[];
607
+ }
608
+ /** Result payload for taxonomy listing. */
609
+ interface TaxonomyListResult {
610
+ groups: TaxonomyGroup[];
611
+ }
581
612
  /** Server-side SDK client for Stow's API. */
582
613
  declare class StowServer {
583
614
  private readonly apiKey;
@@ -850,6 +881,21 @@ declare class StowServer {
850
881
  removeTag(key: string, tagId: string, options?: {
851
882
  bucket?: string;
852
883
  }): Promise<void>;
884
+ /**
885
+ * Taxonomies namespace for discovering available taxonomy terms.
886
+ *
887
+ * @example
888
+ * ```typescript
889
+ * const { groups } = await stow.taxonomies.list();
890
+ * for (const group of groups) {
891
+ * console.log(group.slug, group.taxonomies.map(t => t.slug));
892
+ * }
893
+ * ```
894
+ */
895
+ get taxonomies(): {
896
+ list: () => Promise<TaxonomyListResult>;
897
+ };
898
+ private listTaxonomies;
853
899
  /**
854
900
  * Search namespace for vector similarity search
855
901
  */
@@ -918,4 +964,4 @@ declare class StowServer {
918
964
  private renameProfileCluster;
919
965
  }
920
966
 
921
- export { type BucketResult, type ColorSearchRequest, type ColorSearchResult, type ColorSearchResultItem, type ConfirmUploadRequest, 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 SearchFilters, type SearchIncludeField, type SearchResultItem, type SimilarSearchRequest, type SimilarSearchResult, StowError, StowServer, type StowServerConfig, type TaskTriggerResult, type TextSearchRequest, type TransformOptions, type UpdateBucketRequest, type UploadResult, type WhoamiResult };
967
+ export { type AppliedFilters, type BucketResult, type ColorSearchRequest, type ColorSearchResult, type ColorSearchResultItem, type ConfirmUploadRequest, 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 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 UpdateBucketRequest, type UploadResult, type WhoamiResult };
package/dist/index.d.ts CHANGED
@@ -389,6 +389,8 @@ type FileIncludeField = "tags" | "taxonomies";
389
389
  /** Input payload for text-based semantic search. */
390
390
  interface TextSearchRequest {
391
391
  bucket?: string;
392
+ /** File keys to exclude from results (e.g. already-seen items). Max 500. */
393
+ excludeKeys?: string[];
392
394
  filters?: SearchFilters;
393
395
  include?: SearchIncludeField[];
394
396
  limit?: number;
@@ -457,7 +459,7 @@ interface SimilarSearchRequest {
457
459
  clusterId?: string;
458
460
  /** Blend multiple cluster centroids as query vector. Requires profileId. */
459
461
  clusterIds?: string[];
460
- /** File keys to exclude from results (e.g. already-seen items). Max 200. */
462
+ /** File keys to exclude from results (e.g. already-seen items). Max 500. */
461
463
  excludeKeys?: string[];
462
464
  /** Find files similar to this file key */
463
465
  fileKey?: string;
@@ -480,7 +482,7 @@ interface DiverseSearchRequest {
480
482
  clusterId?: string;
481
483
  /** Blend multiple cluster centroids as query vector. Requires profileId. */
482
484
  clusterIds?: string[];
483
- /** File keys to exclude from results (e.g. already-seen items). Max 200. */
485
+ /** File keys to exclude from results (e.g. already-seen items). Max 500. */
484
486
  excludeKeys?: string[];
485
487
  /** Find diverse files seeded by this file key */
486
488
  fileKey?: string;
@@ -525,8 +527,18 @@ interface SearchResultItem {
525
527
  }>;
526
528
  width?: number | null;
527
529
  }
530
+ /** Which filter categories were active in the request. */
531
+ interface AppliedFilters {
532
+ color?: string[];
533
+ contentType?: string[];
534
+ metadata?: string[];
535
+ tags?: string[];
536
+ taxonomies?: string[];
537
+ taxonomyGroups?: string[];
538
+ }
528
539
  /** Metadata describing server-side filter pruning. */
529
540
  interface FilteredMetadata {
541
+ appliedFilters: AppliedFilters;
530
542
  candidatesScanned: number;
531
543
  requested: number;
532
544
  returned: number;
@@ -542,6 +554,8 @@ interface ColorSearchRequest {
542
554
  bucket?: string;
543
555
  /** Only search the dominant (first) color per file */
544
556
  dominantOnly?: boolean;
557
+ /** File keys to exclude from results (e.g. already-seen items). Max 500. */
558
+ excludeKeys?: string[];
545
559
  /** Target color as hex (e.g. "#FF0000") */
546
560
  hex?: string;
547
561
  /** Max results (default 10, max 50) */
@@ -561,6 +575,7 @@ interface ColorSearchResultItem {
561
575
  colorDistance: number;
562
576
  contentType: string;
563
577
  createdAt: string;
578
+ height: number | null;
564
579
  id: string;
565
580
  key: string;
566
581
  matchedColor: {
@@ -573,11 +588,27 @@ interface ColorSearchResultItem {
573
588
  position: number;
574
589
  proportion: number;
575
590
  };
591
+ width: number | null;
576
592
  }
577
593
  /** Result payload for color similarity search. */
578
594
  interface ColorSearchResult {
579
595
  results: ColorSearchResultItem[];
580
596
  }
597
+ /** A taxonomy term within a group. */
598
+ interface TaxonomyTerm {
599
+ name: string;
600
+ slug: string;
601
+ }
602
+ /** A taxonomy group with its terms. */
603
+ interface TaxonomyGroup {
604
+ name: string;
605
+ slug: string;
606
+ taxonomies: TaxonomyTerm[];
607
+ }
608
+ /** Result payload for taxonomy listing. */
609
+ interface TaxonomyListResult {
610
+ groups: TaxonomyGroup[];
611
+ }
581
612
  /** Server-side SDK client for Stow's API. */
582
613
  declare class StowServer {
583
614
  private readonly apiKey;
@@ -850,6 +881,21 @@ declare class StowServer {
850
881
  removeTag(key: string, tagId: string, options?: {
851
882
  bucket?: string;
852
883
  }): Promise<void>;
884
+ /**
885
+ * Taxonomies namespace for discovering available taxonomy terms.
886
+ *
887
+ * @example
888
+ * ```typescript
889
+ * const { groups } = await stow.taxonomies.list();
890
+ * for (const group of groups) {
891
+ * console.log(group.slug, group.taxonomies.map(t => t.slug));
892
+ * }
893
+ * ```
894
+ */
895
+ get taxonomies(): {
896
+ list: () => Promise<TaxonomyListResult>;
897
+ };
898
+ private listTaxonomies;
853
899
  /**
854
900
  * Search namespace for vector similarity search
855
901
  */
@@ -918,4 +964,4 @@ declare class StowServer {
918
964
  private renameProfileCluster;
919
965
  }
920
966
 
921
- export { type BucketResult, type ColorSearchRequest, type ColorSearchResult, type ColorSearchResultItem, type ConfirmUploadRequest, 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 SearchFilters, type SearchIncludeField, type SearchResultItem, type SimilarSearchRequest, type SimilarSearchResult, StowError, StowServer, type StowServerConfig, type TaskTriggerResult, type TextSearchRequest, type TransformOptions, type UpdateBucketRequest, type UploadResult, type WhoamiResult };
967
+ export { type AppliedFilters, type BucketResult, type ColorSearchRequest, type ColorSearchResult, type ColorSearchResultItem, type ConfirmUploadRequest, 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 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 UpdateBucketRequest, type UploadResult, type WhoamiResult };
package/dist/index.js CHANGED
@@ -294,12 +294,12 @@ var StowServer = class {
294
294
  constructor(config) {
295
295
  if (typeof config === "string") {
296
296
  this.apiKey = config;
297
- this.baseUrl = "https://app.stow.sh";
297
+ this.baseUrl = "https://api.stow.sh";
298
298
  this.timeout = 3e4;
299
299
  this.retries = 3;
300
300
  } else {
301
301
  this.apiKey = config.apiKey;
302
- this.baseUrl = config.baseUrl || "https://app.stow.sh";
302
+ this.baseUrl = config.baseUrl || "https://api.stow.sh";
303
303
  this.bucket = config.bucket;
304
304
  this.timeout = config.timeout ?? 3e4;
305
305
  this.retries = config.retries ?? 3;
@@ -315,20 +315,20 @@ var StowServer = class {
315
315
  * Return account usage and API key info for the current credential.
316
316
  */
317
317
  whoami() {
318
- return this.request("/api/whoami", { method: "GET" }, whoamiSchema);
318
+ return this.request("/whoami", { method: "GET" }, whoamiSchema);
319
319
  }
320
320
  /**
321
321
  * List all buckets available to the current organization.
322
322
  */
323
323
  listBuckets() {
324
- return this.request("/api/buckets", { method: "GET" }, listBucketsSchema);
324
+ return this.request("/buckets", { method: "GET" }, listBucketsSchema);
325
325
  }
326
326
  /**
327
327
  * Create a new bucket.
328
328
  */
329
329
  async createBucket(request) {
330
330
  const result = await this.request(
331
- "/api/buckets",
331
+ "/buckets",
332
332
  {
333
333
  method: "POST",
334
334
  headers: { "Content-Type": "application/json" },
@@ -343,7 +343,7 @@ var StowServer = class {
343
343
  */
344
344
  async getBucket(id) {
345
345
  const result = await this.request(
346
- `/api/buckets/${encodeURIComponent(id)}`,
346
+ `/buckets/${encodeURIComponent(id)}`,
347
347
  { method: "GET" },
348
348
  bucketResponseSchema
349
349
  );
@@ -354,7 +354,7 @@ var StowServer = class {
354
354
  */
355
355
  async updateBucket(id, updates) {
356
356
  const result = await this.request(
357
- `/api/buckets/${encodeURIComponent(id)}`,
357
+ `/buckets/${encodeURIComponent(id)}`,
358
358
  {
359
359
  method: "PATCH",
360
360
  headers: { "Content-Type": "application/json" },
@@ -369,7 +369,7 @@ var StowServer = class {
369
369
  */
370
370
  async updateBucketByName(name, updates) {
371
371
  const result = await this.request(
372
- `/api/buckets/_?bucket=${encodeURIComponent(name)}`,
372
+ `/buckets/_?bucket=${encodeURIComponent(name)}`,
373
373
  {
374
374
  method: "PATCH",
375
375
  headers: { "Content-Type": "application/json" },
@@ -389,7 +389,7 @@ var StowServer = class {
389
389
  * Delete a bucket by id.
390
390
  */
391
391
  async deleteBucket(id) {
392
- await this.request(`/api/buckets/${encodeURIComponent(id)}`, {
392
+ await this.request(`/buckets/${encodeURIComponent(id)}`, {
393
393
  method: "DELETE"
394
394
  });
395
395
  }
@@ -517,7 +517,7 @@ var StowServer = class {
517
517
  }
518
518
  return this.request(
519
519
  this.withBucket(
520
- presign.confirmUrl || "/api/presign/confirm",
520
+ presign.confirmUrl || "/presign/confirm",
521
521
  options?.bucket
522
522
  ),
523
523
  {
@@ -543,7 +543,7 @@ var StowServer = class {
543
543
  */
544
544
  async uploadFromUrl(url, filename, options) {
545
545
  const result = await this.request(
546
- this.withBucket("/api/upload", options?.bucket),
546
+ this.withBucket("/upload", options?.bucket),
547
547
  {
548
548
  method: "POST",
549
549
  headers: { "Content-Type": "application/json" },
@@ -576,7 +576,7 @@ var StowServer = class {
576
576
  */
577
577
  async queueUploadFromUrl(url, filename, options) {
578
578
  return this.request(
579
- this.withBucket("/api/upload", options?.bucket),
579
+ this.withBucket("/upload", options?.bucket),
580
580
  {
581
581
  method: "POST",
582
582
  headers: { "Content-Type": "application/json" },
@@ -614,7 +614,7 @@ var StowServer = class {
614
614
  contentHash
615
615
  } = request;
616
616
  return this.request(
617
- this.withBucket("/api/presign", bucket),
617
+ this.withBucket("/presign", bucket),
618
618
  {
619
619
  method: "POST",
620
620
  headers: { "Content-Type": "application/json" },
@@ -648,7 +648,7 @@ var StowServer = class {
648
648
  altText
649
649
  } = request;
650
650
  return this.request(
651
- this.withBucket("/api/presign/confirm", bucket),
651
+ this.withBucket("/presign/confirm", bucket),
652
652
  {
653
653
  method: "POST",
654
654
  headers: { "Content-Type": "application/json" },
@@ -689,7 +689,7 @@ var StowServer = class {
689
689
  if (options?.include?.length) {
690
690
  params.set("include", options.include.join(","));
691
691
  }
692
- const path = `/api/files?${params}`;
692
+ const path = `/files?${params}`;
693
693
  return this.request(
694
694
  this.withBucket(path, options?.bucket),
695
695
  { method: "GET" },
@@ -700,7 +700,7 @@ var StowServer = class {
700
700
  * Delete a file by key
701
701
  */
702
702
  async deleteFile(key, options) {
703
- const path = `/api/files/${encodeURIComponent(key)}`;
703
+ const path = `/files/${encodeURIComponent(key)}`;
704
704
  await this.request(this.withBucket(path, options?.bucket), {
705
705
  method: "DELETE"
706
706
  });
@@ -709,7 +709,7 @@ var StowServer = class {
709
709
  * Update metadata on an existing file
710
710
  */
711
711
  updateFileMetadata(key, metadata, options) {
712
- const path = `/api/files/${encodeURIComponent(key)}`;
712
+ const path = `/files/${encodeURIComponent(key)}`;
713
713
  return this.request(this.withBucket(path, options?.bucket), {
714
714
  method: "PATCH",
715
715
  headers: { "Content-Type": "application/json" },
@@ -727,7 +727,7 @@ var StowServer = class {
727
727
  params.set("include", options.include.join(","));
728
728
  }
729
729
  const qs = params.toString();
730
- const path = `/api/files/${encodeURIComponent(key)}${qs ? `?${qs}` : ""}`;
730
+ const path = `/files/${encodeURIComponent(key)}${qs ? `?${qs}` : ""}`;
731
731
  return this.request(
732
732
  this.withBucket(path, options?.bucket),
733
733
  { method: "GET" },
@@ -739,7 +739,7 @@ var StowServer = class {
739
739
  * Requires a searchable bucket.
740
740
  */
741
741
  extractColors(key, options) {
742
- const path = `/api/files/${encodeURIComponent(key)}/colors`;
742
+ const path = `/files/${encodeURIComponent(key)}/colors`;
743
743
  return this.request(
744
744
  this.withBucket(path, options?.bucket),
745
745
  { method: "POST" },
@@ -750,7 +750,7 @@ var StowServer = class {
750
750
  * Extract dimensions (width/height) from an image or video file.
751
751
  */
752
752
  extractDimensions(key, options) {
753
- const path = `/api/files/${encodeURIComponent(key)}/dimensions`;
753
+ const path = `/files/${encodeURIComponent(key)}/dimensions`;
754
754
  return this.request(
755
755
  this.withBucket(path, options?.bucket),
756
756
  { method: "POST" },
@@ -762,7 +762,7 @@ var StowServer = class {
762
762
  * Requires a searchable bucket.
763
763
  */
764
764
  embed(key, options) {
765
- const path = `/api/files/${encodeURIComponent(key)}/embedding`;
765
+ const path = `/files/${encodeURIComponent(key)}/embedding`;
766
766
  return this.request(
767
767
  this.withBucket(path, options?.bucket),
768
768
  { method: "POST" },
@@ -774,7 +774,7 @@ var StowServer = class {
774
774
  * Requires a searchable bucket.
775
775
  */
776
776
  generateTitle(key, options) {
777
- const path = `/api/files/${encodeURIComponent(key)}/title`;
777
+ const path = `/files/${encodeURIComponent(key)}/title`;
778
778
  return this.request(
779
779
  this.withBucket(path, options?.bucket),
780
780
  { method: "POST" },
@@ -786,7 +786,7 @@ var StowServer = class {
786
786
  * Requires a searchable bucket.
787
787
  */
788
788
  generateDescription(key, options) {
789
- const path = `/api/files/${encodeURIComponent(key)}/description`;
789
+ const path = `/files/${encodeURIComponent(key)}/description`;
790
790
  return this.request(
791
791
  this.withBucket(path, options?.bucket),
792
792
  { method: "POST" },
@@ -798,7 +798,7 @@ var StowServer = class {
798
798
  * Requires a searchable bucket.
799
799
  */
800
800
  generateAltText(key, options) {
801
- const path = `/api/files/${encodeURIComponent(key)}/alt-text`;
801
+ const path = `/files/${encodeURIComponent(key)}/alt-text`;
802
802
  return this.request(
803
803
  this.withBucket(path, options?.bucket),
804
804
  { method: "POST" },
@@ -813,7 +813,7 @@ var StowServer = class {
813
813
  * tasks are re-dispatched as if the file were newly uploaded.
814
814
  */
815
815
  replaceFile(key, url, options) {
816
- const path = `/api/files/${encodeURIComponent(key)}/replace`;
816
+ const path = `/files/${encodeURIComponent(key)}/replace`;
817
817
  return this.request(
818
818
  this.withBucket(path, options?.bucket),
819
819
  {
@@ -870,17 +870,17 @@ var StowServer = class {
870
870
  };
871
871
  }
872
872
  listTags() {
873
- return this.request("/api/tags", { method: "GET" });
873
+ return this.request("/tags", { method: "GET" });
874
874
  }
875
875
  createTag(params) {
876
- return this.request("/api/tags", {
876
+ return this.request("/tags", {
877
877
  method: "POST",
878
878
  headers: { "Content-Type": "application/json" },
879
879
  body: JSON.stringify(params)
880
880
  });
881
881
  }
882
882
  async deleteTag(id) {
883
- await this.request(`/api/tags/${encodeURIComponent(id)}`, {
883
+ await this.request(`/tags/${encodeURIComponent(id)}`, {
884
884
  method: "DELETE"
885
885
  });
886
886
  }
@@ -891,7 +891,7 @@ var StowServer = class {
891
891
  * Add tags to a file
892
892
  */
893
893
  async addTags(key, tagIds, options) {
894
- const path = `/api/files/${encodeURIComponent(key)}/tags`;
894
+ const path = `/files/${encodeURIComponent(key)}/tags`;
895
895
  await this.request(this.withBucket(path, options?.bucket), {
896
896
  method: "POST",
897
897
  headers: { "Content-Type": "application/json" },
@@ -902,12 +902,34 @@ var StowServer = class {
902
902
  * Remove a tag from a file
903
903
  */
904
904
  async removeTag(key, tagId, options) {
905
- const path = `/api/files/${encodeURIComponent(key)}/tags/${encodeURIComponent(tagId)}`;
905
+ const path = `/files/${encodeURIComponent(key)}/tags/${encodeURIComponent(tagId)}`;
906
906
  await this.request(this.withBucket(path, options?.bucket), {
907
907
  method: "DELETE"
908
908
  });
909
909
  }
910
910
  // ============================================================
911
+ // TAXONOMIES - Discover taxonomy groups and terms
912
+ // ============================================================
913
+ /**
914
+ * Taxonomies namespace for discovering available taxonomy terms.
915
+ *
916
+ * @example
917
+ * ```typescript
918
+ * const { groups } = await stow.taxonomies.list();
919
+ * for (const group of groups) {
920
+ * console.log(group.slug, group.taxonomies.map(t => t.slug));
921
+ * }
922
+ * ```
923
+ */
924
+ get taxonomies() {
925
+ return {
926
+ list: () => this.listTaxonomies()
927
+ };
928
+ }
929
+ listTaxonomies() {
930
+ return this.request("/taxonomies", { method: "GET" });
931
+ }
932
+ // ============================================================
911
933
  // SEARCH - Vector similarity search
912
934
  // ============================================================
913
935
  /**
@@ -923,7 +945,7 @@ var StowServer = class {
923
945
  }
924
946
  searchSimilar(params) {
925
947
  const bucket = this.resolveBucket(params.bucket);
926
- return this.request("/api/search/similar", {
948
+ return this.request("/search/similar", {
927
949
  method: "POST",
928
950
  headers: { "Content-Type": "application/json" },
929
951
  body: JSON.stringify({
@@ -942,7 +964,7 @@ var StowServer = class {
942
964
  }
943
965
  searchDiverse(params) {
944
966
  const bucket = this.resolveBucket(params.bucket);
945
- return this.request("/api/search/diverse", {
967
+ return this.request("/search/diverse", {
946
968
  method: "POST",
947
969
  headers: { "Content-Type": "application/json" },
948
970
  body: JSON.stringify({
@@ -962,13 +984,14 @@ var StowServer = class {
962
984
  }
963
985
  searchText(params) {
964
986
  const bucket = this.resolveBucket(params.bucket);
965
- return this.request("/api/search/text", {
987
+ return this.request("/search/text", {
966
988
  method: "POST",
967
989
  headers: { "Content-Type": "application/json" },
968
990
  body: JSON.stringify({
969
991
  query: params.query,
970
992
  ...bucket ? { bucket } : {},
971
993
  ...params.limit ? { limit: params.limit } : {},
994
+ ...params.excludeKeys?.length ? { excludeKeys: params.excludeKeys } : {},
972
995
  ...params.filters ? { filters: params.filters } : {},
973
996
  ...params.include?.length ? { include: params.include } : {}
974
997
  })
@@ -976,7 +999,7 @@ var StowServer = class {
976
999
  }
977
1000
  searchColor(params) {
978
1001
  const bucket = this.resolveBucket(params.bucket);
979
- return this.request("/api/search/color", {
1002
+ return this.request("/search/color", {
980
1003
  method: "POST",
981
1004
  headers: { "Content-Type": "application/json" },
982
1005
  body: JSON.stringify({
@@ -984,6 +1007,7 @@ var StowServer = class {
984
1007
  ...params.oklab ? { oklab: params.oklab } : {},
985
1008
  ...bucket ? { bucket } : {},
986
1009
  ...params.limit ? { limit: params.limit } : {},
1010
+ ...params.excludeKeys?.length ? { excludeKeys: params.excludeKeys } : {},
987
1011
  ...params.minProportion !== void 0 ? { minProportion: params.minProportion } : {},
988
1012
  ...params.dominantOnly ? { dominantOnly: params.dominantOnly } : {}
989
1013
  })
@@ -1008,7 +1032,7 @@ var StowServer = class {
1008
1032
  const contentType = options?.contentType || "application/octet-stream";
1009
1033
  const filename = options?.filename || "file";
1010
1034
  const buffer = Buffer.isBuffer(file) ? file : Buffer.from(await file.arrayBuffer());
1011
- const presign = await this.request("/api/drops/presign", {
1035
+ const presign = await this.request("/drops/presign", {
1012
1036
  method: "POST",
1013
1037
  headers: { "Content-Type": "application/json" },
1014
1038
  body: JSON.stringify({
@@ -1026,7 +1050,7 @@ var StowServer = class {
1026
1050
  throw new StowError("Failed to upload to storage", putRes.status);
1027
1051
  }
1028
1052
  return this.request(
1029
- presign.confirmUrl || "/api/drops/presign/confirm",
1053
+ presign.confirmUrl || "/drops/presign/confirm",
1030
1054
  {
1031
1055
  method: "POST",
1032
1056
  headers: { "Content-Type": "application/json" },
@@ -1046,13 +1070,13 @@ var StowServer = class {
1046
1070
  * List all drops for the authenticated user
1047
1071
  */
1048
1072
  listDrops() {
1049
- return this.request("/api/drops", { method: "GET" }, listDropsSchema);
1073
+ return this.request("/drops", { method: "GET" }, listDropsSchema);
1050
1074
  }
1051
1075
  /**
1052
1076
  * Delete a drop by ID
1053
1077
  */
1054
1078
  async deleteDrop(id) {
1055
- await this.request(`/api/drops/${encodeURIComponent(id)}`, {
1079
+ await this.request(`/drops/${encodeURIComponent(id)}`, {
1056
1080
  method: "DELETE"
1057
1081
  });
1058
1082
  }
@@ -1078,7 +1102,7 @@ var StowServer = class {
1078
1102
  }
1079
1103
  createProfile(params) {
1080
1104
  return this.request(
1081
- "/api/profiles",
1105
+ "/profiles",
1082
1106
  {
1083
1107
  method: "POST",
1084
1108
  headers: { "Content-Type": "application/json" },
@@ -1093,19 +1117,19 @@ var StowServer = class {
1093
1117
  }
1094
1118
  getProfile(id) {
1095
1119
  return this.request(
1096
- `/api/profiles/${encodeURIComponent(id)}`,
1120
+ `/profiles/${encodeURIComponent(id)}`,
1097
1121
  { method: "GET" },
1098
1122
  profileResultSchema
1099
1123
  );
1100
1124
  }
1101
1125
  async deleteProfile(id) {
1102
- await this.request(`/api/profiles/${encodeURIComponent(id)}`, {
1126
+ await this.request(`/profiles/${encodeURIComponent(id)}`, {
1103
1127
  method: "DELETE"
1104
1128
  });
1105
1129
  }
1106
1130
  addProfileFiles(id, fileKeys, bucket) {
1107
1131
  return this.request(
1108
- `/api/profiles/${encodeURIComponent(id)}/files`,
1132
+ `/profiles/${encodeURIComponent(id)}/files`,
1109
1133
  {
1110
1134
  method: "POST",
1111
1135
  headers: { "Content-Type": "application/json" },
@@ -1119,7 +1143,7 @@ var StowServer = class {
1119
1143
  }
1120
1144
  removeProfileFiles(id, fileKeys, bucket) {
1121
1145
  return this.request(
1122
- `/api/profiles/${encodeURIComponent(id)}/files`,
1146
+ `/profiles/${encodeURIComponent(id)}/files`,
1123
1147
  {
1124
1148
  method: "DELETE",
1125
1149
  headers: { "Content-Type": "application/json" },
@@ -1133,7 +1157,7 @@ var StowServer = class {
1133
1157
  }
1134
1158
  signalProfile(id, signals, bucket) {
1135
1159
  return this.request(
1136
- `/api/profiles/${encodeURIComponent(id)}/signals`,
1160
+ `/profiles/${encodeURIComponent(id)}/signals`,
1137
1161
  {
1138
1162
  method: "POST",
1139
1163
  headers: { "Content-Type": "application/json" },
@@ -1147,7 +1171,7 @@ var StowServer = class {
1147
1171
  }
1148
1172
  deleteProfileSignals(id, signalIds) {
1149
1173
  return this.request(
1150
- `/api/profiles/${encodeURIComponent(id)}/signals`,
1174
+ `/profiles/${encodeURIComponent(id)}/signals`,
1151
1175
  {
1152
1176
  method: "DELETE",
1153
1177
  headers: { "Content-Type": "application/json" },
@@ -1157,12 +1181,12 @@ var StowServer = class {
1157
1181
  );
1158
1182
  }
1159
1183
  getProfileClusters(id) {
1160
- return this.request(`/api/profiles/${encodeURIComponent(id)}/clusters`, {
1184
+ return this.request(`/profiles/${encodeURIComponent(id)}/clusters`, {
1161
1185
  method: "GET"
1162
1186
  });
1163
1187
  }
1164
1188
  reclusterProfile(id, params) {
1165
- return this.request(`/api/profiles/${encodeURIComponent(id)}/clusters`, {
1189
+ return this.request(`/profiles/${encodeURIComponent(id)}/clusters`, {
1166
1190
  method: "POST",
1167
1191
  headers: { "Content-Type": "application/json" },
1168
1192
  body: JSON.stringify({
@@ -1172,7 +1196,7 @@ var StowServer = class {
1172
1196
  }
1173
1197
  renameProfileCluster(profileId, clusterId, params) {
1174
1198
  return this.request(
1175
- `/api/profiles/${encodeURIComponent(profileId)}/clusters/${encodeURIComponent(clusterId)}`,
1199
+ `/profiles/${encodeURIComponent(profileId)}/clusters/${encodeURIComponent(clusterId)}`,
1176
1200
  {
1177
1201
  method: "PUT",
1178
1202
  headers: { "Content-Type": "application/json" },
package/dist/index.mjs CHANGED
@@ -269,12 +269,12 @@ var StowServer = class {
269
269
  constructor(config) {
270
270
  if (typeof config === "string") {
271
271
  this.apiKey = config;
272
- this.baseUrl = "https://app.stow.sh";
272
+ this.baseUrl = "https://api.stow.sh";
273
273
  this.timeout = 3e4;
274
274
  this.retries = 3;
275
275
  } else {
276
276
  this.apiKey = config.apiKey;
277
- this.baseUrl = config.baseUrl || "https://app.stow.sh";
277
+ this.baseUrl = config.baseUrl || "https://api.stow.sh";
278
278
  this.bucket = config.bucket;
279
279
  this.timeout = config.timeout ?? 3e4;
280
280
  this.retries = config.retries ?? 3;
@@ -290,20 +290,20 @@ var StowServer = class {
290
290
  * Return account usage and API key info for the current credential.
291
291
  */
292
292
  whoami() {
293
- return this.request("/api/whoami", { method: "GET" }, whoamiSchema);
293
+ return this.request("/whoami", { method: "GET" }, whoamiSchema);
294
294
  }
295
295
  /**
296
296
  * List all buckets available to the current organization.
297
297
  */
298
298
  listBuckets() {
299
- return this.request("/api/buckets", { method: "GET" }, listBucketsSchema);
299
+ return this.request("/buckets", { method: "GET" }, listBucketsSchema);
300
300
  }
301
301
  /**
302
302
  * Create a new bucket.
303
303
  */
304
304
  async createBucket(request) {
305
305
  const result = await this.request(
306
- "/api/buckets",
306
+ "/buckets",
307
307
  {
308
308
  method: "POST",
309
309
  headers: { "Content-Type": "application/json" },
@@ -318,7 +318,7 @@ var StowServer = class {
318
318
  */
319
319
  async getBucket(id) {
320
320
  const result = await this.request(
321
- `/api/buckets/${encodeURIComponent(id)}`,
321
+ `/buckets/${encodeURIComponent(id)}`,
322
322
  { method: "GET" },
323
323
  bucketResponseSchema
324
324
  );
@@ -329,7 +329,7 @@ var StowServer = class {
329
329
  */
330
330
  async updateBucket(id, updates) {
331
331
  const result = await this.request(
332
- `/api/buckets/${encodeURIComponent(id)}`,
332
+ `/buckets/${encodeURIComponent(id)}`,
333
333
  {
334
334
  method: "PATCH",
335
335
  headers: { "Content-Type": "application/json" },
@@ -344,7 +344,7 @@ var StowServer = class {
344
344
  */
345
345
  async updateBucketByName(name, updates) {
346
346
  const result = await this.request(
347
- `/api/buckets/_?bucket=${encodeURIComponent(name)}`,
347
+ `/buckets/_?bucket=${encodeURIComponent(name)}`,
348
348
  {
349
349
  method: "PATCH",
350
350
  headers: { "Content-Type": "application/json" },
@@ -364,7 +364,7 @@ var StowServer = class {
364
364
  * Delete a bucket by id.
365
365
  */
366
366
  async deleteBucket(id) {
367
- await this.request(`/api/buckets/${encodeURIComponent(id)}`, {
367
+ await this.request(`/buckets/${encodeURIComponent(id)}`, {
368
368
  method: "DELETE"
369
369
  });
370
370
  }
@@ -492,7 +492,7 @@ var StowServer = class {
492
492
  }
493
493
  return this.request(
494
494
  this.withBucket(
495
- presign.confirmUrl || "/api/presign/confirm",
495
+ presign.confirmUrl || "/presign/confirm",
496
496
  options?.bucket
497
497
  ),
498
498
  {
@@ -518,7 +518,7 @@ var StowServer = class {
518
518
  */
519
519
  async uploadFromUrl(url, filename, options) {
520
520
  const result = await this.request(
521
- this.withBucket("/api/upload", options?.bucket),
521
+ this.withBucket("/upload", options?.bucket),
522
522
  {
523
523
  method: "POST",
524
524
  headers: { "Content-Type": "application/json" },
@@ -551,7 +551,7 @@ var StowServer = class {
551
551
  */
552
552
  async queueUploadFromUrl(url, filename, options) {
553
553
  return this.request(
554
- this.withBucket("/api/upload", options?.bucket),
554
+ this.withBucket("/upload", options?.bucket),
555
555
  {
556
556
  method: "POST",
557
557
  headers: { "Content-Type": "application/json" },
@@ -589,7 +589,7 @@ var StowServer = class {
589
589
  contentHash
590
590
  } = request;
591
591
  return this.request(
592
- this.withBucket("/api/presign", bucket),
592
+ this.withBucket("/presign", bucket),
593
593
  {
594
594
  method: "POST",
595
595
  headers: { "Content-Type": "application/json" },
@@ -623,7 +623,7 @@ var StowServer = class {
623
623
  altText
624
624
  } = request;
625
625
  return this.request(
626
- this.withBucket("/api/presign/confirm", bucket),
626
+ this.withBucket("/presign/confirm", bucket),
627
627
  {
628
628
  method: "POST",
629
629
  headers: { "Content-Type": "application/json" },
@@ -664,7 +664,7 @@ var StowServer = class {
664
664
  if (options?.include?.length) {
665
665
  params.set("include", options.include.join(","));
666
666
  }
667
- const path = `/api/files?${params}`;
667
+ const path = `/files?${params}`;
668
668
  return this.request(
669
669
  this.withBucket(path, options?.bucket),
670
670
  { method: "GET" },
@@ -675,7 +675,7 @@ var StowServer = class {
675
675
  * Delete a file by key
676
676
  */
677
677
  async deleteFile(key, options) {
678
- const path = `/api/files/${encodeURIComponent(key)}`;
678
+ const path = `/files/${encodeURIComponent(key)}`;
679
679
  await this.request(this.withBucket(path, options?.bucket), {
680
680
  method: "DELETE"
681
681
  });
@@ -684,7 +684,7 @@ var StowServer = class {
684
684
  * Update metadata on an existing file
685
685
  */
686
686
  updateFileMetadata(key, metadata, options) {
687
- const path = `/api/files/${encodeURIComponent(key)}`;
687
+ const path = `/files/${encodeURIComponent(key)}`;
688
688
  return this.request(this.withBucket(path, options?.bucket), {
689
689
  method: "PATCH",
690
690
  headers: { "Content-Type": "application/json" },
@@ -702,7 +702,7 @@ var StowServer = class {
702
702
  params.set("include", options.include.join(","));
703
703
  }
704
704
  const qs = params.toString();
705
- const path = `/api/files/${encodeURIComponent(key)}${qs ? `?${qs}` : ""}`;
705
+ const path = `/files/${encodeURIComponent(key)}${qs ? `?${qs}` : ""}`;
706
706
  return this.request(
707
707
  this.withBucket(path, options?.bucket),
708
708
  { method: "GET" },
@@ -714,7 +714,7 @@ var StowServer = class {
714
714
  * Requires a searchable bucket.
715
715
  */
716
716
  extractColors(key, options) {
717
- const path = `/api/files/${encodeURIComponent(key)}/colors`;
717
+ const path = `/files/${encodeURIComponent(key)}/colors`;
718
718
  return this.request(
719
719
  this.withBucket(path, options?.bucket),
720
720
  { method: "POST" },
@@ -725,7 +725,7 @@ var StowServer = class {
725
725
  * Extract dimensions (width/height) from an image or video file.
726
726
  */
727
727
  extractDimensions(key, options) {
728
- const path = `/api/files/${encodeURIComponent(key)}/dimensions`;
728
+ const path = `/files/${encodeURIComponent(key)}/dimensions`;
729
729
  return this.request(
730
730
  this.withBucket(path, options?.bucket),
731
731
  { method: "POST" },
@@ -737,7 +737,7 @@ var StowServer = class {
737
737
  * Requires a searchable bucket.
738
738
  */
739
739
  embed(key, options) {
740
- const path = `/api/files/${encodeURIComponent(key)}/embedding`;
740
+ const path = `/files/${encodeURIComponent(key)}/embedding`;
741
741
  return this.request(
742
742
  this.withBucket(path, options?.bucket),
743
743
  { method: "POST" },
@@ -749,7 +749,7 @@ var StowServer = class {
749
749
  * Requires a searchable bucket.
750
750
  */
751
751
  generateTitle(key, options) {
752
- const path = `/api/files/${encodeURIComponent(key)}/title`;
752
+ const path = `/files/${encodeURIComponent(key)}/title`;
753
753
  return this.request(
754
754
  this.withBucket(path, options?.bucket),
755
755
  { method: "POST" },
@@ -761,7 +761,7 @@ var StowServer = class {
761
761
  * Requires a searchable bucket.
762
762
  */
763
763
  generateDescription(key, options) {
764
- const path = `/api/files/${encodeURIComponent(key)}/description`;
764
+ const path = `/files/${encodeURIComponent(key)}/description`;
765
765
  return this.request(
766
766
  this.withBucket(path, options?.bucket),
767
767
  { method: "POST" },
@@ -773,7 +773,7 @@ var StowServer = class {
773
773
  * Requires a searchable bucket.
774
774
  */
775
775
  generateAltText(key, options) {
776
- const path = `/api/files/${encodeURIComponent(key)}/alt-text`;
776
+ const path = `/files/${encodeURIComponent(key)}/alt-text`;
777
777
  return this.request(
778
778
  this.withBucket(path, options?.bucket),
779
779
  { method: "POST" },
@@ -788,7 +788,7 @@ var StowServer = class {
788
788
  * tasks are re-dispatched as if the file were newly uploaded.
789
789
  */
790
790
  replaceFile(key, url, options) {
791
- const path = `/api/files/${encodeURIComponent(key)}/replace`;
791
+ const path = `/files/${encodeURIComponent(key)}/replace`;
792
792
  return this.request(
793
793
  this.withBucket(path, options?.bucket),
794
794
  {
@@ -845,17 +845,17 @@ var StowServer = class {
845
845
  };
846
846
  }
847
847
  listTags() {
848
- return this.request("/api/tags", { method: "GET" });
848
+ return this.request("/tags", { method: "GET" });
849
849
  }
850
850
  createTag(params) {
851
- return this.request("/api/tags", {
851
+ return this.request("/tags", {
852
852
  method: "POST",
853
853
  headers: { "Content-Type": "application/json" },
854
854
  body: JSON.stringify(params)
855
855
  });
856
856
  }
857
857
  async deleteTag(id) {
858
- await this.request(`/api/tags/${encodeURIComponent(id)}`, {
858
+ await this.request(`/tags/${encodeURIComponent(id)}`, {
859
859
  method: "DELETE"
860
860
  });
861
861
  }
@@ -866,7 +866,7 @@ var StowServer = class {
866
866
  * Add tags to a file
867
867
  */
868
868
  async addTags(key, tagIds, options) {
869
- const path = `/api/files/${encodeURIComponent(key)}/tags`;
869
+ const path = `/files/${encodeURIComponent(key)}/tags`;
870
870
  await this.request(this.withBucket(path, options?.bucket), {
871
871
  method: "POST",
872
872
  headers: { "Content-Type": "application/json" },
@@ -877,12 +877,34 @@ var StowServer = class {
877
877
  * Remove a tag from a file
878
878
  */
879
879
  async removeTag(key, tagId, options) {
880
- const path = `/api/files/${encodeURIComponent(key)}/tags/${encodeURIComponent(tagId)}`;
880
+ const path = `/files/${encodeURIComponent(key)}/tags/${encodeURIComponent(tagId)}`;
881
881
  await this.request(this.withBucket(path, options?.bucket), {
882
882
  method: "DELETE"
883
883
  });
884
884
  }
885
885
  // ============================================================
886
+ // TAXONOMIES - Discover taxonomy groups and terms
887
+ // ============================================================
888
+ /**
889
+ * Taxonomies namespace for discovering available taxonomy terms.
890
+ *
891
+ * @example
892
+ * ```typescript
893
+ * const { groups } = await stow.taxonomies.list();
894
+ * for (const group of groups) {
895
+ * console.log(group.slug, group.taxonomies.map(t => t.slug));
896
+ * }
897
+ * ```
898
+ */
899
+ get taxonomies() {
900
+ return {
901
+ list: () => this.listTaxonomies()
902
+ };
903
+ }
904
+ listTaxonomies() {
905
+ return this.request("/taxonomies", { method: "GET" });
906
+ }
907
+ // ============================================================
886
908
  // SEARCH - Vector similarity search
887
909
  // ============================================================
888
910
  /**
@@ -898,7 +920,7 @@ var StowServer = class {
898
920
  }
899
921
  searchSimilar(params) {
900
922
  const bucket = this.resolveBucket(params.bucket);
901
- return this.request("/api/search/similar", {
923
+ return this.request("/search/similar", {
902
924
  method: "POST",
903
925
  headers: { "Content-Type": "application/json" },
904
926
  body: JSON.stringify({
@@ -917,7 +939,7 @@ var StowServer = class {
917
939
  }
918
940
  searchDiverse(params) {
919
941
  const bucket = this.resolveBucket(params.bucket);
920
- return this.request("/api/search/diverse", {
942
+ return this.request("/search/diverse", {
921
943
  method: "POST",
922
944
  headers: { "Content-Type": "application/json" },
923
945
  body: JSON.stringify({
@@ -937,13 +959,14 @@ var StowServer = class {
937
959
  }
938
960
  searchText(params) {
939
961
  const bucket = this.resolveBucket(params.bucket);
940
- return this.request("/api/search/text", {
962
+ return this.request("/search/text", {
941
963
  method: "POST",
942
964
  headers: { "Content-Type": "application/json" },
943
965
  body: JSON.stringify({
944
966
  query: params.query,
945
967
  ...bucket ? { bucket } : {},
946
968
  ...params.limit ? { limit: params.limit } : {},
969
+ ...params.excludeKeys?.length ? { excludeKeys: params.excludeKeys } : {},
947
970
  ...params.filters ? { filters: params.filters } : {},
948
971
  ...params.include?.length ? { include: params.include } : {}
949
972
  })
@@ -951,7 +974,7 @@ var StowServer = class {
951
974
  }
952
975
  searchColor(params) {
953
976
  const bucket = this.resolveBucket(params.bucket);
954
- return this.request("/api/search/color", {
977
+ return this.request("/search/color", {
955
978
  method: "POST",
956
979
  headers: { "Content-Type": "application/json" },
957
980
  body: JSON.stringify({
@@ -959,6 +982,7 @@ var StowServer = class {
959
982
  ...params.oklab ? { oklab: params.oklab } : {},
960
983
  ...bucket ? { bucket } : {},
961
984
  ...params.limit ? { limit: params.limit } : {},
985
+ ...params.excludeKeys?.length ? { excludeKeys: params.excludeKeys } : {},
962
986
  ...params.minProportion !== void 0 ? { minProportion: params.minProportion } : {},
963
987
  ...params.dominantOnly ? { dominantOnly: params.dominantOnly } : {}
964
988
  })
@@ -983,7 +1007,7 @@ var StowServer = class {
983
1007
  const contentType = options?.contentType || "application/octet-stream";
984
1008
  const filename = options?.filename || "file";
985
1009
  const buffer = Buffer.isBuffer(file) ? file : Buffer.from(await file.arrayBuffer());
986
- const presign = await this.request("/api/drops/presign", {
1010
+ const presign = await this.request("/drops/presign", {
987
1011
  method: "POST",
988
1012
  headers: { "Content-Type": "application/json" },
989
1013
  body: JSON.stringify({
@@ -1001,7 +1025,7 @@ var StowServer = class {
1001
1025
  throw new StowError("Failed to upload to storage", putRes.status);
1002
1026
  }
1003
1027
  return this.request(
1004
- presign.confirmUrl || "/api/drops/presign/confirm",
1028
+ presign.confirmUrl || "/drops/presign/confirm",
1005
1029
  {
1006
1030
  method: "POST",
1007
1031
  headers: { "Content-Type": "application/json" },
@@ -1021,13 +1045,13 @@ var StowServer = class {
1021
1045
  * List all drops for the authenticated user
1022
1046
  */
1023
1047
  listDrops() {
1024
- return this.request("/api/drops", { method: "GET" }, listDropsSchema);
1048
+ return this.request("/drops", { method: "GET" }, listDropsSchema);
1025
1049
  }
1026
1050
  /**
1027
1051
  * Delete a drop by ID
1028
1052
  */
1029
1053
  async deleteDrop(id) {
1030
- await this.request(`/api/drops/${encodeURIComponent(id)}`, {
1054
+ await this.request(`/drops/${encodeURIComponent(id)}`, {
1031
1055
  method: "DELETE"
1032
1056
  });
1033
1057
  }
@@ -1053,7 +1077,7 @@ var StowServer = class {
1053
1077
  }
1054
1078
  createProfile(params) {
1055
1079
  return this.request(
1056
- "/api/profiles",
1080
+ "/profiles",
1057
1081
  {
1058
1082
  method: "POST",
1059
1083
  headers: { "Content-Type": "application/json" },
@@ -1068,19 +1092,19 @@ var StowServer = class {
1068
1092
  }
1069
1093
  getProfile(id) {
1070
1094
  return this.request(
1071
- `/api/profiles/${encodeURIComponent(id)}`,
1095
+ `/profiles/${encodeURIComponent(id)}`,
1072
1096
  { method: "GET" },
1073
1097
  profileResultSchema
1074
1098
  );
1075
1099
  }
1076
1100
  async deleteProfile(id) {
1077
- await this.request(`/api/profiles/${encodeURIComponent(id)}`, {
1101
+ await this.request(`/profiles/${encodeURIComponent(id)}`, {
1078
1102
  method: "DELETE"
1079
1103
  });
1080
1104
  }
1081
1105
  addProfileFiles(id, fileKeys, bucket) {
1082
1106
  return this.request(
1083
- `/api/profiles/${encodeURIComponent(id)}/files`,
1107
+ `/profiles/${encodeURIComponent(id)}/files`,
1084
1108
  {
1085
1109
  method: "POST",
1086
1110
  headers: { "Content-Type": "application/json" },
@@ -1094,7 +1118,7 @@ var StowServer = class {
1094
1118
  }
1095
1119
  removeProfileFiles(id, fileKeys, bucket) {
1096
1120
  return this.request(
1097
- `/api/profiles/${encodeURIComponent(id)}/files`,
1121
+ `/profiles/${encodeURIComponent(id)}/files`,
1098
1122
  {
1099
1123
  method: "DELETE",
1100
1124
  headers: { "Content-Type": "application/json" },
@@ -1108,7 +1132,7 @@ var StowServer = class {
1108
1132
  }
1109
1133
  signalProfile(id, signals, bucket) {
1110
1134
  return this.request(
1111
- `/api/profiles/${encodeURIComponent(id)}/signals`,
1135
+ `/profiles/${encodeURIComponent(id)}/signals`,
1112
1136
  {
1113
1137
  method: "POST",
1114
1138
  headers: { "Content-Type": "application/json" },
@@ -1122,7 +1146,7 @@ var StowServer = class {
1122
1146
  }
1123
1147
  deleteProfileSignals(id, signalIds) {
1124
1148
  return this.request(
1125
- `/api/profiles/${encodeURIComponent(id)}/signals`,
1149
+ `/profiles/${encodeURIComponent(id)}/signals`,
1126
1150
  {
1127
1151
  method: "DELETE",
1128
1152
  headers: { "Content-Type": "application/json" },
@@ -1132,12 +1156,12 @@ var StowServer = class {
1132
1156
  );
1133
1157
  }
1134
1158
  getProfileClusters(id) {
1135
- return this.request(`/api/profiles/${encodeURIComponent(id)}/clusters`, {
1159
+ return this.request(`/profiles/${encodeURIComponent(id)}/clusters`, {
1136
1160
  method: "GET"
1137
1161
  });
1138
1162
  }
1139
1163
  reclusterProfile(id, params) {
1140
- return this.request(`/api/profiles/${encodeURIComponent(id)}/clusters`, {
1164
+ return this.request(`/profiles/${encodeURIComponent(id)}/clusters`, {
1141
1165
  method: "POST",
1142
1166
  headers: { "Content-Type": "application/json" },
1143
1167
  body: JSON.stringify({
@@ -1147,7 +1171,7 @@ var StowServer = class {
1147
1171
  }
1148
1172
  renameProfileCluster(profileId, clusterId, params) {
1149
1173
  return this.request(
1150
- `/api/profiles/${encodeURIComponent(profileId)}/clusters/${encodeURIComponent(clusterId)}`,
1174
+ `/profiles/${encodeURIComponent(profileId)}/clusters/${encodeURIComponent(clusterId)}`,
1151
1175
  {
1152
1176
  method: "PUT",
1153
1177
  headers: { "Content-Type": "application/json" },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@howells/stow-server",
3
- "version": "0.6.0",
3
+ "version": "2.0.0",
4
4
  "description": "Server-side SDK for Stow file storage",
5
5
  "license": "MIT",
6
6
  "repository": {