contree-client 0.2.1-dev0 → 0.2.2
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 -5
- package/lib/client.js +81 -6
- package/lib/models.js +1 -1
- package/lib/operations.d.ts +3 -3
- package/lib/runtime.d.ts +4 -2
- package/lib/runtime.js +17 -4
- package/lib/specInfo.js +1 -1
- package/lib/testing.d.ts +2 -2
- package/package.json +1 -1
package/lib/client.d.ts
CHANGED
|
@@ -34,13 +34,13 @@ export interface ContreeClientOptions {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
export declare class ContreeClient {
|
|
37
|
-
token: string;
|
|
37
|
+
token: string | null;
|
|
38
38
|
baseUrl: string;
|
|
39
39
|
project: string | null;
|
|
40
40
|
timeout: number | null;
|
|
41
41
|
retry: RetryPolicy | null;
|
|
42
42
|
identity: string | null;
|
|
43
|
-
constructor(token: string, options?: ContreeClientOptions);
|
|
43
|
+
constructor(token: string | null, options?: ContreeClientOptions);
|
|
44
44
|
static fromProfile(
|
|
45
45
|
profile?: string | Profile | null,
|
|
46
46
|
options?: ContreeClientOptions & { configPath?: string | null },
|
|
@@ -215,10 +215,10 @@ 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;
|
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.
|
|
@@ -34,6 +39,10 @@ import * as operations from "./operations.js";
|
|
|
34
39
|
* unlike the Python adapters there is exactly one transport. Pass a
|
|
35
40
|
* custom `fetch` implementation (undici dispatcher wrappers, MSW,
|
|
36
41
|
* ...) via the constructor options to customize it.
|
|
42
|
+
*
|
|
43
|
+
* `token` may be null, like `project`: the client then sends no
|
|
44
|
+
* `Authorization` header, which is all the endpoints that need no
|
|
45
|
+
* authentication want.
|
|
37
46
|
*/
|
|
38
47
|
export class ContreeClient {
|
|
39
48
|
constructor(
|
|
@@ -54,7 +63,7 @@ export class ContreeClient {
|
|
|
54
63
|
`unsupported baseUrl scheme ${parsed.protocol} in ${baseUrl}: use http:// or https://`,
|
|
55
64
|
);
|
|
56
65
|
}
|
|
57
|
-
this.token = token;
|
|
66
|
+
this.token = token ?? null;
|
|
58
67
|
this.baseUrl = baseUrl.replace(/\/+$/, "");
|
|
59
68
|
this.project = project;
|
|
60
69
|
this.timeout = timeout;
|
|
@@ -107,8 +116,11 @@ export class ContreeClient {
|
|
|
107
116
|
}
|
|
108
117
|
|
|
109
118
|
buildHeaders(spec) {
|
|
110
|
-
const headers = {
|
|
111
|
-
if (this.
|
|
119
|
+
const headers = {};
|
|
120
|
+
if (this.token) {
|
|
121
|
+
headers["Authorization"] = `Bearer ${this.token}`;
|
|
122
|
+
}
|
|
123
|
+
if (this.project) {
|
|
112
124
|
headers["Project"] = this.project;
|
|
113
125
|
}
|
|
114
126
|
if (spec.contentType) {
|
|
@@ -409,8 +421,13 @@ export class ContreeClient {
|
|
|
409
421
|
|
|
410
422
|
/** Stream operation events with transparent reconnection: network
|
|
411
423
|
* drops, in-band SSE error frames and retryable API statuses
|
|
412
|
-
* (410/425/5xx) reconnect from the last received event id
|
|
413
|
-
*
|
|
424
|
+
* (410/425/5xx) reconnect from the last received event id. A status
|
|
425
|
+
* meaning the events endpoint itself doesn't exist for this
|
|
426
|
+
* operation/server (400/404/405/406) stops reconnecting and instead
|
|
427
|
+
* polls getOperationStatus() until the operation is terminal, then
|
|
428
|
+
* yields a synthesized `completion` event built from that status
|
|
429
|
+
* (there is no real event log to relay). Other API errors
|
|
430
|
+
* propagate. Ends after the `completion` event. */
|
|
414
431
|
async *followOperationEvents(
|
|
415
432
|
operationId,
|
|
416
433
|
{ last_event_id = null, spid = null, since = null, timeout = null } = {},
|
|
@@ -450,6 +467,64 @@ export class ContreeClient {
|
|
|
450
467
|
lastId = error.lastEventId;
|
|
451
468
|
}
|
|
452
469
|
} else if (error instanceof ContreeAPIError) {
|
|
470
|
+
if (EVENTS_UNAVAILABLE_STATUSES.has(error.status)) {
|
|
471
|
+
// the endpoint is gone, not just failing: reconnecting the
|
|
472
|
+
// same request will never work, but the operation may
|
|
473
|
+
// still finish - stop touching /events and poll status
|
|
474
|
+
// instead for the rest of this wait
|
|
475
|
+
for (;;) {
|
|
476
|
+
checkDeadline();
|
|
477
|
+
let response;
|
|
478
|
+
try {
|
|
479
|
+
response = await this.getOperationStatus(operationId);
|
|
480
|
+
} catch (pollError) {
|
|
481
|
+
if (
|
|
482
|
+
!(pollError instanceof ContreeError) &&
|
|
483
|
+
!this._transportRetryable(pollError)
|
|
484
|
+
) {
|
|
485
|
+
throw pollError;
|
|
486
|
+
}
|
|
487
|
+
response = null;
|
|
488
|
+
}
|
|
489
|
+
if (
|
|
490
|
+
response !== null &&
|
|
491
|
+
response.status !== undefined &&
|
|
492
|
+
isTerminalStatus(response.status)
|
|
493
|
+
) {
|
|
494
|
+
// no event log to relay, but a caller of
|
|
495
|
+
// followOperationEvents must still observe a terminal
|
|
496
|
+
// completion rather than nothing at all
|
|
497
|
+
lastId = lastId === null ? 0 : lastId + 1;
|
|
498
|
+
yield new OperationEvent({
|
|
499
|
+
id: lastId,
|
|
500
|
+
ts: new Date(),
|
|
501
|
+
type: "completion",
|
|
502
|
+
data: new EventDataCompletion({
|
|
503
|
+
status: response.status,
|
|
504
|
+
duration_ms:
|
|
505
|
+
typeof response.duration === "number"
|
|
506
|
+
? Math.round(response.duration * 1000)
|
|
507
|
+
: 0,
|
|
508
|
+
result_image_uuid: response.result_image_uuid,
|
|
509
|
+
error: response.error,
|
|
510
|
+
image_size_bytes:
|
|
511
|
+
typeof response.image_size === "number"
|
|
512
|
+
? response.image_size
|
|
513
|
+
: undefined,
|
|
514
|
+
}),
|
|
515
|
+
});
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
let pollDelay = delays.next().value;
|
|
519
|
+
if (deadline !== null) {
|
|
520
|
+
pollDelay = Math.min(
|
|
521
|
+
pollDelay,
|
|
522
|
+
Math.max(0, deadline - monotonic()),
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
await sleep(pollDelay);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
453
528
|
const retryable =
|
|
454
529
|
error.status === 410 ||
|
|
455
530
|
error.status === 425 ||
|
package/lib/models.js
CHANGED
|
@@ -585,7 +585,7 @@ export class StreamRepr {
|
|
|
585
585
|
}
|
|
586
586
|
}
|
|
587
587
|
|
|
588
|
-
/** Stdin payload.
|
|
588
|
+
/** Stdin payload. Delivery to the child is always complete — */
|
|
589
589
|
export class ClosableStreamRepr {
|
|
590
590
|
constructor(fields = {}) {
|
|
591
591
|
this.value = fields.value;
|
package/lib/operations.d.ts
CHANGED
|
@@ -246,10 +246,10 @@ 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;
|
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.2";
|
|
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
|
+
"23d748a2918b1124b3072d54d17d8eb43aa00d0b969bc1fa718f34ac884ee887";
|
package/lib/testing.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ export declare class ContreeClient extends GeneratedClient {
|
|
|
17
17
|
mocks: Map<string, Outcome[]>;
|
|
18
18
|
calls: Call[];
|
|
19
19
|
constructedWith: {
|
|
20
|
-
token: string;
|
|
20
|
+
token: string | null;
|
|
21
21
|
baseUrl: string;
|
|
22
22
|
project: string | null;
|
|
23
23
|
timeout: number | null;
|
|
@@ -25,7 +25,7 @@ export declare class ContreeClient extends GeneratedClient {
|
|
|
25
25
|
identity: string | null;
|
|
26
26
|
};
|
|
27
27
|
constructor(
|
|
28
|
-
token?: string,
|
|
28
|
+
token?: string | null,
|
|
29
29
|
options?: ConstructorParameters<typeof GeneratedClient>[1],
|
|
30
30
|
);
|
|
31
31
|
mock(
|