@synnaxlabs/client 0.38.1 → 0.39.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 +7 -7
- package/dist/access/payload.d.ts +6 -6
- package/dist/access/payload.d.ts.map +1 -1
- package/dist/access/policy/client.d.ts +5 -3
- package/dist/access/policy/client.d.ts.map +1 -1
- package/dist/access/policy/external.d.ts +1 -0
- package/dist/access/policy/external.d.ts.map +1 -1
- package/dist/access/policy/ontology.d.ts +5 -0
- package/dist/access/policy/ontology.d.ts.map +1 -0
- package/dist/access/policy/payload.d.ts +86 -89
- package/dist/access/policy/payload.d.ts.map +1 -1
- package/dist/access/policy/retriever.d.ts +7 -6
- package/dist/access/policy/retriever.d.ts.map +1 -1
- package/dist/access/policy/writer.d.ts +2 -2
- package/dist/access/policy/writer.d.ts.map +1 -1
- package/dist/auth/auth.d.ts +2 -1
- package/dist/auth/auth.d.ts.map +1 -1
- package/dist/channel/client.d.ts +6 -5
- package/dist/channel/client.d.ts.map +1 -1
- package/dist/channel/payload.d.ts +13 -11
- package/dist/channel/payload.d.ts.map +1 -1
- package/dist/channel/retriever.d.ts +9 -6
- package/dist/channel/retriever.d.ts.map +1 -1
- package/dist/channel/writer.d.ts +6 -4
- package/dist/channel/writer.d.ts.map +1 -1
- package/dist/client.cjs +30 -30
- package/dist/client.d.ts +4 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +3376 -3423
- package/dist/connection/checker.d.ts +5 -4
- package/dist/connection/checker.d.ts.map +1 -1
- package/dist/control/state.d.ts +10 -8
- package/dist/control/state.d.ts.map +1 -1
- package/dist/errors.d.ts +5 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/framer/adapter.d.ts +14 -15
- package/dist/framer/adapter.d.ts.map +1 -1
- package/dist/framer/client.d.ts +13 -15
- package/dist/framer/client.d.ts.map +1 -1
- package/dist/framer/deleter.d.ts +3 -2
- package/dist/framer/deleter.d.ts.map +1 -1
- package/dist/framer/frame.d.ts +31 -27
- package/dist/framer/frame.d.ts.map +1 -1
- package/dist/framer/iterator.d.ts +4 -5
- package/dist/framer/iterator.d.ts.map +1 -1
- package/dist/framer/streamer.d.ts +5 -6
- package/dist/framer/streamer.d.ts.map +1 -1
- package/dist/framer/writer.d.ts +42 -39
- package/dist/framer/writer.d.ts.map +1 -1
- package/dist/hardware/device/client.d.ts +17 -12
- package/dist/hardware/device/client.d.ts.map +1 -1
- package/dist/hardware/device/payload.d.ts +19 -16
- package/dist/hardware/device/payload.d.ts.map +1 -1
- package/dist/hardware/rack/client.d.ts +15 -15
- package/dist/hardware/rack/client.d.ts.map +1 -1
- package/dist/hardware/rack/payload.d.ts +9 -8
- package/dist/hardware/rack/payload.d.ts.map +1 -1
- package/dist/hardware/task/client.d.ts +38 -29
- package/dist/hardware/task/client.d.ts.map +1 -1
- package/dist/hardware/task/payload.d.ts +58 -53
- package/dist/hardware/task/payload.d.ts.map +1 -1
- package/dist/label/client.d.ts +4 -3
- package/dist/label/client.d.ts.map +1 -1
- package/dist/label/payload.d.ts +4 -4
- package/dist/label/payload.d.ts.map +1 -1
- package/dist/label/retriever.d.ts.map +1 -1
- package/dist/label/writer.d.ts +13 -10
- package/dist/label/writer.d.ts.map +1 -1
- package/dist/ontology/client.d.ts +12 -10
- package/dist/ontology/client.d.ts.map +1 -1
- package/dist/ontology/group/client.d.ts +5 -4
- package/dist/ontology/group/client.d.ts.map +1 -1
- package/dist/ontology/group/group.d.ts +7 -5
- package/dist/ontology/group/group.d.ts.map +1 -1
- package/dist/ontology/group/payload.d.ts +6 -5
- package/dist/ontology/group/payload.d.ts.map +1 -1
- package/dist/ontology/group/writer.d.ts +8 -8
- package/dist/ontology/group/writer.d.ts.map +1 -1
- package/dist/ontology/payload.d.ts +72 -62
- package/dist/ontology/payload.d.ts.map +1 -1
- package/dist/ontology/writer.d.ts.map +1 -1
- package/dist/ranger/alias.d.ts +9 -10
- package/dist/ranger/alias.d.ts.map +1 -1
- package/dist/ranger/client.d.ts +18 -18
- 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 +18 -14
- package/dist/ranger/kv.d.ts.map +1 -1
- package/dist/ranger/payload.d.ts +13 -13
- package/dist/ranger/payload.d.ts.map +1 -1
- package/dist/ranger/writer.d.ts +14 -14
- package/dist/ranger/writer.d.ts.map +1 -1
- package/dist/setupspecs.d.ts.map +1 -1
- package/dist/signals/observable.d.ts +3 -1
- package/dist/signals/observable.d.ts.map +1 -1
- package/dist/user/client.d.ts +5 -3
- package/dist/user/client.d.ts.map +1 -1
- package/dist/user/payload.d.ts +7 -6
- package/dist/user/payload.d.ts.map +1 -1
- package/dist/user/retriever.d.ts +2 -1
- package/dist/user/retriever.d.ts.map +1 -1
- package/dist/user/writer.d.ts +2 -2
- package/dist/user/writer.d.ts.map +1 -1
- package/dist/util/decodeJSONString.d.ts +3 -0
- package/dist/util/decodeJSONString.d.ts.map +1 -0
- package/dist/util/parseWithoutKeyConversion.d.ts +3 -0
- package/dist/util/parseWithoutKeyConversion.d.ts.map +1 -0
- package/dist/util/retrieve.d.ts +1 -1
- package/dist/util/retrieve.d.ts.map +1 -1
- package/dist/util/telem.d.ts.map +1 -1
- package/dist/util/zod.d.ts.map +1 -1
- package/dist/workspace/client.d.ts +6 -60
- package/dist/workspace/client.d.ts.map +1 -1
- package/dist/workspace/external.d.ts +3 -0
- package/dist/workspace/external.d.ts.map +1 -0
- package/dist/workspace/index.d.ts +1 -1
- package/dist/workspace/index.d.ts.map +1 -1
- package/dist/workspace/lineplot/client.d.ts +5 -44
- package/dist/workspace/lineplot/client.d.ts.map +1 -1
- package/dist/workspace/lineplot/external.d.ts +3 -0
- package/dist/workspace/lineplot/external.d.ts.map +1 -0
- package/dist/workspace/lineplot/index.d.ts +1 -1
- package/dist/workspace/lineplot/index.d.ts.map +1 -1
- package/dist/workspace/lineplot/payload.d.ts +45 -0
- package/dist/workspace/lineplot/payload.d.ts.map +1 -0
- package/dist/workspace/log/client.d.ts +5 -44
- package/dist/workspace/log/client.d.ts.map +1 -1
- package/dist/workspace/log/external.d.ts +3 -0
- package/dist/workspace/log/external.d.ts.map +1 -0
- package/dist/workspace/log/index.d.ts +1 -1
- package/dist/workspace/log/index.d.ts.map +1 -1
- package/dist/workspace/log/payload.d.ts +45 -0
- package/dist/workspace/log/payload.d.ts.map +1 -0
- package/dist/workspace/payload.d.ts +60 -0
- package/dist/workspace/payload.d.ts.map +1 -0
- package/dist/workspace/schematic/client.d.ts +5 -68
- package/dist/workspace/schematic/client.d.ts.map +1 -1
- package/dist/workspace/schematic/external.d.ts +3 -0
- package/dist/workspace/schematic/external.d.ts.map +1 -0
- package/dist/workspace/schematic/index.d.ts +1 -1
- package/dist/workspace/schematic/index.d.ts.map +1 -1
- package/dist/workspace/schematic/payload.d.ts +71 -0
- package/dist/workspace/schematic/payload.d.ts.map +1 -0
- package/dist/workspace/table/client.d.ts +5 -57
- package/dist/workspace/table/client.d.ts.map +1 -1
- package/dist/workspace/table/external.d.ts +3 -0
- package/dist/workspace/table/external.d.ts.map +1 -0
- package/dist/workspace/table/index.d.ts +1 -1
- package/dist/workspace/table/index.d.ts.map +1 -1
- package/dist/workspace/table/payload.d.ts +60 -0
- package/dist/workspace/table/payload.d.ts.map +1 -0
- package/examples/node/basicReadWrite.js +26 -26
- package/examples/node/liveStream.js +15 -15
- package/examples/node/seriesAndFrames.js +38 -38
- package/examples/node/streamWrite.js +47 -45
- package/package.json +15 -13
- package/src/access/payload.ts +12 -12
- package/src/access/policy/client.ts +13 -12
- package/src/access/policy/external.ts +1 -0
- package/src/access/policy/ontology.ts +17 -0
- package/src/access/policy/payload.ts +7 -19
- package/src/access/policy/policy.spec.ts +16 -16
- package/src/access/policy/retriever.ts +2 -1
- package/src/access/policy/writer.ts +4 -4
- package/src/auth/auth.spec.ts +27 -23
- package/src/auth/auth.ts +7 -11
- package/src/channel/batchRetriever.spec.ts +25 -22
- package/src/channel/client.ts +19 -21
- package/src/channel/payload.ts +16 -20
- package/src/channel/retriever.ts +20 -21
- package/src/channel/writer.ts +11 -13
- package/src/client.ts +6 -16
- package/src/connection/checker.ts +9 -11
- package/src/connection/connection.spec.ts +17 -5
- package/src/control/state.ts +8 -9
- package/src/errors.spec.ts +1 -1
- package/src/errors.ts +8 -0
- package/src/framer/adapter.spec.ts +28 -23
- package/src/framer/adapter.ts +37 -41
- package/src/framer/client.spec.ts +5 -11
- package/src/framer/client.ts +34 -38
- package/src/framer/deleter.ts +5 -6
- package/src/framer/frame.ts +62 -50
- package/src/framer/iterator.ts +11 -16
- package/src/framer/streamer.spec.ts +2 -10
- package/src/framer/streamer.ts +15 -19
- package/src/framer/writer.spec.ts +48 -7
- package/src/framer/writer.ts +39 -31
- package/src/hardware/device/client.ts +64 -39
- package/src/hardware/device/device.spec.ts +49 -33
- package/src/hardware/device/payload.ts +29 -29
- package/src/hardware/rack/client.ts +52 -65
- package/src/hardware/rack/payload.ts +9 -18
- package/src/hardware/rack/rack.spec.ts +12 -0
- package/src/hardware/task/client.ts +160 -131
- package/src/hardware/task/payload.ts +49 -68
- package/src/hardware/task/task.spec.ts +98 -81
- package/src/label/client.ts +12 -15
- package/src/label/payload.ts +3 -9
- package/src/label/retriever.ts +3 -7
- package/src/label/writer.ts +8 -15
- package/src/ontology/client.ts +17 -22
- package/src/ontology/group/client.ts +5 -5
- package/src/ontology/group/group.spec.ts +4 -4
- package/src/ontology/group/group.ts +10 -7
- package/src/ontology/group/payload.ts +11 -35
- package/src/ontology/group/writer.ts +22 -26
- package/src/ontology/ontology.spec.ts +15 -15
- package/src/ontology/payload.ts +67 -43
- package/src/ontology/writer.ts +16 -23
- package/src/ranger/alias.ts +25 -42
- package/src/ranger/client.ts +29 -38
- package/src/ranger/external.ts +1 -1
- package/src/ranger/kv.ts +9 -32
- package/src/ranger/payload.ts +14 -36
- package/src/ranger/ranger.spec.ts +1 -2
- package/src/ranger/writer.ts +8 -26
- package/src/signals/observable.ts +3 -4
- package/src/user/client.ts +8 -4
- package/src/user/payload.ts +5 -9
- package/src/user/retriever.ts +1 -1
- package/src/user/user.spec.ts +17 -15
- package/src/user/writer.ts +3 -10
- package/src/util/decodeJSONString.ts +13 -0
- package/src/util/parseWithoutKeyConversion.ts +19 -0
- package/src/util/retrieve.spec.ts +3 -13
- package/src/util/retrieve.ts +2 -12
- package/src/util/telem.ts +1 -1
- package/src/vite-env.d.ts +1 -0
- package/src/workspace/client.ts +30 -57
- package/src/workspace/external.ts +11 -0
- package/src/workspace/index.ts +1 -1
- package/src/workspace/lineplot/client.ts +22 -36
- package/src/workspace/lineplot/external.ts +11 -0
- package/src/workspace/lineplot/index.ts +1 -1
- package/src/workspace/lineplot/linePlot.spec.ts +1 -2
- package/src/workspace/lineplot/payload.ts +32 -0
- package/src/workspace/log/client.ts +25 -39
- package/src/workspace/log/external.ts +11 -0
- package/src/workspace/log/index.ts +1 -1
- package/src/workspace/log/log.spec.ts +5 -18
- package/src/workspace/log/payload.ts +32 -0
- package/src/workspace/payload.ts +36 -0
- package/src/workspace/schematic/client.ts +30 -56
- package/src/workspace/schematic/external.ts +11 -0
- package/src/workspace/schematic/index.ts +1 -1
- package/src/workspace/schematic/payload.ts +37 -0
- package/src/workspace/schematic/schematic.spec.ts +15 -6
- package/src/workspace/table/client.ts +27 -50
- package/src/workspace/table/external.ts +11 -0
- package/src/workspace/table/index.ts +1 -1
- package/src/workspace/table/payload.ts +36 -0
- package/src/workspace/workspace.spec.ts +1 -2
- package/dist/channel/creator.d.ts +0 -9
- package/dist/channel/creator.d.ts.map +0 -1
- package/src/channel/creator.ts +0 -37
|
@@ -12,7 +12,7 @@ import { DataType, Rate, TimeRange, TimeSpan, TimeStamp } from "@synnaxlabs/x/te
|
|
|
12
12
|
import { describe, expect, test } from "vitest";
|
|
13
13
|
|
|
14
14
|
import { type channel } from "@/channel";
|
|
15
|
-
import { UnauthorizedError } from "@/errors";
|
|
15
|
+
import { UnauthorizedError, ValidationError } from "@/errors";
|
|
16
16
|
import { ALWAYS_INDEX_PERSIST_ON_AUTO_COMMIT, WriterMode } from "@/framer/writer";
|
|
17
17
|
import { newClient } from "@/setupspecs";
|
|
18
18
|
import { randomSeries } from "@/util/telem";
|
|
@@ -22,7 +22,7 @@ const client = newClient();
|
|
|
22
22
|
const newChannel = async (): Promise<channel.Channel> =>
|
|
23
23
|
await client.channels.create({
|
|
24
24
|
leaseholder: 1,
|
|
25
|
-
name: `test-${id.
|
|
25
|
+
name: `test-${id.create()}`,
|
|
26
26
|
rate: Rate.hz(1),
|
|
27
27
|
dataType: DataType.FLOAT64,
|
|
28
28
|
});
|
|
@@ -40,6 +40,7 @@ describe("Writer", () => {
|
|
|
40
40
|
}
|
|
41
41
|
expect(true).toBeTruthy();
|
|
42
42
|
});
|
|
43
|
+
|
|
43
44
|
test("write to unknown channel key", async () => {
|
|
44
45
|
const ch = await newChannel();
|
|
45
46
|
const writer = await client.openWriter({ start: 0, channels: ch.key });
|
|
@@ -48,6 +49,7 @@ describe("Writer", () => {
|
|
|
48
49
|
).rejects.toThrow("Channel billy bob not found");
|
|
49
50
|
await writer.close();
|
|
50
51
|
});
|
|
52
|
+
|
|
51
53
|
test("stream when mode is set ot persist only", async () => {
|
|
52
54
|
const ch = await newChannel();
|
|
53
55
|
const stream = await client.openStreamer(ch.key);
|
|
@@ -68,6 +70,7 @@ describe("Writer", () => {
|
|
|
68
70
|
]);
|
|
69
71
|
expect(v).toEqual(123);
|
|
70
72
|
});
|
|
73
|
+
|
|
71
74
|
test("write with auto commit on", async () => {
|
|
72
75
|
const ch = await newChannel();
|
|
73
76
|
const writer = await client.openWriter({
|
|
@@ -85,6 +88,7 @@ describe("Writer", () => {
|
|
|
85
88
|
const f = await client.read(new TimeRange(0, TimeStamp.seconds(10)), ch.key);
|
|
86
89
|
expect(f.length).toEqual(10);
|
|
87
90
|
});
|
|
91
|
+
|
|
88
92
|
test("write with auto commit and alwaysPersist", async () => {
|
|
89
93
|
const ch = await newChannel();
|
|
90
94
|
const writer = await client.openWriter({
|
|
@@ -100,6 +104,7 @@ describe("Writer", () => {
|
|
|
100
104
|
}
|
|
101
105
|
expect(true).toBeTruthy();
|
|
102
106
|
});
|
|
107
|
+
|
|
103
108
|
test("write with auto commit and a set interval", async () => {
|
|
104
109
|
const ch = await newChannel();
|
|
105
110
|
const writer = await client.openWriter({
|
|
@@ -115,6 +120,41 @@ describe("Writer", () => {
|
|
|
115
120
|
}
|
|
116
121
|
expect(true).toBeTruthy();
|
|
117
122
|
});
|
|
123
|
+
|
|
124
|
+
test("write with out of order timestamp", async () => {
|
|
125
|
+
const indexCh = await client.channels.create({
|
|
126
|
+
name: "idx",
|
|
127
|
+
dataType: DataType.TIMESTAMP,
|
|
128
|
+
isIndex: true,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
const dataCh = await client.channels.create({
|
|
132
|
+
name: "data",
|
|
133
|
+
dataType: DataType.FLOAT64,
|
|
134
|
+
index: indexCh.key,
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
const writer = await client.openWriter({
|
|
138
|
+
start: TimeStamp.now(),
|
|
139
|
+
channels: [indexCh.key, dataCh.key],
|
|
140
|
+
enableAutoCommit: true,
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
let errAccumulated: boolean = false;
|
|
144
|
+
for (let i = 0; i < 10; i++) {
|
|
145
|
+
await new Promise((resolve) => setTimeout(resolve, 5));
|
|
146
|
+
errAccumulated = !(await writer.write({
|
|
147
|
+
[indexCh.key]: BigInt(i),
|
|
148
|
+
[dataCh.key]: i,
|
|
149
|
+
}));
|
|
150
|
+
if (errAccumulated) break;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
expect(errAccumulated).toBeTruthy();
|
|
154
|
+
|
|
155
|
+
await expect(writer.close()).rejects.toThrow(ValidationError);
|
|
156
|
+
});
|
|
157
|
+
|
|
118
158
|
test("write with errOnUnauthorized", async () => {
|
|
119
159
|
const ch = await newChannel();
|
|
120
160
|
const w1 = await client.openWriter({
|
|
@@ -123,14 +163,11 @@ describe("Writer", () => {
|
|
|
123
163
|
});
|
|
124
164
|
|
|
125
165
|
await expect(
|
|
126
|
-
client.openWriter({
|
|
127
|
-
start: 0,
|
|
128
|
-
channels: ch.key,
|
|
129
|
-
errOnUnauthorized: true,
|
|
130
|
-
}),
|
|
166
|
+
client.openWriter({ start: 0, channels: ch.key, errOnUnauthorized: true }),
|
|
131
167
|
).rejects.toThrow(UnauthorizedError);
|
|
132
168
|
await w1.close();
|
|
133
169
|
});
|
|
170
|
+
|
|
134
171
|
test("setAuthority", async () => {
|
|
135
172
|
const ch = await newChannel();
|
|
136
173
|
const w1 = await client.openWriter({
|
|
@@ -159,6 +196,7 @@ describe("Writer", () => {
|
|
|
159
196
|
await w1.close();
|
|
160
197
|
await w2.close();
|
|
161
198
|
});
|
|
199
|
+
|
|
162
200
|
test("setAuthority with name keys", async () => {
|
|
163
201
|
const ch = await newChannel();
|
|
164
202
|
const w1 = await client.openWriter({
|
|
@@ -187,6 +225,7 @@ describe("Writer", () => {
|
|
|
187
225
|
await w1.close();
|
|
188
226
|
await w2.close();
|
|
189
227
|
});
|
|
228
|
+
|
|
190
229
|
test("setAuthority with name-value pair", async () => {
|
|
191
230
|
const ch = await newChannel();
|
|
192
231
|
const w1 = await client.openWriter({
|
|
@@ -215,6 +254,7 @@ describe("Writer", () => {
|
|
|
215
254
|
await w1.close();
|
|
216
255
|
await w2.close();
|
|
217
256
|
});
|
|
257
|
+
|
|
218
258
|
test("setAuthority on all channels", async () => {
|
|
219
259
|
const ch = await newChannel();
|
|
220
260
|
const w1 = await client.openWriter({
|
|
@@ -244,6 +284,7 @@ describe("Writer", () => {
|
|
|
244
284
|
await w2.close();
|
|
245
285
|
});
|
|
246
286
|
});
|
|
287
|
+
|
|
247
288
|
describe("Client", () => {
|
|
248
289
|
test("Client - basic write", async () => {
|
|
249
290
|
const ch = await newChannel();
|
package/src/framer/writer.ts
CHANGED
|
@@ -23,10 +23,9 @@ import {
|
|
|
23
23
|
import { toArray } from "@synnaxlabs/x/toArray";
|
|
24
24
|
import { z } from "zod";
|
|
25
25
|
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
import { type CrudeFrame, frameZ } from "@/framer/frame";
|
|
26
|
+
import { channel } from "@/channel";
|
|
27
|
+
import { WriteAdapter } from "@/framer/adapter";
|
|
28
|
+
import { type Crude, frameZ } from "@/framer/frame";
|
|
30
29
|
import { StreamProxy } from "@/framer/streamProxy";
|
|
31
30
|
|
|
32
31
|
enum Command {
|
|
@@ -64,7 +63,7 @@ export const ALWAYS_INDEX_PERSIST_ON_AUTO_COMMIT: TimeSpan = new TimeSpan(-1);
|
|
|
64
63
|
const netConfigZ = z.object({
|
|
65
64
|
start: TimeStamp.z.optional(),
|
|
66
65
|
controlSubject: control.subjectZ.optional(),
|
|
67
|
-
keys:
|
|
66
|
+
keys: channel.keyZ.array().optional(),
|
|
68
67
|
authorities: control.Authority.z.array().optional(),
|
|
69
68
|
mode: z.nativeEnum(WriterMode).optional(),
|
|
70
69
|
errOnUnauthorized: z.boolean().optional(),
|
|
@@ -72,7 +71,7 @@ const netConfigZ = z.object({
|
|
|
72
71
|
autoIndexPersistInterval: TimeSpan.z.optional(),
|
|
73
72
|
});
|
|
74
73
|
|
|
75
|
-
|
|
74
|
+
interface Config extends z.infer<typeof netConfigZ> {}
|
|
76
75
|
|
|
77
76
|
const reqZ = z.object({
|
|
78
77
|
command: z.nativeEnum(Command),
|
|
@@ -80,7 +79,7 @@ const reqZ = z.object({
|
|
|
80
79
|
frame: frameZ.optional(),
|
|
81
80
|
});
|
|
82
81
|
|
|
83
|
-
|
|
82
|
+
interface Request extends z.infer<typeof reqZ> {}
|
|
84
83
|
|
|
85
84
|
const resZ = z.object({
|
|
86
85
|
ack: z.boolean(),
|
|
@@ -88,11 +87,11 @@ const resZ = z.object({
|
|
|
88
87
|
error: errorZ.optional().nullable(),
|
|
89
88
|
});
|
|
90
89
|
|
|
91
|
-
|
|
90
|
+
interface Response extends z.infer<typeof resZ> {}
|
|
92
91
|
|
|
93
92
|
export interface WriterConfig {
|
|
94
93
|
// channels denote the channels to write to.
|
|
95
|
-
channels: Params;
|
|
94
|
+
channels: channel.Params;
|
|
96
95
|
// start sets the starting timestamp for the first sample in the writer.
|
|
97
96
|
start?: CrudeTimeStamp;
|
|
98
97
|
// controlSubject sets the control subject of the writer.
|
|
@@ -158,23 +157,21 @@ export interface WriterConfig {
|
|
|
158
157
|
export class Writer {
|
|
159
158
|
private static readonly ENDPOINT = "/frame/write";
|
|
160
159
|
private readonly stream: StreamProxy<typeof reqZ, typeof resZ>;
|
|
161
|
-
private readonly adapter:
|
|
160
|
+
private readonly adapter: WriteAdapter;
|
|
161
|
+
private errAccumulated: boolean = false;
|
|
162
162
|
|
|
163
|
-
private constructor(
|
|
164
|
-
stream: Stream<typeof reqZ, typeof resZ>,
|
|
165
|
-
adapter: WriteFrameAdapter,
|
|
166
|
-
) {
|
|
163
|
+
private constructor(stream: Stream<typeof reqZ, typeof resZ>, adapter: WriteAdapter) {
|
|
167
164
|
this.stream = new StreamProxy("Writer", stream);
|
|
168
165
|
this.adapter = adapter;
|
|
169
166
|
}
|
|
170
167
|
|
|
171
168
|
static async _open(
|
|
172
|
-
retriever: Retriever,
|
|
169
|
+
retriever: channel.Retriever,
|
|
173
170
|
client: StreamClient,
|
|
174
171
|
{
|
|
175
172
|
channels,
|
|
176
173
|
start = TimeStamp.now(),
|
|
177
|
-
authorities = control.Authority.
|
|
174
|
+
authorities = control.Authority.ABSOLUTE,
|
|
178
175
|
controlSubject: subject,
|
|
179
176
|
mode = WriterMode.PersistStream,
|
|
180
177
|
errOnUnauthorized = false,
|
|
@@ -182,7 +179,7 @@ export class Writer {
|
|
|
182
179
|
autoIndexPersistInterval = TimeSpan.SECOND,
|
|
183
180
|
}: WriterConfig,
|
|
184
181
|
): Promise<Writer> {
|
|
185
|
-
const adapter = await
|
|
182
|
+
const adapter = await WriteAdapter.open(retriever, channels);
|
|
186
183
|
const stream = await client.stream(Writer.ENDPOINT, reqZ, resZ);
|
|
187
184
|
const writer = new Writer(stream, adapter);
|
|
188
185
|
await writer.execute({
|
|
@@ -201,14 +198,19 @@ export class Writer {
|
|
|
201
198
|
return writer;
|
|
202
199
|
}
|
|
203
200
|
|
|
204
|
-
async
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
201
|
+
private async checkForAccumulatedError(): Promise<boolean> {
|
|
202
|
+
if (!this.errAccumulated && this.stream.received()) {
|
|
203
|
+
this.errAccumulated = true;
|
|
204
|
+
while (this.stream.received()) await this.stream.receive();
|
|
205
|
+
}
|
|
206
|
+
return this.errAccumulated;
|
|
207
|
+
}
|
|
209
208
|
|
|
209
|
+
async write(channel: channel.KeyOrName, data: CrudeSeries): Promise<boolean>;
|
|
210
|
+
async write(channel: channel.KeysOrNames, data: CrudeSeries[]): Promise<boolean>;
|
|
211
|
+
async write(frame: Crude | Record<channel.KeyOrName, CrudeSeries>): Promise<boolean>;
|
|
210
212
|
async write(
|
|
211
|
-
channelsOrData: Params | Record<KeyOrName, CrudeSeries> |
|
|
213
|
+
channelsOrData: channel.Params | Record<channel.KeyOrName, CrudeSeries> | Crude,
|
|
212
214
|
series?: CrudeSeries | CrudeSeries[],
|
|
213
215
|
): Promise<boolean>;
|
|
214
216
|
|
|
@@ -227,9 +229,10 @@ export class Writer {
|
|
|
227
229
|
* should acknowledge the error by calling the error method or closing the writer.
|
|
228
230
|
*/
|
|
229
231
|
async write(
|
|
230
|
-
channelsOrData: Params | Record<KeyOrName, CrudeSeries> |
|
|
232
|
+
channelsOrData: channel.Params | Record<channel.KeyOrName, CrudeSeries> | Crude,
|
|
231
233
|
series?: CrudeSeries | CrudeSeries[],
|
|
232
234
|
): Promise<boolean> {
|
|
235
|
+
if (await this.checkForAccumulatedError()) return false;
|
|
233
236
|
const frame = await this.adapter.adapt(channelsOrData, series);
|
|
234
237
|
this.stream.send({ command: Command.Write, frame: frame.toPayload() });
|
|
235
238
|
return true;
|
|
@@ -237,21 +240,27 @@ export class Writer {
|
|
|
237
240
|
|
|
238
241
|
async setAuthority(value: number): Promise<boolean>;
|
|
239
242
|
|
|
240
|
-
async setAuthority(
|
|
243
|
+
async setAuthority(
|
|
244
|
+
key: channel.KeyOrName,
|
|
245
|
+
authority: control.Authority,
|
|
246
|
+
): Promise<boolean>;
|
|
241
247
|
|
|
242
|
-
async setAuthority(
|
|
248
|
+
async setAuthority(
|
|
249
|
+
value: Record<channel.KeyOrName, control.Authority>,
|
|
250
|
+
): Promise<boolean>;
|
|
243
251
|
|
|
244
252
|
async setAuthority(
|
|
245
|
-
value: Record<KeyOrName, control.Authority> | KeyOrName | number,
|
|
253
|
+
value: Record<channel.KeyOrName, control.Authority> | channel.KeyOrName | number,
|
|
246
254
|
authority?: control.Authority,
|
|
247
255
|
): Promise<boolean> {
|
|
256
|
+
if (await this.checkForAccumulatedError()) return false;
|
|
248
257
|
let config: Config;
|
|
249
258
|
if (typeof value === "number" && authority == null)
|
|
250
259
|
config = { keys: [], authorities: [value] };
|
|
251
260
|
else {
|
|
252
|
-
let oValue: Record<KeyOrName, control.Authority>;
|
|
261
|
+
let oValue: Record<channel.KeyOrName, control.Authority>;
|
|
253
262
|
if (typeof value === "string" || typeof value === "number")
|
|
254
|
-
oValue = { [value]: authority } as Record<KeyOrName, control.Authority>;
|
|
263
|
+
oValue = { [value]: authority } as Record<channel.KeyOrName, control.Authority>;
|
|
255
264
|
else oValue = value;
|
|
256
265
|
oValue = await this.adapter.adaptObjectKeys(oValue);
|
|
257
266
|
config = {
|
|
@@ -272,7 +281,7 @@ export class Writer {
|
|
|
272
281
|
* After the caller acknowledges the error, they can attempt to commit again.
|
|
273
282
|
*/
|
|
274
283
|
async commit(): Promise<boolean> {
|
|
275
|
-
if (this.
|
|
284
|
+
if (await this.checkForAccumulatedError()) return false;
|
|
276
285
|
const res = await this.execute({ command: Command.Commit });
|
|
277
286
|
return res.ack;
|
|
278
287
|
}
|
|
@@ -282,7 +291,6 @@ export class Writer {
|
|
|
282
291
|
* state, allowing the writer to be used again.
|
|
283
292
|
*/
|
|
284
293
|
async error(): Promise<Error | null> {
|
|
285
|
-
this.stream.send({ command: Command.Error });
|
|
286
294
|
const res = await this.execute({ command: Command.Error });
|
|
287
295
|
return res.error != null ? decodeError(res.error) : null;
|
|
288
296
|
}
|
|
@@ -15,28 +15,30 @@ import { z } from "zod";
|
|
|
15
15
|
import { type framer } from "@/framer";
|
|
16
16
|
import {
|
|
17
17
|
type Device,
|
|
18
|
-
type DeviceKey,
|
|
19
|
-
deviceKeyZ,
|
|
20
18
|
deviceZ,
|
|
21
|
-
type
|
|
22
|
-
|
|
19
|
+
type Key,
|
|
20
|
+
keyZ,
|
|
21
|
+
type New,
|
|
22
|
+
newZ,
|
|
23
|
+
ONTOLOGY_TYPE,
|
|
23
24
|
} from "@/hardware/device/payload";
|
|
25
|
+
import { ontology } from "@/ontology";
|
|
24
26
|
import { signals } from "@/signals";
|
|
25
27
|
import { checkForMultipleOrNoResults } from "@/util/retrieve";
|
|
26
28
|
import { nullableArrayZ } from "@/util/zod";
|
|
27
29
|
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
+
const SET_CHANNEL_NAME = "sy_device_set";
|
|
31
|
+
const DELETE_CHANNEL_NAME = "sy_device_delete";
|
|
30
32
|
|
|
31
33
|
const RETRIEVE_ENDPOINT = "/hardware/device/retrieve";
|
|
32
34
|
const CREATE_ENDPOINT = "/hardware/device/create";
|
|
33
35
|
const DELETE_ENDPOINT = "/hardware/device/delete";
|
|
34
36
|
|
|
35
|
-
const createReqZ = z.object({ devices:
|
|
37
|
+
const createReqZ = z.object({ devices: newZ.array() });
|
|
36
38
|
|
|
37
39
|
const createResZ = z.object({ devices: deviceZ.array() });
|
|
38
40
|
|
|
39
|
-
const deleteReqZ = z.object({ keys:
|
|
41
|
+
const deleteReqZ = z.object({ keys: keyZ.array() });
|
|
40
42
|
|
|
41
43
|
const deleteResZ = z.object({});
|
|
42
44
|
|
|
@@ -44,21 +46,22 @@ const retrieveReqZ = z.object({
|
|
|
44
46
|
search: z.string().optional(),
|
|
45
47
|
limit: z.number().optional(),
|
|
46
48
|
offset: z.number().optional(),
|
|
47
|
-
keys:
|
|
49
|
+
keys: keyZ.array().optional(),
|
|
48
50
|
names: z.string().array().optional(),
|
|
49
51
|
makes: z.string().array().optional(),
|
|
50
52
|
});
|
|
51
53
|
|
|
52
|
-
|
|
54
|
+
interface RetrieveRequest extends z.input<typeof retrieveReqZ> {}
|
|
53
55
|
|
|
54
|
-
export
|
|
56
|
+
export interface RetrieveOptions
|
|
57
|
+
extends Pick<RetrieveRequest, "limit" | "offset" | "makes"> {}
|
|
55
58
|
|
|
56
|
-
|
|
59
|
+
interface PageOptions extends Pick<RetrieveOptions, "makes"> {}
|
|
57
60
|
|
|
58
61
|
const retrieveResZ = z.object({ devices: nullableArrayZ(deviceZ) });
|
|
59
62
|
|
|
60
|
-
export class Client implements AsyncTermSearcher<string,
|
|
61
|
-
readonly type =
|
|
63
|
+
export class Client implements AsyncTermSearcher<string, Key, Device> {
|
|
64
|
+
readonly type = ONTOLOGY_TYPE;
|
|
62
65
|
private readonly client: UnaryClient;
|
|
63
66
|
private readonly frameClient: framer.Client;
|
|
64
67
|
|
|
@@ -67,20 +70,29 @@ export class Client implements AsyncTermSearcher<string, DeviceKey, Device> {
|
|
|
67
70
|
this.frameClient = frameClient;
|
|
68
71
|
}
|
|
69
72
|
|
|
70
|
-
async retrieve<
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
async retrieve<
|
|
74
|
+
Properties extends UnknownRecord = UnknownRecord,
|
|
75
|
+
Make extends string = string,
|
|
76
|
+
Model extends string = string,
|
|
77
|
+
>(key: string, options?: RetrieveOptions): Promise<Device<Properties, Make, Model>>;
|
|
78
|
+
|
|
79
|
+
async retrieve<
|
|
80
|
+
Properties extends UnknownRecord = UnknownRecord,
|
|
81
|
+
Make extends string = string,
|
|
82
|
+
Model extends string = string,
|
|
83
|
+
>(
|
|
76
84
|
keys: string[],
|
|
77
85
|
options?: RetrieveOptions,
|
|
78
|
-
): Promise<Array<Device<
|
|
86
|
+
): Promise<Array<Device<Properties, Make, Model>>>;
|
|
79
87
|
|
|
80
|
-
async retrieve<
|
|
88
|
+
async retrieve<
|
|
89
|
+
Properties extends UnknownRecord = UnknownRecord,
|
|
90
|
+
Make extends string = string,
|
|
91
|
+
Model extends string = string,
|
|
92
|
+
>(
|
|
81
93
|
keys: string | string[],
|
|
82
94
|
options?: RetrieveOptions,
|
|
83
|
-
): Promise<Device<
|
|
95
|
+
): Promise<Device<Properties, Make, Model> | Array<Device<Properties, Make, Model>>> {
|
|
84
96
|
const isSingle = !Array.isArray(keys);
|
|
85
97
|
const res = await sendRequired(
|
|
86
98
|
this.client,
|
|
@@ -90,7 +102,9 @@ export class Client implements AsyncTermSearcher<string, DeviceKey, Device> {
|
|
|
90
102
|
retrieveResZ,
|
|
91
103
|
);
|
|
92
104
|
checkForMultipleOrNoResults("Device", keys, res.devices, isSingle);
|
|
93
|
-
return
|
|
105
|
+
return isSingle
|
|
106
|
+
? (res.devices[0] as Device<Properties, Make, Model>)
|
|
107
|
+
: (res.devices as Array<Device<Properties, Make, Model>>);
|
|
94
108
|
}
|
|
95
109
|
|
|
96
110
|
async search(term: string, options?: RetrieveOptions): Promise<Device[]> {
|
|
@@ -117,17 +131,23 @@ export class Client implements AsyncTermSearcher<string, DeviceKey, Device> {
|
|
|
117
131
|
).devices;
|
|
118
132
|
}
|
|
119
133
|
|
|
120
|
-
async create<
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
134
|
+
async create<
|
|
135
|
+
Properties extends UnknownRecord = UnknownRecord,
|
|
136
|
+
Make extends string = string,
|
|
137
|
+
Model extends string = string,
|
|
138
|
+
>(device: New<Properties, Make>): Promise<Device<Properties, Make, Model>>;
|
|
139
|
+
async create<
|
|
140
|
+
Properties extends UnknownRecord = UnknownRecord,
|
|
141
|
+
Make extends string = string,
|
|
142
|
+
Model extends string = string,
|
|
143
|
+
>(devices: New<Properties, Make>[]): Promise<Device<Properties, Make, Model>[]>;
|
|
144
|
+
async create<
|
|
145
|
+
Properties extends UnknownRecord = UnknownRecord,
|
|
146
|
+
Make extends string = string,
|
|
147
|
+
Model extends string = string,
|
|
148
|
+
>(
|
|
149
|
+
devices: New<Properties, Make> | New<Properties, Make>[],
|
|
150
|
+
): Promise<Device<Properties, Make, Model> | Device<Properties, Make, Model>[]> {
|
|
131
151
|
const isSingle = !Array.isArray(devices);
|
|
132
152
|
const res = await sendRequired(
|
|
133
153
|
this.client,
|
|
@@ -136,7 +156,9 @@ export class Client implements AsyncTermSearcher<string, DeviceKey, Device> {
|
|
|
136
156
|
createReqZ,
|
|
137
157
|
createResZ,
|
|
138
158
|
);
|
|
139
|
-
return isSingle
|
|
159
|
+
return isSingle
|
|
160
|
+
? (res.devices[0] as Device<Properties, Make, Model>)
|
|
161
|
+
: (res.devices as Device<Properties, Make, Model>[]);
|
|
140
162
|
}
|
|
141
163
|
|
|
142
164
|
async delete(keys: string | string[]): Promise<void> {
|
|
@@ -152,15 +174,15 @@ export class Client implements AsyncTermSearcher<string, DeviceKey, Device> {
|
|
|
152
174
|
async openDeviceTracker(): Promise<signals.Observable<string, Device>> {
|
|
153
175
|
return await signals.openObservable<string, Device>(
|
|
154
176
|
this.frameClient,
|
|
155
|
-
|
|
156
|
-
|
|
177
|
+
SET_CHANNEL_NAME,
|
|
178
|
+
DELETE_CHANNEL_NAME,
|
|
157
179
|
decodeDeviceChanges,
|
|
158
180
|
);
|
|
159
181
|
}
|
|
160
182
|
|
|
161
183
|
newSearcherWithOptions(
|
|
162
184
|
options: RetrieveOptions,
|
|
163
|
-
): AsyncTermSearcher<string,
|
|
185
|
+
): AsyncTermSearcher<string, Key, Device> {
|
|
164
186
|
return {
|
|
165
187
|
type: this.type,
|
|
166
188
|
search: async (term: string) => await this.search(term, options),
|
|
@@ -176,3 +198,6 @@ const decodeDeviceChanges: signals.Decoder<string, Device> = (variant, data) =>
|
|
|
176
198
|
return data.toStrings().map((k) => ({ variant, key: k, value: undefined }));
|
|
177
199
|
return data.parseJSON(deviceZ).map((d) => ({ variant, key: d.key, value: d }));
|
|
178
200
|
};
|
|
201
|
+
|
|
202
|
+
export const ontologyID = (key: Key): ontology.ID =>
|
|
203
|
+
new ontology.ID({ type: ONTOLOGY_TYPE, key });
|
|
@@ -13,42 +13,58 @@ import { newClient } from "@/setupspecs";
|
|
|
13
13
|
|
|
14
14
|
const client = newClient();
|
|
15
15
|
|
|
16
|
-
describe("Device", () => {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
properties: { cat: "dog" },
|
|
29
|
-
});
|
|
30
|
-
expect(d.key).toEqual("SN222");
|
|
31
|
-
expect(d.name).toBe("test");
|
|
32
|
-
expect(d.make).toBe("ni");
|
|
16
|
+
describe("Device", async () => {
|
|
17
|
+
const testRack = await client.hardware.racks.create({ name: "test" });
|
|
18
|
+
describe("create", () => {
|
|
19
|
+
it("should create a device on a rack", async () => {
|
|
20
|
+
const d = await client.hardware.devices.create({
|
|
21
|
+
rack: testRack.key,
|
|
22
|
+
location: "Dev1",
|
|
23
|
+
key: "SN222",
|
|
24
|
+
name: "test",
|
|
25
|
+
make: "ni",
|
|
26
|
+
model: "dog",
|
|
27
|
+
properties: { cat: "dog" },
|
|
33
28
|
});
|
|
29
|
+
expect(d.key).toEqual("SN222");
|
|
30
|
+
expect(d.name).toBe("test");
|
|
31
|
+
expect(d.make).toBe("ni");
|
|
34
32
|
});
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
33
|
+
});
|
|
34
|
+
it("should properly encode and decode properties", async () => {
|
|
35
|
+
const properties = {
|
|
36
|
+
rate: 10,
|
|
37
|
+
stateIndexChannel: 234,
|
|
38
|
+
inputChannels: { port1: 34214 },
|
|
39
|
+
outputChannels: [{ port2: 232 }],
|
|
40
|
+
};
|
|
41
|
+
const d = await client.hardware.devices.create({
|
|
42
|
+
key: "SN222",
|
|
43
|
+
rack: testRack.key,
|
|
44
|
+
location: "Dev1",
|
|
45
|
+
name: "test",
|
|
46
|
+
make: "ni",
|
|
47
|
+
model: "dog",
|
|
48
|
+
properties,
|
|
49
|
+
});
|
|
50
|
+
const retrieved = await client.hardware.devices.retrieve(d.key);
|
|
51
|
+
expect(retrieved.properties).toEqual(properties);
|
|
52
|
+
});
|
|
53
|
+
describe("retrieve", () => {
|
|
54
|
+
it("should retrieve a device by its key", async () => {
|
|
55
|
+
const d = await client.hardware.devices.create({
|
|
56
|
+
key: "SN222",
|
|
57
|
+
rack: testRack.key,
|
|
58
|
+
location: "Dev1",
|
|
59
|
+
name: "test",
|
|
60
|
+
make: "ni",
|
|
61
|
+
model: "dog",
|
|
62
|
+
properties: { cat: "dog" },
|
|
51
63
|
});
|
|
64
|
+
const retrieved = await client.hardware.devices.retrieve(d.key);
|
|
65
|
+
expect(retrieved.key).toBe(d.key);
|
|
66
|
+
expect(retrieved.name).toBe("test");
|
|
67
|
+
expect(retrieved.make).toBe("ni");
|
|
52
68
|
});
|
|
53
69
|
});
|
|
54
70
|
});
|
|
@@ -10,44 +10,44 @@
|
|
|
10
10
|
import { binary, type UnknownRecord } from "@synnaxlabs/x";
|
|
11
11
|
import { z } from "zod";
|
|
12
12
|
|
|
13
|
-
import { rackKeyZ } from "@/hardware/rack/payload";
|
|
14
|
-
import {
|
|
13
|
+
import { keyZ as rackKeyZ } from "@/hardware/rack/payload";
|
|
14
|
+
import { decodeJSONString } from "@/util/decodeJSONString";
|
|
15
15
|
|
|
16
|
-
export const
|
|
16
|
+
export const keyZ = z.string();
|
|
17
|
+
export type Key = z.infer<typeof keyZ>;
|
|
17
18
|
|
|
18
19
|
export const deviceZ = z.object({
|
|
19
|
-
key:
|
|
20
|
+
key: keyZ,
|
|
20
21
|
rack: rackKeyZ,
|
|
21
22
|
name: z.string(),
|
|
22
23
|
make: z.string(),
|
|
23
24
|
model: z.string(),
|
|
24
25
|
location: z.string(),
|
|
25
26
|
configured: z.boolean().optional(),
|
|
26
|
-
properties: z.record(z.unknown()).or(
|
|
27
|
-
z.string().transform((c) => {
|
|
28
|
-
if (c === "") return {};
|
|
29
|
-
return binary.JSON_CODEC.decodeString(c);
|
|
30
|
-
}),
|
|
31
|
-
) as z.ZodType<UnknownRecord>,
|
|
27
|
+
properties: z.record(z.unknown()).or(z.string().transform(decodeJSONString)),
|
|
32
28
|
});
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
>
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
29
|
+
export interface Device<
|
|
30
|
+
Properties extends UnknownRecord = UnknownRecord,
|
|
31
|
+
Make extends string = string,
|
|
32
|
+
Model extends string = string,
|
|
33
|
+
> extends Omit<z.output<typeof deviceZ>, "properties"> {
|
|
34
|
+
properties: Properties;
|
|
35
|
+
make: Make;
|
|
36
|
+
model: Model;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const newZ = deviceZ.extend({
|
|
42
40
|
properties: z.unknown().transform((c) => binary.JSON_CODEC.encodeString(c)),
|
|
43
41
|
});
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
>
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
42
|
+
export interface New<
|
|
43
|
+
Properties extends UnknownRecord = UnknownRecord,
|
|
44
|
+
Make extends string = string,
|
|
45
|
+
Model extends string = string,
|
|
46
|
+
> extends Omit<z.input<typeof newZ>, "properties"> {
|
|
47
|
+
properties: Properties;
|
|
48
|
+
make: Make;
|
|
49
|
+
model: Model;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const ONTOLOGY_TYPE = "device";
|
|
53
|
+
export type OntologyType = typeof ONTOLOGY_TYPE;
|