contree-client 0.1.3 → 0.2.1-dev0

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/lib/client.d.ts CHANGED
@@ -3,21 +3,24 @@
3
3
  import type { Profile } from "./profiles.js";
4
4
  import type { RequestSpec, ResponseData, RetryPolicy } from "./runtime.js";
5
5
  import type {
6
+ ClosableStreamRepr,
6
7
  DirectoryList,
7
8
  File,
8
9
  FileResponse,
9
10
  FileSpec,
10
11
  FilesListResponse,
12
+ GrepResult,
11
13
  Image,
12
14
  ImageImportRegistry,
13
15
  ImageListResponse,
16
+ InstanceNetworking,
14
17
  InstanceResourcesLimits,
18
+ InstanceResult,
15
19
  InstanceSpawnResponse,
16
20
  OperationEvent,
17
21
  OperationResponse,
18
22
  OperationStatus,
19
23
  OperationSummary,
20
- StreamRepr,
21
24
  WhoAmIResponse,
22
25
  } from "./models.js";
23
26
 
@@ -135,7 +138,8 @@ export declare class ContreeClient {
135
138
  uid?: number | undefined;
136
139
  gid?: number | undefined;
137
140
  resources_limits?: InstanceResourcesLimits | undefined;
138
- stdin?: StreamRepr | undefined;
141
+ networking?: InstanceNetworking | undefined;
142
+ stdin?: ClosableStreamRepr | undefined;
139
143
  timeout?: number | undefined;
140
144
  truncate_output_at?: number | undefined;
141
145
  files?: Record<string, FileSpec> | undefined;
@@ -163,6 +167,38 @@ export declare class ContreeClient {
163
167
  last_event_id?: number | null;
164
168
  },
165
169
  ): AsyncGenerator<OperationEvent>;
170
+ operationSubprocessCreate(
171
+ operationId: string,
172
+ command: string,
173
+ options?: {
174
+ args?: string[] | undefined;
175
+ shell?: boolean | undefined;
176
+ env?: Record<string, string> | null | undefined;
177
+ cwd?: string | undefined;
178
+ uid?: number | undefined;
179
+ gid?: number | undefined;
180
+ stdin?: ClosableStreamRepr | undefined;
181
+ truncate_output_at?: number | undefined;
182
+ },
183
+ ): Promise<number>;
184
+ operationSubprocess(
185
+ operationId: string,
186
+ spid: number,
187
+ ): Promise<InstanceResult>;
188
+ operationSubprocessKill(
189
+ operationId: string,
190
+ spid: number,
191
+ options?: { signal?: string | null },
192
+ ): Promise<null>;
193
+ operationSubprocessStdin(
194
+ operationId: string,
195
+ spid: number,
196
+ value: string,
197
+ options?: {
198
+ encoding?: "ascii" | "base64" | undefined;
199
+ close?: boolean | undefined;
200
+ },
201
+ ): Promise<null>;
166
202
  inspectFindImageByTag(tag: string): Promise<string>;
167
203
  inspectImage(imageUuid: string): Promise<Image>;
168
204
  inspectImageDownload(imageUuid: string, path: string): Promise<Uint8Array>;
@@ -177,5 +213,18 @@ export declare class ContreeClient {
177
213
  ): AsyncGenerator<Uint8Array>;
178
214
  checkImageArchive(imageUuid: string, path: string): Promise<boolean>;
179
215
  inspectImageList(imageUuid: string, path: string): Promise<DirectoryList>;
216
+ inspectImageGrep(
217
+ imageUuid: string,
218
+ pattern: string,
219
+ options?: {
220
+ path?: string | null;
221
+ glob?: string | null;
222
+ max_count?: number | null;
223
+ max_total?: number | null;
224
+ case?: "sensitive" | "insensitive" | "smart" | null;
225
+ before?: number | null;
226
+ after?: number | null;
227
+ },
228
+ ): Promise<GrepResult>;
180
229
  whoami(): Promise<WhoAmIResponse>;
181
230
  }
package/lib/client.js CHANGED
@@ -216,11 +216,6 @@ export class ContreeClient {
216
216
  if (policy === null) {
217
217
  return await this._reconnecting(spec);
218
218
  }
219
- if (!spec.idempotent && !policy.retryUnsafe) {
220
- // a lost response after a non-idempotent request (POST) could
221
- // mean a second execution server-side
222
- return await this.request(spec);
223
- }
224
219
  if (
225
220
  typeof ReadableStream !== "undefined" &&
226
221
  spec.body instanceof ReadableStream
@@ -228,6 +223,13 @@ export class ContreeClient {
228
223
  // a stream cannot be replayed: single attempt
229
224
  return await this.request(spec);
230
225
  }
226
+ // a lost response after a non-idempotent request (POST) could
227
+ // mean a second execution server-side: never blind-retry unless
228
+ // the caller explicitly opted into that risk. 425 Too Early and
229
+ // 429 Too Many Requests are the exceptions - the backend's
230
+ // contract guarantees both mean the request was rejected before
231
+ // any processing, so replaying is always safe.
232
+ const replaySafe = spec.idempotent || policy.retryUnsafe;
231
233
  const delays = retryDelays(policy.delays);
232
234
  let attempts = 0;
233
235
  for (;;) {
@@ -239,6 +241,7 @@ export class ContreeClient {
239
241
  response = await this.request(spec);
240
242
  } catch (error) {
241
243
  if (
244
+ !replaySafe ||
242
245
  !this._transportRetryable(error) ||
243
246
  this._transportNonretryable(error) ||
244
247
  exhausted
@@ -251,6 +254,9 @@ export class ContreeClient {
251
254
  if (!policy.retryableStatus(response.status) || exhausted) {
252
255
  return response;
253
256
  }
257
+ if (!replaySafe && response.status !== 425 && response.status !== 429) {
258
+ return response;
259
+ }
254
260
  const retryAfter = retryAfterDelay(response);
255
261
  await sleep(retryAfter !== null ? retryAfter : delays.next().value);
256
262
  }
@@ -730,6 +736,43 @@ export class ContreeClient {
730
736
  }
731
737
  }
732
738
 
739
+ /** Spawn an additional subprocess inside a running instance (POST /operations/{operationId}/subprocesses) */
740
+ async operationSubprocessCreate(operationId, command, options = {}) {
741
+ const spec = operations.buildOperationSubprocessCreate(
742
+ operationId,
743
+ command,
744
+ options,
745
+ );
746
+ return operations.parseOperationSubprocessCreate(await this.call(spec));
747
+ }
748
+
749
+ /** Result of one subprocess, reconstructed from its events (GET /operations/{operationId}/subprocesses/{spid}) */
750
+ async operationSubprocess(operationId, spid) {
751
+ const spec = operations.buildOperationSubprocess(operationId, spid);
752
+ return operations.parseOperationSubprocess(await this.call(spec));
753
+ }
754
+
755
+ /** Kill one subprocess (DELETE /operations/{operationId}/subprocesses/{spid}) */
756
+ async operationSubprocessKill(operationId, spid, options = {}) {
757
+ const spec = operations.buildOperationSubprocessKill(
758
+ operationId,
759
+ spid,
760
+ options,
761
+ );
762
+ return operations.parseOperationSubprocessKill(await this.call(spec));
763
+ }
764
+
765
+ /** Write to a subprocess's stdin and/or close it (POST /operations/{operationId}/subprocesses/{spid}/stdin) */
766
+ async operationSubprocessStdin(operationId, spid, value, options = {}) {
767
+ const spec = operations.buildOperationSubprocessStdin(
768
+ operationId,
769
+ spid,
770
+ value,
771
+ options,
772
+ );
773
+ return operations.parseOperationSubprocessStdin(await this.call(spec));
774
+ }
775
+
733
776
  /** Find image by tag (GET /inspect/) */
734
777
  async inspectFindImageByTag(tag) {
735
778
  const spec = operations.buildInspectFindImageByTag(tag);
@@ -778,6 +821,12 @@ export class ContreeClient {
778
821
  return operations.parseInspectImageList(await this.call(spec));
779
822
  }
780
823
 
824
+ /** Search file contents in image (GET /inspect/{image_uuid}/grep) */
825
+ async inspectImageGrep(imageUuid, pattern, options = {}) {
826
+ const spec = operations.buildInspectImageGrep(imageUuid, pattern, options);
827
+ return operations.parseInspectImageGrep(await this.call(spec));
828
+ }
829
+
781
830
  /** Get current token information (GET /whoami) */
782
831
  async whoami() {
783
832
  const spec = operations.buildWhoami();
package/lib/models.d.ts CHANGED
@@ -78,6 +78,51 @@ export declare class DirectoryList {
78
78
  toWire(): Record<string, unknown>;
79
79
  }
80
80
 
81
+ export declare class GrepSubmatch {
82
+ text: string;
83
+ start: number;
84
+ end: number;
85
+ constructor(fields?: { text?: string; start?: number; end?: number });
86
+ static fromWire(data: Record<string, unknown>): GrepSubmatch;
87
+ toWire(): Record<string, unknown>;
88
+ }
89
+
90
+ export declare class GrepMatch {
91
+ path: string;
92
+ line_number: number;
93
+ absolute_offset: number;
94
+ line_text: string;
95
+ line_bytes: number;
96
+ submatches: GrepSubmatch[];
97
+ type: "match" | "context";
98
+ constructor(fields?: {
99
+ path?: string;
100
+ line_number?: number;
101
+ absolute_offset?: number;
102
+ line_text?: string;
103
+ line_bytes?: number;
104
+ submatches?: GrepSubmatch[];
105
+ type?: "match" | "context";
106
+ });
107
+ static fromWire(data: Record<string, unknown>): GrepMatch;
108
+ toWire(): Record<string, unknown>;
109
+ }
110
+
111
+ export declare class GrepResult {
112
+ path: string;
113
+ patterns: string[];
114
+ matches: GrepMatch[];
115
+ truncated: boolean;
116
+ constructor(fields?: {
117
+ path?: string;
118
+ patterns?: string[];
119
+ matches?: GrepMatch[];
120
+ truncated?: boolean;
121
+ });
122
+ static fromWire(data: Record<string, unknown>): GrepResult;
123
+ toWire(): Record<string, unknown>;
124
+ }
125
+
81
126
  export declare class ImageImportRegistryCredentials {
82
127
  username?: string;
83
128
  password?: string;
@@ -186,6 +231,19 @@ export declare class StreamRepr {
186
231
  static fromText(value: string): StreamRepr;
187
232
  }
188
233
 
234
+ export declare class ClosableStreamRepr {
235
+ value: string;
236
+ encoding?: "ascii" | "base64";
237
+ close?: boolean;
238
+ constructor(fields?: {
239
+ value?: string;
240
+ encoding?: "ascii" | "base64" | null;
241
+ close?: boolean | null;
242
+ });
243
+ static fromWire(data: Record<string, unknown>): ClosableStreamRepr;
244
+ toWire(): Record<string, unknown>;
245
+ }
246
+
189
247
  export declare class InstanceResourcesLimits {
190
248
  max_layer_bytes?: number;
191
249
  constructor(fields?: { max_layer_bytes?: number | null });
@@ -193,6 +251,38 @@ export declare class InstanceResourcesLimits {
193
251
  toWire(): Record<string, unknown>;
194
252
  }
195
253
 
254
+ export declare class InstanceNetworking {
255
+ enabled?: boolean;
256
+ constructor(fields?: { enabled?: boolean | null });
257
+ static fromWire(data: Record<string, unknown>): InstanceNetworking;
258
+ toWire(): Record<string, unknown>;
259
+ }
260
+
261
+ export declare class ExecSpec {
262
+ command: string;
263
+ args?: string[];
264
+ shell?: boolean;
265
+ env?: Record<string, string> | null;
266
+ cwd?: string;
267
+ uid?: number;
268
+ gid?: number;
269
+ stdin?: ClosableStreamRepr;
270
+ truncate_output_at?: number;
271
+ constructor(fields?: {
272
+ command?: string;
273
+ args?: string[] | null;
274
+ shell?: boolean | null;
275
+ env?: Record<string, string> | null;
276
+ cwd?: string | null;
277
+ uid?: number | null;
278
+ gid?: number | null;
279
+ stdin?: ClosableStreamRepr | null;
280
+ truncate_output_at?: number | null;
281
+ });
282
+ static fromWire(data: Record<string, unknown>): ExecSpec;
283
+ toWire(): Record<string, unknown>;
284
+ }
285
+
196
286
  export declare class FileSpec {
197
287
  uuid?: string;
198
288
  uid?: number;
@@ -221,7 +311,8 @@ export declare class InstanceSpawnRequest {
221
311
  uid?: number;
222
312
  gid?: number;
223
313
  resources_limits?: InstanceResourcesLimits;
224
- stdin?: StreamRepr;
314
+ networking?: InstanceNetworking;
315
+ stdin?: ClosableStreamRepr;
225
316
  timeout?: number;
226
317
  truncate_output_at?: number;
227
318
  files?: Record<string, FileSpec>;
@@ -238,7 +329,8 @@ export declare class InstanceSpawnRequest {
238
329
  uid?: number | null;
239
330
  gid?: number | null;
240
331
  resources_limits?: InstanceResourcesLimits | null;
241
- stdin?: StreamRepr | null;
332
+ networking?: InstanceNetworking | null;
333
+ stdin?: ClosableStreamRepr | null;
242
334
  timeout?: number | null;
243
335
  truncate_output_at?: number | null;
244
336
  files?: Record<string, FileSpec> | null;
@@ -335,7 +427,8 @@ export declare class InstanceSpawnResponse {
335
427
  uid?: number;
336
428
  gid?: number;
337
429
  resources_limits?: InstanceResourcesLimits;
338
- stdin?: StreamRepr;
430
+ networking?: InstanceNetworking;
431
+ stdin?: ClosableStreamRepr;
339
432
  timeout?: number;
340
433
  truncate_output_at?: number;
341
434
  disposable?: boolean;
@@ -354,7 +447,8 @@ export declare class InstanceSpawnResponse {
354
447
  uid?: number | null;
355
448
  gid?: number | null;
356
449
  resources_limits?: InstanceResourcesLimits | null;
357
- stdin?: StreamRepr | null;
450
+ networking?: InstanceNetworking | null;
451
+ stdin?: ClosableStreamRepr | null;
358
452
  timeout?: number | null;
359
453
  truncate_output_at?: number | null;
360
454
  disposable?: boolean | null;
@@ -407,7 +501,8 @@ export declare class OperationInstanceMetadata {
407
501
  uid?: number;
408
502
  gid?: number;
409
503
  resources_limits?: InstanceResourcesLimits;
410
- stdin?: StreamRepr;
504
+ networking?: InstanceNetworking;
505
+ stdin?: ClosableStreamRepr;
411
506
  timeout?: number;
412
507
  truncate_output_at?: number;
413
508
  files?: Record<string, FileSpec>;
@@ -425,7 +520,8 @@ export declare class OperationInstanceMetadata {
425
520
  uid?: number | null;
426
521
  gid?: number | null;
427
522
  resources_limits?: InstanceResourcesLimits | null;
428
- stdin?: StreamRepr | null;
523
+ networking?: InstanceNetworking | null;
524
+ stdin?: ClosableStreamRepr | null;
429
525
  timeout?: number | null;
430
526
  truncate_output_at?: number | null;
431
527
  files?: Record<string, FileSpec> | null;
@@ -668,6 +764,7 @@ export declare class EventDataExit {
668
764
  timed_out: boolean;
669
765
  duration_ms: number;
670
766
  resources: EventResources;
767
+ core_dump?: boolean;
671
768
  constructor(fields?: {
672
769
  pid?: number;
673
770
  code?: number;
@@ -675,6 +772,7 @@ export declare class EventDataExit {
675
772
  timed_out?: boolean;
676
773
  duration_ms?: number;
677
774
  resources?: EventResources;
775
+ core_dump?: boolean | null;
678
776
  });
679
777
  static fromWire(data: Record<string, unknown>): EventDataExit;
680
778
  toWire(): Record<string, unknown>;
package/lib/models.js CHANGED
@@ -157,6 +157,127 @@ export class DirectoryList {
157
157
  }
158
158
  }
159
159
 
160
+ export class GrepSubmatch {
161
+ constructor(fields = {}) {
162
+ this.text = fields.text;
163
+ this.start = fields.start;
164
+ this.end = fields.end;
165
+ }
166
+
167
+ static fromWire(data) {
168
+ return new GrepSubmatch({
169
+ text: data["text"],
170
+ start: data["start"],
171
+ end: data["end"],
172
+ });
173
+ }
174
+
175
+ toWire() {
176
+ const data = {};
177
+ if (this.text !== undefined) {
178
+ data["text"] = this.text;
179
+ }
180
+ if (this.start !== undefined) {
181
+ data["start"] = this.start;
182
+ }
183
+ if (this.end !== undefined) {
184
+ data["end"] = this.end;
185
+ }
186
+ return data;
187
+ }
188
+ }
189
+
190
+ export class GrepMatch {
191
+ constructor(fields = {}) {
192
+ this.path = fields.path;
193
+ this.line_number = fields.line_number;
194
+ this.absolute_offset = fields.absolute_offset;
195
+ this.line_text = fields.line_text;
196
+ this.line_bytes = fields.line_bytes;
197
+ this.submatches = fields.submatches;
198
+ this.type = fields.type;
199
+ }
200
+
201
+ static fromWire(data) {
202
+ return new GrepMatch({
203
+ path: data["path"],
204
+ line_number: data["line_number"],
205
+ absolute_offset: data["absolute_offset"],
206
+ line_text: data["line_text"],
207
+ line_bytes: data["line_bytes"],
208
+ submatches: data["submatches"].map((item) => GrepSubmatch.fromWire(item)),
209
+ type: data["type"],
210
+ });
211
+ }
212
+
213
+ toWire() {
214
+ const data = {};
215
+ if (this.path !== undefined) {
216
+ data["path"] = this.path;
217
+ }
218
+ if (this.line_number !== undefined) {
219
+ data["line_number"] = this.line_number;
220
+ }
221
+ if (this.absolute_offset !== undefined) {
222
+ data["absolute_offset"] = this.absolute_offset;
223
+ }
224
+ if (this.line_text !== undefined) {
225
+ data["line_text"] = this.line_text;
226
+ }
227
+ if (this.line_bytes !== undefined) {
228
+ data["line_bytes"] = this.line_bytes;
229
+ }
230
+ if (this.submatches !== undefined) {
231
+ data["submatches"] =
232
+ this.submatches === null
233
+ ? null
234
+ : this.submatches.map((item) => item.toWire());
235
+ }
236
+ if (this.type !== undefined) {
237
+ data["type"] = this.type;
238
+ }
239
+ return data;
240
+ }
241
+ }
242
+
243
+ export class GrepResult {
244
+ constructor(fields = {}) {
245
+ this.path = fields.path;
246
+ this.patterns = fields.patterns;
247
+ this.matches = fields.matches;
248
+ this.truncated = fields.truncated;
249
+ }
250
+
251
+ static fromWire(data) {
252
+ return new GrepResult({
253
+ path: data["path"],
254
+ patterns: data["patterns"],
255
+ matches: data["matches"].map((item) => GrepMatch.fromWire(item)),
256
+ truncated: data["truncated"],
257
+ });
258
+ }
259
+
260
+ toWire() {
261
+ const data = {};
262
+ if (this.path !== undefined) {
263
+ data["path"] = this.path;
264
+ }
265
+ if (this.patterns !== undefined) {
266
+ data["patterns"] = this.patterns;
267
+ }
268
+ if (this.matches !== undefined) {
269
+ data["matches"] =
270
+ this.matches === null
271
+ ? null
272
+ : this.matches.map((item) => item.toWire());
273
+ }
274
+ if (this.truncated !== undefined) {
275
+ data["truncated"] = this.truncated;
276
+ }
277
+ return data;
278
+ }
279
+ }
280
+
160
281
  export class ImageImportRegistryCredentials {
161
282
  constructor(fields = {}) {
162
283
  this.username = fields.username;
@@ -464,6 +585,37 @@ export class StreamRepr {
464
585
  }
465
586
  }
466
587
 
588
+ /** Stdin payload. Unlike output streams it is never truncated; */
589
+ export class ClosableStreamRepr {
590
+ constructor(fields = {}) {
591
+ this.value = fields.value;
592
+ this.encoding = fields.encoding;
593
+ this.close = fields.close;
594
+ }
595
+
596
+ static fromWire(data) {
597
+ return new ClosableStreamRepr({
598
+ value: data["value"],
599
+ encoding: data["encoding"],
600
+ close: data["close"],
601
+ });
602
+ }
603
+
604
+ toWire() {
605
+ const data = {};
606
+ if (this.value !== undefined) {
607
+ data["value"] = this.value;
608
+ }
609
+ if (this.encoding !== undefined) {
610
+ data["encoding"] = this.encoding;
611
+ }
612
+ if (this.close !== undefined) {
613
+ data["close"] = this.close;
614
+ }
615
+ return data;
616
+ }
617
+ }
618
+
467
619
  export class InstanceResourcesLimits {
468
620
  constructor(fields = {}) {
469
621
  this.max_layer_bytes = fields.max_layer_bytes;
@@ -484,6 +636,90 @@ export class InstanceResourcesLimits {
484
636
  }
485
637
  }
486
638
 
639
+ export class InstanceNetworking {
640
+ constructor(fields = {}) {
641
+ this.enabled = fields.enabled;
642
+ }
643
+
644
+ static fromWire(data) {
645
+ return new InstanceNetworking({
646
+ enabled: data["enabled"],
647
+ });
648
+ }
649
+
650
+ toWire() {
651
+ const data = {};
652
+ if (this.enabled !== undefined) {
653
+ data["enabled"] = this.enabled;
654
+ }
655
+ return data;
656
+ }
657
+ }
658
+
659
+ /** Process-execution surface shared between `InstanceSpawnRequest` */
660
+ export class ExecSpec {
661
+ constructor(fields = {}) {
662
+ this.command = fields.command;
663
+ this.args = fields.args;
664
+ this.shell = fields.shell;
665
+ this.env = fields.env;
666
+ this.cwd = fields.cwd;
667
+ this.uid = fields.uid;
668
+ this.gid = fields.gid;
669
+ this.stdin = fields.stdin;
670
+ this.truncate_output_at = fields.truncate_output_at;
671
+ }
672
+
673
+ static fromWire(data) {
674
+ return new ExecSpec({
675
+ command: data["command"],
676
+ args: data["args"],
677
+ shell: data["shell"],
678
+ env: data["env"],
679
+ cwd: data["cwd"],
680
+ uid: data["uid"],
681
+ gid: data["gid"],
682
+ stdin:
683
+ data["stdin"] == null
684
+ ? data["stdin"]
685
+ : ClosableStreamRepr.fromWire(data["stdin"]),
686
+ truncate_output_at: data["truncate_output_at"],
687
+ });
688
+ }
689
+
690
+ toWire() {
691
+ const data = {};
692
+ if (this.command !== undefined) {
693
+ data["command"] = this.command;
694
+ }
695
+ if (this.args !== undefined) {
696
+ data["args"] = this.args;
697
+ }
698
+ if (this.shell !== undefined) {
699
+ data["shell"] = this.shell;
700
+ }
701
+ if (this.env !== undefined) {
702
+ data["env"] = this.env;
703
+ }
704
+ if (this.cwd !== undefined) {
705
+ data["cwd"] = this.cwd;
706
+ }
707
+ if (this.uid !== undefined) {
708
+ data["uid"] = this.uid;
709
+ }
710
+ if (this.gid !== undefined) {
711
+ data["gid"] = this.gid;
712
+ }
713
+ if (this.stdin !== undefined) {
714
+ data["stdin"] = this.stdin === null ? null : this.stdin.toWire();
715
+ }
716
+ if (this.truncate_output_at !== undefined) {
717
+ data["truncate_output_at"] = this.truncate_output_at;
718
+ }
719
+ return data;
720
+ }
721
+ }
722
+
487
723
  export class FileSpec {
488
724
  constructor(fields = {}) {
489
725
  this.uuid = fields.uuid;
@@ -538,6 +774,7 @@ export class InstanceSpawnRequest {
538
774
  this.uid = fields.uid;
539
775
  this.gid = fields.gid;
540
776
  this.resources_limits = fields.resources_limits;
777
+ this.networking = fields.networking;
541
778
  this.stdin = fields.stdin;
542
779
  this.timeout = fields.timeout;
543
780
  this.truncate_output_at = fields.truncate_output_at;
@@ -561,10 +798,14 @@ export class InstanceSpawnRequest {
561
798
  data["resources_limits"] == null
562
799
  ? data["resources_limits"]
563
800
  : InstanceResourcesLimits.fromWire(data["resources_limits"]),
801
+ networking:
802
+ data["networking"] == null
803
+ ? data["networking"]
804
+ : InstanceNetworking.fromWire(data["networking"]),
564
805
  stdin:
565
806
  data["stdin"] == null
566
807
  ? data["stdin"]
567
- : StreamRepr.fromWire(data["stdin"]),
808
+ : ClosableStreamRepr.fromWire(data["stdin"]),
568
809
  timeout: data["timeout"],
569
810
  truncate_output_at: data["truncate_output_at"],
570
811
  files:
@@ -618,6 +859,10 @@ export class InstanceSpawnRequest {
618
859
  data["resources_limits"] =
619
860
  this.resources_limits === null ? null : this.resources_limits.toWire();
620
861
  }
862
+ if (this.networking !== undefined) {
863
+ data["networking"] =
864
+ this.networking === null ? null : this.networking.toWire();
865
+ }
621
866
  if (this.stdin !== undefined) {
622
867
  data["stdin"] = this.stdin === null ? null : this.stdin.toWire();
623
868
  }
@@ -850,6 +1095,7 @@ export class InstanceSpawnResponse {
850
1095
  this.uid = fields.uid;
851
1096
  this.gid = fields.gid;
852
1097
  this.resources_limits = fields.resources_limits;
1098
+ this.networking = fields.networking;
853
1099
  this.stdin = fields.stdin;
854
1100
  this.timeout = fields.timeout;
855
1101
  this.truncate_output_at = fields.truncate_output_at;
@@ -875,10 +1121,14 @@ export class InstanceSpawnResponse {
875
1121
  data["resources_limits"] == null
876
1122
  ? data["resources_limits"]
877
1123
  : InstanceResourcesLimits.fromWire(data["resources_limits"]),
1124
+ networking:
1125
+ data["networking"] == null
1126
+ ? data["networking"]
1127
+ : InstanceNetworking.fromWire(data["networking"]),
878
1128
  stdin:
879
1129
  data["stdin"] == null
880
1130
  ? data["stdin"]
881
- : StreamRepr.fromWire(data["stdin"]),
1131
+ : ClosableStreamRepr.fromWire(data["stdin"]),
882
1132
  timeout: data["timeout"],
883
1133
  truncate_output_at: data["truncate_output_at"],
884
1134
  disposable: data["disposable"],
@@ -937,6 +1187,10 @@ export class InstanceSpawnResponse {
937
1187
  data["resources_limits"] =
938
1188
  this.resources_limits === null ? null : this.resources_limits.toWire();
939
1189
  }
1190
+ if (this.networking !== undefined) {
1191
+ data["networking"] =
1192
+ this.networking === null ? null : this.networking.toWire();
1193
+ }
940
1194
  if (this.stdin !== undefined) {
941
1195
  data["stdin"] = this.stdin === null ? null : this.stdin.toWire();
942
1196
  }
@@ -1051,6 +1305,7 @@ export class OperationInstanceMetadata {
1051
1305
  this.uid = fields.uid;
1052
1306
  this.gid = fields.gid;
1053
1307
  this.resources_limits = fields.resources_limits;
1308
+ this.networking = fields.networking;
1054
1309
  this.stdin = fields.stdin;
1055
1310
  this.timeout = fields.timeout;
1056
1311
  this.truncate_output_at = fields.truncate_output_at;
@@ -1075,10 +1330,14 @@ export class OperationInstanceMetadata {
1075
1330
  data["resources_limits"] == null
1076
1331
  ? data["resources_limits"]
1077
1332
  : InstanceResourcesLimits.fromWire(data["resources_limits"]),
1333
+ networking:
1334
+ data["networking"] == null
1335
+ ? data["networking"]
1336
+ : InstanceNetworking.fromWire(data["networking"]),
1078
1337
  stdin:
1079
1338
  data["stdin"] == null
1080
1339
  ? data["stdin"]
1081
- : StreamRepr.fromWire(data["stdin"]),
1340
+ : ClosableStreamRepr.fromWire(data["stdin"]),
1082
1341
  timeout: data["timeout"],
1083
1342
  truncate_output_at: data["truncate_output_at"],
1084
1343
  files:
@@ -1136,6 +1395,10 @@ export class OperationInstanceMetadata {
1136
1395
  data["resources_limits"] =
1137
1396
  this.resources_limits === null ? null : this.resources_limits.toWire();
1138
1397
  }
1398
+ if (this.networking !== undefined) {
1399
+ data["networking"] =
1400
+ this.networking === null ? null : this.networking.toWire();
1401
+ }
1139
1402
  if (this.stdin !== undefined) {
1140
1403
  data["stdin"] = this.stdin === null ? null : this.stdin.toWire();
1141
1404
  }
@@ -1788,6 +2051,7 @@ export class EventDataExit {
1788
2051
  this.timed_out = fields.timed_out;
1789
2052
  this.duration_ms = fields.duration_ms;
1790
2053
  this.resources = fields.resources;
2054
+ this.core_dump = fields.core_dump;
1791
2055
  }
1792
2056
 
1793
2057
  static fromWire(data) {
@@ -1798,6 +2062,7 @@ export class EventDataExit {
1798
2062
  timed_out: data["timed_out"],
1799
2063
  duration_ms: data["duration_ms"],
1800
2064
  resources: EventResources.fromWire(data["resources"]),
2065
+ core_dump: data["core_dump"],
1801
2066
  });
1802
2067
  }
1803
2068
 
@@ -1822,6 +2087,9 @@ export class EventDataExit {
1822
2087
  data["resources"] =
1823
2088
  this.resources === null ? null : this.resources.toWire();
1824
2089
  }
2090
+ if (this.core_dump !== undefined) {
2091
+ data["core_dump"] = this.core_dump;
2092
+ }
1825
2093
  return data;
1826
2094
  }
1827
2095
  }
@@ -3,20 +3,23 @@
3
3
  import type { RequestSpec, ResponseData } from "./runtime.js";
4
4
 
5
5
  import type {
6
+ ClosableStreamRepr,
6
7
  DirectoryList,
7
8
  File,
8
9
  FileResponse,
9
10
  FileSpec,
10
11
  FilesListResponse,
12
+ GrepResult,
11
13
  Image,
12
14
  ImageImportRegistry,
13
15
  ImageListResponse,
16
+ InstanceNetworking,
14
17
  InstanceResourcesLimits,
18
+ InstanceResult,
15
19
  InstanceSpawnResponse,
16
20
  OperationResponse,
17
21
  OperationStatus,
18
22
  OperationSummary,
19
- StreamRepr,
20
23
  WhoAmIResponse,
21
24
  } from "./models.js";
22
25
 
@@ -94,7 +97,8 @@ export declare function buildSpawnInstance(
94
97
  uid?: number | undefined;
95
98
  gid?: number | undefined;
96
99
  resources_limits?: InstanceResourcesLimits | undefined;
97
- stdin?: StreamRepr | undefined;
100
+ networking?: InstanceNetworking | undefined;
101
+ stdin?: ClosableStreamRepr | undefined;
98
102
  timeout?: number | undefined;
99
103
  truncate_output_at?: number | undefined;
100
104
  files?: Record<string, FileSpec> | undefined;
@@ -141,6 +145,58 @@ export declare function buildIterOperationEvents(
141
145
  },
142
146
  ): RequestSpec;
143
147
 
148
+ export declare function buildOperationSubprocessCreate(
149
+ operationId: string,
150
+ command: string,
151
+ options?: {
152
+ args?: string[] | undefined;
153
+ shell?: boolean | undefined;
154
+ env?: Record<string, string> | null | undefined;
155
+ cwd?: string | undefined;
156
+ uid?: number | undefined;
157
+ gid?: number | undefined;
158
+ stdin?: ClosableStreamRepr | undefined;
159
+ truncate_output_at?: number | undefined;
160
+ },
161
+ ): RequestSpec;
162
+
163
+ export declare function parseOperationSubprocessCreate(
164
+ response: ResponseData,
165
+ ): number;
166
+
167
+ export declare function buildOperationSubprocess(
168
+ operationId: string,
169
+ spid: number,
170
+ ): RequestSpec;
171
+
172
+ export declare function parseOperationSubprocess(
173
+ response: ResponseData,
174
+ ): InstanceResult;
175
+
176
+ export declare function buildOperationSubprocessKill(
177
+ operationId: string,
178
+ spid: number,
179
+ options?: { signal?: string | null },
180
+ ): RequestSpec;
181
+
182
+ export declare function parseOperationSubprocessKill(
183
+ response: ResponseData,
184
+ ): null;
185
+
186
+ export declare function buildOperationSubprocessStdin(
187
+ operationId: string,
188
+ spid: number,
189
+ value: string,
190
+ options?: {
191
+ encoding?: "ascii" | "base64" | undefined;
192
+ close?: boolean | undefined;
193
+ },
194
+ ): RequestSpec;
195
+
196
+ export declare function parseOperationSubprocessStdin(
197
+ response: ResponseData,
198
+ ): null;
199
+
144
200
  export declare function buildInspectFindImageByTag(tag: string): RequestSpec;
145
201
 
146
202
  export declare function parseInspectFindImageByTag(
@@ -188,6 +244,24 @@ export declare function parseInspectImageList(
188
244
  response: ResponseData,
189
245
  ): DirectoryList;
190
246
 
247
+ export declare function buildInspectImageGrep(
248
+ imageUuid: string,
249
+ pattern: string,
250
+ options?: {
251
+ path?: string | null;
252
+ glob?: string | null;
253
+ max_count?: number | null;
254
+ max_total?: number | null;
255
+ case?: "sensitive" | "insensitive" | "smart" | null;
256
+ before?: number | null;
257
+ after?: number | null;
258
+ },
259
+ ): RequestSpec;
260
+
261
+ export declare function parseInspectImageGrep(
262
+ response: ResponseData,
263
+ ): GrepResult;
264
+
191
265
  export declare function buildWhoami(): RequestSpec;
192
266
 
193
267
  export declare function parseWhoami(response: ResponseData): WhoAmIResponse;
package/lib/operations.js CHANGED
@@ -9,13 +9,17 @@ import {
9
9
  } from "./runtime.js";
10
10
 
11
11
  import {
12
+ ClosableStreamRepr,
12
13
  DirectoryList,
14
+ ExecSpec,
13
15
  File,
14
16
  FileResponse,
15
17
  FilesListResponse,
18
+ GrepResult,
16
19
  Image,
17
20
  ImageImportRequest,
18
21
  ImageListResponse,
22
+ InstanceResult,
19
23
  InstanceSpawnRequest,
20
24
  InstanceSpawnResponse,
21
25
  OperationResponse,
@@ -111,11 +115,7 @@ export function parseUpdateImageTag(response) {
111
115
 
112
116
  /** Build the request for `POST /images/import`. */
113
117
  export function buildImportImage(registry, { tag, timeout } = {}) {
114
- const payload = new ImageImportRequest({
115
- registry: registry,
116
- tag,
117
- timeout,
118
- }).toWire();
118
+ const payload = new ImageImportRequest({ registry, tag, timeout }).toWire();
119
119
  return {
120
120
  method: "POST",
121
121
  path: `/images/import`,
@@ -235,6 +235,7 @@ export function buildSpawnInstance(
235
235
  uid,
236
236
  gid,
237
237
  resources_limits,
238
+ networking,
238
239
  stdin,
239
240
  timeout,
240
241
  truncate_output_at,
@@ -242,8 +243,8 @@ export function buildSpawnInstance(
242
243
  } = {},
243
244
  ) {
244
245
  const payload = new InstanceSpawnRequest({
245
- command: command,
246
- image: image,
246
+ command,
247
+ image,
247
248
  disposable,
248
249
  hostname,
249
250
  args,
@@ -254,6 +255,7 @@ export function buildSpawnInstance(
254
255
  uid,
255
256
  gid,
256
257
  resources_limits,
258
+ networking,
257
259
  stdin,
258
260
  timeout,
259
261
  truncate_output_at,
@@ -386,6 +388,115 @@ export function buildIterOperationEvents(
386
388
  };
387
389
  }
388
390
 
391
+ /** Build the request for `POST /operations/{operationId}/subprocesses`. */
392
+ export function buildOperationSubprocessCreate(
393
+ operationId,
394
+ command,
395
+ { args, shell, env, cwd, uid, gid, stdin, truncate_output_at } = {},
396
+ ) {
397
+ const payload = new ExecSpec({
398
+ operation_id: operationId,
399
+ command,
400
+ args,
401
+ shell,
402
+ env,
403
+ cwd,
404
+ uid,
405
+ gid,
406
+ stdin,
407
+ truncate_output_at,
408
+ }).toWire();
409
+ return {
410
+ method: "POST",
411
+ path: `/operations/${quotePath(operationId)}/subprocesses`,
412
+ idempotent: false,
413
+ body: JSON.stringify(payload),
414
+ contentType: "application/json",
415
+ };
416
+ }
417
+
418
+ /** Parse the response of `POST /operations/{operationId}/subprocesses`. */
419
+ export function parseOperationSubprocessCreate(response) {
420
+ if (response.status >= 200 && response.status < 300) {
421
+ return Number(jsonObject(response)["spid"]);
422
+ }
423
+ throw errorForResponse(response);
424
+ }
425
+
426
+ /** Build the request for `GET /operations/{operationId}/subprocesses/{spid}`. */
427
+ export function buildOperationSubprocess(operationId, spid) {
428
+ return {
429
+ method: "GET",
430
+ path: `/operations/${quotePath(operationId)}/subprocesses/${quotePath(spid)}`,
431
+ idempotent: true,
432
+ };
433
+ }
434
+
435
+ /** Parse the response of `GET /operations/{operationId}/subprocesses/{spid}`. */
436
+ export function parseOperationSubprocess(response) {
437
+ if (response.status >= 200 && response.status < 300) {
438
+ return InstanceResult.fromWire(jsonObject(response));
439
+ }
440
+ throw errorForResponse(response);
441
+ }
442
+
443
+ /** Build the request for `DELETE /operations/{operationId}/subprocesses/{spid}`. */
444
+ export function buildOperationSubprocessKill(
445
+ operationId,
446
+ spid,
447
+ { signal = null } = {},
448
+ ) {
449
+ const query = {};
450
+ if (signal != null) {
451
+ query["signal"] = signal;
452
+ }
453
+ return {
454
+ method: "DELETE",
455
+ path: `/operations/${quotePath(operationId)}/subprocesses/${quotePath(spid)}`,
456
+ idempotent: true,
457
+ query,
458
+ };
459
+ }
460
+
461
+ /** Parse the response of `DELETE /operations/{operationId}/subprocesses/{spid}`. */
462
+ export function parseOperationSubprocessKill(response) {
463
+ if (response.status >= 200 && response.status < 300) {
464
+ return null;
465
+ }
466
+ throw errorForResponse(response);
467
+ }
468
+
469
+ /** Build the request for `POST /operations/{operationId}/subprocesses/{spid}/stdin`. */
470
+ export function buildOperationSubprocessStdin(
471
+ operationId,
472
+ spid,
473
+ value,
474
+ { encoding, close } = {},
475
+ ) {
476
+ const payload = new ClosableStreamRepr({
477
+ operation_id: operationId,
478
+ spid,
479
+ value,
480
+ encoding,
481
+ close,
482
+ }).toWire();
483
+ return {
484
+ method: "POST",
485
+ path: `/operations/${quotePath(operationId)}/subprocesses/${quotePath(spid)}/stdin`,
486
+ idempotent: false,
487
+ body: JSON.stringify(payload),
488
+ contentType: "application/json",
489
+ };
490
+ }
491
+
492
+ /** Parse the response of `POST /operations/{operationId}/subprocesses/{spid}/stdin`. */
493
+ export function parseOperationSubprocessStdin(response) {
494
+ if (response.status >= 200 && response.status < 300) {
495
+ return null;
496
+ }
497
+ throw errorForResponse(response);
498
+ }
499
+
389
500
  /** Build the request for `GET /inspect/`. */
390
501
  export function buildInspectFindImageByTag(tag) {
391
502
  const query = {};
@@ -529,6 +640,59 @@ export function parseInspectImageList(response) {
529
640
  throw errorForResponse(response);
530
641
  }
531
642
 
643
+ /** Build the request for `GET /inspect/{image_uuid}/grep`. */
644
+ export function buildInspectImageGrep(
645
+ imageUuid,
646
+ pattern,
647
+ {
648
+ path = null,
649
+ glob = null,
650
+ max_count = null,
651
+ max_total = null,
652
+ case: case_ = null,
653
+ before = null,
654
+ after = null,
655
+ } = {},
656
+ ) {
657
+ const query = {};
658
+ query["pattern"] = pattern;
659
+ if (path != null) {
660
+ query["path"] = path;
661
+ }
662
+ if (glob != null) {
663
+ query["glob"] = glob;
664
+ }
665
+ if (max_count != null) {
666
+ query["max_count"] = String(max_count);
667
+ }
668
+ if (max_total != null) {
669
+ query["max_total"] = String(max_total);
670
+ }
671
+ if (case_ != null) {
672
+ query["case"] = case_;
673
+ }
674
+ if (before != null) {
675
+ query["before"] = String(before);
676
+ }
677
+ if (after != null) {
678
+ query["after"] = String(after);
679
+ }
680
+ return {
681
+ method: "GET",
682
+ path: `/inspect/${quotePath(imageUuid)}/grep`,
683
+ idempotent: true,
684
+ query,
685
+ };
686
+ }
687
+
688
+ /** Parse the response of `GET /inspect/{image_uuid}/grep`. */
689
+ export function parseInspectImageGrep(response) {
690
+ if (response.status >= 200 && response.status < 300) {
691
+ return GrepResult.fromWire(jsonObject(response));
692
+ }
693
+ throw errorForResponse(response);
694
+ }
695
+
532
696
  /** Build the request for `GET /whoami`. */
533
697
  export function buildWhoami() {
534
698
  return { method: "GET", path: `/whoami`, idempotent: true };
package/lib/runtime.js CHANGED
@@ -14,7 +14,7 @@ import {
14
14
 
15
15
  export const CHUNK_SIZE = 65536;
16
16
 
17
- export const PACKAGE_VERSION = "0.1.3";
17
+ export const PACKAGE_VERSION = "0.2.1-dev0";
18
18
  export const UA_PRODUCT = `contree-client-js/${PACKAGE_VERSION}`;
19
19
 
20
20
  const NODE_VERSION =
@@ -47,10 +47,15 @@ export function* retryDelays(delays = RETRY_DELAYS) {
47
47
  }
48
48
  }
49
49
 
50
- /** Opt-in retries for transient failures of buffered requests. */
50
+ /** Opt-in retries for transient failures of buffered requests.
51
+ *
52
+ * 425 (Too Early) and 429 (Too Many Requests) are a backend contract:
53
+ * both mean the request was rejected before any processing, so
54
+ * replaying them is always safe - even for a POST the caller hasn't
55
+ * opted into unsafe retries for (see `call()`). */
51
56
  export class RetryPolicy {
52
57
  constructor({
53
- statuses = [410, 425],
58
+ statuses = [410, 425, 429],
54
59
  serverErrors = true,
55
60
  delays = RETRY_DELAYS,
56
61
  maxAttempts = 10,
package/lib/specInfo.js CHANGED
@@ -5,4 +5,4 @@ export const DEFAULT_BASE_URL = "https://api.tokenfactory.nebius.com/sandboxes";
5
5
  // sha256 of the exact OpenAPI document this package was built
6
6
  // from - the build input provenance
7
7
  export const SPEC_SHA256 =
8
- "3782df855d7ae14556e221f4f37a67fb6aeb65121396cb009a5e7a0995abd06b";
8
+ "2bfd239341e6f61ccba1aafb39cef7b476d56f424156860a204f089d7d79b7bf";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "contree-client",
3
- "version": "0.1.3",
3
+ "version": "0.2.1-dev0",
4
4
  "description": "JavaScript client for the Contree API, generated from the OpenAPI spec",
5
5
  "homepage": "https://contree.dev/",
6
6
  "repository": {