@synnaxlabs/client 0.30.0 → 0.31.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 +6 -6
- package/api/client.api.md +615 -261
- package/dist/access/client.d.ts +2 -7
- package/dist/access/client.d.ts.map +1 -1
- package/dist/access/payload.d.ts +7 -102
- package/dist/access/payload.d.ts.map +1 -1
- package/dist/access/policy/client.d.ts +17 -0
- package/dist/access/policy/client.d.ts.map +1 -0
- package/dist/access/policy/external.d.ts +3 -0
- package/dist/access/policy/external.d.ts.map +1 -0
- package/dist/access/policy/index.d.ts +2 -0
- package/dist/access/policy/index.d.ts.map +1 -0
- package/dist/access/policy/payload.d.ts +163 -0
- package/dist/access/policy/payload.d.ts.map +1 -0
- package/dist/access/policy/policy.spec.d.ts +2 -0
- package/dist/access/policy/policy.spec.d.ts.map +1 -0
- package/dist/access/policy/retriever.d.ts +36 -0
- package/dist/access/policy/retriever.d.ts.map +1 -0
- package/dist/access/policy/writer.d.ts +9 -0
- package/dist/access/policy/writer.d.ts.map +1 -0
- package/dist/auth/auth.d.ts +6 -30
- package/dist/auth/auth.d.ts.map +1 -1
- package/dist/channel/payload.d.ts +17 -17
- package/dist/channel/payload.d.ts.map +1 -1
- package/dist/channel/retriever.d.ts +8 -8
- package/dist/client.cjs +31 -21
- package/dist/client.js +2962 -2233
- package/dist/framer/client.d.ts +4 -1
- package/dist/framer/client.d.ts.map +1 -1
- package/dist/framer/frame.d.ts +27 -80
- package/dist/framer/frame.d.ts.map +1 -1
- package/dist/framer/streamer.d.ts +3 -1
- package/dist/framer/streamer.d.ts.map +1 -1
- package/dist/framer/writer.d.ts +24 -16
- package/dist/framer/writer.d.ts.map +1 -1
- package/dist/hardware/device/client.d.ts +2 -2
- package/dist/hardware/device/payload.d.ts +1 -1
- package/dist/hardware/device/payload.d.ts.map +1 -1
- package/dist/hardware/rack/payload.d.ts +1 -1
- package/dist/hardware/rack/payload.d.ts.map +1 -1
- package/dist/hardware/task/client.d.ts +2 -2
- package/dist/hardware/task/ni/types.d.ts +16 -16
- package/dist/hardware/task/payload.d.ts +13 -13
- package/dist/hardware/task/payload.d.ts.map +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/label/payload.d.ts +1 -1
- package/dist/label/payload.d.ts.map +1 -1
- package/dist/label/writer.d.ts +5 -5
- package/dist/ontology/client.d.ts +32 -30
- package/dist/ontology/client.d.ts.map +1 -1
- package/dist/ontology/payload.d.ts +62 -63
- package/dist/ontology/payload.d.ts.map +1 -1
- package/dist/ranger/payload.d.ts +2 -2
- package/dist/ranger/payload.d.ts.map +1 -1
- package/dist/ranger/writer.d.ts +5 -5
- package/dist/user/client.d.ts +13 -3
- package/dist/user/client.d.ts.map +1 -1
- package/dist/user/payload.d.ts +34 -3
- package/dist/user/payload.d.ts.map +1 -1
- package/dist/user/retriever.d.ts +21 -0
- package/dist/user/retriever.d.ts.map +1 -0
- package/dist/user/user.spec.d.ts +2 -0
- package/dist/user/user.spec.d.ts.map +1 -0
- package/dist/user/writer.d.ts +11 -0
- package/dist/user/writer.d.ts.map +1 -0
- package/dist/workspace/lineplot/payload.d.ts +1 -1
- package/dist/workspace/lineplot/payload.d.ts.map +1 -1
- package/dist/workspace/payload.d.ts +1 -1
- package/dist/workspace/payload.d.ts.map +1 -1
- package/dist/workspace/schematic/client.d.ts.map +1 -1
- package/dist/workspace/schematic/payload.d.ts +1 -1
- package/dist/workspace/schematic/payload.d.ts.map +1 -1
- package/examples/node/package-lock.json +963 -134
- package/examples/node/package.json +1 -1
- package/package.json +3 -3
- package/src/access/client.ts +4 -70
- package/src/access/payload.ts +14 -24
- package/src/access/policy/client.ts +65 -0
- package/src/access/policy/external.ts +11 -0
- package/src/access/policy/index.ts +10 -0
- package/src/access/policy/payload.ts +45 -0
- package/src/access/policy/policy.spec.ts +331 -0
- package/src/access/policy/retriever.ts +43 -0
- package/src/access/policy/writer.ts +65 -0
- package/src/auth/auth.ts +32 -10
- package/src/channel/payload.ts +2 -2
- package/src/framer/client.ts +7 -1
- package/src/framer/frame.spec.ts +21 -12
- package/src/framer/frame.ts +9 -24
- package/src/framer/streamer.spec.ts +48 -0
- package/src/framer/streamer.ts +7 -4
- package/src/framer/writer.ts +0 -2
- package/src/hardware/device/payload.ts +2 -2
- package/src/hardware/rack/payload.ts +2 -2
- package/src/hardware/task/payload.ts +2 -2
- package/src/index.ts +16 -13
- package/src/label/payload.ts +2 -2
- package/src/ontology/client.ts +35 -34
- package/src/ontology/payload.ts +28 -35
- package/src/ranger/payload.ts +5 -7
- package/src/setupspecs.ts +2 -2
- package/src/user/client.ts +63 -19
- package/src/user/payload.ts +14 -7
- package/src/user/retriever.ts +41 -0
- package/src/user/user.spec.ts +289 -0
- package/src/user/writer.ts +91 -0
- package/src/workspace/lineplot/payload.ts +2 -2
- package/src/workspace/payload.ts +2 -2
- package/src/workspace/schematic/client.ts +1 -1
- package/src/workspace/schematic/payload.ts +2 -2
- package/src/workspace/workspace.spec.ts +1 -1
- package/dist/access/access.spec.d.ts +0 -2
- package/dist/access/access.spec.d.ts.map +0 -1
- package/src/access/access.spec.ts +0 -276
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// Copyright 2024 Synnax Labs, Inc.
|
|
2
|
+
//
|
|
3
|
+
// Use of this software is governed by the Business Source License included in the file
|
|
4
|
+
// licenses/BSL.txt.
|
|
5
|
+
//
|
|
6
|
+
// As of the Change Date specified in that file, in accordance with the Business Source
|
|
7
|
+
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
|
+
// included in the file licenses/APL.txt.
|
|
9
|
+
|
|
10
|
+
import { sendRequired, type UnaryClient } from "@synnaxlabs/freighter";
|
|
11
|
+
import { toArray } from "@synnaxlabs/x";
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
type Key,
|
|
16
|
+
keyZ,
|
|
17
|
+
type NewPolicy,
|
|
18
|
+
newPolicyZ,
|
|
19
|
+
type Policy,
|
|
20
|
+
policyZ,
|
|
21
|
+
} from "@/access/policy/payload";
|
|
22
|
+
|
|
23
|
+
const createReqZ = z.object({ policies: policyZ.partial({ key: true }).array() });
|
|
24
|
+
const createResZ = z.object({ policies: policyZ.array() });
|
|
25
|
+
|
|
26
|
+
const deleteReqZ = z.object({ keys: keyZ.array() });
|
|
27
|
+
const deleteResZ = z.object({});
|
|
28
|
+
|
|
29
|
+
const CREATE_ENDPOINT = "/access/policy/create";
|
|
30
|
+
const DELETE_ENDPOINT = "/access/policy/delete";
|
|
31
|
+
|
|
32
|
+
export class Writer {
|
|
33
|
+
private readonly client: UnaryClient;
|
|
34
|
+
|
|
35
|
+
constructor(client: UnaryClient) {
|
|
36
|
+
this.client = client;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async create(policies: NewPolicy | NewPolicy[]): Promise<Policy[]> {
|
|
40
|
+
const parsedPolicies = newPolicyZ.array().parse(toArray(policies));
|
|
41
|
+
const req = parsedPolicies.map((policy) => ({
|
|
42
|
+
objects: toArray(policy.objects),
|
|
43
|
+
actions: toArray(policy.actions),
|
|
44
|
+
subjects: toArray(policy.subjects),
|
|
45
|
+
}));
|
|
46
|
+
const res = await sendRequired<typeof createReqZ, typeof createResZ>(
|
|
47
|
+
this.client,
|
|
48
|
+
CREATE_ENDPOINT,
|
|
49
|
+
{ policies: req },
|
|
50
|
+
createReqZ,
|
|
51
|
+
createResZ,
|
|
52
|
+
);
|
|
53
|
+
return res.policies;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async delete(keys: Key | Key[]): Promise<void> {
|
|
57
|
+
await sendRequired<typeof deleteReqZ, typeof deleteResZ>(
|
|
58
|
+
this.client,
|
|
59
|
+
DELETE_ENDPOINT,
|
|
60
|
+
{ keys: toArray(keys) },
|
|
61
|
+
deleteReqZ,
|
|
62
|
+
deleteResZ,
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
}
|
package/src/auth/auth.ts
CHANGED
|
@@ -7,36 +7,43 @@
|
|
|
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 { type Middleware, type UnaryClient } from "@synnaxlabs/freighter";
|
|
10
|
+
import { type Middleware, sendRequired, type UnaryClient } from "@synnaxlabs/freighter";
|
|
11
11
|
import { z } from "zod";
|
|
12
12
|
|
|
13
13
|
import { InvalidTokenError } from "@/errors";
|
|
14
14
|
import { user } from "@/user";
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
const insecureCredentialsZ = z.object({
|
|
17
17
|
username: z.string(),
|
|
18
18
|
password: z.string(),
|
|
19
19
|
});
|
|
20
|
-
|
|
20
|
+
type InsecureCredentials = z.infer<typeof insecureCredentialsZ>;
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
const tokenResponseZ = z.object({
|
|
23
23
|
token: z.string(),
|
|
24
|
-
user: user.
|
|
24
|
+
user: user.userZ,
|
|
25
25
|
});
|
|
26
26
|
|
|
27
|
-
export type TokenResponse = z.infer<typeof tokenResponseZ>;
|
|
28
|
-
|
|
29
27
|
const LOGIN_ENDPOINT = "/auth/login";
|
|
30
28
|
|
|
31
29
|
const MAX_RETRIES = 3;
|
|
32
30
|
|
|
31
|
+
const CHANGE_PASSWORD_ENDPOINT = "/auth/change-password";
|
|
32
|
+
|
|
33
|
+
const changePasswordReqZ = z.object({
|
|
34
|
+
username: z.string(),
|
|
35
|
+
password: z.string(),
|
|
36
|
+
newPassword: z.string().min(1),
|
|
37
|
+
});
|
|
38
|
+
const changePasswordResZ = z.object({});
|
|
39
|
+
|
|
33
40
|
export class Client {
|
|
34
41
|
token: string | undefined;
|
|
35
42
|
private readonly client: UnaryClient;
|
|
36
43
|
private readonly credentials: InsecureCredentials;
|
|
37
|
-
|
|
44
|
+
authenticating: Promise<Error | null> | undefined;
|
|
38
45
|
authenticated: boolean;
|
|
39
|
-
user: user.
|
|
46
|
+
user: user.User | undefined;
|
|
40
47
|
private retryCount: number;
|
|
41
48
|
|
|
42
49
|
constructor(client: UnaryClient, credentials: InsecureCredentials) {
|
|
@@ -46,6 +53,22 @@ export class Client {
|
|
|
46
53
|
this.retryCount = 0;
|
|
47
54
|
}
|
|
48
55
|
|
|
56
|
+
async changePassword(newPassword: string): Promise<void> {
|
|
57
|
+
if (!this.authenticated) throw new Error("Not authenticated");
|
|
58
|
+
await sendRequired<typeof changePasswordReqZ, typeof changePasswordResZ>(
|
|
59
|
+
this.client,
|
|
60
|
+
CHANGE_PASSWORD_ENDPOINT,
|
|
61
|
+
{
|
|
62
|
+
username: this.credentials.username,
|
|
63
|
+
password: this.credentials.password,
|
|
64
|
+
newPassword,
|
|
65
|
+
},
|
|
66
|
+
changePasswordReqZ,
|
|
67
|
+
changePasswordResZ,
|
|
68
|
+
);
|
|
69
|
+
this.credentials.password = newPassword;
|
|
70
|
+
}
|
|
71
|
+
|
|
49
72
|
middleware(): Middleware {
|
|
50
73
|
const mw: Middleware = async (reqCtx, next) => {
|
|
51
74
|
if (!this.authenticated && !reqCtx.target.endsWith(LOGIN_ENDPOINT)) {
|
|
@@ -54,7 +77,6 @@ export class Client {
|
|
|
54
77
|
this.client
|
|
55
78
|
.send(
|
|
56
79
|
LOGIN_ENDPOINT,
|
|
57
|
-
|
|
58
80
|
this.credentials,
|
|
59
81
|
insecureCredentialsZ,
|
|
60
82
|
tokenResponseZ,
|
package/src/channel/payload.ts
CHANGED
|
@@ -48,7 +48,7 @@ export const newPayload = payload.extend({
|
|
|
48
48
|
|
|
49
49
|
export type NewPayload = z.input<typeof newPayload>;
|
|
50
50
|
|
|
51
|
-
export const
|
|
51
|
+
export const ONTOLOGY_TYPE: ontology.ResourceType = "channel";
|
|
52
52
|
|
|
53
53
|
export const ontologyID = (key: Key): ontology.ID =>
|
|
54
|
-
new ontology.ID({ type:
|
|
54
|
+
new ontology.ID({ type: ONTOLOGY_TYPE, key: key.toString() });
|
package/src/framer/client.ts
CHANGED
|
@@ -24,6 +24,12 @@ import { Frame } from "@/framer/frame";
|
|
|
24
24
|
import { Iterator, IteratorConfig } from "@/framer/iterator";
|
|
25
25
|
import { Streamer, type StreamerConfig } from "@/framer/streamer";
|
|
26
26
|
import { Writer, type WriterConfig, WriterMode } from "@/framer/writer";
|
|
27
|
+
import { ontology } from "@/ontology";
|
|
28
|
+
|
|
29
|
+
export const ONTOLOGY_TYPE: ontology.ResourceType = "framer";
|
|
30
|
+
|
|
31
|
+
export const ontologyID = (key: Key): ontology.ID =>
|
|
32
|
+
new ontology.ID({ type: ONTOLOGY_TYPE, key: key.toString() });
|
|
27
33
|
|
|
28
34
|
export class Client {
|
|
29
35
|
private readonly streamClient: StreamClient;
|
|
@@ -93,7 +99,7 @@ export class Client {
|
|
|
93
99
|
|
|
94
100
|
async openStreamer(config: StreamerConfig | Params): Promise<Streamer> {
|
|
95
101
|
if (Array.isArray(config) || typeof config !== "object")
|
|
96
|
-
config = { channels: config as Params };
|
|
102
|
+
config = { channels: config as Params, downsampleFactor: 1 };
|
|
97
103
|
return await Streamer._open(this.retriever, this.streamClient, config);
|
|
98
104
|
}
|
|
99
105
|
|
package/src/framer/frame.spec.ts
CHANGED
|
@@ -75,19 +75,28 @@ describe("framer.Frame", () => {
|
|
|
75
75
|
expect(f.colType).toEqual("name");
|
|
76
76
|
});
|
|
77
77
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
dataType: new DataType("float32"),
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
78
|
+
describe("payload parsing", () => {
|
|
79
|
+
it("should correctly parse a series payload", () => {
|
|
80
|
+
const f = new framer.Frame({
|
|
81
|
+
keys: [12],
|
|
82
|
+
series: [
|
|
83
|
+
{ dataType: new DataType("float32"), data: new SharedArrayBuffer(12) },
|
|
84
|
+
],
|
|
85
|
+
});
|
|
86
|
+
expect(f.length.valueOf()).toEqual(3);
|
|
87
|
+
expect(f.columns.length).toEqual(1);
|
|
88
|
+
expect(f.series.length).toEqual(1);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("should correctly parse a series with null data", () => {
|
|
92
|
+
const f = new framer.Frame({
|
|
93
|
+
keys: [12],
|
|
94
|
+
series: [{ dataType: "float32", data: null }],
|
|
95
|
+
});
|
|
96
|
+
expect(f.length.valueOf()).toEqual(0);
|
|
97
|
+
expect(f.columns.length).toEqual(1);
|
|
98
|
+
expect(f.series.length).toEqual(1);
|
|
87
99
|
});
|
|
88
|
-
expect(f.length.valueOf()).toEqual(3);
|
|
89
|
-
expect(f.columns.length).toEqual(1);
|
|
90
|
-
expect(f.series.length).toEqual(1);
|
|
91
100
|
});
|
|
92
101
|
|
|
93
102
|
test("from record", () => {
|
package/src/framer/frame.ts
CHANGED
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
// included in the file licenses/APL.txt.
|
|
9
9
|
|
|
10
10
|
import {
|
|
11
|
-
DataType,
|
|
12
11
|
MultiSeries,
|
|
13
12
|
Series,
|
|
13
|
+
SeriesPayload,
|
|
14
14
|
Size,
|
|
15
15
|
type TelemValue,
|
|
16
16
|
TimeRange,
|
|
@@ -55,7 +55,7 @@ const validateMatchedColsAndSeries = (columns: Params, series: Series[]): void =
|
|
|
55
55
|
|
|
56
56
|
export type CrudeFrame =
|
|
57
57
|
| Frame
|
|
58
|
-
|
|
|
58
|
+
| CrudeFramePayload
|
|
59
59
|
| Map<KeyOrName, Series[] | Series>
|
|
60
60
|
| Record<KeyOrName, Series[] | Series>;
|
|
61
61
|
|
|
@@ -117,6 +117,8 @@ export class Frame {
|
|
|
117
117
|
if (isObject) {
|
|
118
118
|
if ("keys" in columnsOrData && "series" in columnsOrData) {
|
|
119
119
|
const data_ = columnsOrData as FramePayload;
|
|
120
|
+
data_.series ??= [];
|
|
121
|
+
data_.keys ??= [];
|
|
120
122
|
const series = data_.series.map((a) => seriesFromPayload(a));
|
|
121
123
|
validateMatchedColsAndSeries(data_.keys, series);
|
|
122
124
|
data_.keys.forEach((key, i) => this.push(key, series[i]));
|
|
@@ -396,37 +398,20 @@ export class Frame {
|
|
|
396
398
|
}
|
|
397
399
|
}
|
|
398
400
|
|
|
399
|
-
export const series = z.object({
|
|
400
|
-
timeRange: TimeRange.z.optional(),
|
|
401
|
-
alignment: z
|
|
402
|
-
.bigint()
|
|
403
|
-
.or(z.string().transform((s) => BigInt(s)))
|
|
404
|
-
.optional(),
|
|
405
|
-
dataType: DataType.z,
|
|
406
|
-
data: z.string().transform(
|
|
407
|
-
(s) =>
|
|
408
|
-
new Uint8Array(
|
|
409
|
-
atob(s)
|
|
410
|
-
.split("")
|
|
411
|
-
.map((c) => c.charCodeAt(0)),
|
|
412
|
-
).buffer,
|
|
413
|
-
),
|
|
414
|
-
});
|
|
415
|
-
|
|
416
|
-
export type SeriesPayload = z.infer<typeof series>;
|
|
417
|
-
|
|
418
401
|
export const frameZ = z.object({
|
|
419
402
|
keys: z.union([
|
|
420
403
|
z.null().transform(() => [] as number[]),
|
|
421
404
|
z.number().array().optional().default([]),
|
|
422
405
|
]),
|
|
423
406
|
series: z.union([
|
|
424
|
-
z.null().transform(() => [] as Array<z.infer<typeof
|
|
425
|
-
|
|
407
|
+
z.null().transform(() => [] as Array<z.infer<typeof Series.crudeZ>>),
|
|
408
|
+
Series.crudeZ.array().optional().default([]),
|
|
426
409
|
]),
|
|
427
410
|
});
|
|
428
411
|
|
|
429
|
-
export type FramePayload = z.
|
|
412
|
+
export type FramePayload = z.output<typeof frameZ>;
|
|
413
|
+
|
|
414
|
+
export type CrudeFramePayload = z.input<typeof frameZ>;
|
|
430
415
|
|
|
431
416
|
export const seriesFromPayload = (series: SeriesPayload): Series => {
|
|
432
417
|
const { dataType, data, timeRange, alignment } = series;
|
|
@@ -50,4 +50,52 @@ describe("Streamer", () => {
|
|
|
50
50
|
it("should throw an error when the streamer is opened with a channel that does not exist", async () => {
|
|
51
51
|
await expect(client.openStreamer([5678])).rejects.toThrow("not found");
|
|
52
52
|
});
|
|
53
|
+
test("downsample factor of 1", async () => {
|
|
54
|
+
const ch = await newChannel();
|
|
55
|
+
const streamer = await client.openStreamer({channels: ch.key, downsampleFactor: 1});
|
|
56
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
57
|
+
const writer = await client.openWriter({
|
|
58
|
+
start: TimeStamp.now(),
|
|
59
|
+
channels: ch.key,
|
|
60
|
+
});
|
|
61
|
+
try {
|
|
62
|
+
await writer.write(ch.key, new Float64Array([1, 2, 3, 4, 5]));
|
|
63
|
+
} finally {
|
|
64
|
+
await writer.close();
|
|
65
|
+
}
|
|
66
|
+
const d = await streamer.read();
|
|
67
|
+
expect(Array.from(d.get(ch.key))).toEqual([1, 2, 3, 4, 5]);
|
|
68
|
+
});
|
|
69
|
+
test("downsample factor of 2", async () => {
|
|
70
|
+
const ch = await newChannel();
|
|
71
|
+
const streamer = await client.openStreamer({channels: ch.key, downsampleFactor: 2});
|
|
72
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
73
|
+
const writer = await client.openWriter({
|
|
74
|
+
start: TimeStamp.now(),
|
|
75
|
+
channels: ch.key,
|
|
76
|
+
});
|
|
77
|
+
try {
|
|
78
|
+
await writer.write(ch.key, new Float64Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]));
|
|
79
|
+
} finally {
|
|
80
|
+
await writer.close();
|
|
81
|
+
}
|
|
82
|
+
const d = await streamer.read();
|
|
83
|
+
expect(Array.from(d.get(ch.key))).toEqual([1, 3, 5, 7, 9]);
|
|
84
|
+
});
|
|
85
|
+
test("downsample factor of 10", async () => {
|
|
86
|
+
const ch = await newChannel();
|
|
87
|
+
const streamer = await client.openStreamer({channels: ch.key, downsampleFactor: 10});
|
|
88
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
89
|
+
const writer = await client.openWriter({
|
|
90
|
+
start: TimeStamp.now(),
|
|
91
|
+
channels: ch.key,
|
|
92
|
+
});
|
|
93
|
+
try {
|
|
94
|
+
await writer.write(ch.key, new Float64Array([1, 2, 3, 4, 5, 6,7,8,9,10]));
|
|
95
|
+
} finally {
|
|
96
|
+
await writer.close();
|
|
97
|
+
}
|
|
98
|
+
const d = await streamer.read();
|
|
99
|
+
expect(Array.from(d.get(ch.key))).toEqual([1]);
|
|
100
|
+
});
|
|
53
101
|
});
|
package/src/framer/streamer.ts
CHANGED
|
@@ -17,7 +17,7 @@ import { ReadFrameAdapter } from "@/framer/adapter";
|
|
|
17
17
|
import { Frame, frameZ } from "@/framer/frame";
|
|
18
18
|
import { StreamProxy } from "@/framer/streamProxy";
|
|
19
19
|
|
|
20
|
-
const reqZ = z.object({ keys: z.number().array() });
|
|
20
|
+
const reqZ = z.object({ keys: z.number().array() , downsampleFactor: z.number() });
|
|
21
21
|
|
|
22
22
|
const resZ = z.object({
|
|
23
23
|
frame: frameZ,
|
|
@@ -28,11 +28,13 @@ const ENDPOINT = "/frame/stream";
|
|
|
28
28
|
|
|
29
29
|
export interface StreamerConfig {
|
|
30
30
|
channels: Params;
|
|
31
|
+
downsampleFactor?: number;
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
export class Streamer implements AsyncIterator<Frame>, AsyncIterable<Frame> {
|
|
34
35
|
private readonly stream: StreamProxy<typeof reqZ, typeof resZ>;
|
|
35
36
|
private readonly adapter: ReadFrameAdapter;
|
|
37
|
+
private readonly downsampleFactor: number;
|
|
36
38
|
|
|
37
39
|
private constructor(
|
|
38
40
|
stream: Stream<typeof reqZ, typeof resZ>,
|
|
@@ -40,6 +42,7 @@ export class Streamer implements AsyncIterator<Frame>, AsyncIterable<Frame> {
|
|
|
40
42
|
) {
|
|
41
43
|
this.stream = new StreamProxy("Streamer", stream);
|
|
42
44
|
this.adapter = adapter;
|
|
45
|
+
this.downsampleFactor = 1;
|
|
43
46
|
}
|
|
44
47
|
|
|
45
48
|
get keys(): Key[] {
|
|
@@ -49,12 +52,12 @@ export class Streamer implements AsyncIterator<Frame>, AsyncIterable<Frame> {
|
|
|
49
52
|
static async _open(
|
|
50
53
|
retriever: Retriever,
|
|
51
54
|
client: StreamClient,
|
|
52
|
-
{ channels }: StreamerConfig,
|
|
55
|
+
{ channels, downsampleFactor }: StreamerConfig,
|
|
53
56
|
): Promise<Streamer> {
|
|
54
57
|
const adapter = await ReadFrameAdapter.open(retriever, channels);
|
|
55
58
|
const stream = await client.stream(ENDPOINT, reqZ, resZ);
|
|
56
59
|
const streamer = new Streamer(stream, adapter);
|
|
57
|
-
stream.send({ keys: adapter.keys });
|
|
60
|
+
stream.send({ keys: adapter.keys, downsampleFactor: downsampleFactor ?? 1 });
|
|
58
61
|
const [, err] = await stream.receive();
|
|
59
62
|
if (err != null) throw err;
|
|
60
63
|
return streamer;
|
|
@@ -76,7 +79,7 @@ export class Streamer implements AsyncIterator<Frame>, AsyncIterable<Frame> {
|
|
|
76
79
|
|
|
77
80
|
async update(channels: Params): Promise<void> {
|
|
78
81
|
await this.adapter.update(channels);
|
|
79
|
-
this.stream.send({ keys: this.adapter.keys });
|
|
82
|
+
this.stream.send({ keys: this.adapter.keys, downsampleFactor: this.downsampleFactor });
|
|
80
83
|
}
|
|
81
84
|
|
|
82
85
|
close(): void {
|
package/src/framer/writer.ts
CHANGED
|
@@ -231,7 +231,6 @@ export class Writer {
|
|
|
231
231
|
series?: CrudeSeries | CrudeSeries[],
|
|
232
232
|
): Promise<boolean> {
|
|
233
233
|
const frame = await this.adapter.adapt(channelsOrData, series);
|
|
234
|
-
// @ts-expect-error - zod issues
|
|
235
234
|
this.stream.send({ command: Command.Write, frame: frame.toPayload() });
|
|
236
235
|
return true;
|
|
237
236
|
}
|
|
@@ -298,7 +297,6 @@ export class Writer {
|
|
|
298
297
|
}
|
|
299
298
|
|
|
300
299
|
async execute(req: Request): Promise<Response> {
|
|
301
|
-
// @ts-expect-error - frame payload adjustments
|
|
302
300
|
this.stream.send(req);
|
|
303
301
|
while (true) {
|
|
304
302
|
const res = await this.stream.receive();
|
|
@@ -47,7 +47,7 @@ export type NewDevice<P extends UnknownRecord = UnknownRecord> = Omit<
|
|
|
47
47
|
"properties"
|
|
48
48
|
> & { properties: P };
|
|
49
49
|
|
|
50
|
-
export const
|
|
50
|
+
export const ONTOLOGY_TYPE: ontology.ResourceType = "device";
|
|
51
51
|
|
|
52
52
|
export const ontologyID = (key: DeviceKey): ontology.ID =>
|
|
53
|
-
new ontology.ID({ type:
|
|
53
|
+
new ontology.ID({ type: ONTOLOGY_TYPE, key: key.toString() });
|
|
@@ -26,7 +26,7 @@ export const newRackZ = rackZ.partial({ key: true });
|
|
|
26
26
|
|
|
27
27
|
export type NewRack = z.input<typeof newRackZ>;
|
|
28
28
|
|
|
29
|
-
export const
|
|
29
|
+
export const ONTOLOGY_TYPE: ontology.ResourceType = "rack";
|
|
30
30
|
|
|
31
31
|
export const ontologyID = (key: RackKey): ontology.ID =>
|
|
32
|
-
new ontology.ID({ type:
|
|
32
|
+
new ontology.ID({ type: ONTOLOGY_TYPE, key: key.toString() });
|
|
@@ -96,7 +96,7 @@ export const commandZ = z.object({
|
|
|
96
96
|
export type StateObservable<D extends UnknownRecord = UnknownRecord> =
|
|
97
97
|
observe.ObservableAsyncCloseable<State<D>>;
|
|
98
98
|
|
|
99
|
-
export const
|
|
99
|
+
export const ONTOLOGY_TYPE: ontology.ResourceType = "task";
|
|
100
100
|
|
|
101
101
|
export const ontologyID = (key: TaskKey): ontology.ID =>
|
|
102
|
-
new ontology.ID({ type:
|
|
102
|
+
new ontology.ID({ type: ONTOLOGY_TYPE, key: key.toString() });
|
package/src/index.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
|
+
export { access } from "@/access";
|
|
11
|
+
export { policy } from "@/access/policy";
|
|
10
12
|
export * from "@/channel";
|
|
11
13
|
export { Channel } from "@/channel/client";
|
|
12
14
|
export { default as Synnax, type SynnaxProps, synnaxPropsZ } from "@/client";
|
|
@@ -32,29 +34,30 @@ export { label } from "@/label";
|
|
|
32
34
|
export { ontology } from "@/ontology";
|
|
33
35
|
export { ranger } from "@/ranger";
|
|
34
36
|
export { signals } from "@/signals";
|
|
37
|
+
export { user } from "@/user";
|
|
35
38
|
export { workspace } from "@/workspace";
|
|
36
|
-
export
|
|
37
|
-
|
|
38
|
-
CrudeDensity,
|
|
39
|
-
CrudeRate,
|
|
40
|
-
CrudeSize,
|
|
41
|
-
CrudeTimeSpan,
|
|
42
|
-
CrudeTimeStamp,
|
|
43
|
-
NumericTelemValue,
|
|
44
|
-
TelemValue,
|
|
45
|
-
TimeStampStringFormat,
|
|
46
|
-
TypedArray,
|
|
47
|
-
TZInfo,
|
|
48
|
-
} from "@synnaxlabs/x/telem";
|
|
39
|
+
export { linePlot } from "@/workspace/lineplot";
|
|
40
|
+
export { schematic } from "@/workspace/schematic";
|
|
49
41
|
export {
|
|
42
|
+
type CrudeDataType,
|
|
43
|
+
type CrudeDensity,
|
|
44
|
+
type CrudeRate,
|
|
45
|
+
type CrudeSize,
|
|
46
|
+
type CrudeTimeSpan,
|
|
47
|
+
type CrudeTimeStamp,
|
|
50
48
|
DataType,
|
|
51
49
|
Density,
|
|
52
50
|
MultiSeries,
|
|
51
|
+
type NumericTelemValue,
|
|
53
52
|
Rate,
|
|
54
53
|
Series,
|
|
54
|
+
type TelemValue,
|
|
55
55
|
TimeRange,
|
|
56
56
|
TimeSpan,
|
|
57
57
|
TimeStamp,
|
|
58
|
+
type TimeStampStringFormat,
|
|
59
|
+
type TypedArray,
|
|
60
|
+
type TZInfo,
|
|
58
61
|
} from "@synnaxlabs/x/telem";
|
|
59
62
|
import { control } from "@synnaxlabs/x";
|
|
60
63
|
export const Authority = control.Authority;
|
package/src/label/payload.ts
CHANGED
|
@@ -25,7 +25,7 @@ export const labelZ = z.object({
|
|
|
25
25
|
|
|
26
26
|
export type Label = z.infer<typeof labelZ>;
|
|
27
27
|
|
|
28
|
-
export const
|
|
28
|
+
export const ONTOLOGY_TYPE: ontology.ResourceType = "label";
|
|
29
29
|
|
|
30
30
|
export const ontologyID = (key: Key): ontology.ID =>
|
|
31
|
-
new ontology.ID({ type:
|
|
31
|
+
new ontology.ID({ type: ONTOLOGY_TYPE, key });
|
package/src/ontology/client.ts
CHANGED
|
@@ -13,19 +13,18 @@ import { type AsyncTermSearcher } from "@synnaxlabs/x/search";
|
|
|
13
13
|
import { z } from "zod";
|
|
14
14
|
|
|
15
15
|
import { QueryError } from "@/errors";
|
|
16
|
-
import { framer } from "@/framer";
|
|
17
|
-
import { Frame } from "@/framer/frame";
|
|
16
|
+
import { type framer } from "@/framer";
|
|
18
17
|
import { group } from "@/ontology/group";
|
|
19
18
|
import {
|
|
20
|
-
CrudeID,
|
|
19
|
+
type CrudeID,
|
|
21
20
|
ID,
|
|
22
|
-
IDPayload,
|
|
21
|
+
type IDPayload,
|
|
23
22
|
idZ,
|
|
24
23
|
parseRelationship,
|
|
25
|
-
RelationshipChange,
|
|
26
|
-
RelationshipDirection,
|
|
24
|
+
type RelationshipChange,
|
|
25
|
+
type RelationshipDirection,
|
|
27
26
|
type Resource,
|
|
28
|
-
ResourceChange,
|
|
27
|
+
type ResourceChange,
|
|
29
28
|
resourceSchemaZ,
|
|
30
29
|
resourceTypeZ,
|
|
31
30
|
} from "@/ontology/payload";
|
|
@@ -92,12 +91,12 @@ export class Client implements AsyncTermSearcher<string, string, Resource> {
|
|
|
92
91
|
|
|
93
92
|
/**
|
|
94
93
|
* Retrieves the resource in the ontology with the given ID.
|
|
95
|
-
* @param id The ID of the resource to retrieve.
|
|
96
|
-
* @param options Additional options for the retrieval.
|
|
97
|
-
* @param options.includeSchema Whether to include the schema of the resource in the
|
|
94
|
+
* @param id - The ID of the resource to retrieve.
|
|
95
|
+
* @param options - Additional options for the retrieval.
|
|
96
|
+
* @param options.includeSchema - Whether to include the schema of the resource in the
|
|
98
97
|
* results.
|
|
99
|
-
* @param options.excludeFieldData Whether to exclude the field data of the resource
|
|
100
|
-
* the results.
|
|
98
|
+
* @param options.excludeFieldData - Whether to exclude the field data of the resource
|
|
99
|
+
* in the results.
|
|
101
100
|
* @returns The resource with the given ID.
|
|
102
101
|
* @throws {QueryError} If no resource is found with the given ID.
|
|
103
102
|
*/
|
|
@@ -105,12 +104,13 @@ export class Client implements AsyncTermSearcher<string, string, Resource> {
|
|
|
105
104
|
|
|
106
105
|
/**
|
|
107
106
|
* Retrieves the resources in the ontology with the given IDs.
|
|
108
|
-
*
|
|
109
|
-
* @param
|
|
110
|
-
* @param options
|
|
111
|
-
*
|
|
112
|
-
* @param options.excludeFieldData Whether to exclude the field data of the resources in
|
|
107
|
+
*
|
|
108
|
+
* @param ids - The IDs of the resources to retrieve.
|
|
109
|
+
* @param options - Additional options for the retrieval.
|
|
110
|
+
* @param options.includeSchema - Whether to include the schema of the resources in
|
|
113
111
|
* the results.
|
|
112
|
+
* @param options.excludeFieldData - Whether to exclude the field data of the
|
|
113
|
+
* resources in the results.
|
|
114
114
|
* @returns The resources with the given IDs.
|
|
115
115
|
* @throws {QueryError} If no resource is found with any of the given IDs.
|
|
116
116
|
*/
|
|
@@ -164,10 +164,12 @@ export class Client implements AsyncTermSearcher<string, string, Resource> {
|
|
|
164
164
|
/**
|
|
165
165
|
* Retrieves the parents of the resources with the given IDs.
|
|
166
166
|
*
|
|
167
|
-
* @param ids the IDs of the resources whose parents to retrieve
|
|
168
|
-
* @param options additional options for the retrieval
|
|
169
|
-
* @param options.includeSchema whether to include the schema of the parents in the
|
|
170
|
-
*
|
|
167
|
+
* @param ids - the IDs of the resources whose parents to retrieve
|
|
168
|
+
* @param options - additional options for the retrieval
|
|
169
|
+
* @param options.includeSchema - whether to include the schema of the parents in the
|
|
170
|
+
* results
|
|
171
|
+
* @param options.excludeFieldData - whether to exclude the field data of the parents
|
|
172
|
+
* in the results
|
|
171
173
|
* @returns the parents of the resources with the given IDs
|
|
172
174
|
*/
|
|
173
175
|
async retrieveParents(
|
|
@@ -179,8 +181,8 @@ export class Client implements AsyncTermSearcher<string, string, Resource> {
|
|
|
179
181
|
|
|
180
182
|
/**
|
|
181
183
|
* Adds children to a resource in the ontology.
|
|
182
|
-
* @param id The ID of the resource to add children to.
|
|
183
|
-
* @param children The IDs of the children to add.
|
|
184
|
+
* @param id - The ID of the resource to add children to.
|
|
185
|
+
* @param children - The IDs of the children to add.
|
|
184
186
|
*/
|
|
185
187
|
async addChildren(id: CrudeID, ...children: CrudeID[]): Promise<void> {
|
|
186
188
|
return await this.writer.addChildren(id, ...children);
|
|
@@ -188,9 +190,8 @@ export class Client implements AsyncTermSearcher<string, string, Resource> {
|
|
|
188
190
|
|
|
189
191
|
/**
|
|
190
192
|
* Removes children from a resource in the ontology.
|
|
191
|
-
* @param id The ID of the resource to remove children from.
|
|
192
|
-
* @param children The IDs of the children
|
|
193
|
-
* to remove.
|
|
193
|
+
* @param id - The ID of the resource to remove children from.
|
|
194
|
+
* @param children - The IDs of the children to remove.
|
|
194
195
|
*/
|
|
195
196
|
async removeChildren(id: CrudeID, ...children: CrudeID[]): Promise<void> {
|
|
196
197
|
return await this.writer.removeChildren(id, ...children);
|
|
@@ -198,9 +199,9 @@ export class Client implements AsyncTermSearcher<string, string, Resource> {
|
|
|
198
199
|
|
|
199
200
|
/**
|
|
200
201
|
* Moves children from one resource to another in the ontology.
|
|
201
|
-
* @param from The ID of the resource to move children from.
|
|
202
|
-
* @param to The ID of the resource to move children to.
|
|
203
|
-
* @param children The IDs of the children to move.
|
|
202
|
+
* @param from - The ID of the resource to move children from.
|
|
203
|
+
* @param to - The ID of the resource to move children to.
|
|
204
|
+
* @param children - The IDs of the children to move.
|
|
204
205
|
*/
|
|
205
206
|
async moveChildren(
|
|
206
207
|
from: CrudeID,
|
|
@@ -294,7 +295,7 @@ export class ChangeTracker {
|
|
|
294
295
|
}
|
|
295
296
|
}
|
|
296
297
|
|
|
297
|
-
private async update(frame: Frame): Promise<void> {
|
|
298
|
+
private async update(frame: framer.Frame): Promise<void> {
|
|
298
299
|
const resSets = await this.parseResourceSets(frame);
|
|
299
300
|
const resDeletes = this.parseResourceDeletes(frame);
|
|
300
301
|
const allResources = resSets.concat(resDeletes);
|
|
@@ -306,7 +307,7 @@ export class ChangeTracker {
|
|
|
306
307
|
this.relationshipObs.notify(relSets.concat(relDeletes));
|
|
307
308
|
}
|
|
308
309
|
|
|
309
|
-
private parseRelationshipSets(frame: Frame): RelationshipChange[] {
|
|
310
|
+
private parseRelationshipSets(frame: framer.Frame): RelationshipChange[] {
|
|
310
311
|
const relationships = frame.get(RELATIONSHIP_SET_NAME);
|
|
311
312
|
if (relationships.length === 0) return [];
|
|
312
313
|
return Array.from(relationships.as("string")).map((rel) => ({
|
|
@@ -316,7 +317,7 @@ export class ChangeTracker {
|
|
|
316
317
|
}));
|
|
317
318
|
}
|
|
318
319
|
|
|
319
|
-
private parseRelationshipDeletes(frame: Frame): RelationshipChange[] {
|
|
320
|
+
private parseRelationshipDeletes(frame: framer.Frame): RelationshipChange[] {
|
|
320
321
|
const relationships = frame.get(RELATIONSHIP_DELETE_NAME);
|
|
321
322
|
if (relationships.length === 0) return [];
|
|
322
323
|
return Array.from(relationships.as("string")).map((rel) => ({
|
|
@@ -325,7 +326,7 @@ export class ChangeTracker {
|
|
|
325
326
|
}));
|
|
326
327
|
}
|
|
327
328
|
|
|
328
|
-
private async parseResourceSets(frame: Frame): Promise<ResourceChange[]> {
|
|
329
|
+
private async parseResourceSets(frame: framer.Frame): Promise<ResourceChange[]> {
|
|
329
330
|
const sets = frame.get(RESOURCE_SET_NAME);
|
|
330
331
|
if (sets.length === 0) return [];
|
|
331
332
|
// We should only ever get one series of sets
|
|
@@ -343,7 +344,7 @@ export class ChangeTracker {
|
|
|
343
344
|
}
|
|
344
345
|
}
|
|
345
346
|
|
|
346
|
-
private parseResourceDeletes(frame: Frame): ResourceChange[] {
|
|
347
|
+
private parseResourceDeletes(frame: framer.Frame): ResourceChange[] {
|
|
347
348
|
const deletes = frame.get(RESOURCE_DELETE_NAME);
|
|
348
349
|
if (deletes.length === 0) return [];
|
|
349
350
|
// We should only ever get one series of deletes
|