contree-client 0.2.0 → 0.2.1
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 +5 -3
- package/lib/client.js +71 -3
- package/lib/models.d.ts +2 -0
- package/lib/models.js +5 -0
- package/lib/operations.d.ts +5 -3
- package/lib/operations.js +8 -0
- package/lib/runtime.d.ts +4 -2
- package/lib/runtime.js +17 -4
- package/lib/specInfo.js +1 -1
- package/package.json +1 -1
package/lib/client.d.ts
CHANGED
|
@@ -215,13 +215,15 @@ export declare class ContreeClient {
|
|
|
215
215
|
inspectImageList(imageUuid: string, path: string): Promise<DirectoryList>;
|
|
216
216
|
inspectImageGrep(
|
|
217
217
|
imageUuid: string,
|
|
218
|
-
pattern: string,
|
|
218
|
+
pattern: string | readonly string[],
|
|
219
219
|
options?: {
|
|
220
|
-
path?: string | null;
|
|
221
|
-
glob?: string | null;
|
|
220
|
+
path?: string | readonly string[] | null;
|
|
221
|
+
glob?: string | readonly string[] | null;
|
|
222
222
|
max_count?: number | null;
|
|
223
223
|
max_total?: number | null;
|
|
224
224
|
case?: "sensitive" | "insensitive" | "smart" | null;
|
|
225
|
+
before?: number | null;
|
|
226
|
+
after?: number | null;
|
|
225
227
|
},
|
|
226
228
|
): Promise<GrepResult>;
|
|
227
229
|
whoami(): Promise<WhoAmIResponse>;
|
package/lib/client.js
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
} from "./errors.js";
|
|
9
9
|
import { AUTH_TYPE_IAM, ProfileError, resolveProfile } from "./profiles.js";
|
|
10
10
|
import {
|
|
11
|
+
EVENTS_UNAVAILABLE_STATUSES,
|
|
11
12
|
IS_NODE,
|
|
12
13
|
SSEParser,
|
|
13
14
|
TIGHT_LOOP_FLOOR,
|
|
@@ -25,7 +26,11 @@ import {
|
|
|
25
26
|
sleep,
|
|
26
27
|
} from "./runtime.js";
|
|
27
28
|
import { DEFAULT_BASE_URL } from "./specInfo.js";
|
|
28
|
-
import {
|
|
29
|
+
import {
|
|
30
|
+
EventDataCompletion,
|
|
31
|
+
OperationEvent,
|
|
32
|
+
isTerminalStatus,
|
|
33
|
+
} from "./models.js";
|
|
29
34
|
import * as operations from "./operations.js";
|
|
30
35
|
|
|
31
36
|
/** Contree API client on top of the platform fetch.
|
|
@@ -409,8 +414,13 @@ export class ContreeClient {
|
|
|
409
414
|
|
|
410
415
|
/** Stream operation events with transparent reconnection: network
|
|
411
416
|
* drops, in-band SSE error frames and retryable API statuses
|
|
412
|
-
* (410/425/5xx) reconnect from the last received event id
|
|
413
|
-
*
|
|
417
|
+
* (410/425/5xx) reconnect from the last received event id. A status
|
|
418
|
+
* meaning the events endpoint itself doesn't exist for this
|
|
419
|
+
* operation/server (400/404/405/406) stops reconnecting and instead
|
|
420
|
+
* polls getOperationStatus() until the operation is terminal, then
|
|
421
|
+
* yields a synthesized `completion` event built from that status
|
|
422
|
+
* (there is no real event log to relay). Other API errors
|
|
423
|
+
* propagate. Ends after the `completion` event. */
|
|
414
424
|
async *followOperationEvents(
|
|
415
425
|
operationId,
|
|
416
426
|
{ last_event_id = null, spid = null, since = null, timeout = null } = {},
|
|
@@ -450,6 +460,64 @@ export class ContreeClient {
|
|
|
450
460
|
lastId = error.lastEventId;
|
|
451
461
|
}
|
|
452
462
|
} else if (error instanceof ContreeAPIError) {
|
|
463
|
+
if (EVENTS_UNAVAILABLE_STATUSES.has(error.status)) {
|
|
464
|
+
// the endpoint is gone, not just failing: reconnecting the
|
|
465
|
+
// same request will never work, but the operation may
|
|
466
|
+
// still finish - stop touching /events and poll status
|
|
467
|
+
// instead for the rest of this wait
|
|
468
|
+
for (;;) {
|
|
469
|
+
checkDeadline();
|
|
470
|
+
let response;
|
|
471
|
+
try {
|
|
472
|
+
response = await this.getOperationStatus(operationId);
|
|
473
|
+
} catch (pollError) {
|
|
474
|
+
if (
|
|
475
|
+
!(pollError instanceof ContreeError) &&
|
|
476
|
+
!this._transportRetryable(pollError)
|
|
477
|
+
) {
|
|
478
|
+
throw pollError;
|
|
479
|
+
}
|
|
480
|
+
response = null;
|
|
481
|
+
}
|
|
482
|
+
if (
|
|
483
|
+
response !== null &&
|
|
484
|
+
response.status !== undefined &&
|
|
485
|
+
isTerminalStatus(response.status)
|
|
486
|
+
) {
|
|
487
|
+
// no event log to relay, but a caller of
|
|
488
|
+
// followOperationEvents must still observe a terminal
|
|
489
|
+
// completion rather than nothing at all
|
|
490
|
+
lastId = lastId === null ? 0 : lastId + 1;
|
|
491
|
+
yield new OperationEvent({
|
|
492
|
+
id: lastId,
|
|
493
|
+
ts: new Date(),
|
|
494
|
+
type: "completion",
|
|
495
|
+
data: new EventDataCompletion({
|
|
496
|
+
status: response.status,
|
|
497
|
+
duration_ms:
|
|
498
|
+
typeof response.duration === "number"
|
|
499
|
+
? Math.round(response.duration * 1000)
|
|
500
|
+
: 0,
|
|
501
|
+
result_image_uuid: response.result_image_uuid,
|
|
502
|
+
error: response.error,
|
|
503
|
+
image_size_bytes:
|
|
504
|
+
typeof response.image_size === "number"
|
|
505
|
+
? response.image_size
|
|
506
|
+
: undefined,
|
|
507
|
+
}),
|
|
508
|
+
});
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
let pollDelay = delays.next().value;
|
|
512
|
+
if (deadline !== null) {
|
|
513
|
+
pollDelay = Math.min(
|
|
514
|
+
pollDelay,
|
|
515
|
+
Math.max(0, deadline - monotonic()),
|
|
516
|
+
);
|
|
517
|
+
}
|
|
518
|
+
await sleep(pollDelay);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
453
521
|
const retryable =
|
|
454
522
|
error.status === 410 ||
|
|
455
523
|
error.status === 425 ||
|
package/lib/models.d.ts
CHANGED
|
@@ -94,6 +94,7 @@ export declare class GrepMatch {
|
|
|
94
94
|
line_text: string;
|
|
95
95
|
line_bytes: number;
|
|
96
96
|
submatches: GrepSubmatch[];
|
|
97
|
+
type: "match" | "context";
|
|
97
98
|
constructor(fields?: {
|
|
98
99
|
path?: string;
|
|
99
100
|
line_number?: number;
|
|
@@ -101,6 +102,7 @@ export declare class GrepMatch {
|
|
|
101
102
|
line_text?: string;
|
|
102
103
|
line_bytes?: number;
|
|
103
104
|
submatches?: GrepSubmatch[];
|
|
105
|
+
type?: "match" | "context";
|
|
104
106
|
});
|
|
105
107
|
static fromWire(data: Record<string, unknown>): GrepMatch;
|
|
106
108
|
toWire(): Record<string, unknown>;
|
package/lib/models.js
CHANGED
|
@@ -195,6 +195,7 @@ export class GrepMatch {
|
|
|
195
195
|
this.line_text = fields.line_text;
|
|
196
196
|
this.line_bytes = fields.line_bytes;
|
|
197
197
|
this.submatches = fields.submatches;
|
|
198
|
+
this.type = fields.type;
|
|
198
199
|
}
|
|
199
200
|
|
|
200
201
|
static fromWire(data) {
|
|
@@ -205,6 +206,7 @@ export class GrepMatch {
|
|
|
205
206
|
line_text: data["line_text"],
|
|
206
207
|
line_bytes: data["line_bytes"],
|
|
207
208
|
submatches: data["submatches"].map((item) => GrepSubmatch.fromWire(item)),
|
|
209
|
+
type: data["type"],
|
|
208
210
|
});
|
|
209
211
|
}
|
|
210
212
|
|
|
@@ -231,6 +233,9 @@ export class GrepMatch {
|
|
|
231
233
|
? null
|
|
232
234
|
: this.submatches.map((item) => item.toWire());
|
|
233
235
|
}
|
|
236
|
+
if (this.type !== undefined) {
|
|
237
|
+
data["type"] = this.type;
|
|
238
|
+
}
|
|
234
239
|
return data;
|
|
235
240
|
}
|
|
236
241
|
}
|
package/lib/operations.d.ts
CHANGED
|
@@ -246,13 +246,15 @@ export declare function parseInspectImageList(
|
|
|
246
246
|
|
|
247
247
|
export declare function buildInspectImageGrep(
|
|
248
248
|
imageUuid: string,
|
|
249
|
-
pattern: string,
|
|
249
|
+
pattern: string | readonly string[],
|
|
250
250
|
options?: {
|
|
251
|
-
path?: string | null;
|
|
252
|
-
glob?: string | null;
|
|
251
|
+
path?: string | readonly string[] | null;
|
|
252
|
+
glob?: string | readonly string[] | null;
|
|
253
253
|
max_count?: number | null;
|
|
254
254
|
max_total?: number | null;
|
|
255
255
|
case?: "sensitive" | "insensitive" | "smart" | null;
|
|
256
|
+
before?: number | null;
|
|
257
|
+
after?: number | null;
|
|
256
258
|
},
|
|
257
259
|
): RequestSpec;
|
|
258
260
|
|
package/lib/operations.js
CHANGED
|
@@ -650,6 +650,8 @@ export function buildInspectImageGrep(
|
|
|
650
650
|
max_count = null,
|
|
651
651
|
max_total = null,
|
|
652
652
|
case: case_ = null,
|
|
653
|
+
before = null,
|
|
654
|
+
after = null,
|
|
653
655
|
} = {},
|
|
654
656
|
) {
|
|
655
657
|
const query = {};
|
|
@@ -669,6 +671,12 @@ export function buildInspectImageGrep(
|
|
|
669
671
|
if (case_ != null) {
|
|
670
672
|
query["case"] = case_;
|
|
671
673
|
}
|
|
674
|
+
if (before != null) {
|
|
675
|
+
query["before"] = String(before);
|
|
676
|
+
}
|
|
677
|
+
if (after != null) {
|
|
678
|
+
query["after"] = String(after);
|
|
679
|
+
}
|
|
672
680
|
return {
|
|
673
681
|
method: "GET",
|
|
674
682
|
path: `/inspect/${quotePath(imageUuid)}/grep`,
|
package/lib/runtime.d.ts
CHANGED
|
@@ -21,7 +21,7 @@ export type RequestBody =
|
|
|
21
21
|
export interface RequestSpec {
|
|
22
22
|
method: string;
|
|
23
23
|
path: string;
|
|
24
|
-
query?: Record<string, string>;
|
|
24
|
+
query?: Record<string, string | readonly string[]>;
|
|
25
25
|
headers?: Record<string, string>;
|
|
26
26
|
body?: RequestBody;
|
|
27
27
|
contentType?: string | null;
|
|
@@ -58,7 +58,9 @@ export declare function sleep(seconds: number): Promise<void>;
|
|
|
58
58
|
export declare function monotonic(): number;
|
|
59
59
|
export declare function isUuid(ref: string): boolean;
|
|
60
60
|
export declare function quotePath(value: unknown): string;
|
|
61
|
-
export declare function encodeQuery(
|
|
61
|
+
export declare function encodeQuery(
|
|
62
|
+
query: Record<string, string | readonly string[]>,
|
|
63
|
+
): string;
|
|
62
64
|
export declare function formatTimeParam(value: string | number | Date): string;
|
|
63
65
|
export declare function parseDatetime(value: string): Date;
|
|
64
66
|
export declare function bytesToText(bytes: Uint8Array): string;
|
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.2.
|
|
17
|
+
export const PACKAGE_VERSION = "0.2.1";
|
|
18
18
|
export const UA_PRODUCT = `contree-client-js/${PACKAGE_VERSION}`;
|
|
19
19
|
|
|
20
20
|
const NODE_VERSION =
|
|
@@ -38,6 +38,17 @@ export const RETRY_DELAYS = Object.freeze([0.1, 0.2, 0.5, 1.0, 2.0, 5.0]);
|
|
|
38
38
|
// returning immediate empty streams does not spin the client
|
|
39
39
|
export const TIGHT_LOOP_FLOOR = 0.5;
|
|
40
40
|
|
|
41
|
+
// the events route itself doesn't exist for this operation/server
|
|
42
|
+
// (malformed request an older backend rejects, or a reverse proxy
|
|
43
|
+
// that never forwards it) rather than merely being down: reconnecting
|
|
44
|
+
// will never succeed, but the operation itself may still complete -
|
|
45
|
+
// degrade to polling instead of failing the whole wait. 401/403 are
|
|
46
|
+
// deliberately excluded: an auth/permission failure here likely means
|
|
47
|
+
// the whole client is broken, not just this route, so it still throws
|
|
48
|
+
export const EVENTS_UNAVAILABLE_STATUSES = Object.freeze(
|
|
49
|
+
new Set([400, 404, 405, 406]),
|
|
50
|
+
);
|
|
51
|
+
|
|
41
52
|
/** An endless ladder of backoff delays: the ladder is walked once and
|
|
42
53
|
* then the tail delay repeats forever. */
|
|
43
54
|
export function* retryDelays(delays = RETRY_DELAYS) {
|
|
@@ -140,9 +151,11 @@ export function quotePath(value) {
|
|
|
140
151
|
|
|
141
152
|
export function encodeQuery(query) {
|
|
142
153
|
return Object.entries(query)
|
|
143
|
-
.
|
|
144
|
-
(
|
|
145
|
-
|
|
154
|
+
.flatMap(([key, value]) =>
|
|
155
|
+
(Array.isArray(value) ? value : [value]).map(
|
|
156
|
+
(item) =>
|
|
157
|
+
`${encodeURIComponent(key)}=${encodeURIComponent(item).replaceAll("%2F", "/")}`,
|
|
158
|
+
),
|
|
146
159
|
)
|
|
147
160
|
.join("&");
|
|
148
161
|
}
|
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
|
-
"
|
|
8
|
+
"2bfd239341e6f61ccba1aafb39cef7b476d56f424156860a204f089d7d79b7bf";
|