@synnaxlabs/client 0.43.1 → 0.44.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/.turbo/turbo-build.log +7 -7
- package/dist/access/payload.d.ts +1 -1
- package/dist/access/payload.d.ts.map +1 -1
- package/dist/access/policy/client.d.ts +263 -6
- package/dist/access/policy/client.d.ts.map +1 -1
- package/dist/access/policy/external.d.ts +0 -1
- package/dist/access/policy/external.d.ts.map +1 -1
- package/dist/access/policy/payload.d.ts +105 -93
- package/dist/access/policy/payload.d.ts.map +1 -1
- package/dist/auth/auth.d.ts +1 -1
- package/dist/auth/auth.d.ts.map +1 -1
- package/dist/channel/client.d.ts +23 -17
- package/dist/channel/client.d.ts.map +1 -1
- package/dist/channel/payload.d.ts +151 -21
- package/dist/channel/payload.d.ts.map +1 -1
- package/dist/channel/retriever.d.ts +9 -16
- package/dist/channel/retriever.d.ts.map +1 -1
- package/dist/channel/writer.d.ts +1 -1
- package/dist/channel/writer.d.ts.map +1 -1
- package/dist/client.cjs +27 -135
- package/dist/client.d.ts +3 -3
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +8657 -28963
- package/dist/connection/checker.d.ts +1 -1
- package/dist/connection/checker.d.ts.map +1 -1
- package/dist/control/client.d.ts +1 -0
- package/dist/control/client.d.ts.map +1 -1
- package/dist/control/state.d.ts +6 -6
- package/dist/control/state.d.ts.map +1 -1
- package/dist/errors.d.ts +18 -5
- package/dist/errors.d.ts.map +1 -1
- package/dist/framer/adapter.d.ts +3 -3
- package/dist/framer/adapter.d.ts.map +1 -1
- package/dist/framer/client.d.ts +4 -13
- package/dist/framer/client.d.ts.map +1 -1
- package/dist/framer/codec.d.ts +1 -1
- package/dist/framer/codec.d.ts.map +1 -1
- package/dist/framer/deleter.d.ts +5 -5
- package/dist/framer/deleter.d.ts.map +1 -1
- package/dist/framer/frame.d.ts +5 -7
- package/dist/framer/frame.d.ts.map +1 -1
- package/dist/framer/streamProxy.d.ts +1 -1
- package/dist/framer/streamProxy.d.ts.map +1 -1
- package/dist/framer/streamer.d.ts +235 -20
- package/dist/framer/streamer.d.ts.map +1 -1
- package/dist/framer/writer.d.ts +302 -33
- package/dist/framer/writer.d.ts.map +1 -1
- package/dist/hardware/device/client.d.ts +49 -28
- package/dist/hardware/device/client.d.ts.map +1 -1
- package/dist/hardware/device/payload.d.ts +126 -46
- package/dist/hardware/device/payload.d.ts.map +1 -1
- package/dist/hardware/rack/client.d.ts +78 -22
- package/dist/hardware/rack/client.d.ts.map +1 -1
- package/dist/hardware/rack/payload.d.ts +99 -56
- package/dist/hardware/rack/payload.d.ts.map +1 -1
- package/dist/hardware/task/client.d.ts +100 -41
- package/dist/hardware/task/client.d.ts.map +1 -1
- package/dist/hardware/task/payload.d.ts +83 -61
- package/dist/hardware/task/payload.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/label/client.d.ts +138 -20
- package/dist/label/client.d.ts.map +1 -1
- package/dist/label/external.d.ts +0 -2
- package/dist/label/external.d.ts.map +1 -1
- package/dist/label/payload.d.ts +4 -5
- package/dist/label/payload.d.ts.map +1 -1
- package/dist/ontology/client.d.ts +45 -135
- package/dist/ontology/client.d.ts.map +1 -1
- package/dist/ontology/group/group.d.ts +3 -3
- package/dist/ontology/group/group.d.ts.map +1 -1
- package/dist/ontology/group/payload.d.ts +3 -27
- package/dist/ontology/group/payload.d.ts.map +1 -1
- package/dist/ontology/payload.d.ts +114 -243
- package/dist/ontology/payload.d.ts.map +1 -1
- package/dist/ontology/writer.d.ts +4 -4
- package/dist/ontology/writer.d.ts.map +1 -1
- package/dist/ranger/alias.d.ts +15 -5
- package/dist/ranger/alias.d.ts.map +1 -1
- package/dist/ranger/client.d.ts +91 -30
- package/dist/ranger/client.d.ts.map +1 -1
- package/dist/ranger/external.d.ts +1 -1
- package/dist/ranger/external.d.ts.map +1 -1
- package/dist/ranger/kv.d.ts +11 -12
- package/dist/ranger/kv.d.ts.map +1 -1
- package/dist/ranger/payload.d.ts +19 -44
- package/dist/ranger/payload.d.ts.map +1 -1
- package/dist/ranger/writer.d.ts +22 -19
- package/dist/ranger/writer.d.ts.map +1 -1
- package/dist/testutil/client.d.ts +4 -0
- package/dist/testutil/client.d.ts.map +1 -0
- package/dist/user/client.d.ts +59 -6
- package/dist/user/client.d.ts.map +1 -1
- package/dist/user/payload.d.ts +4 -6
- package/dist/user/payload.d.ts.map +1 -1
- package/dist/user/retriever.d.ts +2 -2
- package/dist/user/retriever.d.ts.map +1 -1
- package/dist/util/decodeJSONString.d.ts +2 -2
- package/dist/util/decodeJSONString.d.ts.map +1 -1
- package/dist/util/parseWithoutKeyConversion.d.ts +2 -2
- package/dist/util/parseWithoutKeyConversion.d.ts.map +1 -1
- package/dist/util/retrieve.d.ts +1 -1
- package/dist/util/retrieve.d.ts.map +1 -1
- package/dist/util/zod.d.ts +1 -1
- package/dist/util/zod.d.ts.map +1 -1
- package/dist/workspace/client.d.ts +17 -6
- package/dist/workspace/client.d.ts.map +1 -1
- package/dist/workspace/lineplot/client.d.ts +2 -2
- package/dist/workspace/lineplot/client.d.ts.map +1 -1
- package/dist/workspace/lineplot/payload.d.ts +8 -9
- package/dist/workspace/lineplot/payload.d.ts.map +1 -1
- package/dist/workspace/log/client.d.ts +2 -2
- package/dist/workspace/log/client.d.ts.map +1 -1
- package/dist/workspace/log/payload.d.ts +8 -9
- package/dist/workspace/log/payload.d.ts.map +1 -1
- package/dist/workspace/payload.d.ts +10 -11
- package/dist/workspace/payload.d.ts.map +1 -1
- package/dist/workspace/schematic/client.d.ts +2 -2
- package/dist/workspace/schematic/client.d.ts.map +1 -1
- package/dist/workspace/schematic/payload.d.ts +10 -11
- package/dist/workspace/schematic/payload.d.ts.map +1 -1
- package/dist/workspace/table/client.d.ts +2 -2
- package/dist/workspace/table/client.d.ts.map +1 -1
- package/dist/workspace/table/payload.d.ts +10 -11
- package/dist/workspace/table/payload.d.ts.map +1 -1
- package/examples/node/package-lock.json +47 -39
- package/examples/node/package.json +2 -1
- package/examples/node/streamWrite.js +5 -11
- package/package.json +14 -13
- package/src/access/payload.ts +1 -1
- package/src/access/policy/client.ts +87 -32
- package/src/access/policy/external.ts +0 -1
- package/src/access/policy/payload.ts +4 -4
- package/src/access/policy/policy.spec.ts +86 -83
- package/src/auth/auth.spec.ts +29 -18
- package/src/auth/auth.ts +1 -1
- package/src/channel/batchRetriever.spec.ts +4 -9
- package/src/channel/channel.spec.ts +24 -6
- package/src/channel/client.ts +52 -51
- package/src/channel/payload.ts +15 -16
- package/src/channel/retriever.ts +26 -41
- package/src/channel/writer.ts +7 -4
- package/src/client.ts +4 -4
- package/src/connection/checker.ts +1 -1
- package/src/connection/connection.spec.ts +31 -23
- package/src/control/client.ts +2 -2
- package/src/control/state.spec.ts +3 -3
- package/src/control/state.ts +1 -1
- package/src/errors.spec.ts +9 -5
- package/src/errors.ts +28 -15
- package/src/framer/adapter.spec.ts +118 -9
- package/src/framer/adapter.ts +24 -11
- package/src/framer/client.spec.ts +125 -2
- package/src/framer/client.ts +41 -47
- package/src/framer/codec.ts +1 -1
- package/src/framer/deleter.spec.ts +2 -2
- package/src/framer/deleter.ts +1 -1
- package/src/framer/frame.ts +1 -4
- package/src/framer/iterator.spec.ts +8 -8
- package/src/framer/iterator.ts +1 -1
- package/src/framer/streamProxy.ts +1 -1
- package/src/framer/streamer.spec.ts +185 -36
- package/src/framer/streamer.ts +28 -36
- package/src/framer/writer.spec.ts +7 -6
- package/src/framer/writer.ts +97 -111
- package/src/hardware/device/client.ts +45 -131
- package/src/hardware/device/device.spec.ts +163 -52
- package/src/hardware/device/payload.ts +10 -21
- package/src/hardware/rack/client.ts +87 -105
- package/src/hardware/rack/payload.ts +4 -13
- package/src/hardware/rack/rack.spec.ts +28 -35
- package/src/hardware/task/client.ts +335 -291
- package/src/hardware/task/payload.ts +86 -62
- package/src/hardware/task/task.spec.ts +208 -32
- package/src/index.ts +2 -1
- package/src/label/client.ts +100 -95
- package/src/label/external.ts +0 -2
- package/src/label/label.spec.ts +8 -6
- package/src/label/payload.ts +3 -4
- package/src/ontology/client.ts +41 -324
- package/src/ontology/group/group.spec.ts +2 -2
- package/src/ontology/group/group.ts +4 -5
- package/src/ontology/group/payload.ts +2 -25
- package/src/ontology/group/writer.ts +1 -1
- package/src/ontology/ontology.spec.ts +355 -41
- package/src/ontology/payload.ts +77 -112
- package/src/ontology/writer.ts +8 -17
- package/src/ranger/alias.ts +45 -37
- package/src/ranger/client.ts +144 -149
- package/src/ranger/external.ts +1 -1
- package/src/ranger/kv.ts +9 -27
- package/src/ranger/payload.ts +23 -37
- package/src/ranger/ranger.spec.ts +37 -56
- package/src/ranger/writer.ts +1 -1
- package/src/{signals/index.ts → testutil/client.ts} +11 -1
- package/src/user/client.ts +122 -47
- package/src/user/payload.ts +2 -5
- package/src/user/retriever.ts +1 -1
- package/src/user/user.spec.ts +31 -31
- package/src/user/writer.ts +1 -1
- package/src/util/decodeJSONString.ts +3 -3
- package/src/util/parseWithoutKeyConversion.ts +2 -2
- package/src/util/retrieve.ts +1 -1
- package/src/util/zod.ts +1 -1
- package/src/workspace/client.ts +20 -36
- package/src/workspace/lineplot/client.ts +5 -7
- package/src/workspace/lineplot/lineplot.spec.ts +2 -2
- package/src/workspace/lineplot/payload.ts +4 -7
- package/src/workspace/log/client.ts +5 -7
- package/src/workspace/log/log.spec.ts +2 -2
- package/src/workspace/log/payload.ts +4 -7
- package/src/workspace/payload.ts +4 -7
- package/src/workspace/schematic/client.ts +5 -7
- package/src/workspace/schematic/payload.ts +4 -7
- package/src/workspace/schematic/schematic.spec.ts +2 -2
- package/src/workspace/table/client.ts +5 -7
- package/src/workspace/table/payload.ts +4 -7
- package/src/workspace/table/table.spec.ts +2 -2
- package/src/workspace/workspace.spec.ts +2 -2
- package/dist/access/policy/ontology.d.ts +0 -5
- package/dist/access/policy/ontology.d.ts.map +0 -1
- package/dist/access/policy/retriever.d.ts +0 -40
- package/dist/access/policy/retriever.d.ts.map +0 -1
- package/dist/access/policy/writer.d.ts +0 -9
- package/dist/access/policy/writer.d.ts.map +0 -1
- package/dist/label/retriever.d.ts +0 -14
- package/dist/label/retriever.d.ts.map +0 -1
- package/dist/label/writer.d.ts +0 -54
- package/dist/label/writer.d.ts.map +0 -1
- package/dist/setupspecs.d.ts +0 -5
- package/dist/setupspecs.d.ts.map +0 -1
- package/dist/signals/external.d.ts +0 -2
- package/dist/signals/external.d.ts.map +0 -1
- package/dist/signals/index.d.ts +0 -2
- package/dist/signals/index.d.ts.map +0 -1
- package/dist/signals/observable.d.ts +0 -12
- package/dist/signals/observable.d.ts.map +0 -1
- package/src/access/policy/ontology.ts +0 -17
- package/src/access/policy/retriever.ts +0 -44
- package/src/access/policy/writer.ts +0 -65
- package/src/label/retriever.ts +0 -63
- package/src/label/writer.ts +0 -95
- package/src/setupspecs.ts +0 -27
- package/src/signals/external.ts +0 -10
- package/src/signals/observable.ts +0 -42
|
@@ -7,13 +7,12 @@
|
|
|
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 { id,
|
|
11
|
-
import { describe, expect, it } from "vitest";
|
|
10
|
+
import { id, unique } from "@synnaxlabs/x";
|
|
11
|
+
import { beforeAll, describe, expect, it } from "vitest";
|
|
12
12
|
|
|
13
|
-
import {
|
|
14
|
-
import { newClient } from "@/setupspecs";
|
|
13
|
+
import { createTestClient } from "@/testutil/client";
|
|
15
14
|
|
|
16
|
-
const client =
|
|
15
|
+
const client = createTestClient();
|
|
17
16
|
|
|
18
17
|
describe("Device", async () => {
|
|
19
18
|
const testRack = await client.hardware.racks.create({ name: "test" });
|
|
@@ -50,7 +49,8 @@ describe("Device", async () => {
|
|
|
50
49
|
model: "dog",
|
|
51
50
|
properties,
|
|
52
51
|
});
|
|
53
|
-
const retrieved = await client.hardware.devices.retrieve(d.key);
|
|
52
|
+
const retrieved = await client.hardware.devices.retrieve({ key: d.key });
|
|
53
|
+
expect(retrieved.key).toEqual(d.key);
|
|
54
54
|
expect(retrieved.properties).toEqual(properties);
|
|
55
55
|
});
|
|
56
56
|
describe("retrieve", () => {
|
|
@@ -64,7 +64,7 @@ describe("Device", async () => {
|
|
|
64
64
|
model: "dog",
|
|
65
65
|
properties: { cat: "dog" },
|
|
66
66
|
});
|
|
67
|
-
const retrieved = await client.hardware.devices.retrieve(d.key);
|
|
67
|
+
const retrieved = await client.hardware.devices.retrieve({ key: d.key });
|
|
68
68
|
expect(retrieved.key).toBe(d.key);
|
|
69
69
|
expect(retrieved.name).toBe("test");
|
|
70
70
|
expect(retrieved.make).toBe("ni");
|
|
@@ -88,27 +88,13 @@ describe("Device", async () => {
|
|
|
88
88
|
model: "dog",
|
|
89
89
|
properties: { cat: "dog" },
|
|
90
90
|
});
|
|
91
|
-
const retrieved = await client.hardware.devices.retrieve(
|
|
91
|
+
const retrieved = await client.hardware.devices.retrieve({
|
|
92
|
+
keys: [d1.key, d2.key],
|
|
93
|
+
});
|
|
92
94
|
expect(retrieved.length).toBe(2);
|
|
93
95
|
expect(retrieved[0].key).toBe(d1.key);
|
|
94
96
|
expect(retrieved[1].key).toBe(d2.key);
|
|
95
97
|
});
|
|
96
|
-
it("should handle ignoreNotFound option", async () => {
|
|
97
|
-
// Test multiple device retrieval
|
|
98
|
-
const results = await client.hardware.devices.retrieve(
|
|
99
|
-
["nonexistent_key1", "nonexistent_key2"],
|
|
100
|
-
{ ignoreNotFound: true },
|
|
101
|
-
);
|
|
102
|
-
expect(results).toEqual([]);
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
it("should throw an error when device not found and ignoreNotFound is false", async () => {
|
|
106
|
-
await expect(
|
|
107
|
-
client.hardware.devices.retrieve(["nonexistent_key"], {
|
|
108
|
-
ignoreNotFound: false,
|
|
109
|
-
}),
|
|
110
|
-
).rejects.toThrow(NotFoundError);
|
|
111
|
-
});
|
|
112
98
|
|
|
113
99
|
describe("state", () => {
|
|
114
100
|
it("should not include state by default", async () => {
|
|
@@ -122,11 +108,11 @@ describe("Device", async () => {
|
|
|
122
108
|
properties: { cat: "dog" },
|
|
123
109
|
});
|
|
124
110
|
|
|
125
|
-
const retrieved = await client.hardware.devices.retrieve(d.key);
|
|
126
|
-
expect(retrieved.
|
|
111
|
+
const retrieved = await client.hardware.devices.retrieve({ key: d.key });
|
|
112
|
+
expect(retrieved.status).toBeUndefined();
|
|
127
113
|
});
|
|
128
114
|
|
|
129
|
-
it("should include
|
|
115
|
+
it("should include status when includeStatus is true", async () => {
|
|
130
116
|
const d = await client.hardware.devices.create({
|
|
131
117
|
key: id.create(),
|
|
132
118
|
rack: testRack.key,
|
|
@@ -139,12 +125,13 @@ describe("Device", async () => {
|
|
|
139
125
|
|
|
140
126
|
await expect
|
|
141
127
|
.poll(async () => {
|
|
142
|
-
const {
|
|
143
|
-
|
|
128
|
+
const { status } = await client.hardware.devices.retrieve({
|
|
129
|
+
key: d.key,
|
|
130
|
+
includeStatus: true,
|
|
144
131
|
});
|
|
145
|
-
return
|
|
132
|
+
return status != null;
|
|
146
133
|
})
|
|
147
|
-
.
|
|
134
|
+
.toBe(true);
|
|
148
135
|
});
|
|
149
136
|
|
|
150
137
|
it("should include state for multiple devices", async () => {
|
|
@@ -170,22 +157,17 @@ describe("Device", async () => {
|
|
|
170
157
|
|
|
171
158
|
await expect
|
|
172
159
|
.poll(async () => {
|
|
173
|
-
const retrievedDevices = await client.hardware.devices.retrieve(
|
|
174
|
-
[d1.key, d2.key],
|
|
175
|
-
|
|
176
|
-
);
|
|
160
|
+
const retrievedDevices = await client.hardware.devices.retrieve({
|
|
161
|
+
keys: [d1.key, d2.key],
|
|
162
|
+
includeStatus: true,
|
|
163
|
+
});
|
|
177
164
|
if (retrievedDevices.length !== 2) return false;
|
|
178
|
-
return retrievedDevices.every(({
|
|
165
|
+
return retrievedDevices.every(({ status }) => status !== undefined);
|
|
179
166
|
})
|
|
180
|
-
.
|
|
167
|
+
.toBe(true);
|
|
181
168
|
});
|
|
182
169
|
|
|
183
170
|
it("should handle state with type-safe details", async () => {
|
|
184
|
-
interface DeviceStateDetails {
|
|
185
|
-
status: string;
|
|
186
|
-
temperature: number;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
171
|
const key = id.create();
|
|
190
172
|
await client.hardware.devices.create({
|
|
191
173
|
key,
|
|
@@ -199,19 +181,148 @@ describe("Device", async () => {
|
|
|
199
181
|
|
|
200
182
|
await expect
|
|
201
183
|
.poll(async () => {
|
|
202
|
-
const retrieved = await client.hardware.devices.retrieve
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
DeviceStateDetails
|
|
207
|
-
>(key, { includeState: true });
|
|
184
|
+
const retrieved = await client.hardware.devices.retrieve({
|
|
185
|
+
key,
|
|
186
|
+
includeStatus: true,
|
|
187
|
+
});
|
|
208
188
|
return (
|
|
209
|
-
retrieved.
|
|
210
|
-
retrieved.
|
|
211
|
-
retrieved.
|
|
189
|
+
retrieved.status !== undefined &&
|
|
190
|
+
retrieved.status.variant === "info" &&
|
|
191
|
+
retrieved.status.details.device === key
|
|
212
192
|
);
|
|
213
193
|
})
|
|
214
|
-
.
|
|
194
|
+
.toBe(true);
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
describe("request object format", () => {
|
|
199
|
+
const testDevices: Array<{
|
|
200
|
+
key: string;
|
|
201
|
+
name: string;
|
|
202
|
+
make: string;
|
|
203
|
+
model: string;
|
|
204
|
+
location: string;
|
|
205
|
+
}> = [];
|
|
206
|
+
|
|
207
|
+
beforeAll(async () => {
|
|
208
|
+
const deviceConfigs = [
|
|
209
|
+
{ name: "sensor1", make: "ni", model: "pxi-6281", location: "Lab1" },
|
|
210
|
+
{ name: "sensor2", make: "ni", model: "pxi-6284", location: "Lab2" },
|
|
211
|
+
{ name: "actuator1", make: "labjack", model: "t7", location: "Lab1" },
|
|
212
|
+
{ name: "actuator2", make: "labjack", model: "t4", location: "Lab3" },
|
|
213
|
+
{ name: "controller", make: "opc", model: "server", location: "Lab2" },
|
|
214
|
+
];
|
|
215
|
+
|
|
216
|
+
for (const config of deviceConfigs) {
|
|
217
|
+
const key = id.create();
|
|
218
|
+
await client.hardware.devices.create({
|
|
219
|
+
key,
|
|
220
|
+
rack: testRack.key,
|
|
221
|
+
location: config.location,
|
|
222
|
+
name: config.name,
|
|
223
|
+
make: config.make,
|
|
224
|
+
model: config.model,
|
|
225
|
+
properties: { test: true },
|
|
226
|
+
});
|
|
227
|
+
testDevices.push({ key, ...config });
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it("should retrieve devices by names", async () => {
|
|
232
|
+
const result = await client.hardware.devices.retrieve({
|
|
233
|
+
names: ["sensor1", "actuator1"],
|
|
234
|
+
});
|
|
235
|
+
expect(result.length).toBeGreaterThanOrEqual(2);
|
|
236
|
+
expect(unique.unique(result.map((d) => d.name).sort())).toEqual([
|
|
237
|
+
"actuator1",
|
|
238
|
+
"sensor1",
|
|
239
|
+
]);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it("should retrieve devices by makes", async () => {
|
|
243
|
+
const result = await client.hardware.devices.retrieve({
|
|
244
|
+
makes: ["ni"],
|
|
245
|
+
});
|
|
246
|
+
expect(result.length).toBeGreaterThanOrEqual(2);
|
|
247
|
+
expect(result.every((d) => d.make === "ni")).toBe(true);
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it("should retrieve devices by models", async () => {
|
|
251
|
+
const result = await client.hardware.devices.retrieve({
|
|
252
|
+
models: ["pxi-6281", "t7"],
|
|
253
|
+
});
|
|
254
|
+
expect(result.length).toBeGreaterThanOrEqual(2);
|
|
255
|
+
expect(unique.unique(result.map((d) => d.model).sort())).toEqual([
|
|
256
|
+
"pxi-6281",
|
|
257
|
+
"t7",
|
|
258
|
+
]);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it("should retrieve devices by locations", async () => {
|
|
262
|
+
const result = await client.hardware.devices.retrieve({
|
|
263
|
+
locations: ["Lab1"],
|
|
264
|
+
});
|
|
265
|
+
expect(result.length).toBeGreaterThanOrEqual(2);
|
|
266
|
+
expect(result.every((d) => d.location === "Lab1")).toBe(true);
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it("should retrieve devices by racks", async () => {
|
|
270
|
+
const result = await client.hardware.devices.retrieve({
|
|
271
|
+
racks: [testRack.key],
|
|
272
|
+
});
|
|
273
|
+
expect(result.length).toBeGreaterThanOrEqual(5);
|
|
274
|
+
expect(result.every((d) => d.rack === testRack.key)).toBe(true);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
it("should retrieve devices by search term", async () => {
|
|
278
|
+
const result = await client.hardware.devices.retrieve({
|
|
279
|
+
searchTerm: "sensor1",
|
|
280
|
+
});
|
|
281
|
+
expect(result.length).toBeGreaterThanOrEqual(2);
|
|
282
|
+
expect(result.every((d) => d.name.includes("sensor"))).toBe(true);
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
it("should support pagination with limit and offset", async () => {
|
|
286
|
+
const firstPage = await client.hardware.devices.retrieve({
|
|
287
|
+
racks: [testRack.key],
|
|
288
|
+
limit: 2,
|
|
289
|
+
offset: 0,
|
|
290
|
+
});
|
|
291
|
+
expect(firstPage).toHaveLength(2);
|
|
292
|
+
|
|
293
|
+
const secondPage = await client.hardware.devices.retrieve({
|
|
294
|
+
racks: [testRack.key],
|
|
295
|
+
limit: 2,
|
|
296
|
+
offset: 2,
|
|
297
|
+
});
|
|
298
|
+
expect(secondPage).toHaveLength(2);
|
|
299
|
+
|
|
300
|
+
const firstPageKeys = firstPage.map((d) => d.key);
|
|
301
|
+
const secondPageKeys = secondPage.map((d) => d.key);
|
|
302
|
+
expect(firstPageKeys.every((key) => !secondPageKeys.includes(key))).toBe(true);
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it("should support combined filters", async () => {
|
|
306
|
+
const result = await client.hardware.devices.retrieve({
|
|
307
|
+
makes: ["ni"],
|
|
308
|
+
locations: ["Lab1", "Lab2"],
|
|
309
|
+
includeStatus: true,
|
|
310
|
+
});
|
|
311
|
+
expect(result.length).toBeGreaterThanOrEqual(1);
|
|
312
|
+
expect(
|
|
313
|
+
result.every((d) => d.make === "ni" && ["Lab1", "Lab2"].includes(d.location)),
|
|
314
|
+
).toBe(true);
|
|
315
|
+
|
|
316
|
+
await expect
|
|
317
|
+
.poll(async () => {
|
|
318
|
+
const devices = await client.hardware.devices.retrieve({
|
|
319
|
+
makes: ["ni"],
|
|
320
|
+
locations: ["Lab1", "Lab2"],
|
|
321
|
+
includeStatus: true,
|
|
322
|
+
});
|
|
323
|
+
return devices.every((d) => d.status !== undefined);
|
|
324
|
+
})
|
|
325
|
+
.toBe(true);
|
|
215
326
|
});
|
|
216
327
|
});
|
|
217
328
|
});
|
|
@@ -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 { binary,
|
|
11
|
-
import { z } from "zod
|
|
10
|
+
import { binary, record, status, zod } from "@synnaxlabs/x";
|
|
11
|
+
import { z } from "zod";
|
|
12
12
|
|
|
13
13
|
import { keyZ as rackKeyZ } from "@/hardware/rack/payload";
|
|
14
14
|
import { decodeJSONString } from "@/util/decodeJSONString";
|
|
@@ -16,16 +16,9 @@ import { decodeJSONString } from "@/util/decodeJSONString";
|
|
|
16
16
|
export const keyZ = z.string();
|
|
17
17
|
export type Key = z.infer<typeof keyZ>;
|
|
18
18
|
|
|
19
|
-
export const
|
|
20
|
-
key: keyZ,
|
|
21
|
-
variant: status.variantZ.or(z.literal("").transform<status.Variant>(() => "info")),
|
|
22
|
-
details: unknownRecordZ.or(z.string().transform(decodeJSONString)),
|
|
23
|
-
});
|
|
19
|
+
export const statusZ = status.statusZ(z.object({ rack: rackKeyZ, device: keyZ }));
|
|
24
20
|
|
|
25
|
-
export interface
|
|
26
|
-
extends Omit<z.infer<typeof stateZ>, "details"> {
|
|
27
|
-
details: Details;
|
|
28
|
-
}
|
|
21
|
+
export interface Status extends z.infer<typeof statusZ> {}
|
|
29
22
|
|
|
30
23
|
export const deviceZ = z.object({
|
|
31
24
|
key: keyZ,
|
|
@@ -35,27 +28,26 @@ export const deviceZ = z.object({
|
|
|
35
28
|
model: z.string(),
|
|
36
29
|
location: z.string(),
|
|
37
30
|
configured: z.boolean().optional(),
|
|
38
|
-
properties:
|
|
39
|
-
|
|
31
|
+
properties: record.unknownZ.or(z.string().transform(decodeJSONString)),
|
|
32
|
+
status: zod.nullToUndefined(statusZ),
|
|
40
33
|
});
|
|
41
34
|
|
|
42
35
|
export interface Device<
|
|
43
|
-
Properties extends
|
|
36
|
+
Properties extends record.Unknown = record.Unknown,
|
|
44
37
|
Make extends string = string,
|
|
45
38
|
Model extends string = string,
|
|
46
|
-
|
|
47
|
-
> extends Omit<z.infer<typeof deviceZ>, "properties" | "state"> {
|
|
39
|
+
> extends Omit<z.infer<typeof deviceZ>, "properties" | "status"> {
|
|
48
40
|
properties: Properties;
|
|
49
41
|
make: Make;
|
|
50
42
|
model: Model;
|
|
51
|
-
|
|
43
|
+
status?: Status;
|
|
52
44
|
}
|
|
53
45
|
|
|
54
46
|
export const newZ = deviceZ.extend({
|
|
55
47
|
properties: z.unknown().transform((c) => binary.JSON_CODEC.encodeString(c)),
|
|
56
48
|
});
|
|
57
49
|
export interface New<
|
|
58
|
-
Properties extends
|
|
50
|
+
Properties extends record.Unknown = record.Unknown,
|
|
59
51
|
Make extends string = string,
|
|
60
52
|
Model extends string = string,
|
|
61
53
|
> extends Omit<z.input<typeof newZ>, "properties"> {
|
|
@@ -63,6 +55,3 @@ export interface New<
|
|
|
63
55
|
make: Make;
|
|
64
56
|
model: Model;
|
|
65
57
|
}
|
|
66
|
-
|
|
67
|
-
export const ONTOLOGY_TYPE = "device";
|
|
68
|
-
export type OntologyType = typeof ONTOLOGY_TYPE;
|
|
@@ -8,73 +8,81 @@
|
|
|
8
8
|
// included in the file licenses/APL.txt.
|
|
9
9
|
|
|
10
10
|
import { sendRequired, type UnaryClient } from "@synnaxlabs/freighter";
|
|
11
|
-
import { type UnknownRecord } from "@synnaxlabs/x";
|
|
12
11
|
import { array } from "@synnaxlabs/x/array";
|
|
13
|
-
import {
|
|
14
|
-
import { z } from "zod/v4";
|
|
12
|
+
import { z } from "zod";
|
|
15
13
|
|
|
16
|
-
import { framer } from "@/framer";
|
|
17
14
|
import {
|
|
18
15
|
type Key,
|
|
19
16
|
keyZ,
|
|
20
17
|
type New,
|
|
21
18
|
newZ,
|
|
22
|
-
ONTOLOGY_TYPE,
|
|
23
19
|
type Payload,
|
|
24
20
|
rackZ,
|
|
25
|
-
type
|
|
26
|
-
stateZ,
|
|
21
|
+
type Status,
|
|
27
22
|
} from "@/hardware/rack/payload";
|
|
28
23
|
import { type task } from "@/hardware/task";
|
|
29
|
-
import { ontology } from "@/ontology";
|
|
30
|
-
import {
|
|
24
|
+
import { type ontology } from "@/ontology";
|
|
25
|
+
import { checkForMultipleOrNoResults } from "@/util/retrieve";
|
|
31
26
|
import { nullableArrayZ } from "@/util/zod";
|
|
32
27
|
|
|
33
28
|
const RETRIEVE_ENDPOINT = "/hardware/rack/retrieve";
|
|
34
29
|
const CREATE_ENDPOINT = "/hardware/rack/create";
|
|
35
30
|
const DELETE_ENDPOINT = "/hardware/rack/delete";
|
|
36
31
|
|
|
37
|
-
const
|
|
32
|
+
export const STATUS_CHANNEL_NAME = "sy_rack_status";
|
|
33
|
+
export const SET_CHANNEL_NAME = "sy_rack_set";
|
|
34
|
+
export const DELETE_CHANNEL_NAME = "sy_rack_delete";
|
|
38
35
|
|
|
39
36
|
const retrieveReqZ = z.object({
|
|
40
37
|
keys: keyZ.array().optional(),
|
|
41
38
|
names: z.string().array().optional(),
|
|
42
|
-
|
|
39
|
+
searchTerm: z.string().optional(),
|
|
43
40
|
embedded: z.boolean().optional(),
|
|
44
41
|
hostIsNode: z.boolean().optional(),
|
|
45
42
|
limit: z.number().optional(),
|
|
46
43
|
offset: z.number().optional(),
|
|
47
|
-
|
|
44
|
+
includeStatus: z.boolean().optional(),
|
|
48
45
|
});
|
|
49
|
-
|
|
50
46
|
const retrieveResZ = z.object({ racks: nullableArrayZ(rackZ) });
|
|
51
47
|
|
|
52
|
-
const
|
|
48
|
+
const singleRetrieveArgsZ = z.union([
|
|
49
|
+
z
|
|
50
|
+
.object({
|
|
51
|
+
key: keyZ,
|
|
52
|
+
includeStatus: z.boolean().optional(),
|
|
53
|
+
})
|
|
54
|
+
.transform(({ key, includeStatus }) => ({ keys: [key], includeStatus })),
|
|
55
|
+
z
|
|
56
|
+
.object({
|
|
57
|
+
name: z.string(),
|
|
58
|
+
includeStatus: z.boolean().optional(),
|
|
59
|
+
})
|
|
60
|
+
.transform(({ name, includeStatus }) => ({ names: [name], includeStatus })),
|
|
61
|
+
]);
|
|
62
|
+
export type SingleRetrieveArgs = z.input<typeof singleRetrieveArgsZ>;
|
|
63
|
+
|
|
64
|
+
const multiRetrieveArgsZ = retrieveReqZ;
|
|
65
|
+
|
|
66
|
+
export type MultiRetrieveArgs = z.input<typeof multiRetrieveArgsZ>;
|
|
67
|
+
|
|
68
|
+
const retrieveArgsZ = z.union([singleRetrieveArgsZ, multiRetrieveArgsZ]);
|
|
53
69
|
|
|
70
|
+
export type RetrieveArgs = z.input<typeof retrieveArgsZ>;
|
|
71
|
+
|
|
72
|
+
const createReqZ = z.object({ racks: newZ.array() });
|
|
54
73
|
const createResZ = z.object({ racks: rackZ.array() });
|
|
55
74
|
|
|
56
75
|
const deleteReqZ = z.object({ keys: keyZ.array() });
|
|
57
|
-
|
|
58
76
|
const deleteResZ = z.object({});
|
|
59
77
|
|
|
60
|
-
export
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export class Client implements AsyncTermSearcher<string, Key, Payload> {
|
|
65
|
-
readonly type = ONTOLOGY_TYPE;
|
|
78
|
+
export class Client {
|
|
79
|
+
readonly type = "rack";
|
|
66
80
|
private readonly client: UnaryClient;
|
|
67
81
|
private readonly tasks: task.Client;
|
|
68
|
-
private readonly frameClient: framer.Client;
|
|
69
82
|
|
|
70
|
-
constructor(
|
|
71
|
-
client: UnaryClient,
|
|
72
|
-
taskClient: task.Client,
|
|
73
|
-
frameClient: framer.Client,
|
|
74
|
-
) {
|
|
83
|
+
constructor(client: UnaryClient, taskClient: task.Client) {
|
|
75
84
|
this.client = client;
|
|
76
85
|
this.tasks = taskClient;
|
|
77
|
-
this.frameClient = frameClient;
|
|
78
86
|
}
|
|
79
87
|
|
|
80
88
|
async delete(keys: Key | Key[]): Promise<void> {
|
|
@@ -99,117 +107,91 @@ export class Client implements AsyncTermSearcher<string, Key, Payload> {
|
|
|
99
107
|
createResZ,
|
|
100
108
|
);
|
|
101
109
|
const sugared = this.sugar(res.racks);
|
|
102
|
-
|
|
103
|
-
return sugared;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
async search(term: string): Promise<Rack[]> {
|
|
107
|
-
const res = await sendRequired<typeof retrieveReqZ, typeof retrieveResZ>(
|
|
108
|
-
this.client,
|
|
109
|
-
RETRIEVE_ENDPOINT,
|
|
110
|
-
{ search: term },
|
|
111
|
-
retrieveReqZ,
|
|
112
|
-
retrieveResZ,
|
|
113
|
-
);
|
|
114
|
-
return this.sugar(res.racks);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
async page(offset: number, limit: number): Promise<Rack[]> {
|
|
118
|
-
const res = await sendRequired<typeof retrieveReqZ, typeof retrieveResZ>(
|
|
119
|
-
this.client,
|
|
120
|
-
RETRIEVE_ENDPOINT,
|
|
121
|
-
{ offset, limit },
|
|
122
|
-
retrieveReqZ,
|
|
123
|
-
retrieveResZ,
|
|
124
|
-
);
|
|
125
|
-
return this.sugar(res.racks);
|
|
110
|
+
return isSingle ? sugared[0] : sugared;
|
|
126
111
|
}
|
|
127
112
|
|
|
128
|
-
async retrieve(
|
|
129
|
-
async retrieve(
|
|
130
|
-
async retrieve(
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
): Promise<Rack | Rack[]> {
|
|
134
|
-
const { variant, normalized, single } = analyzeParams(racks, {
|
|
135
|
-
string: "names",
|
|
136
|
-
number: "keys",
|
|
137
|
-
});
|
|
138
|
-
const res = await sendRequired<typeof retrieveReqZ, typeof retrieveResZ>(
|
|
113
|
+
async retrieve(args: SingleRetrieveArgs): Promise<Rack>;
|
|
114
|
+
async retrieve(args: MultiRetrieveArgs): Promise<Rack[]>;
|
|
115
|
+
async retrieve(args: RetrieveArgs): Promise<Rack | Rack[]> {
|
|
116
|
+
const isSingle = "key" in args || "name" in args;
|
|
117
|
+
const res = await sendRequired(
|
|
139
118
|
this.client,
|
|
140
119
|
RETRIEVE_ENDPOINT,
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
includeState: options?.includeState,
|
|
144
|
-
},
|
|
145
|
-
retrieveReqZ,
|
|
120
|
+
args,
|
|
121
|
+
retrieveArgsZ,
|
|
146
122
|
retrieveResZ,
|
|
147
123
|
);
|
|
148
124
|
const sugared = this.sugar(res.racks);
|
|
149
|
-
checkForMultipleOrNoResults("Rack",
|
|
150
|
-
return
|
|
125
|
+
checkForMultipleOrNoResults("Rack", args, sugared, isSingle);
|
|
126
|
+
return isSingle ? sugared[0] : sugared;
|
|
151
127
|
}
|
|
152
128
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
},
|
|
162
|
-
);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
private sugar(payloads: Payload[]): Rack[] {
|
|
166
|
-
return payloads.map(
|
|
167
|
-
({ key, name, state }) => new Rack(key, name, this.tasks, state),
|
|
168
|
-
);
|
|
129
|
+
sugar(payload: Payload): Rack;
|
|
130
|
+
sugar(payloads: Payload[]): Rack[];
|
|
131
|
+
sugar(payloads: Payload | Payload[]): Rack | Rack[] {
|
|
132
|
+
const isSingle = !Array.isArray(payloads);
|
|
133
|
+
const sugared = array
|
|
134
|
+
.toArray(payloads)
|
|
135
|
+
.map(({ key, name, status }) => new Rack(key, name, this.tasks, status));
|
|
136
|
+
return isSingle ? sugared[0] : sugared;
|
|
169
137
|
}
|
|
170
138
|
}
|
|
171
139
|
|
|
172
140
|
export class Rack {
|
|
173
141
|
key: Key;
|
|
174
142
|
name: string;
|
|
175
|
-
|
|
143
|
+
status?: Status;
|
|
176
144
|
private readonly tasks: task.Client;
|
|
177
145
|
|
|
178
|
-
constructor(key: Key, name: string, taskClient: task.Client,
|
|
146
|
+
constructor(key: Key, name: string, taskClient: task.Client, status?: Status) {
|
|
179
147
|
this.key = key;
|
|
180
148
|
this.name = name;
|
|
181
149
|
this.tasks = taskClient;
|
|
182
|
-
this.
|
|
150
|
+
this.status = status;
|
|
183
151
|
}
|
|
184
152
|
|
|
185
153
|
async listTasks(): Promise<task.Task[]> {
|
|
186
|
-
return await this.tasks.retrieve(this.key);
|
|
154
|
+
return await this.tasks.retrieve({ rack: this.key });
|
|
187
155
|
}
|
|
188
156
|
|
|
189
|
-
async
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
157
|
+
async createTask(task: task.New): Promise<task.Task>;
|
|
158
|
+
async createTask<
|
|
159
|
+
Type extends z.ZodLiteral<string> = z.ZodLiteral<string>,
|
|
160
|
+
Config extends z.ZodType = z.ZodType,
|
|
161
|
+
StatusData extends z.ZodType = z.ZodType,
|
|
162
|
+
>(
|
|
163
|
+
task: task.New<Type, Config>,
|
|
164
|
+
schemas: task.Schemas<Type, Config, StatusData>,
|
|
165
|
+
): Promise<task.Task<Type, Config, StatusData>>;
|
|
196
166
|
|
|
197
167
|
async createTask<
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
>(
|
|
168
|
+
Type extends z.ZodLiteral<string> = z.ZodLiteral<string>,
|
|
169
|
+
Config extends z.ZodType = z.ZodType,
|
|
170
|
+
StatusData extends z.ZodType = z.ZodType,
|
|
171
|
+
>(
|
|
172
|
+
task: task.New<Type, Config>,
|
|
173
|
+
schemas?: task.Schemas<Type, Config, StatusData>,
|
|
174
|
+
): Promise<task.Task<Type, Config, StatusData>> {
|
|
202
175
|
task.key = (
|
|
203
176
|
(BigInt(this.key) << 32n) +
|
|
204
177
|
(BigInt(task.key ?? 0) & 0xffffffffn)
|
|
205
178
|
).toString();
|
|
206
|
-
return await this.tasks.create
|
|
179
|
+
return await this.tasks.create(
|
|
180
|
+
task,
|
|
181
|
+
schemas as Required<task.Schemas<Type, Config, StatusData>>,
|
|
182
|
+
);
|
|
207
183
|
}
|
|
208
184
|
|
|
209
|
-
async deleteTask(task:
|
|
185
|
+
async deleteTask(task: task.Key): Promise<void> {
|
|
210
186
|
await this.tasks.delete([task]);
|
|
211
187
|
}
|
|
188
|
+
|
|
189
|
+
get payload(): Payload {
|
|
190
|
+
return { key: this.key, name: this.name, status: this.status };
|
|
191
|
+
}
|
|
212
192
|
}
|
|
213
193
|
|
|
214
|
-
export const ontologyID = (key: Key): ontology.ID =>
|
|
215
|
-
|
|
194
|
+
export const ontologyID = (key: Key): ontology.ID => ({
|
|
195
|
+
type: "rack",
|
|
196
|
+
key: key.toString(),
|
|
197
|
+
});
|
|
@@ -8,31 +8,22 @@
|
|
|
8
8
|
// included in the file licenses/APL.txt.
|
|
9
9
|
|
|
10
10
|
import { status, zod } from "@synnaxlabs/x";
|
|
11
|
-
import {
|
|
12
|
-
import { z } from "zod/v4";
|
|
11
|
+
import { z } from "zod";
|
|
13
12
|
|
|
14
13
|
export const keyZ = z.uint32();
|
|
15
14
|
export type Key = z.infer<typeof keyZ>;
|
|
16
15
|
|
|
17
|
-
export const
|
|
18
|
-
key: keyZ,
|
|
19
|
-
variant: status.variantZ.or(z.literal("").transform<status.Variant>(() => "info")),
|
|
20
|
-
message: z.string(),
|
|
21
|
-
lastReceived: TimeStamp.z,
|
|
22
|
-
});
|
|
16
|
+
export const statusZ = status.statusZ(z.object({ rack: keyZ }));
|
|
23
17
|
|
|
24
|
-
export interface
|
|
18
|
+
export interface Status extends z.infer<typeof statusZ> {}
|
|
25
19
|
|
|
26
20
|
export const rackZ = z.object({
|
|
27
21
|
key: keyZ,
|
|
28
22
|
name: z.string(),
|
|
29
|
-
|
|
23
|
+
status: zod.nullToUndefined(statusZ),
|
|
30
24
|
});
|
|
31
25
|
|
|
32
26
|
export interface Payload extends z.infer<typeof rackZ> {}
|
|
33
27
|
|
|
34
28
|
export const newZ = rackZ.partial({ key: true });
|
|
35
29
|
export interface New extends z.input<typeof newZ> {}
|
|
36
|
-
|
|
37
|
-
export const ONTOLOGY_TYPE = "rack";
|
|
38
|
-
export type OntologyType = typeof ONTOLOGY_TYPE;
|