@synnaxlabs/client 0.44.2 → 0.44.4
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/.turbo/turbo-build.log +6 -6
- package/dist/channel/client.d.ts +1 -0
- package/dist/channel/client.d.ts.map +1 -1
- package/dist/channel/payload.d.ts +15 -15
- package/dist/channel/payload.d.ts.map +1 -1
- package/dist/channel/retriever.d.ts +1 -1
- package/dist/channel/writer.d.ts +2 -2
- package/dist/channel/writer.d.ts.map +1 -1
- package/dist/client.cjs +24 -24
- package/dist/client.d.ts +2 -2
- package/dist/client.js +3099 -2742
- package/dist/control/state.d.ts +4 -4
- package/dist/framer/deleter.d.ts +1 -1
- package/dist/framer/streamer.d.ts +16 -16
- package/dist/framer/streamer.d.ts.map +1 -1
- package/dist/framer/writer.d.ts +24 -24
- package/dist/framer/writer.d.ts.map +1 -1
- package/dist/hardware/task/client.d.ts +7 -0
- package/dist/hardware/task/client.d.ts.map +1 -1
- package/dist/ontology/group/client.d.ts +2 -0
- package/dist/ontology/group/client.d.ts.map +1 -1
- package/dist/ranger/alias.d.ts +1 -1
- package/dist/ranger/alias.d.ts.map +1 -1
- package/dist/testutil/client.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/channel/client.ts +5 -3
- package/src/channel/payload.ts +10 -2
- package/src/channel/writer.ts +2 -1
- package/src/framer/streamer.spec.ts +1 -1
- package/src/framer/streamer.ts +4 -3
- package/src/framer/writer.ts +26 -16
- package/src/hardware/task/client.ts +93 -20
- package/src/ontology/group/client.ts +3 -0
- package/src/ranger/alias.ts +1 -4
- package/src/testutil/client.ts +7 -0
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// included in the file licenses/APL.txt.
|
|
9
9
|
|
|
10
10
|
import { sendRequired, type UnaryClient } from "@synnaxlabs/freighter";
|
|
11
|
-
import { caseconv, id } from "@synnaxlabs/x";
|
|
11
|
+
import { caseconv, id, strings } from "@synnaxlabs/x";
|
|
12
12
|
import { array } from "@synnaxlabs/x/array";
|
|
13
13
|
import { type CrudeTimeSpan, TimeSpan } from "@synnaxlabs/x/telem";
|
|
14
14
|
import { z } from "zod";
|
|
@@ -409,7 +409,17 @@ export class Client {
|
|
|
409
409
|
return isSingle ? res[0] : res;
|
|
410
410
|
}
|
|
411
411
|
|
|
412
|
-
async executeCommand(task: Key, type: string, args?: {}): Promise<string
|
|
412
|
+
async executeCommand(task: Key, type: string, args?: {}): Promise<string>;
|
|
413
|
+
|
|
414
|
+
async executeCommand(commands: NewCommand[]): Promise<string[]>;
|
|
415
|
+
|
|
416
|
+
async executeCommand(
|
|
417
|
+
task: Key | NewCommand[],
|
|
418
|
+
type?: string,
|
|
419
|
+
args?: {},
|
|
420
|
+
): Promise<string | string[]> {
|
|
421
|
+
if (Array.isArray(task)) return await executeCommands(this.frameClient, task);
|
|
422
|
+
if (type == null) throw new Error("Type is required");
|
|
413
423
|
return await executeCommand(this.frameClient, task, type, args);
|
|
414
424
|
}
|
|
415
425
|
|
|
@@ -419,8 +429,35 @@ export class Client {
|
|
|
419
429
|
timeout: CrudeTimeSpan,
|
|
420
430
|
args?: {},
|
|
421
431
|
name?: string,
|
|
432
|
+
statusDataZ?: StatusData,
|
|
433
|
+
): Promise<Status<StatusData>>;
|
|
434
|
+
async executeCommandSync<StatusData extends z.ZodType = z.ZodType>(
|
|
435
|
+
commands: NewCommand[],
|
|
436
|
+
timeout: CrudeTimeSpan,
|
|
437
|
+
statusDataZ?: StatusData,
|
|
438
|
+
): Promise<Status<StatusData>[]>;
|
|
439
|
+
|
|
440
|
+
async executeCommandSync<StatusData extends z.ZodType = z.ZodType>(
|
|
441
|
+
task: Key | NewCommand[],
|
|
442
|
+
type: string | CrudeTimeSpan,
|
|
443
|
+
timeout?: CrudeTimeSpan | StatusData,
|
|
444
|
+
args?: {},
|
|
445
|
+
name?: string,
|
|
422
446
|
statusDataZ: StatusData = z.unknown() as unknown as StatusData,
|
|
423
|
-
): Promise<Status<StatusData
|
|
447
|
+
): Promise<Status<StatusData> | Status<StatusData>[]> {
|
|
448
|
+
if (Array.isArray(task)) {
|
|
449
|
+
const retrieveNames = async () => {
|
|
450
|
+
const ts = await this.retrieve({ keys: task.map((t) => t.task) });
|
|
451
|
+
return ts.map((t) => t.name);
|
|
452
|
+
};
|
|
453
|
+
return await executeCommandsSync(
|
|
454
|
+
this.frameClient,
|
|
455
|
+
task,
|
|
456
|
+
type as CrudeTimeSpan,
|
|
457
|
+
statusDataZ,
|
|
458
|
+
retrieveNames,
|
|
459
|
+
);
|
|
460
|
+
}
|
|
424
461
|
const retrieveName = async () => {
|
|
425
462
|
const t = await this.retrieve({ key: task });
|
|
426
463
|
return t.name;
|
|
@@ -428,8 +465,8 @@ export class Client {
|
|
|
428
465
|
return await executeCommandSync(
|
|
429
466
|
this.frameClient,
|
|
430
467
|
task,
|
|
431
|
-
type,
|
|
432
|
-
timeout,
|
|
468
|
+
type as string,
|
|
469
|
+
timeout as CrudeTimeSpan,
|
|
433
470
|
name ?? retrieveName,
|
|
434
471
|
statusDataZ,
|
|
435
472
|
args,
|
|
@@ -444,13 +481,24 @@ const executeCommand = async (
|
|
|
444
481
|
task: Key,
|
|
445
482
|
type: string,
|
|
446
483
|
args?: {},
|
|
447
|
-
): Promise<string> => {
|
|
484
|
+
): Promise<string> => (await executeCommands(frameClient, [{ args, task, type }]))[0];
|
|
485
|
+
|
|
486
|
+
export interface NewCommand {
|
|
487
|
+
task: Key;
|
|
488
|
+
type: string;
|
|
489
|
+
args?: {};
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
const executeCommands = async (
|
|
493
|
+
frameClient: framer.Client | null,
|
|
494
|
+
commands: NewCommand[],
|
|
495
|
+
): Promise<string[]> => {
|
|
448
496
|
if (frameClient == null) throw NOT_CREATED_ERROR;
|
|
449
|
-
const key = id.create();
|
|
450
497
|
const w = await frameClient.openWriter(COMMAND_CHANNEL_NAME);
|
|
451
|
-
|
|
498
|
+
const cmds = commands.map((c) => ({ ...c, key: id.create() }));
|
|
499
|
+
await w.write(COMMAND_CHANNEL_NAME, cmds);
|
|
452
500
|
await w.close();
|
|
453
|
-
return key;
|
|
501
|
+
return cmds.map((c) => c.key);
|
|
454
502
|
};
|
|
455
503
|
|
|
456
504
|
const executeCommandSync = async <StatusData extends z.ZodType = z.ZodType>(
|
|
@@ -461,24 +509,45 @@ const executeCommandSync = async <StatusData extends z.ZodType = z.ZodType>(
|
|
|
461
509
|
tskName: string | (() => Promise<string>),
|
|
462
510
|
statusDataZ: StatusData,
|
|
463
511
|
args?: {},
|
|
464
|
-
): Promise<Status<StatusData>> =>
|
|
512
|
+
): Promise<Status<StatusData>> =>
|
|
513
|
+
(
|
|
514
|
+
await executeCommandsSync(
|
|
515
|
+
frameClient,
|
|
516
|
+
[{ args, task, type }],
|
|
517
|
+
timeout,
|
|
518
|
+
statusDataZ,
|
|
519
|
+
tskName,
|
|
520
|
+
)
|
|
521
|
+
)[0];
|
|
522
|
+
|
|
523
|
+
const executeCommandsSync = async <StatusData extends z.ZodType = z.ZodType>(
|
|
524
|
+
frameClient: framer.Client | null,
|
|
525
|
+
commands: NewCommand[],
|
|
526
|
+
timeout: CrudeTimeSpan,
|
|
527
|
+
statusDataZ: StatusData,
|
|
528
|
+
tskName: string | string[] | (() => Promise<string | string[]>),
|
|
529
|
+
): Promise<Status<StatusData>[]> => {
|
|
465
530
|
if (frameClient == null) throw NOT_CREATED_ERROR;
|
|
466
531
|
const streamer = await frameClient.openStreamer(STATUS_CHANNEL_NAME);
|
|
467
|
-
const
|
|
532
|
+
const cmdKeys = await executeCommands(frameClient, commands);
|
|
468
533
|
const parsedTimeout = new TimeSpan(timeout);
|
|
469
|
-
|
|
534
|
+
let states: Status<StatusData>[] = [];
|
|
470
535
|
let timeoutID: NodeJS.Timeout | undefined;
|
|
471
536
|
const timeoutPromise = new Promise<never>((_, reject) => {
|
|
472
537
|
timeoutID = setTimeout(() => {
|
|
473
|
-
void (async () =>
|
|
474
|
-
|
|
538
|
+
void (async () => {
|
|
539
|
+
const taskKeys = commands.map((c) => c.task);
|
|
540
|
+
reject(await formatTimeoutError("command", tskName, parsedTimeout, taskKeys));
|
|
541
|
+
})();
|
|
475
542
|
}, parsedTimeout.milliseconds);
|
|
476
543
|
});
|
|
477
544
|
try {
|
|
478
545
|
while (true) {
|
|
479
546
|
const frame = await Promise.race([streamer.read(), timeoutPromise]);
|
|
480
547
|
const state = statusZ(statusDataZ).parse(frame.at(-1)[STATUS_CHANNEL_NAME]);
|
|
481
|
-
if (state.key
|
|
548
|
+
if (!cmdKeys.includes(state.key)) continue;
|
|
549
|
+
states = [...states.filter((s) => s.key !== state.key), state];
|
|
550
|
+
if (states.length === cmdKeys.length) return states;
|
|
482
551
|
}
|
|
483
552
|
} finally {
|
|
484
553
|
clearTimeout(timeoutID);
|
|
@@ -488,21 +557,25 @@ const executeCommandSync = async <StatusData extends z.ZodType = z.ZodType>(
|
|
|
488
557
|
|
|
489
558
|
const formatTimeoutError = async (
|
|
490
559
|
type: string,
|
|
491
|
-
name: string | (() => Promise<string>),
|
|
560
|
+
name: string | string[] | (() => Promise<string | string[]>),
|
|
492
561
|
timeout: TimeSpan,
|
|
493
|
-
key: Key,
|
|
562
|
+
key: Key | Key[],
|
|
494
563
|
): Promise<Error> => {
|
|
495
564
|
const formattedType = caseconv.capitalize(type);
|
|
496
565
|
const formattedTimeout = timeout.toString();
|
|
497
566
|
try {
|
|
498
|
-
|
|
567
|
+
let names: string[];
|
|
568
|
+
if (typeof name === "string") names = [name];
|
|
569
|
+
else if (Array.isArray(name)) names = name;
|
|
570
|
+
else names = array.toArray(await name());
|
|
571
|
+
const formattedName = strings.naturalLanguageJoin(names);
|
|
499
572
|
return new Error(
|
|
500
|
-
`${formattedType} command to ${
|
|
573
|
+
`${formattedType} command to ${formattedName} timed out after ${formattedTimeout}`,
|
|
501
574
|
);
|
|
502
575
|
} catch (e) {
|
|
503
576
|
console.error("Failed to retrieve task name for timeout error:", e);
|
|
504
577
|
return new Error(
|
|
505
|
-
`${formattedType} command to task with key ${key} timed out after ${formattedTimeout}`,
|
|
578
|
+
`${formattedType} command to task with key ${strings.naturalLanguageJoin(key)} timed out after ${formattedTimeout}`,
|
|
506
579
|
);
|
|
507
580
|
}
|
|
508
581
|
};
|
|
@@ -14,6 +14,9 @@ import { Group } from "@/ontology/group/group";
|
|
|
14
14
|
import { type Key, type Name, type Payload } from "@/ontology/group/payload";
|
|
15
15
|
import { Writer } from "@/ontology/group/writer";
|
|
16
16
|
|
|
17
|
+
export const SET_CHANNEL_NAME = "sy_group_set";
|
|
18
|
+
export const DELETE_CHANNEL_NAME = "sy_group_delete";
|
|
19
|
+
|
|
17
20
|
export class Client {
|
|
18
21
|
private readonly creator: Writer;
|
|
19
22
|
|
package/src/ranger/alias.ts
CHANGED
|
@@ -23,10 +23,7 @@ const resolveReqZ = z.object({ range: keyZ, aliases: z.string().array() });
|
|
|
23
23
|
|
|
24
24
|
const resolveResZ = z.object({ aliases: z.record(z.string(), channel.keyZ) });
|
|
25
25
|
|
|
26
|
-
const setReqZ = z.object({
|
|
27
|
-
range: keyZ,
|
|
28
|
-
aliases: z.record(channel.keyZ.or(z.string()), z.string()),
|
|
29
|
-
});
|
|
26
|
+
const setReqZ = z.object({ range: keyZ, aliases: z.record(channel.keyZ, z.string()) });
|
|
30
27
|
|
|
31
28
|
const setResZ = z.unknown();
|
|
32
29
|
|
package/src/testutil/client.ts
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
8
|
// included in the file licenses/APL.txt.
|
|
9
9
|
|
|
10
|
+
import { TimeSpan } from "@synnaxlabs/x";
|
|
11
|
+
|
|
10
12
|
import Synnax, { type SynnaxProps } from "@/client";
|
|
11
13
|
|
|
12
14
|
export const TEST_CLIENT_PROPS: SynnaxProps = {
|
|
@@ -14,6 +16,11 @@ export const TEST_CLIENT_PROPS: SynnaxProps = {
|
|
|
14
16
|
port: 9090,
|
|
15
17
|
username: "synnax",
|
|
16
18
|
password: "seldon",
|
|
19
|
+
retry: {
|
|
20
|
+
maxRetries: 4,
|
|
21
|
+
baseInterval: TimeSpan.seconds(1),
|
|
22
|
+
scale: 1.5,
|
|
23
|
+
},
|
|
17
24
|
};
|
|
18
25
|
|
|
19
26
|
export const createTestClient = (props?: Partial<SynnaxProps>): Synnax =>
|