@synnaxlabs/client 0.55.0 → 0.56.0
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 +10 -13
- package/dist/client.cjs +60 -36
- package/dist/client.js +6362 -4738
- package/dist/src/access/policy/client.d.ts +70 -80
- package/dist/src/access/policy/client.d.ts.map +1 -1
- package/dist/src/access/policy/types.gen.d.ts +18 -20
- package/dist/src/access/policy/types.gen.d.ts.map +1 -1
- package/dist/src/access/role/client.d.ts.map +1 -1
- package/dist/src/access/role/types.gen.d.ts +2 -2
- package/dist/src/actions/actions.d.ts +68 -0
- package/dist/src/actions/actions.d.ts.map +1 -0
- package/dist/src/actions/actions.spec.d.ts +2 -0
- package/dist/src/actions/actions.spec.d.ts.map +1 -0
- package/dist/src/actions/external.d.ts +2 -0
- package/dist/src/actions/external.d.ts.map +1 -0
- package/dist/src/actions/index.d.ts +2 -0
- package/dist/src/actions/index.d.ts.map +1 -0
- package/dist/src/arc/client.d.ts.map +1 -1
- package/dist/src/arc/compiler/types.gen.d.ts +1 -1
- package/dist/src/arc/compiler/types.gen.d.ts.map +1 -1
- package/dist/src/arc/graph/types.gen.d.ts +29 -29
- package/dist/src/arc/graph/types.gen.d.ts.map +1 -1
- package/dist/src/arc/ir/types.gen.d.ts +123 -123
- package/dist/src/arc/ir/types.gen.d.ts.map +1 -1
- package/dist/src/arc/module/types.gen.d.ts +45 -45
- package/dist/src/arc/program/types.gen.d.ts +45 -45
- package/dist/src/arc/types/types.gen.d.ts +11 -11
- package/dist/src/arc/types/types.gen.d.ts.map +1 -1
- package/dist/src/arc/types.gen.d.ts +99 -99
- package/dist/src/auth/auth.d.ts +3 -3
- package/dist/src/auth/auth.d.ts.map +1 -1
- package/dist/src/channel/client.d.ts +2 -2
- package/dist/src/channel/client.d.ts.map +1 -1
- package/dist/src/channel/retriever.d.ts +5 -8
- package/dist/src/channel/retriever.d.ts.map +1 -1
- package/dist/src/channel/types.gen.d.ts +3 -3
- package/dist/src/channel/writer.d.ts.map +1 -1
- package/dist/src/connection/checker.d.ts +1 -1
- package/dist/src/connection/checker.d.ts.map +1 -1
- package/dist/src/device/client.d.ts.map +1 -1
- package/dist/src/device/types.gen.d.ts +6 -8
- package/dist/src/device/types.gen.d.ts.map +1 -1
- package/dist/src/errors.d.ts +2 -0
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/framer/adapter.d.ts.map +1 -1
- package/dist/src/framer/client.d.ts +2 -2
- package/dist/src/framer/codec.d.ts +9 -1
- package/dist/src/framer/codec.d.ts.map +1 -1
- package/dist/src/framer/deleter.d.ts.map +1 -1
- package/dist/src/framer/frame.d.ts +1 -1
- package/dist/src/framer/iterator.d.ts +84 -3
- package/dist/src/framer/iterator.d.ts.map +1 -1
- package/dist/src/framer/streamProxy.d.ts.map +1 -1
- package/dist/src/framer/streamer.d.ts +1 -3
- package/dist/src/framer/streamer.d.ts.map +1 -1
- package/dist/src/framer/types.gen.d.ts +18 -0
- package/dist/src/framer/types.gen.d.ts.map +1 -1
- package/dist/src/framer/writer.d.ts +8 -8
- package/dist/src/framer/writer.d.ts.map +1 -1
- package/dist/src/group/client.d.ts +1 -2
- package/dist/src/group/client.d.ts.map +1 -1
- package/dist/src/group/types.gen.d.ts +2 -2
- package/dist/src/index.d.ts +2 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/label/client.d.ts +5 -8
- package/dist/src/label/client.d.ts.map +1 -1
- package/dist/src/lineplot/client.d.ts.map +1 -1
- package/dist/src/lineplot/types.gen.d.ts +2 -2
- package/dist/src/log/client.d.ts.map +1 -1
- package/dist/src/log/types.gen.d.ts +2 -2
- package/dist/src/ontology/client.d.ts +1 -3
- package/dist/src/ontology/client.d.ts.map +1 -1
- package/dist/src/ontology/payload.d.ts +12 -16
- package/dist/src/ontology/payload.d.ts.map +1 -1
- package/dist/src/ontology/types.gen.d.ts +1 -2
- package/dist/src/ontology/types.gen.d.ts.map +1 -1
- package/dist/src/ontology/writer.d.ts +5 -10
- package/dist/src/ontology/writer.d.ts.map +1 -1
- package/dist/src/rack/client.d.ts.map +1 -1
- package/dist/src/rack/types.gen.d.ts +3 -3
- package/dist/src/ranger/alias/client.d.ts.map +1 -1
- package/dist/src/ranger/client.d.ts.map +1 -1
- package/dist/src/ranger/kv/client.d.ts.map +1 -1
- package/dist/src/ranger/types.gen.d.ts +6 -6
- package/dist/src/ranger/types.gen.d.ts.map +1 -1
- package/dist/src/ranger/writer.d.ts +2 -3
- package/dist/src/ranger/writer.d.ts.map +1 -1
- package/dist/src/schematic/actions.d.ts +147 -0
- package/dist/src/schematic/actions.d.ts.map +1 -0
- package/dist/src/schematic/actions.gen.d.ts +484 -0
- package/dist/src/schematic/actions.gen.d.ts.map +1 -0
- package/dist/src/schematic/actions.spec.d.ts +2 -0
- package/dist/src/schematic/actions.spec.d.ts.map +1 -0
- package/dist/src/schematic/client.d.ts +53 -2
- package/dist/src/schematic/client.d.ts.map +1 -1
- package/dist/src/schematic/external.d.ts +2 -0
- package/dist/src/schematic/external.d.ts.map +1 -1
- package/dist/src/schematic/symbol/client.d.ts.map +1 -1
- package/dist/src/schematic/symbol/types.gen.d.ts +48 -58
- package/dist/src/schematic/symbol/types.gen.d.ts.map +1 -1
- package/dist/src/schematic/types.gen.d.ts +131 -5
- package/dist/src/schematic/types.gen.d.ts.map +1 -1
- package/dist/src/status/client.d.ts.map +1 -1
- package/dist/src/status/payload.d.ts +3 -3
- package/dist/src/table/actions.d.ts +156 -0
- package/dist/src/table/actions.d.ts.map +1 -0
- package/dist/src/table/actions.gen.d.ts +587 -0
- package/dist/src/table/actions.gen.d.ts.map +1 -0
- package/dist/src/table/client.d.ts +28 -2
- package/dist/src/table/client.d.ts.map +1 -1
- package/dist/src/table/external.d.ts +2 -0
- package/dist/src/table/external.d.ts.map +1 -1
- package/dist/src/table/types.gen.d.ts +71 -4
- package/dist/src/table/types.gen.d.ts.map +1 -1
- package/dist/src/task/client.d.ts.map +1 -1
- package/dist/src/task/types.gen.d.ts +7 -7
- package/dist/src/task/types.gen.d.ts.map +1 -1
- package/dist/src/user/client.d.ts +2 -2
- package/dist/src/user/client.d.ts.map +1 -1
- package/dist/src/user/types.gen.d.ts +2 -2
- package/dist/src/view/client.d.ts.map +1 -1
- package/dist/src/view/types.gen.d.ts +2 -2
- package/dist/src/workspace/client.d.ts.map +1 -1
- package/dist/src/workspace/types.gen.d.ts +3 -3
- package/dist/src/workspace/types.gen.d.ts.map +1 -1
- package/package.json +10 -9
- package/src/access/policy/client.ts +4 -7
- package/src/access/role/client.ts +6 -26
- package/src/actions/actions.spec.ts +229 -0
- package/src/actions/actions.ts +104 -0
- package/src/actions/external.ts +10 -0
- package/src/actions/index.ts +10 -0
- package/src/arc/client.ts +3 -7
- package/src/arc/compiler/types.gen.ts +2 -1
- package/src/arc/ir/types.gen.ts +2 -2
- package/src/arc/lsp.spec.ts +3 -7
- package/src/arc/types/types.gen.ts +3 -3
- package/src/auth/auth.spec.ts +12 -13
- package/src/auth/auth.ts +35 -33
- package/src/channel/batchRetriever.spec.ts +13 -4
- package/src/channel/client.ts +8 -6
- package/src/channel/retriever.ts +7 -16
- package/src/channel/writer.ts +4 -20
- package/src/connection/checker.ts +4 -5
- package/src/connection/connection.spec.ts +5 -8
- package/src/device/client.ts +5 -8
- package/src/device/types.gen.ts +4 -4
- package/src/errors.ts +8 -9
- package/src/framer/adapter.ts +2 -4
- package/src/framer/codec.spec.ts +53 -3
- package/src/framer/codec.ts +58 -25
- package/src/framer/deleter.ts +2 -8
- package/src/framer/iterator.ts +42 -39
- package/src/framer/streamProxy.ts +11 -12
- package/src/framer/streamer.spec.ts +1 -1
- package/src/framer/streamer.ts +2 -7
- package/src/framer/types.gen.ts +20 -0
- package/src/framer/writer.spec.ts +77 -0
- package/src/framer/writer.ts +53 -28
- package/src/group/client.ts +4 -7
- package/src/index.ts +3 -2
- package/src/label/client.ts +6 -16
- package/src/lineplot/client.ts +6 -21
- package/src/log/client.ts +6 -21
- package/src/ontology/client.ts +2 -3
- package/src/ontology/types.gen.ts +0 -1
- package/src/ontology/writer.ts +4 -7
- package/src/rack/client.ts +4 -7
- package/src/ranger/alias/client.ts +6 -11
- package/src/ranger/client.ts +2 -3
- package/src/ranger/kv/client.ts +4 -7
- package/src/ranger/writer.ts +4 -17
- package/src/schematic/access.spec.ts +6 -6
- package/src/schematic/actions.gen.ts +200 -0
- package/src/schematic/actions.spec.ts +699 -0
- package/src/schematic/actions.ts +168 -0
- package/src/schematic/client.ts +34 -30
- package/src/schematic/external.ts +2 -0
- package/src/schematic/schematic.spec.ts +233 -69
- package/src/schematic/symbol/client.ts +6 -11
- package/src/schematic/symbol/types.gen.ts +1 -10
- package/src/schematic/types.gen.ts +55 -6
- package/src/status/client.ts +4 -10
- package/src/table/access.spec.ts +0 -6
- package/src/table/actions.gen.ts +243 -0
- package/src/table/actions.ts +255 -0
- package/src/table/client.ts +21 -25
- package/src/table/external.ts +2 -0
- package/src/table/table.spec.ts +588 -43
- package/src/table/types.gen.ts +58 -5
- package/src/task/client.ts +7 -11
- package/src/task/types.gen.ts +8 -6
- package/src/user/client.ts +6 -11
- package/src/view/client.ts +4 -7
- package/src/workspace/client.ts +6 -16
- package/src/workspace/types.gen.ts +2 -1
|
@@ -7,7 +7,7 @@
|
|
|
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 { DataType, errors, Rate } from "@synnaxlabs/x";
|
|
10
|
+
import { DataType, errors, Rate, TimeSpan } from "@synnaxlabs/x";
|
|
11
11
|
import { describe, expect, it, vi } from "vitest";
|
|
12
12
|
|
|
13
13
|
import { channel } from "@/channel";
|
|
@@ -57,7 +57,10 @@ describe("channelchannel.Retriever", () => {
|
|
|
57
57
|
operations: [],
|
|
58
58
|
}));
|
|
59
59
|
});
|
|
60
|
-
const retriever = new channel.DebouncedBatchRetriever(
|
|
60
|
+
const retriever = new channel.DebouncedBatchRetriever(
|
|
61
|
+
base,
|
|
62
|
+
TimeSpan.milliseconds(10),
|
|
63
|
+
);
|
|
61
64
|
const res = await Promise.all([
|
|
62
65
|
retriever.retrieve([1]),
|
|
63
66
|
retriever.retrieve([2]),
|
|
@@ -86,7 +89,10 @@ describe("channelchannel.Retriever", () => {
|
|
|
86
89
|
operations: [],
|
|
87
90
|
}));
|
|
88
91
|
});
|
|
89
|
-
const retriever = new channel.DebouncedBatchRetriever(
|
|
92
|
+
const retriever = new channel.DebouncedBatchRetriever(
|
|
93
|
+
base,
|
|
94
|
+
TimeSpan.milliseconds(10),
|
|
95
|
+
);
|
|
90
96
|
const res = await Promise.all([
|
|
91
97
|
retriever.retrieve([1]),
|
|
92
98
|
retriever.retrieve([2]),
|
|
@@ -100,7 +106,10 @@ describe("channelchannel.Retriever", () => {
|
|
|
100
106
|
const base = new MockRetriever(async (): Promise<channel.Payload[]> => {
|
|
101
107
|
throw new Error("failed to fetch");
|
|
102
108
|
});
|
|
103
|
-
const retriever = new channel.DebouncedBatchRetriever(
|
|
109
|
+
const retriever = new channel.DebouncedBatchRetriever(
|
|
110
|
+
base,
|
|
111
|
+
TimeSpan.milliseconds(10),
|
|
112
|
+
);
|
|
104
113
|
await expect(retriever.retrieve([1])).rejects.toThrow("failed to fetch");
|
|
105
114
|
});
|
|
106
115
|
});
|
package/src/channel/client.ts
CHANGED
|
@@ -7,15 +7,17 @@
|
|
|
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 {
|
|
10
|
+
import { type UnaryClient } from "@synnaxlabs/freighter";
|
|
11
11
|
import {
|
|
12
12
|
array,
|
|
13
13
|
type CrudeDensity,
|
|
14
14
|
type CrudeTimeRange,
|
|
15
|
+
type CrudeTimeSpan,
|
|
15
16
|
type CrudeTimeStamp,
|
|
16
17
|
DataType,
|
|
17
18
|
type MultiSeries,
|
|
18
19
|
status,
|
|
20
|
+
TimeSpan,
|
|
19
21
|
type TypedArray,
|
|
20
22
|
} from "@synnaxlabs/x";
|
|
21
23
|
import { z } from "zod";
|
|
@@ -387,8 +389,7 @@ export class Client {
|
|
|
387
389
|
*/
|
|
388
390
|
async delete(params: Params): Promise<void> {
|
|
389
391
|
const { normalized, variant } = analyzeParams(params);
|
|
390
|
-
if (variant === "keys")
|
|
391
|
-
return await this.writer.delete({ keys: normalized as Key[] });
|
|
392
|
+
if (variant === "keys") return await this.writer.delete({ keys: normalized });
|
|
392
393
|
return await this.writer.delete({ names: normalized as string[] });
|
|
393
394
|
}
|
|
394
395
|
|
|
@@ -398,7 +399,9 @@ export class Client {
|
|
|
398
399
|
return await this.writer.rename(array.toArray(keys), array.toArray(names));
|
|
399
400
|
}
|
|
400
401
|
|
|
401
|
-
createDebouncedBatchRetriever(
|
|
402
|
+
createDebouncedBatchRetriever(
|
|
403
|
+
deb: CrudeTimeSpan = TimeSpan.milliseconds(10),
|
|
404
|
+
): Retriever {
|
|
402
405
|
return new CacheRetriever(
|
|
403
406
|
new DebouncedBatchRetriever(new ClusterRetriever(this.client), deb),
|
|
404
407
|
);
|
|
@@ -414,8 +417,7 @@ export class Client {
|
|
|
414
417
|
}
|
|
415
418
|
|
|
416
419
|
async retrieveGroup(): Promise<group.Group> {
|
|
417
|
-
const res = await
|
|
418
|
-
this.client,
|
|
420
|
+
const res = await this.client.send(
|
|
419
421
|
"/channel/retrieve-group",
|
|
420
422
|
{},
|
|
421
423
|
retrieveGroupReqZ,
|
package/src/channel/retriever.ts
CHANGED
|
@@ -7,8 +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 {
|
|
11
|
-
import { array, DataType, debounce, zod } from "@synnaxlabs/x";
|
|
10
|
+
import { type UnaryClient } from "@synnaxlabs/freighter";
|
|
11
|
+
import { array, type CrudeTimeSpan, DataType, debounce, zod } from "@synnaxlabs/x";
|
|
12
12
|
import { Mutex } from "async-mutex";
|
|
13
13
|
import { z } from "zod";
|
|
14
14
|
|
|
@@ -36,13 +36,10 @@ const reqZ = z.object({
|
|
|
36
36
|
internal: z.boolean().optional(),
|
|
37
37
|
legacyCalculated: z.boolean().optional(),
|
|
38
38
|
});
|
|
39
|
-
export
|
|
39
|
+
export type RetrieveRequest = z.input<typeof reqZ>;
|
|
40
40
|
|
|
41
|
-
export
|
|
42
|
-
|
|
43
|
-
"keys" | "names" | "search"
|
|
44
|
-
> {}
|
|
45
|
-
export interface PageOptions extends Omit<RetrieveOptions, "offset" | "limit"> {}
|
|
41
|
+
export type RetrieveOptions = Omit<RetrieveRequest, "keys" | "names" | "search">;
|
|
42
|
+
export type PageOptions = Omit<RetrieveOptions, "offset" | "limit">;
|
|
46
43
|
|
|
47
44
|
const resZ = z.object({ channels: array.nullishToEmpty(payloadZ) });
|
|
48
45
|
|
|
@@ -86,13 +83,7 @@ export class ClusterRetriever implements Retriever {
|
|
|
86
83
|
}
|
|
87
84
|
|
|
88
85
|
private async execute(request: RetrieveRequest): Promise<Payload[]> {
|
|
89
|
-
const res = await
|
|
90
|
-
this.client,
|
|
91
|
-
"/channel/retrieve",
|
|
92
|
-
request,
|
|
93
|
-
reqZ,
|
|
94
|
-
resZ,
|
|
95
|
-
);
|
|
86
|
+
const res = await this.client.send("/channel/retrieve", request, reqZ, resZ);
|
|
96
87
|
return res.channels;
|
|
97
88
|
}
|
|
98
89
|
}
|
|
@@ -204,7 +195,7 @@ export class DebouncedBatchRetriever implements Retriever {
|
|
|
204
195
|
private readonly wrapped: Retriever;
|
|
205
196
|
private readonly debouncedRun: () => void;
|
|
206
197
|
|
|
207
|
-
constructor(wrapped: Retriever, deb:
|
|
198
|
+
constructor(wrapped: Retriever, deb: CrudeTimeSpan) {
|
|
208
199
|
this.wrapped = wrapped;
|
|
209
200
|
this.debouncedRun = debounce(() => {
|
|
210
201
|
void this.run();
|
package/src/channel/writer.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
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 {
|
|
10
|
+
import { type UnaryClient } from "@synnaxlabs/freighter";
|
|
11
11
|
import { type DataType } from "@synnaxlabs/x";
|
|
12
12
|
import { z } from "zod";
|
|
13
13
|
|
|
@@ -47,11 +47,7 @@ export class Writer {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
async create(channels: New[]): Promise<Payload[]> {
|
|
50
|
-
const { channels: created } = await
|
|
51
|
-
typeof createReqZ,
|
|
52
|
-
typeof createResZ
|
|
53
|
-
>(
|
|
54
|
-
this.client,
|
|
50
|
+
const { channels: created } = await this.client.send(
|
|
55
51
|
"/channel/create",
|
|
56
52
|
{
|
|
57
53
|
channels: channels.map((c) => ({
|
|
@@ -68,25 +64,13 @@ export class Writer {
|
|
|
68
64
|
|
|
69
65
|
async delete(props: DeleteProps): Promise<void> {
|
|
70
66
|
const keys = keyZ.array().parse(props.keys ?? []);
|
|
71
|
-
await
|
|
72
|
-
this.client,
|
|
73
|
-
"/channel/delete",
|
|
74
|
-
props,
|
|
75
|
-
deleteReqZ,
|
|
76
|
-
deleteResZ,
|
|
77
|
-
);
|
|
67
|
+
await this.client.send("/channel/delete", props, deleteReqZ, deleteResZ);
|
|
78
68
|
if (keys.length > 0) this.cache.delete(keys);
|
|
79
69
|
if (props.names != null) this.cache.delete(props.names);
|
|
80
70
|
}
|
|
81
71
|
|
|
82
72
|
async rename(keys: Key[], names: string[]): Promise<void> {
|
|
83
|
-
await
|
|
84
|
-
this.client,
|
|
85
|
-
"/channel/rename",
|
|
86
|
-
{ keys, names },
|
|
87
|
-
renameReqZ,
|
|
88
|
-
renameResZ,
|
|
89
|
-
);
|
|
73
|
+
await this.client.send("/channel/rename", { keys, names }, renameReqZ, renameResZ);
|
|
90
74
|
this.cache.rename(keys, names);
|
|
91
75
|
}
|
|
92
76
|
}
|
|
@@ -7,7 +7,7 @@
|
|
|
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 {
|
|
10
|
+
import { type UnaryClient } from "@synnaxlabs/freighter";
|
|
11
11
|
import {
|
|
12
12
|
ClockSkewCalculator,
|
|
13
13
|
type CrudeTimeSpan,
|
|
@@ -85,14 +85,14 @@ export class Checker {
|
|
|
85
85
|
*/
|
|
86
86
|
constructor(
|
|
87
87
|
client: UnaryClient,
|
|
88
|
-
pollFreq:
|
|
88
|
+
pollFreq: CrudeTimeSpan = TimeSpan.seconds(30),
|
|
89
89
|
clientVersion: string,
|
|
90
90
|
name?: string,
|
|
91
91
|
clockSkewThreshold: CrudeTimeSpan = TimeSpan.seconds(1),
|
|
92
92
|
) {
|
|
93
93
|
this._state = { ...DEFAULT };
|
|
94
94
|
this.client = client;
|
|
95
|
-
this.pollFrequency = pollFreq;
|
|
95
|
+
this.pollFrequency = new TimeSpan(pollFreq);
|
|
96
96
|
this.clientVersion = clientVersion;
|
|
97
97
|
this.name = name;
|
|
98
98
|
this.skewCalc = new ClockSkewCalculator();
|
|
@@ -117,8 +117,7 @@ export class Checker {
|
|
|
117
117
|
this.checking = true;
|
|
118
118
|
try {
|
|
119
119
|
if (measureSkew) this.skewCalc.start();
|
|
120
|
-
const res = await
|
|
121
|
-
this.client,
|
|
120
|
+
const res = await this.client.send(
|
|
122
121
|
"/connectivity/check",
|
|
123
122
|
undefined,
|
|
124
123
|
requestZ,
|
|
@@ -90,14 +90,11 @@ describe("connectivity", () => {
|
|
|
90
90
|
});
|
|
91
91
|
describe("clock skew", () => {
|
|
92
92
|
const createMockClient = (nodeTime: TimeStamp): UnaryClient => ({
|
|
93
|
-
send: vi.fn().mockResolvedValue(
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
},
|
|
99
|
-
null,
|
|
100
|
-
]) as UnaryClient["send"],
|
|
93
|
+
send: vi.fn().mockResolvedValue({
|
|
94
|
+
clusterKey: "test-cluster",
|
|
95
|
+
nodeVersion: __VERSION__,
|
|
96
|
+
nodeTime,
|
|
97
|
+
}),
|
|
101
98
|
use: vi.fn(),
|
|
102
99
|
});
|
|
103
100
|
|
package/src/device/client.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
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 {
|
|
10
|
+
import { type UnaryClient } from "@synnaxlabs/freighter";
|
|
11
11
|
import { array, type record, zod } from "@synnaxlabs/x";
|
|
12
12
|
import { z } from "zod";
|
|
13
13
|
|
|
@@ -122,10 +122,9 @@ export class Client {
|
|
|
122
122
|
async retrieve(
|
|
123
123
|
args: RetrieveArgs & { schemas?: DeviceSchemas },
|
|
124
124
|
): Promise<Device | Array<Device>> {
|
|
125
|
-
const { schemas, ...rest } = args
|
|
125
|
+
const { schemas, ...rest } = args;
|
|
126
126
|
const isSingle = typeof rest === "object" && "key" in rest;
|
|
127
|
-
const res = await
|
|
128
|
-
this.client,
|
|
127
|
+
const res = await this.client.send(
|
|
129
128
|
"/device/retrieve",
|
|
130
129
|
rest,
|
|
131
130
|
retrieveArgsZ,
|
|
@@ -166,8 +165,7 @@ export class Client {
|
|
|
166
165
|
schemas?: DeviceSchemas,
|
|
167
166
|
): Promise<Device | Device[]> {
|
|
168
167
|
const isSingle = !Array.isArray(devices);
|
|
169
|
-
const res = await
|
|
170
|
-
this.client,
|
|
168
|
+
const res = await this.client.send(
|
|
171
169
|
"/device/create",
|
|
172
170
|
{ devices: array.toArray(devices) },
|
|
173
171
|
createReqZ(schemas),
|
|
@@ -177,8 +175,7 @@ export class Client {
|
|
|
177
175
|
}
|
|
178
176
|
|
|
179
177
|
async delete(keys: Key | Key[]): Promise<void> {
|
|
180
|
-
await
|
|
181
|
-
this.client,
|
|
178
|
+
await this.client.send(
|
|
182
179
|
"/device/delete",
|
|
183
180
|
{ keys: array.toArray(keys) },
|
|
184
181
|
deleteReqZ,
|
package/src/device/types.gen.ts
CHANGED
|
@@ -15,18 +15,18 @@ import { z } from "zod";
|
|
|
15
15
|
import { ontology } from "@/ontology";
|
|
16
16
|
import { rack } from "@/rack";
|
|
17
17
|
|
|
18
|
+
export const keyZ = z.string();
|
|
19
|
+
export type Key = z.infer<typeof keyZ>;
|
|
20
|
+
|
|
18
21
|
/** StatusDetails contains device-specific status details identifying the device and its associated rack. */
|
|
19
22
|
export const statusDetailsZ = z.object({
|
|
20
23
|
/** rack is the key of the rack this device belongs to. */
|
|
21
24
|
rack: rack.keyZ,
|
|
22
25
|
/** device is the device identifier. */
|
|
23
|
-
device:
|
|
26
|
+
device: keyZ,
|
|
24
27
|
});
|
|
25
28
|
export interface StatusDetails extends z.infer<typeof statusDetailsZ> {}
|
|
26
29
|
|
|
27
|
-
export const keyZ = z.string();
|
|
28
|
-
export type Key = z.infer<typeof keyZ>;
|
|
29
|
-
|
|
30
30
|
export const statusZ = status.statusZ({ details: statusDetailsZ });
|
|
31
31
|
export type Status = z.infer<typeof statusZ>;
|
|
32
32
|
|
package/src/errors.ts
CHANGED
|
@@ -157,15 +157,14 @@ export const validateFieldNotNull = (
|
|
|
157
157
|
};
|
|
158
158
|
|
|
159
159
|
export const errorsMiddleware: Middleware = async (ctx, next) => {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
new Unreachable({
|
|
160
|
+
try {
|
|
161
|
+
return await next(ctx);
|
|
162
|
+
} catch (err) {
|
|
163
|
+
if (err instanceof Unreachable)
|
|
164
|
+
throw new Unreachable({
|
|
166
165
|
message: `Cannot reach Core at ${err.url.host}:${err.url.port}`,
|
|
167
166
|
url: err.url,
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
|
|
167
|
+
});
|
|
168
|
+
throw err;
|
|
169
|
+
}
|
|
171
170
|
};
|
package/src/framer/adapter.ts
CHANGED
|
@@ -164,16 +164,14 @@ export class WriteAdapter {
|
|
|
164
164
|
throw new ValidationError(`
|
|
165
165
|
Received a single channel name or key but no series.
|
|
166
166
|
`);
|
|
167
|
-
if (Array.isArray(series))
|
|
167
|
+
if (Array.isArray(series))
|
|
168
168
|
if (series.some((s) => s instanceof Series || Array.isArray(s)))
|
|
169
169
|
throw new ValidationError(`
|
|
170
170
|
Received a single channel name or key but multiple series.
|
|
171
171
|
`);
|
|
172
172
|
|
|
173
|
-
series = series as CrudeSeries;
|
|
174
|
-
}
|
|
175
173
|
const pld = await this.fetchChannel(columnsOrData);
|
|
176
|
-
const s = new Series({ data: series
|
|
174
|
+
const s = new Series({ data: series, dataType: pld.dataType });
|
|
177
175
|
return new Frame(pld.key, s);
|
|
178
176
|
}
|
|
179
177
|
|
package/src/framer/codec.spec.ts
CHANGED
|
@@ -17,11 +17,13 @@ import { framer } from "@/framer";
|
|
|
17
17
|
import {
|
|
18
18
|
Codec,
|
|
19
19
|
HIGH_PERF_SPECIAL_CHAR,
|
|
20
|
-
|
|
20
|
+
LOW_PERF_SPECIAL_CHAR,
|
|
21
|
+
WSIteratorCodec,
|
|
21
22
|
WSWriterCodec,
|
|
22
23
|
} from "@/framer/codec";
|
|
23
24
|
import { Frame } from "@/framer/frame";
|
|
24
|
-
import {
|
|
25
|
+
import { type IteratorResponse } from "@/framer/iterator";
|
|
26
|
+
import { IteratorResponseVariant, WriterCommand } from "@/framer/types.gen";
|
|
25
27
|
import { type WriteRequest } from "@/framer/writer";
|
|
26
28
|
|
|
27
29
|
describe("encoder", () => {
|
|
@@ -325,9 +327,57 @@ describe("encoder", () => {
|
|
|
325
327
|
const codec = new WSWriterCodec(baseCodec);
|
|
326
328
|
const msg: WebsocketMessage<WriteRequest> = { type: "data", payload: writeReq };
|
|
327
329
|
const encoded = codec.encode(msg);
|
|
328
|
-
expect(encoded[0]).toEqual(
|
|
330
|
+
expect(encoded[0]).toEqual(LOW_PERF_SPECIAL_CHAR);
|
|
329
331
|
const decoded = codec.decode(encoded);
|
|
330
332
|
expect(decoded).toEqual(msg);
|
|
331
333
|
});
|
|
332
334
|
});
|
|
335
|
+
|
|
336
|
+
describe("websocket iterator codec", () => {
|
|
337
|
+
it("should JSON-encode an iterator request without a special char prefix", () => {
|
|
338
|
+
const baseCodec = new Codec([1], [DataType.INT32]);
|
|
339
|
+
const codec = new WSIteratorCodec(baseCodec);
|
|
340
|
+
const msg: WebsocketMessage<unknown> = {
|
|
341
|
+
type: "data",
|
|
342
|
+
payload: { command: 1, span: 0 },
|
|
343
|
+
};
|
|
344
|
+
const encoded = codec.encode(msg);
|
|
345
|
+
// Iterator requests are sent as raw JSON; no special-char prefix.
|
|
346
|
+
// Confirm the first byte is JSON ('{' or '[').
|
|
347
|
+
expect([0x7b, 0x5b]).toContain(encoded[0]);
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
it("should binary-decode a data variant response and synthesize variant=Data", () => {
|
|
351
|
+
const baseCodec = new Codec([1], [DataType.INT32]);
|
|
352
|
+
const fr = new framer.Frame([1], [new Series(new Int32Array([1, 2, 3]))]);
|
|
353
|
+
const codec = new WSIteratorCodec(baseCodec);
|
|
354
|
+
const encoded = new Uint8Array(baseCodec.encode(fr.toPayload(), 1));
|
|
355
|
+
encoded[0] = HIGH_PERF_SPECIAL_CHAR;
|
|
356
|
+
const decoded = codec.decode(encoded) as WebsocketMessage<IteratorResponse>;
|
|
357
|
+
expect(decoded.payload?.variant).toEqual(IteratorResponseVariant.Data);
|
|
358
|
+
const decodedFr = new Frame(decoded.payload?.frame);
|
|
359
|
+
expect(decodedFr.series[0].data).toEqual(fr.series[0].data);
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
it("should JSON-decode an ack variant response prefixed with the low-perf char", () => {
|
|
363
|
+
const baseCodec = new Codec([1], [DataType.INT32]);
|
|
364
|
+
const codec = new WSIteratorCodec(baseCodec);
|
|
365
|
+
const ackMsg: WebsocketMessage<IteratorResponse> = {
|
|
366
|
+
type: "data",
|
|
367
|
+
payload: {
|
|
368
|
+
variant: IteratorResponseVariant.Ack,
|
|
369
|
+
ack: true,
|
|
370
|
+
command: 1,
|
|
371
|
+
},
|
|
372
|
+
};
|
|
373
|
+
// Simulate what the server sends: LOW_PERF_SPECIAL_CHAR + JSON-encoded message.
|
|
374
|
+
const json = new TextEncoder().encode(JSON.stringify(ackMsg));
|
|
375
|
+
const encoded = new Uint8Array(json.byteLength + 1);
|
|
376
|
+
encoded[0] = LOW_PERF_SPECIAL_CHAR;
|
|
377
|
+
encoded.set(json, 1);
|
|
378
|
+
const decoded = codec.decode(encoded) as WebsocketMessage<IteratorResponse>;
|
|
379
|
+
expect(decoded.payload?.variant).toEqual(IteratorResponseVariant.Ack);
|
|
380
|
+
expect(decoded.payload?.ack).toEqual(true);
|
|
381
|
+
});
|
|
382
|
+
});
|
|
333
383
|
});
|
package/src/framer/codec.ts
CHANGED
|
@@ -21,7 +21,7 @@ import { type channel } from "@/channel";
|
|
|
21
21
|
import { ValidationError } from "@/errors";
|
|
22
22
|
import { type Frame, type Payload } from "@/framer/frame";
|
|
23
23
|
import { type StreamerResponse } from "@/framer/streamer";
|
|
24
|
-
import { WriterCommand } from "@/framer/types.gen";
|
|
24
|
+
import { IteratorResponseVariant, WriterCommand } from "@/framer/types.gen";
|
|
25
25
|
import { type WriteRequest } from "@/framer/writer";
|
|
26
26
|
|
|
27
27
|
const seriesPldLength = (series: SeriesPayload): number =>
|
|
@@ -63,7 +63,7 @@ interface CodecState {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
export class Codec {
|
|
66
|
-
contentType: string =
|
|
66
|
+
contentType: string = CONTENT_TYPE;
|
|
67
67
|
private states: Map<number, CodecState> = new Map();
|
|
68
68
|
private currState: CodecState | undefined;
|
|
69
69
|
private seqNum: number = 0;
|
|
@@ -269,36 +269,26 @@ export class Codec {
|
|
|
269
269
|
index += ALIGNMENT_SIZE;
|
|
270
270
|
}
|
|
271
271
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
if (
|
|
275
|
-
if (index >= view.byteLength) return;
|
|
276
|
-
const frameKey = view.getUint32(index, true);
|
|
277
|
-
if (frameKey !== k) return;
|
|
278
|
-
index += KEY_SIZE;
|
|
279
|
-
returnFrame.keys.push(k);
|
|
280
|
-
}
|
|
281
|
-
const dataType = state.keyDataTypes.get(k) as DataType;
|
|
272
|
+
const decodeSeries = (k: channel.Key): boolean => {
|
|
273
|
+
const dataType = state.keyDataTypes.get(k);
|
|
274
|
+
if (dataType == null) return false;
|
|
282
275
|
currSize = 0;
|
|
283
276
|
if (!sizeFlag) {
|
|
284
|
-
if (index + DATA_LENGTH_SIZE > view.byteLength) return;
|
|
277
|
+
if (index + DATA_LENGTH_SIZE > view.byteLength) return false;
|
|
285
278
|
currSize = view.getUint32(index, true);
|
|
286
279
|
index += DATA_LENGTH_SIZE;
|
|
287
280
|
} else currSize = sizeRepresentation;
|
|
288
281
|
|
|
289
282
|
let dataByteLength = currSize;
|
|
290
283
|
if (!dataType.isVariable) dataByteLength *= dataType.density.valueOf();
|
|
291
|
-
if (index + dataByteLength > view.byteLength)
|
|
292
|
-
returnFrame.keys.splice(i, 1);
|
|
293
|
-
return;
|
|
294
|
-
}
|
|
284
|
+
if (index + dataByteLength > view.byteLength) return false;
|
|
295
285
|
const currSeries: SeriesPayload = {
|
|
296
286
|
dataType,
|
|
297
287
|
data: src.slice(index, index + dataByteLength).buffer,
|
|
298
288
|
};
|
|
299
289
|
index += dataByteLength;
|
|
300
290
|
if (!equalTimeRangesFlag && !timeRangesZeroFlag) {
|
|
301
|
-
if (index + TIMESTAMP_SIZE * 2 > view.byteLength) return;
|
|
291
|
+
if (index + TIMESTAMP_SIZE * 2 > view.byteLength) return false;
|
|
302
292
|
const start = view.getBigUint64(index, true);
|
|
303
293
|
index += TIMESTAMP_SIZE;
|
|
304
294
|
const end = view.getBigUint64(index, true);
|
|
@@ -312,7 +302,7 @@ export class Codec {
|
|
|
312
302
|
else currSeries.timeRange = new TimeRange({ start: 0n, end: 0n });
|
|
313
303
|
|
|
314
304
|
if (!equalAlignmentsFlag && !zeroAlignmentsFlag) {
|
|
315
|
-
if (index + ALIGNMENT_SIZE > view.byteLength) return;
|
|
305
|
+
if (index + ALIGNMENT_SIZE > view.byteLength) return false;
|
|
316
306
|
currAlignment = view.getBigUint64(index, true);
|
|
317
307
|
index += ALIGNMENT_SIZE;
|
|
318
308
|
currSeries.alignment = currAlignment;
|
|
@@ -320,16 +310,27 @@ export class Codec {
|
|
|
320
310
|
else currSeries.alignment = 0n;
|
|
321
311
|
|
|
322
312
|
returnFrame.series.push(currSeries);
|
|
323
|
-
|
|
313
|
+
returnFrame.keys.push(k);
|
|
314
|
+
return true;
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
if (channelFlag) state.keys.forEach((k) => decodeSeries(k));
|
|
318
|
+
else
|
|
319
|
+
while (index < view.byteLength) {
|
|
320
|
+
if (index + KEY_SIZE > view.byteLength) break;
|
|
321
|
+
const frameKey = view.getUint32(index, true);
|
|
322
|
+
index += KEY_SIZE;
|
|
323
|
+
if (!decodeSeries(frameKey)) break;
|
|
324
|
+
}
|
|
324
325
|
return returnFrame;
|
|
325
326
|
}
|
|
326
327
|
}
|
|
327
328
|
|
|
328
|
-
export const
|
|
329
|
-
const LOW_PERF_SPECIAL_CHAR_BUF = new Uint8Array([
|
|
329
|
+
export const LOW_PERF_SPECIAL_CHAR = 254;
|
|
330
|
+
const LOW_PERF_SPECIAL_CHAR_BUF = new Uint8Array([LOW_PERF_SPECIAL_CHAR]);
|
|
330
331
|
export const HIGH_PERF_SPECIAL_CHAR = 255;
|
|
331
332
|
const HIGH_PERF_SPECIAL_CHAR_BUF = new Uint8Array([HIGH_PERF_SPECIAL_CHAR]);
|
|
332
|
-
const CONTENT_TYPE = "application/
|
|
333
|
+
const CONTENT_TYPE = "application/vnd.synnax.frame";
|
|
333
334
|
|
|
334
335
|
export class WSWriterCodec implements binary.Codec {
|
|
335
336
|
contentType = CONTENT_TYPE;
|
|
@@ -358,7 +359,7 @@ export class WSWriterCodec implements binary.Codec {
|
|
|
358
359
|
decode<P extends z.ZodType>(data: Uint8Array | ArrayBuffer, schema?: P): z.infer<P> {
|
|
359
360
|
const dv = new DataView(data instanceof Uint8Array ? data.buffer : data);
|
|
360
361
|
const codec = dv.getUint8(0);
|
|
361
|
-
if (codec ===
|
|
362
|
+
if (codec === LOW_PERF_SPECIAL_CHAR)
|
|
362
363
|
return this.lowPerfCodec.decode(data.slice(1), schema);
|
|
363
364
|
const v: WebsocketMessage<WriteRequest> = { type: "data" };
|
|
364
365
|
const frame = this.base.decode(data, 1);
|
|
@@ -384,7 +385,7 @@ export class WSStreamerCodec implements binary.Codec {
|
|
|
384
385
|
decode<P extends z.ZodType>(data: Uint8Array | ArrayBuffer, schema?: P): z.infer<P> {
|
|
385
386
|
const dv = new DataView(data instanceof Uint8Array ? data.buffer : data);
|
|
386
387
|
const codec = dv.getUint8(0);
|
|
387
|
-
if (codec ===
|
|
388
|
+
if (codec === LOW_PERF_SPECIAL_CHAR)
|
|
388
389
|
return this.lowPerfCodec.decode(data.slice(1), schema);
|
|
389
390
|
const v: WebsocketMessage<StreamerResponse> = {
|
|
390
391
|
type: "data",
|
|
@@ -393,3 +394,35 @@ export class WSStreamerCodec implements binary.Codec {
|
|
|
393
394
|
return v as z.infer<P>;
|
|
394
395
|
}
|
|
395
396
|
}
|
|
397
|
+
|
|
398
|
+
export class WSIteratorCodec implements binary.Codec {
|
|
399
|
+
contentType = CONTENT_TYPE;
|
|
400
|
+
private base: Codec;
|
|
401
|
+
private lowPerfCodec: binary.Codec;
|
|
402
|
+
|
|
403
|
+
constructor(base: Codec) {
|
|
404
|
+
this.base = base;
|
|
405
|
+
this.lowPerfCodec = binary.JSON_CODEC;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
encode(payload: unknown): Uint8Array<ArrayBuffer> {
|
|
409
|
+
return this.lowPerfCodec.encode(payload);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
decode<P extends z.ZodType>(data: Uint8Array | ArrayBuffer, schema?: P): z.infer<P> {
|
|
413
|
+
const dv = new DataView(data instanceof Uint8Array ? data.buffer : data);
|
|
414
|
+
const codec = dv.getUint8(0);
|
|
415
|
+
if (codec === LOW_PERF_SPECIAL_CHAR)
|
|
416
|
+
return this.lowPerfCodec.decode(data.slice(1), schema);
|
|
417
|
+
const v: WebsocketMessage<unknown> = {
|
|
418
|
+
type: "data",
|
|
419
|
+
payload: {
|
|
420
|
+
variant: IteratorResponseVariant.Data,
|
|
421
|
+
ack: false,
|
|
422
|
+
command: 0,
|
|
423
|
+
frame: this.base.decode(data, 1),
|
|
424
|
+
},
|
|
425
|
+
};
|
|
426
|
+
return v as z.infer<P>;
|
|
427
|
+
}
|
|
428
|
+
}
|
package/src/framer/deleter.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
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 {
|
|
10
|
+
import { type UnaryClient } from "@synnaxlabs/freighter";
|
|
11
11
|
import { TimeRange } from "@synnaxlabs/x";
|
|
12
12
|
import { z } from "zod";
|
|
13
13
|
|
|
@@ -33,12 +33,6 @@ export class Deleter {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
async delete(props: Request): Promise<void> {
|
|
36
|
-
await
|
|
37
|
-
this.client,
|
|
38
|
-
"/frame/delete",
|
|
39
|
-
props,
|
|
40
|
-
reqZ,
|
|
41
|
-
resZ,
|
|
42
|
-
);
|
|
36
|
+
await this.client.send("/frame/delete", props, reqZ, resZ);
|
|
43
37
|
}
|
|
44
38
|
}
|