@howells/stow-server 0.1.2 → 0.2.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.mjs CHANGED
@@ -1,4 +1,5 @@
1
1
  // src/index.ts
2
+ import { createHash } from "crypto";
2
3
  import { z } from "zod";
3
4
  var StowError = class extends Error {
4
5
  status;
@@ -10,12 +11,74 @@ var StowError = class extends Error {
10
11
  this.code = code;
11
12
  }
12
13
  };
14
+ var fileColorSchema = z.object({
15
+ position: z.number().int(),
16
+ proportion: z.number(),
17
+ hex: z.string(),
18
+ name: z.string().nullable(),
19
+ hsl: z.object({ h: z.number(), s: z.number(), l: z.number() }),
20
+ oklab: z.object({ L: z.number(), a: z.number(), b: z.number() }).nullable(),
21
+ oklch: z.object({ l: z.number(), c: z.number(), h: z.number() }).nullable()
22
+ });
23
+ var fileColorProfileSchema = z.object({
24
+ palette: z.object({
25
+ mood: z.string(),
26
+ brightness: z.number(),
27
+ temperature: z.number(),
28
+ vibrancy: z.number(),
29
+ complexity: z.number(),
30
+ dominantFamily: z.string().nullable()
31
+ }),
32
+ backgroundHex: z.string().nullable(),
33
+ accent: z.object({
34
+ hex: z.string(),
35
+ name: z.string().nullable(),
36
+ oklab: z.object({ L: z.number(), a: z.number(), b: z.number() }).nullable(),
37
+ oklch: z.object({ l: z.number(), c: z.number(), h: z.number() }).nullable()
38
+ }).nullable(),
39
+ extractedAt: z.string(),
40
+ colorCount: z.number().int()
41
+ });
13
42
  var uploadResultSchema = z.object({
14
43
  key: z.string(),
15
44
  url: z.string().nullable(),
16
45
  size: z.number(),
17
46
  contentType: z.string().optional(),
18
- metadata: z.record(z.string(), z.string()).optional()
47
+ metadata: z.record(z.string(), z.string()).optional(),
48
+ deduped: z.boolean().optional()
49
+ });
50
+ var bucketSchema = z.object({
51
+ id: z.string(),
52
+ name: z.string(),
53
+ description: z.string().nullable().optional(),
54
+ isPublic: z.boolean().optional(),
55
+ searchable: z.boolean().optional(),
56
+ allowedTypes: z.array(z.string()).nullable().optional(),
57
+ maxFileSize: z.coerce.number().nullable().optional(),
58
+ storageQuota: z.coerce.number().nullable().optional(),
59
+ fileCountLimit: z.coerce.number().nullable().optional(),
60
+ fileCount: z.coerce.number().optional(),
61
+ usageBytes: z.coerce.number().optional(),
62
+ createdAt: z.string().optional()
63
+ });
64
+ var listBucketsSchema = z.object({
65
+ buckets: z.array(bucketSchema)
66
+ });
67
+ var bucketResponseSchema = z.object({
68
+ bucket: bucketSchema
69
+ });
70
+ var whoamiSchema = z.object({
71
+ user: z.object({ email: z.string() }),
72
+ stats: z.object({
73
+ totalBytes: z.coerce.number(),
74
+ totalFiles: z.coerce.number(),
75
+ bucketCount: z.coerce.number()
76
+ }),
77
+ key: z.object({
78
+ name: z.string(),
79
+ scope: z.string(),
80
+ permissions: z.record(z.string(), z.boolean())
81
+ }).optional()
19
82
  });
20
83
  var listFilesSchema = z.object({
21
84
  files: z.array(
@@ -24,11 +87,26 @@ var listFilesSchema = z.object({
24
87
  size: z.number(),
25
88
  lastModified: z.string(),
26
89
  url: z.string().nullable(),
27
- metadata: z.record(z.string(), z.string()).optional()
90
+ width: z.number().nullable().optional(),
91
+ height: z.number().nullable().optional(),
92
+ duration: z.number().nullable().optional(),
93
+ metadata: z.record(z.string(), z.string()).optional(),
94
+ colorProfile: fileColorProfileSchema.nullable().optional(),
95
+ colors: z.array(fileColorSchema).optional()
28
96
  })
29
97
  ),
30
98
  nextCursor: z.string().nullable()
31
99
  });
100
+ var reprocessResultSchema = z.object({
101
+ key: z.string(),
102
+ triggered: z.array(z.string())
103
+ });
104
+ var replaceResultSchema = z.object({
105
+ key: z.string(),
106
+ size: z.number(),
107
+ contentType: z.string(),
108
+ triggered: z.array(z.string())
109
+ });
32
110
  var errorSchema = z.object({
33
111
  error: z.string(),
34
112
  code: z.string().optional()
@@ -56,7 +134,6 @@ var listDropsSchema = z.object({
56
134
  var presignNewResultSchema = z.object({
57
135
  fileKey: z.string(),
58
136
  uploadUrl: z.string(),
59
- r2Key: z.string(),
60
137
  confirmUrl: z.string(),
61
138
  dedupe: z.literal(false).optional()
62
139
  });
@@ -83,14 +160,31 @@ var fileResultSchema = z.object({
83
160
  size: z.number(),
84
161
  contentType: z.string(),
85
162
  url: z.string().nullable(),
163
+ width: z.number().nullable(),
164
+ height: z.number().nullable(),
165
+ duration: z.number().nullable(),
86
166
  metadata: z.record(z.string(), z.string()).nullable(),
167
+ colorProfile: fileColorProfileSchema.nullable(),
168
+ colors: z.array(fileColorSchema),
87
169
  embeddingStatus: z.string().nullable(),
88
170
  createdAt: z.string()
89
171
  });
172
+ var profileClusterResultSchema = z.object({
173
+ id: z.string(),
174
+ index: z.number().int(),
175
+ name: z.string().nullable(),
176
+ description: z.string().nullable(),
177
+ signalCount: z.number().int(),
178
+ totalWeight: z.number(),
179
+ nameGeneratedAt: z.string().nullable()
180
+ });
90
181
  var profileResultSchema = z.object({
91
182
  id: z.string(),
92
183
  name: z.string().nullable(),
93
184
  fileCount: z.number(),
185
+ signalCount: z.number(),
186
+ vector: z.array(z.number()).nullable(),
187
+ clusters: z.array(profileClusterResultSchema).optional(),
94
188
  createdAt: z.string(),
95
189
  updatedAt: z.string()
96
190
  });
@@ -98,6 +192,38 @@ var profileFilesResultSchema = z.object({
98
192
  id: z.string(),
99
193
  fileCount: z.number()
100
194
  });
195
+ var profileSignalResultSchema = z.object({
196
+ id: z.string(),
197
+ fileKey: z.string(),
198
+ type: z.enum([
199
+ "view",
200
+ "view_long",
201
+ "click",
202
+ "like",
203
+ "save",
204
+ "choose",
205
+ "purchase",
206
+ "share",
207
+ "dismiss",
208
+ "skip",
209
+ "reject",
210
+ "report",
211
+ "custom"
212
+ ]),
213
+ weight: z.number()
214
+ });
215
+ var profileSignalsResponseSchema = z.object({
216
+ profileId: z.string(),
217
+ signals: z.array(profileSignalResultSchema),
218
+ totalSignals: z.number(),
219
+ vectorUpdated: z.boolean()
220
+ });
221
+ var deleteProfileSignalsResponseSchema = z.object({
222
+ profileId: z.string(),
223
+ removed: z.number(),
224
+ totalSignals: z.number(),
225
+ vectorUpdated: z.boolean()
226
+ });
101
227
  var StowServer = class {
102
228
  apiKey;
103
229
  baseUrl;
@@ -124,6 +250,88 @@ var StowServer = class {
124
250
  getBaseUrl() {
125
251
  return this.baseUrl;
126
252
  }
253
+ /**
254
+ * Return account usage and API key info for the current credential.
255
+ */
256
+ whoami() {
257
+ return this.request("/api/whoami", { method: "GET" }, whoamiSchema);
258
+ }
259
+ /**
260
+ * List all buckets available to the current organization.
261
+ */
262
+ listBuckets() {
263
+ return this.request("/api/buckets", { method: "GET" }, listBucketsSchema);
264
+ }
265
+ /**
266
+ * Create a new bucket.
267
+ */
268
+ async createBucket(request) {
269
+ const result = await this.request(
270
+ "/api/buckets",
271
+ {
272
+ method: "POST",
273
+ headers: { "Content-Type": "application/json" },
274
+ body: JSON.stringify(request)
275
+ },
276
+ bucketResponseSchema
277
+ );
278
+ return result.bucket;
279
+ }
280
+ /**
281
+ * Get bucket details by id.
282
+ */
283
+ async getBucket(id) {
284
+ const result = await this.request(
285
+ `/api/buckets/${encodeURIComponent(id)}`,
286
+ { method: "GET" },
287
+ bucketResponseSchema
288
+ );
289
+ return result.bucket;
290
+ }
291
+ /**
292
+ * Update bucket settings by id.
293
+ */
294
+ async updateBucket(id, updates) {
295
+ const result = await this.request(
296
+ `/api/buckets/${encodeURIComponent(id)}`,
297
+ {
298
+ method: "PATCH",
299
+ headers: { "Content-Type": "application/json" },
300
+ body: JSON.stringify(updates)
301
+ },
302
+ bucketResponseSchema
303
+ );
304
+ return result.bucket;
305
+ }
306
+ /**
307
+ * Rename/update a bucket by current bucket name.
308
+ */
309
+ async updateBucketByName(name, updates) {
310
+ const result = await this.request(
311
+ `/api/buckets/_?bucket=${encodeURIComponent(name)}`,
312
+ {
313
+ method: "PATCH",
314
+ headers: { "Content-Type": "application/json" },
315
+ body: JSON.stringify(updates)
316
+ },
317
+ bucketResponseSchema
318
+ );
319
+ return result.bucket;
320
+ }
321
+ /**
322
+ * Rename a bucket by current bucket name.
323
+ */
324
+ renameBucket(name, newName) {
325
+ return this.updateBucketByName(name, { name: newName });
326
+ }
327
+ /**
328
+ * Delete a bucket by id.
329
+ */
330
+ async deleteBucket(id) {
331
+ await this.request(`/api/buckets/${encodeURIComponent(id)}`, {
332
+ method: "DELETE"
333
+ });
334
+ }
127
335
  /**
128
336
  * Resolve the effective bucket for this request.
129
337
  * Per-call override > constructor default.
@@ -149,6 +357,7 @@ var StowServer = class {
149
357
  * - AbortController timeout (default 30s).
150
358
  * - Consumer can pass `signal` in options to cancel.
151
359
  */
360
+ // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: retry + timeout + error normalization intentionally handled in one request pipeline
152
361
  async request(path, options, schema) {
153
362
  const maxAttempts = this.retries + 1;
154
363
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
@@ -183,6 +392,13 @@ var StowServer = class {
183
392
  if (err instanceof StowError) {
184
393
  throw err;
185
394
  }
395
+ if (err instanceof z.ZodError) {
396
+ throw new StowError(
397
+ "Invalid response format",
398
+ 500,
399
+ "INVALID_RESPONSE"
400
+ );
401
+ }
186
402
  if (err instanceof DOMException || err instanceof Error && err.name === "AbortError") {
187
403
  throw new StowError("Request timed out", 408, "TIMEOUT");
188
404
  }
@@ -208,32 +424,58 @@ var StowServer = class {
208
424
  * Upload a file directly from the server
209
425
  */
210
426
  async uploadFile(file, options) {
211
- const formData = new FormData();
212
- const blob = Buffer.isBuffer(file) ? new Blob([new Uint8Array(file)], {
213
- type: options?.contentType || "application/octet-stream"
214
- }) : file;
215
- formData.append("file", blob, options?.filename || "file");
216
- if (options?.route) {
217
- formData.append("route", options.route);
427
+ const filename = options?.filename || "file";
428
+ const buffer = Buffer.isBuffer(file) ? file : Buffer.from(await file.arrayBuffer());
429
+ const contentType = options?.contentType || (!Buffer.isBuffer(file) && file.type ? file.type : "application/octet-stream");
430
+ const contentHash = createHash("sha256").update(buffer).digest("hex");
431
+ const presign = await this.getPresignedUrl({
432
+ filename,
433
+ contentType,
434
+ size: buffer.length,
435
+ ...options?.route ? { route: options.route } : {},
436
+ ...options?.bucket ? { bucket: options.bucket } : {},
437
+ ...options?.metadata ? { metadata: options.metadata } : {},
438
+ contentHash
439
+ });
440
+ if (presign.dedupe) {
441
+ return {
442
+ key: presign.key,
443
+ url: presign.url,
444
+ size: presign.size,
445
+ contentType: presign.contentType,
446
+ deduped: true
447
+ };
218
448
  }
219
- if (options?.metadata) {
220
- formData.append("metadata", JSON.stringify(options.metadata));
449
+ const uploadRes = await fetch(presign.uploadUrl, {
450
+ method: "PUT",
451
+ headers: { "Content-Type": contentType },
452
+ body: new Uint8Array(buffer)
453
+ });
454
+ if (!uploadRes.ok) {
455
+ throw new StowError("Failed to upload to storage", uploadRes.status);
221
456
  }
222
- const result = await this.request(
223
- this.withBucket("/api/upload", options?.bucket),
457
+ return this.request(
458
+ this.withBucket(
459
+ presign.confirmUrl || "/api/presign/confirm",
460
+ options?.bucket
461
+ ),
224
462
  {
225
463
  method: "POST",
226
- body: formData
464
+ headers: { "Content-Type": "application/json" },
465
+ body: JSON.stringify({
466
+ fileKey: presign.fileKey,
467
+ size: buffer.length,
468
+ contentType,
469
+ ...options?.metadata ? { metadata: options.metadata } : {},
470
+ contentHash,
471
+ skipVerify: true,
472
+ ...options?.title ? { title: true } : {},
473
+ ...options?.describe ? { describe: true } : {},
474
+ ...options?.altText ? { altText: true } : {}
475
+ })
227
476
  },
228
- uploadResultSchema
477
+ confirmResultSchema
229
478
  );
230
- return {
231
- key: result.key,
232
- url: result.url,
233
- size: result.size,
234
- contentType: result.contentType || options?.contentType || "application/octet-stream",
235
- ...result.metadata ? { metadata: result.metadata } : {}
236
- };
237
479
  }
238
480
  /**
239
481
  * Upload a file from a URL (server-side fetch + upload)
@@ -248,7 +490,10 @@ var StowServer = class {
248
490
  url,
249
491
  filename,
250
492
  ...options?.metadata ? { metadata: options.metadata } : {},
251
- ...options?.headers ? { headers: options.headers } : {}
493
+ ...options?.headers ? { headers: options.headers } : {},
494
+ ...options?.title ? { title: true } : {},
495
+ ...options?.describe ? { describe: true } : {},
496
+ ...options?.altText ? { altText: true } : {}
252
497
  })
253
498
  },
254
499
  uploadResultSchema
@@ -271,7 +516,15 @@ var StowServer = class {
271
516
  * 4. Client calls confirmUpload to finalize
272
517
  */
273
518
  getPresignedUrl(request) {
274
- const { filename, contentType, size, route, bucket, metadata, contentHash } = request;
519
+ const {
520
+ filename,
521
+ contentType,
522
+ size,
523
+ route,
524
+ bucket,
525
+ metadata,
526
+ contentHash
527
+ } = request;
275
528
  return this.request(
276
529
  this.withBucket("/api/presign", bucket),
277
530
  {
@@ -302,7 +555,10 @@ var StowServer = class {
302
555
  metadata,
303
556
  skipVerify,
304
557
  deferKvSync,
305
- contentHash
558
+ contentHash,
559
+ title,
560
+ describe,
561
+ altText
306
562
  } = request;
307
563
  return this.request(
308
564
  this.withBucket("/api/presign/confirm", bucket),
@@ -316,7 +572,10 @@ var StowServer = class {
316
572
  ...metadata ? { metadata } : {},
317
573
  ...skipVerify ? { skipVerify } : {},
318
574
  ...deferKvSync ? { deferKvSync } : {},
319
- ...contentHash ? { contentHash } : {}
575
+ ...contentHash ? { contentHash } : {},
576
+ ...title ? { title } : {},
577
+ ...describe ? { describe } : {},
578
+ ...altText ? { altText } : {}
320
579
  })
321
580
  },
322
581
  confirmResultSchema
@@ -358,7 +617,7 @@ var StowServer = class {
358
617
  /**
359
618
  * Update metadata on an existing file
360
619
  */
361
- async updateFileMetadata(key, metadata, options) {
620
+ updateFileMetadata(key, metadata, options) {
362
621
  const path = `/api/files/${encodeURIComponent(key)}`;
363
622
  return this.request(this.withBucket(path, options?.bucket), {
364
623
  method: "PATCH",
@@ -369,7 +628,7 @@ var StowServer = class {
369
628
  /**
370
629
  * Get a single file by key
371
630
  */
372
- async getFile(key, options) {
631
+ getFile(key, options) {
373
632
  const path = `/api/files/${encodeURIComponent(key)}`;
374
633
  return this.request(
375
634
  this.withBucket(path, options?.bucket),
@@ -377,6 +636,40 @@ var StowServer = class {
377
636
  fileResultSchema
378
637
  );
379
638
  }
639
+ /**
640
+ * Reprocess a file: reset all derived data (embeddings, colors, dimensions,
641
+ * AI metadata, taxonomies) and re-trigger processing tasks.
642
+ */
643
+ reprocessFile(key, options) {
644
+ const path = `/api/files/${encodeURIComponent(key)}/reprocess`;
645
+ return this.request(
646
+ this.withBucket(path, options?.bucket),
647
+ { method: "POST" },
648
+ reprocessResultSchema
649
+ );
650
+ }
651
+ /**
652
+ * Replace a file's content by fetching from a new URL.
653
+ *
654
+ * Keeps the same file key but replaces the stored object and resets all
655
+ * derived data (dimensions, embeddings, colors, AI metadata). Processing
656
+ * tasks are re-dispatched as if the file were newly uploaded.
657
+ */
658
+ replaceFile(key, url, options) {
659
+ const path = `/api/files/${encodeURIComponent(key)}/replace`;
660
+ return this.request(
661
+ this.withBucket(path, options?.bucket),
662
+ {
663
+ method: "PUT",
664
+ headers: { "Content-Type": "application/json" },
665
+ body: JSON.stringify({
666
+ url,
667
+ ...options?.headers ? { headers: options.headers } : {}
668
+ })
669
+ },
670
+ replaceResultSchema
671
+ );
672
+ }
380
673
  /**
381
674
  * Get a transform URL for an image.
382
675
  *
@@ -388,25 +681,23 @@ var StowServer = class {
388
681
  * @param options - Transform options (width, height, quality, format)
389
682
  */
390
683
  getTransformUrl(url, options) {
391
- const params = new URLSearchParams();
392
- if (options?.width) {
393
- params.set("w", options.width.toString());
684
+ if (!(options && (options.width || options.height || options.quality || options.format))) {
685
+ return url;
394
686
  }
395
- if (options?.height) {
396
- params.set("h", options.height.toString());
687
+ const parsed = new URL(url);
688
+ if (options.width) {
689
+ parsed.searchParams.set("w", String(options.width));
397
690
  }
398
- if (options?.quality) {
399
- params.set("q", options.quality.toString());
691
+ if (options.height) {
692
+ parsed.searchParams.set("h", String(options.height));
400
693
  }
401
- if (options?.format) {
402
- params.set("f", options.format);
694
+ if (options.quality) {
695
+ parsed.searchParams.set("q", String(options.quality));
403
696
  }
404
- const query = params.toString();
405
- if (!query) {
406
- return url;
697
+ if (options.format) {
698
+ parsed.searchParams.set("f", options.format);
407
699
  }
408
- const separator = url.includes("?") ? "&" : "?";
409
- return `${url}${separator}${query}`;
700
+ return parsed.toString();
410
701
  }
411
702
  // ============================================================
412
703
  // TAGS - Org-scoped labels for file organization
@@ -468,10 +759,13 @@ var StowServer = class {
468
759
  get search() {
469
760
  return {
470
761
  similar: (params) => this.searchSimilar(params),
471
- text: (params) => this.searchText(params)
762
+ diverse: (params) => this.searchDiverse(params ?? {}),
763
+ text: (params) => this.searchText(params),
764
+ color: (params) => this.searchColor(params)
472
765
  };
473
766
  }
474
767
  searchSimilar(params) {
768
+ const bucket = this.resolveBucket(params.bucket);
475
769
  return this.request("/api/search/similar", {
476
770
  method: "POST",
477
771
  headers: { "Content-Type": "application/json" },
@@ -479,19 +773,62 @@ var StowServer = class {
479
773
  ...params.fileKey ? { fileKey: params.fileKey } : {},
480
774
  ...params.vector ? { vector: params.vector } : {},
481
775
  ...params.profileId ? { profileId: params.profileId } : {},
482
- ...params.bucket ? { bucket: params.bucket } : {},
483
- ...params.limit ? { limit: params.limit } : {}
776
+ ...params.clusterId ? { clusterId: params.clusterId } : {},
777
+ ...params.clusterIds?.length ? { clusterIds: params.clusterIds } : {},
778
+ ...bucket ? { bucket } : {},
779
+ ...params.limit ? { limit: params.limit } : {},
780
+ ...params.excludeKeys?.length ? { excludeKeys: params.excludeKeys } : {},
781
+ ...params.filters ? { filters: params.filters } : {},
782
+ ...params.include?.length ? { include: params.include } : {}
783
+ })
784
+ });
785
+ }
786
+ searchDiverse(params) {
787
+ const bucket = this.resolveBucket(params.bucket);
788
+ return this.request("/api/search/diverse", {
789
+ method: "POST",
790
+ headers: { "Content-Type": "application/json" },
791
+ body: JSON.stringify({
792
+ ...params.fileKey ? { fileKey: params.fileKey } : {},
793
+ ...params.vector ? { vector: params.vector } : {},
794
+ ...params.profileId ? { profileId: params.profileId } : {},
795
+ ...params.clusterId ? { clusterId: params.clusterId } : {},
796
+ ...params.clusterIds?.length ? { clusterIds: params.clusterIds } : {},
797
+ ...bucket ? { bucket } : {},
798
+ ...params.limit ? { limit: params.limit } : {},
799
+ ...params.lambda !== void 0 ? { lambda: params.lambda } : {},
800
+ ...params.excludeKeys?.length ? { excludeKeys: params.excludeKeys } : {},
801
+ ...params.filters ? { filters: params.filters } : {},
802
+ ...params.include?.length ? { include: params.include } : {}
484
803
  })
485
804
  });
486
805
  }
487
806
  searchText(params) {
807
+ const bucket = this.resolveBucket(params.bucket);
488
808
  return this.request("/api/search/text", {
489
809
  method: "POST",
490
810
  headers: { "Content-Type": "application/json" },
491
811
  body: JSON.stringify({
492
812
  query: params.query,
493
- ...params.bucket ? { bucket: params.bucket } : {},
494
- ...params.limit ? { limit: params.limit } : {}
813
+ ...bucket ? { bucket } : {},
814
+ ...params.limit ? { limit: params.limit } : {},
815
+ ...params.filters ? { filters: params.filters } : {},
816
+ ...params.include?.length ? { include: params.include } : {}
817
+ })
818
+ });
819
+ }
820
+ searchColor(params) {
821
+ const bucket = this.resolveBucket(params.bucket);
822
+ return this.request("/api/search/color", {
823
+ method: "POST",
824
+ headers: { "Content-Type": "application/json" },
825
+ body: JSON.stringify({
826
+ ...params.hex ? { hex: params.hex } : {},
827
+ ...params.oklab ? { oklab: params.oklab } : {},
828
+ ...bucket ? { bucket } : {},
829
+ ...params.limit ? { limit: params.limit } : {},
830
+ ...params.minProportion !== void 0 ? { minProportion: params.minProportion } : {},
831
+ ...params.dominantOnly ? { dominantOnly: params.dominantOnly } : {}
495
832
  })
496
833
  });
497
834
  }
@@ -532,7 +869,7 @@ var StowServer = class {
532
869
  throw new StowError("Failed to upload to storage", putRes.status);
533
870
  }
534
871
  return this.request(
535
- "/api/drops/presign/confirm",
872
+ presign.confirmUrl || "/api/drops/presign/confirm",
536
873
  {
537
874
  method: "POST",
538
875
  headers: { "Content-Type": "application/json" },
@@ -574,7 +911,12 @@ var StowServer = class {
574
911
  get: (id) => this.getProfile(id),
575
912
  delete: (id) => this.deleteProfile(id),
576
913
  addFiles: (id, fileKeys, bucket) => this.addProfileFiles(id, fileKeys, bucket),
577
- removeFiles: (id, fileKeys, bucket) => this.removeProfileFiles(id, fileKeys, bucket)
914
+ removeFiles: (id, fileKeys, bucket) => this.removeProfileFiles(id, fileKeys, bucket),
915
+ signal: (id, signals, bucket) => this.signalProfile(id, signals, bucket),
916
+ deleteSignals: (id, signalIds) => this.deleteProfileSignals(id, signalIds),
917
+ clusters: (id) => this.getProfileClusters(id),
918
+ recluster: (id, params) => this.reclusterProfile(id, params),
919
+ renameCluster: (profileId, clusterId, params) => this.renameProfileCluster(profileId, clusterId, params)
578
920
  };
579
921
  }
580
922
  createProfile(params) {
@@ -632,6 +974,55 @@ var StowServer = class {
632
974
  profileFilesResultSchema
633
975
  );
634
976
  }
977
+ signalProfile(id, signals, bucket) {
978
+ return this.request(
979
+ `/api/profiles/${encodeURIComponent(id)}/signals`,
980
+ {
981
+ method: "POST",
982
+ headers: { "Content-Type": "application/json" },
983
+ body: JSON.stringify({
984
+ signals,
985
+ ...bucket ? { bucket } : {}
986
+ })
987
+ },
988
+ profileSignalsResponseSchema
989
+ );
990
+ }
991
+ deleteProfileSignals(id, signalIds) {
992
+ return this.request(
993
+ `/api/profiles/${encodeURIComponent(id)}/signals`,
994
+ {
995
+ method: "DELETE",
996
+ headers: { "Content-Type": "application/json" },
997
+ body: JSON.stringify({ signalIds })
998
+ },
999
+ deleteProfileSignalsResponseSchema
1000
+ );
1001
+ }
1002
+ getProfileClusters(id) {
1003
+ return this.request(`/api/profiles/${encodeURIComponent(id)}/clusters`, {
1004
+ method: "GET"
1005
+ });
1006
+ }
1007
+ reclusterProfile(id, params) {
1008
+ return this.request(`/api/profiles/${encodeURIComponent(id)}/clusters`, {
1009
+ method: "POST",
1010
+ headers: { "Content-Type": "application/json" },
1011
+ body: JSON.stringify({
1012
+ ...params?.clusterCount !== void 0 ? { clusterCount: params.clusterCount } : {}
1013
+ })
1014
+ });
1015
+ }
1016
+ renameProfileCluster(profileId, clusterId, params) {
1017
+ return this.request(
1018
+ `/api/profiles/${encodeURIComponent(profileId)}/clusters/${encodeURIComponent(clusterId)}`,
1019
+ {
1020
+ method: "PUT",
1021
+ headers: { "Content-Type": "application/json" },
1022
+ body: JSON.stringify(params)
1023
+ }
1024
+ );
1025
+ }
635
1026
  };
636
1027
  export {
637
1028
  StowError,