@runblackcat/sdk 0.1.0-alpha.44 → 0.1.0-alpha.46

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@runblackcat/sdk",
3
- "version": "0.1.0-alpha.44",
3
+ "version": "0.1.0-alpha.46",
4
4
  "description": "TypeScript SDK for the Blackcat sandbox gateway",
5
5
  "license": "Apache-2.0",
6
6
  "repository": "https://github.com/TreebeardHQ/blackcat",
@@ -15,6 +15,7 @@
15
15
  "files": ["sdk/dist", "README.md", "LICENSE"],
16
16
  "scripts": {
17
17
  "build": "bun build sdk/src/index.ts --outdir sdk/dist --target node --format esm && tsc -p sdk/tsconfig.build.json",
18
+ "prepack": "bun run build",
18
19
  "typecheck": "tsc -p sdk/tsconfig.json --noEmit",
19
20
  "test": "bun test sdk/src/index.test.ts"
20
21
  },
@@ -115,19 +115,41 @@ export type TemplateDockerSource = TemplateDockerSourceBase & (TemplatePreparati
115
115
  parameters?: never;
116
116
  prepare?: never;
117
117
  });
118
+ /** A build whose image was uploaded rather than pulled from a registry. */
119
+ export type TemplateUploadedImageSource = Omit<TemplateDockerSourceBase, "docker"> & {
120
+ docker: UploadedImageSource;
121
+ } & (TemplatePreparation | {
122
+ parameters?: never;
123
+ prepare?: never;
124
+ });
125
+ export interface UploadedImageSource {
126
+ /** The `sha256:<hex>` digest returned by `templates.uploadImage`. */
127
+ uploaded_image: string;
128
+ }
129
+ export interface UploadedImage {
130
+ image: string;
131
+ bytes: number;
132
+ /** True when the control plane already held this exact image. */
133
+ unchanged: boolean;
134
+ }
118
135
  export interface TemplateSandboxSource {
119
136
  sandbox: {
120
137
  id: string;
121
138
  };
122
- /** The gateway derives these from the source sandbox when omitted. */
123
- defaults?: TemplateDefaults;
124
- /** The gateway derives this from the source template when omitted. */
139
+ /**
140
+ * A promoted sandbox keeps the machine dimensions it was captured on, so
141
+ * the gateway rejects `defaults` here. Omit `egress` to inherit the source
142
+ * template's policy.
143
+ */
125
144
  egress?: TemplateEgressPolicy;
126
145
  }
127
- export type TemplateSource = TemplateDockerSource | TemplateSandboxSource;
146
+ export type TemplateSource = TemplateDockerSource | TemplateUploadedImageSource | TemplateSandboxSource;
128
147
  export type CreateTemplateInput = {
129
148
  name: string;
130
149
  source: TemplateDockerSource;
150
+ } | {
151
+ name: string;
152
+ source: TemplateUploadedImageSource;
131
153
  } | {
132
154
  name?: string;
133
155
  source: TemplateSandboxSource;
@@ -186,24 +208,6 @@ export interface SandboxLeaseInput {
186
208
  /** Hard lifetime from acquisition, at least ttl_secs and at most 30 days. */
187
209
  renewable_for_secs: number;
188
210
  }
189
- export interface WarmInventoryMember {
190
- id: string;
191
- tenant: string;
192
- template: string;
193
- memory_mib: number;
194
- vcpus: number;
195
- node: string | null;
196
- state: "Warming" | "Warm" | "Retiring";
197
- snapshot: string | null;
198
- last_active: SystemTimeValue;
199
- }
200
- export interface WarmTargetResponse {
201
- enabled: boolean;
202
- fleet_ready_limit: number;
203
- }
204
- export interface WarmInventoryResponse extends WarmTargetResponse {
205
- members: WarmInventoryMember[];
206
- }
207
211
  /** Response returned by POST /v1/sandboxes (the gateway has no template field). */
208
212
  export type CreateSandboxResponse = {
209
213
  request_id: string;
@@ -256,6 +260,24 @@ export interface FleetInterruption {
256
260
  export interface FleetResponse {
257
261
  nodes: FleetNode[];
258
262
  }
263
+ export interface TemplateRefreshPolicy {
264
+ interval_seconds: number;
265
+ plugin_installation: string;
266
+ }
267
+ export interface ConfigureTemplateResourceInput {
268
+ keep_versions: number;
269
+ refresh: TemplateRefreshPolicy | null;
270
+ }
271
+ export interface TemplateResource {
272
+ name: string;
273
+ current_version_id: string;
274
+ retention: {
275
+ keep_versions: number;
276
+ };
277
+ refresh: TemplateRefreshPolicy | null;
278
+ next_refresh_at: number | null;
279
+ last_refresh?: unknown;
280
+ }
259
281
  export interface ExecInput {
260
282
  command: string;
261
283
  args: string[];
@@ -397,15 +419,25 @@ declare class TemplatesResource {
397
419
  constructor(client: GatewayClient);
398
420
  create(input: CreateTemplateInput): Promise<CreateTemplateResponse>;
399
421
  list(): Promise<Template[]>;
422
+ /**
423
+ * Upload a `docker save` / OCI archive as a build input. The image is named
424
+ * by its own content, so re-uploading the same bytes is free, and a build
425
+ * that names it needs no registry credentials anywhere.
426
+ */
427
+ uploadImage(archive: BodyInit, options?: {
428
+ signal?: AbortSignal;
429
+ }): Promise<UploadedImage>;
400
430
  activate(id: string): Promise<{
401
431
  id: string;
402
432
  name: string;
403
433
  version: number;
404
434
  }>;
405
- configureWarm(id: string, input: {
406
- enabled: boolean;
407
- }): Promise<WarmTargetResponse>;
408
- inspectWarm(id: string): Promise<WarmInventoryResponse>;
435
+ }
436
+ declare class TemplateResourcesResource {
437
+ private readonly client;
438
+ constructor(client: GatewayClient);
439
+ get(name: string): Promise<TemplateResource>;
440
+ configure(name: string, input: ConfigureTemplateResourceInput): Promise<TemplateResource>;
409
441
  }
410
442
  declare class TemplateBuildsResource {
411
443
  private readonly client;
@@ -478,8 +510,12 @@ declare class SandboxesResource {
478
510
  }): Promise<void>;
479
511
  writeFileStream(id: string, input: WriteFileStreamInput): Promise<number>;
480
512
  writeFile(id: string, input: WriteFileInput): Promise<number>;
513
+ /**
514
+ * Capture a restore point. The sandbox keeps running, and the returned
515
+ * template version is what it restarts from.
516
+ */
481
517
  snapshot(id: string): Promise<{
482
- snapshot: string;
518
+ template: string;
483
519
  }>;
484
520
  hibernate(id: string, input?: {
485
521
  mode: HibernateMode;
@@ -489,6 +525,7 @@ declare class SandboxesResource {
489
525
  }
490
526
  export declare class BlackcatClient extends GatewayClient {
491
527
  readonly templates: TemplatesResource;
528
+ readonly templateResources: TemplateResourcesResource;
492
529
  readonly templateBuilds: TemplateBuildsResource;
493
530
  readonly sandboxes: SandboxesResource;
494
531
  readonly tokens: TokensResource;
package/sdk/dist/index.js CHANGED
@@ -36,7 +36,7 @@ class BlackcatProtocolError extends Error {
36
36
  this.name = "BlackcatProtocolError";
37
37
  }
38
38
  }
39
- var MAX_FILE_CHUNK = 3 * 1024 * 1024;
39
+ var MAX_FILE_CHUNK = 512 * 1024;
40
40
  var MAX_FILE_READ_CHUNK = 1e6;
41
41
  var MAX_PROCESS_STDIN = 512 * 1024;
42
42
  var MAX_EXEC_STDIN = 512 * 1024;
@@ -323,14 +323,25 @@ class TemplatesResource {
323
323
  list() {
324
324
  return this.client.json("GET", "/v1/templates", undefined, "token");
325
325
  }
326
+ async uploadImage(archive, options) {
327
+ const response = await this.client.raw("POST", "/v1/template-images", archive, "either", "application/octet-stream", false, options?.signal);
328
+ return await response.json();
329
+ }
326
330
  activate(id) {
327
331
  return this.client.json("POST", `/v1/templates/${pathSegment(id)}/activate`, undefined, "token");
328
332
  }
329
- configureWarm(id, input) {
330
- return this.client.json("PUT", `/v1/templates/${pathSegment(id)}/warm`, input, "token");
333
+ }
334
+
335
+ class TemplateResourcesResource {
336
+ client;
337
+ constructor(client) {
338
+ this.client = client;
339
+ }
340
+ get(name) {
341
+ return this.client.json("GET", `/v1/template-resources/${pathSegment(name)}`, undefined, "token");
331
342
  }
332
- inspectWarm(id) {
333
- return this.client.json("GET", `/v1/templates/${pathSegment(id)}/warm`, undefined, "token");
343
+ configure(name, input) {
344
+ return this.client.json("PUT", `/v1/template-resources/${pathSegment(name)}`, input, "token");
334
345
  }
335
346
  }
336
347
 
@@ -599,6 +610,7 @@ class SandboxesResource {
599
610
 
600
611
  class BlackcatClient extends GatewayClient {
601
612
  templates;
613
+ templateResources;
602
614
  templateBuilds;
603
615
  sandboxes;
604
616
  tokens;
@@ -608,6 +620,7 @@ class BlackcatClient extends GatewayClient {
608
620
  assertSecureBlackcatGatewayUrl(options.baseUrl);
609
621
  super(options);
610
622
  this.templates = new TemplatesResource(this);
623
+ this.templateResources = new TemplateResourcesResource(this);
611
624
  this.templateBuilds = new TemplateBuildsResource(this);
612
625
  this.sandboxes = new SandboxesResource(this);
613
626
  this.tokens = new TokensResource(this);