@runblackcat/sdk 0.1.0-alpha.89 → 0.1.0-alpha.90

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/README.md CHANGED
@@ -193,7 +193,7 @@ sandbox.
193
193
  Backpressure is fleet capacity and the durable queue; there are no per-tenant
194
194
  quotas. A queued acquisition that waits past the queue deadline is torn down by
195
195
  the ordinary expiry reconciler. Request-rate limits are operator-set fleet state
196
- (`blackcat admin rate-limits get|set`): token mint and OIDC limits are on by
196
+ (`blackcat admin rate-limits get|set`): session token-mint and OIDC limits are on by
197
197
  default, every workload limit is unlimited until set.
198
198
 
199
199
  The placer sizes the fleet from that backlog through the `CapacityProvider`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@runblackcat/sdk",
3
- "version": "0.1.0-alpha.89",
3
+ "version": "0.1.0-alpha.90",
4
4
  "description": "TypeScript SDK for the Blackcat sandbox gateway",
5
5
  "license": "Apache-2.0",
6
6
  "repository": "https://github.com/TreebeardHQ/blackcat",
@@ -33,7 +33,14 @@ export type FetchFunction = (input: RequestInfo | URL, init?: RequestInit & {
33
33
  }) => Promise<Response>;
34
34
  export interface BlackcatClientOptions {
35
35
  baseUrl: string;
36
+ /**
37
+ * A tenant API key. The gateway accepts it directly on every resource route
38
+ * for the tenant's own resources (limited to the key's operation set), so a
39
+ * trusted server-side caller needs no `tokens.mint` per call. Keep it
40
+ * server-side; hand less-trusted holders a minted `token` instead.
41
+ */
36
42
  apiKey?: string;
43
+ /** A capability token; preferred over `apiKey` when both are set. */
37
44
  token?: string;
38
45
  /** Capability identity and expiry, using idiomatic TypeScript names. */
39
46
  tokenId?: string;
package/sdk/dist/index.js CHANGED
@@ -354,17 +354,17 @@ class TemplatesResource {
354
354
  this.client = client;
355
355
  }
356
356
  create(input) {
357
- return this.client.json("POST", "/v1/templates", input, "token");
357
+ return this.client.json("POST", "/v1/templates", input, "either");
358
358
  }
359
359
  list() {
360
- return this.client.json("GET", "/v1/templates", undefined, "token");
360
+ return this.client.json("GET", "/v1/templates", undefined, "either");
361
361
  }
362
362
  async uploadImage(archive, options) {
363
363
  const response = await this.client.raw("POST", "/v1/template-images", archive, "either", "application/octet-stream", false, options?.signal);
364
364
  return await response.json();
365
365
  }
366
366
  activate(id) {
367
- return this.client.json("POST", `/v1/templates/${pathSegment(id)}/activate`, undefined, "token");
367
+ return this.client.json("POST", `/v1/templates/${pathSegment(id)}/activate`, undefined, "either");
368
368
  }
369
369
  }
370
370
 
@@ -374,13 +374,13 @@ class TemplateResourcesResource {
374
374
  this.client = client;
375
375
  }
376
376
  get(name) {
377
- return this.client.json("GET", `/v1/template-resources/${pathSegment(name)}`, undefined, "token");
377
+ return this.client.json("GET", `/v1/template-resources/${pathSegment(name)}`, undefined, "either");
378
378
  }
379
379
  configure(name, input) {
380
- return this.client.json("PUT", `/v1/template-resources/${pathSegment(name)}`, input, "token");
380
+ return this.client.json("PUT", `/v1/template-resources/${pathSegment(name)}`, input, "either");
381
381
  }
382
382
  delete(name) {
383
- return this.client.json("DELETE", `/v1/template-resources/${pathSegment(name)}`, undefined, "token");
383
+ return this.client.json("DELETE", `/v1/template-resources/${pathSegment(name)}`, undefined, "either");
384
384
  }
385
385
  }
386
386
 
@@ -390,13 +390,13 @@ class TemplateBuildsResource {
390
390
  this.client = client;
391
391
  }
392
392
  create(input) {
393
- return this.client.json("POST", "/v1/template-builds", input, "token");
393
+ return this.client.json("POST", "/v1/template-builds", input, "either");
394
394
  }
395
395
  get(id) {
396
- return this.client.json("GET", `/v1/template-builds/${pathSegment(id)}`, undefined, "token");
396
+ return this.client.json("GET", `/v1/template-builds/${pathSegment(id)}`, undefined, "either");
397
397
  }
398
398
  retry(id) {
399
- return this.client.json("POST", `/v1/template-builds/${pathSegment(id)}/retry`, undefined, "token");
399
+ return this.client.json("POST", `/v1/template-builds/${pathSegment(id)}/retry`, undefined, "either");
400
400
  }
401
401
  }
402
402
 
@@ -427,7 +427,7 @@ class FleetResource {
427
427
  this.client = client;
428
428
  }
429
429
  list() {
430
- return this.client.json("GET", "/v1/fleet", undefined, "token");
430
+ return this.client.json("GET", "/v1/fleet", undefined, "either");
431
431
  }
432
432
  }
433
433
 
@@ -437,16 +437,16 @@ class ReservationsResource {
437
437
  this.client = client;
438
438
  }
439
439
  create(input) {
440
- return this.client.json("POST", "/v1/capacity-reservations", input, "token");
440
+ return this.client.json("POST", "/v1/capacity-reservations", input, "either");
441
441
  }
442
442
  get(id) {
443
- return this.client.json("GET", `/v1/capacity-reservations/${pathSegment(id)}`, undefined, "token");
443
+ return this.client.json("GET", `/v1/capacity-reservations/${pathSegment(id)}`, undefined, "either");
444
444
  }
445
445
  release(id) {
446
- return this.client.json("DELETE", `/v1/capacity-reservations/${pathSegment(id)}`, undefined, "token");
446
+ return this.client.json("DELETE", `/v1/capacity-reservations/${pathSegment(id)}`, undefined, "either");
447
447
  }
448
448
  renew(id, input) {
449
- return this.client.json("POST", `/v1/capacity-reservations/${pathSegment(id)}/renew`, input, "token");
449
+ return this.client.json("POST", `/v1/capacity-reservations/${pathSegment(id)}/renew`, input, "either");
450
450
  }
451
451
  }
452
452
 
@@ -456,34 +456,34 @@ class SandboxesResource {
456
456
  this.client = client;
457
457
  }
458
458
  list() {
459
- return this.client.json("GET", "/v1/sandboxes", undefined, "token");
459
+ return this.client.json("GET", "/v1/sandboxes", undefined, "either");
460
460
  }
461
461
  async create(input, options = {}) {
462
- return parseCreateSandboxResponse(await this.client.json("POST", `/v1/sandboxes${waitQuery(options)}`, withTemplate(input), "token", false), input.request_id);
462
+ return parseCreateSandboxResponse(await this.client.json("POST", `/v1/sandboxes${waitQuery(options)}`, withTemplate(input), "either", false), input.request_id);
463
463
  }
464
464
  async createBatch(input) {
465
- return parseSandboxBatch(await this.client.json("POST", "/v1/sandboxes", withTemplate(input), "token", false), input.request_id);
465
+ return parseSandboxBatch(await this.client.json("POST", "/v1/sandboxes", withTemplate(input), "either", false), input.request_id);
466
466
  }
467
467
  async batch(requestId) {
468
- return parseSandboxBatch(await this.client.json("GET", `/v1/sandboxes/batches/${pathSegment(requestId)}`, undefined, "token"), requestId);
468
+ return parseSandboxBatch(await this.client.json("GET", `/v1/sandboxes/batches/${pathSegment(requestId)}`, undefined, "either"), requestId);
469
469
  }
470
470
  async acquisition(requestId, options = {}) {
471
- return parseCreateSandboxResponse(await this.client.json("GET", `/v1/sandboxes/acquisitions/${pathSegment(requestId)}${waitQuery(options)}`, undefined, "token", options.wait_secs === undefined ? undefined : false), requestId);
471
+ return parseCreateSandboxResponse(await this.client.json("GET", `/v1/sandboxes/acquisitions/${pathSegment(requestId)}${waitQuery(options)}`, undefined, "either", options.wait_secs === undefined ? undefined : false), requestId);
472
472
  }
473
473
  async cancelAcquisition(requestId) {
474
- return parseCreateSandboxResponse(await this.client.json("DELETE", `/v1/sandboxes/acquisitions/${pathSegment(requestId)}`, undefined, "token"), requestId);
474
+ return parseCreateSandboxResponse(await this.client.json("DELETE", `/v1/sandboxes/acquisitions/${pathSegment(requestId)}`, undefined, "either"), requestId);
475
475
  }
476
476
  get(id) {
477
- return this.client.json("GET", `/v1/sandboxes/${pathSegment(id)}`, undefined, "token");
477
+ return this.client.json("GET", `/v1/sandboxes/${pathSegment(id)}`, undefined, "either");
478
478
  }
479
479
  renew(id, ttl_secs) {
480
- return this.client.json("POST", `/v1/sandboxes/${pathSegment(id)}/renew`, { ttl_secs }, "token");
480
+ return this.client.json("POST", `/v1/sandboxes/${pathSegment(id)}/renew`, { ttl_secs }, "either");
481
481
  }
482
482
  grantSshKey(id, input) {
483
- return this.client.json("POST", `/v1/sandboxes/${pathSegment(id)}/ssh-keys`, input, "token");
483
+ return this.client.json("POST", `/v1/sandboxes/${pathSegment(id)}/ssh-keys`, input, "either");
484
484
  }
485
485
  async exec(id, input) {
486
- return this.client.json("POST", `/v1/sandboxes/${pathSegment(id)}/exec`, input, "token", false, execDeadline(input)).then(execResult);
486
+ return this.client.json("POST", `/v1/sandboxes/${pathSegment(id)}/exec`, input, "either", false, execDeadline(input)).then(execResult);
487
487
  }
488
488
  async* execStream(id, input) {
489
489
  if (input.stdin !== undefined && input.stdin.length > MAX_EXEC_STDIN) {
@@ -499,7 +499,7 @@ class SandboxesResource {
499
499
  return chunk;
500
500
  };
501
501
  const decoder = new TextDecoder;
502
- for await (const chunk of this.client.stream("POST", `/v1/sandboxes/${pathSegment(id)}/exec/stream`, JSON.stringify(input), "token", "application/json", true, execDeadline(input))) {
502
+ for await (const chunk of this.client.stream("POST", `/v1/sandboxes/${pathSegment(id)}/exec/stream`, JSON.stringify(input), "either", "application/json", true, execDeadline(input))) {
503
503
  lineBuffer += decoder.decode(chunk, { stream: true });
504
504
  const lines = lineBuffer.split(`
505
505
  `);
@@ -522,10 +522,10 @@ class SandboxesResource {
522
522
  return this.client.json("POST", `/v1/sandboxes/${pathSegment(id)}/processes`, {
523
523
  ...input,
524
524
  ...input.stdin === undefined ? {} : { stdin: Array.from(input.stdin) }
525
- }, "token", false, undefined, { "idempotency-key": requestId });
525
+ }, "either", false, undefined, { "idempotency-key": requestId });
526
526
  }
527
527
  getProcess(id, processId) {
528
- return this.client.json("GET", `/v1/sandboxes/${pathSegment(id)}/processes/${pathSegment(processId)}`, undefined, "token");
528
+ return this.client.json("GET", `/v1/sandboxes/${pathSegment(id)}/processes/${pathSegment(processId)}`, undefined, "either");
529
529
  }
530
530
  async processLogs(id, processId, input = {}) {
531
531
  const options = typeof input === "number" ? { stdout_offset: 0, stderr_offset: 0, max_bytes: input } : input;
@@ -537,7 +537,7 @@ class SandboxesResource {
537
537
  if (options.max_bytes !== undefined)
538
538
  query.set("max_bytes", String(options.max_bytes));
539
539
  const suffix = query.size === 0 ? "" : `?${query.toString()}`;
540
- const response = await this.client.json("GET", `/v1/sandboxes/${pathSegment(id)}/processes/${pathSegment(processId)}/logs${suffix}`, undefined, "token");
540
+ const response = await this.client.json("GET", `/v1/sandboxes/${pathSegment(id)}/processes/${pathSegment(processId)}/logs${suffix}`, undefined, "either");
541
541
  return {
542
542
  ...response,
543
543
  logs: {
@@ -548,13 +548,13 @@ class SandboxesResource {
548
548
  };
549
549
  }
550
550
  cancelProcess(id, processId) {
551
- return this.client.json("DELETE", `/v1/sandboxes/${pathSegment(id)}/processes/${pathSegment(processId)}`, undefined, "token");
551
+ return this.client.json("DELETE", `/v1/sandboxes/${pathSegment(id)}/processes/${pathSegment(processId)}`, undefined, "either");
552
552
  }
553
553
  prepare(id, input, idempotencyKey) {
554
- return this.client.json("POST", `/v1/sandboxes/${pathSegment(id)}/prepare`, input, "token", undefined, undefined, { "idempotency-key": idempotencyKey });
554
+ return this.client.json("POST", `/v1/sandboxes/${pathSegment(id)}/prepare`, input, "either", undefined, undefined, { "idempotency-key": idempotencyKey });
555
555
  }
556
556
  logs(id) {
557
- return this.client.stream("GET", `/v1/sandboxes/${pathSegment(id)}/logs`, undefined, "token", undefined, true);
557
+ return this.client.stream("GET", `/v1/sandboxes/${pathSegment(id)}/logs`, undefined, "either", undefined, true);
558
558
  }
559
559
  async readFileChunk(id, input) {
560
560
  if (input.offset < 0 || input.length <= 0 || input.length > MAX_FILE_READ_CHUNK) {
@@ -565,7 +565,7 @@ class SandboxesResource {
565
565
  offset: String(input.offset),
566
566
  length: String(input.length)
567
567
  });
568
- const response = await this.client.raw("GET", `/v1/sandboxes/${pathSegment(id)}/files/read?${query.toString()}`, undefined, "token");
568
+ const response = await this.client.raw("GET", `/v1/sandboxes/${pathSegment(id)}/files/read?${query.toString()}`, undefined, "either");
569
569
  const data = new Uint8Array(await response.arrayBuffer());
570
570
  const offset = Number(response.headers.get("x-blackcat-offset") ?? input.offset);
571
571
  const eof = response.headers.get("x-blackcat-eof") === "true";
@@ -616,7 +616,7 @@ class SandboxesResource {
616
616
  offset: String(input.offset),
617
617
  truncate: String(input.truncate)
618
618
  });
619
- await this.client.raw("POST", `/v1/sandboxes/${pathSegment(id)}/files/write?${query.toString()}`, requestBody(input.data), "token", "application/octet-stream");
619
+ await this.client.raw("POST", `/v1/sandboxes/${pathSegment(id)}/files/write?${query.toString()}`, requestBody(input.data), "either", "application/octet-stream");
620
620
  }
621
621
  async writeFileStream(id, input) {
622
622
  const start = input.offset ?? 0;
@@ -661,28 +661,28 @@ class SandboxesResource {
661
661
  });
662
662
  }
663
663
  snapshot(id) {
664
- return this.client.json("POST", `/v1/sandboxes/${pathSegment(id)}/snapshot`, undefined, "token");
664
+ return this.client.json("POST", `/v1/sandboxes/${pathSegment(id)}/snapshot`, undefined, "either");
665
665
  }
666
666
  pause(id) {
667
- return this.client.raw("POST", `/v1/sandboxes/${pathSegment(id)}/pause`, undefined, "token").then(() => {
667
+ return this.client.raw("POST", `/v1/sandboxes/${pathSegment(id)}/pause`, undefined, "either").then(() => {
668
668
  return;
669
669
  });
670
670
  }
671
671
  hibernate(id, input) {
672
- return this.client.raw("POST", `/v1/sandboxes/${pathSegment(id)}/hibernate`, input === undefined ? undefined : JSON.stringify(input), "token", input === undefined ? undefined : "application/json", false).then(() => {
672
+ return this.client.raw("POST", `/v1/sandboxes/${pathSegment(id)}/hibernate`, input === undefined ? undefined : JSON.stringify(input), "either", input === undefined ? undefined : "application/json", false).then(() => {
673
673
  return;
674
674
  });
675
675
  }
676
676
  resize(id, input) {
677
- return this.client.json("POST", `/v1/sandboxes/${pathSegment(id)}/resize`, { ...input, request_id: input.request_id ?? `resize-${crypto.randomUUID()}` }, "token", false);
677
+ return this.client.json("POST", `/v1/sandboxes/${pathSegment(id)}/resize`, { ...input, request_id: input.request_id ?? `resize-${crypto.randomUUID()}` }, "either", false);
678
678
  }
679
679
  resume(id) {
680
- return this.client.raw("POST", `/v1/sandboxes/${pathSegment(id)}/resume`, undefined, "token").then(() => {
680
+ return this.client.raw("POST", `/v1/sandboxes/${pathSegment(id)}/resume`, undefined, "either").then(() => {
681
681
  return;
682
682
  });
683
683
  }
684
684
  destroy(id) {
685
- return this.client.json("DELETE", `/v1/sandboxes/${pathSegment(id)}`, undefined, "token");
685
+ return this.client.json("DELETE", `/v1/sandboxes/${pathSegment(id)}`, undefined, "either");
686
686
  }
687
687
  }
688
688