@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
package/src/channel/client.ts
CHANGED
|
@@ -8,8 +8,7 @@
|
|
|
8
8
|
// included in the file licenses/APL.txt.
|
|
9
9
|
|
|
10
10
|
import { sendRequired, type UnaryClient } from "@synnaxlabs/freighter";
|
|
11
|
-
import { array } from "@synnaxlabs/x";
|
|
12
|
-
import { type AsyncTermSearcher } from "@synnaxlabs/x/search";
|
|
11
|
+
import { array, status } from "@synnaxlabs/x";
|
|
13
12
|
import {
|
|
14
13
|
type CrudeDensity,
|
|
15
14
|
type CrudeTimeStamp,
|
|
@@ -18,17 +17,17 @@ import {
|
|
|
18
17
|
type TimeRange,
|
|
19
18
|
type TypedArray,
|
|
20
19
|
} from "@synnaxlabs/x/telem";
|
|
21
|
-
import { z } from "zod
|
|
20
|
+
import { z } from "zod";
|
|
22
21
|
|
|
23
22
|
import {
|
|
24
|
-
channelZ,
|
|
25
23
|
type Key,
|
|
26
24
|
type KeyOrName,
|
|
27
25
|
type Name,
|
|
28
26
|
type New,
|
|
29
|
-
ONTOLOGY_TYPE,
|
|
30
27
|
type Params,
|
|
31
28
|
type Payload,
|
|
29
|
+
payloadZ,
|
|
30
|
+
type Status,
|
|
32
31
|
} from "@/channel/payload";
|
|
33
32
|
import {
|
|
34
33
|
analyzeParams,
|
|
@@ -37,11 +36,12 @@ import {
|
|
|
37
36
|
DebouncedBatchRetriever,
|
|
38
37
|
type RetrieveOptions,
|
|
39
38
|
type Retriever,
|
|
39
|
+
type RetrieveRequest,
|
|
40
40
|
} from "@/channel/retriever";
|
|
41
41
|
import { type Writer } from "@/channel/writer";
|
|
42
42
|
import { ValidationError } from "@/errors";
|
|
43
43
|
import { type framer } from "@/framer";
|
|
44
|
-
import { ontology } from "@/ontology";
|
|
44
|
+
import { type ontology } from "@/ontology";
|
|
45
45
|
import { group } from "@/ontology/group";
|
|
46
46
|
import { checkForMultipleOrNoResults } from "@/util/retrieve";
|
|
47
47
|
|
|
@@ -49,6 +49,9 @@ interface CreateOptions {
|
|
|
49
49
|
retrieveIfNameExists?: boolean;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
export const SET_CHANNEL_NAME = "sy_channel_set";
|
|
53
|
+
export const DELETE_CHANNEL_NAME = "sy_channel_delete";
|
|
54
|
+
|
|
52
55
|
/**
|
|
53
56
|
* Represents a Channel in a Synnax database. Typically, channels should not be
|
|
54
57
|
* instantiated directly, but instead created via the `.channels.create` or retrieved
|
|
@@ -97,7 +100,7 @@ export class Channel {
|
|
|
97
100
|
* An alias for the channel under a specific range. This parameter is unstable and
|
|
98
101
|
* should not be relied upon in the current version of Synnax.
|
|
99
102
|
*/
|
|
100
|
-
|
|
103
|
+
alias: string | undefined;
|
|
101
104
|
/**
|
|
102
105
|
* Whether the channel is virtual. Virtual channels do not store any data in the
|
|
103
106
|
* database, but can still be used for streaming purposes.
|
|
@@ -112,6 +115,10 @@ export class Channel {
|
|
|
112
115
|
* Only used for calculated channels. Specifies the channels required for calculation
|
|
113
116
|
*/
|
|
114
117
|
readonly requires: Key[];
|
|
118
|
+
/**
|
|
119
|
+
* The status of the channel.
|
|
120
|
+
*/
|
|
121
|
+
readonly status?: Status;
|
|
115
122
|
|
|
116
123
|
constructor({
|
|
117
124
|
dataType,
|
|
@@ -124,9 +131,14 @@ export class Channel {
|
|
|
124
131
|
virtual = false,
|
|
125
132
|
frameClient,
|
|
126
133
|
alias,
|
|
134
|
+
status: argsStatus,
|
|
127
135
|
expression = "",
|
|
128
136
|
requires = [],
|
|
129
|
-
}: New & {
|
|
137
|
+
}: New & {
|
|
138
|
+
frameClient?: framer.Client;
|
|
139
|
+
density?: CrudeDensity;
|
|
140
|
+
status?: status.Crude;
|
|
141
|
+
}) {
|
|
130
142
|
this.key = key;
|
|
131
143
|
this.name = name;
|
|
132
144
|
this.dataType = new DataType(dataType);
|
|
@@ -138,6 +150,7 @@ export class Channel {
|
|
|
138
150
|
this.virtual = virtual;
|
|
139
151
|
this.expression = expression;
|
|
140
152
|
this.requires = requires ?? [];
|
|
153
|
+
if (argsStatus != null) this.status = status.create(argsStatus);
|
|
141
154
|
this._frameClient = frameClient ?? null;
|
|
142
155
|
}
|
|
143
156
|
|
|
@@ -153,7 +166,7 @@ export class Channel {
|
|
|
153
166
|
* network transportation, but also provided to you as a convenience.
|
|
154
167
|
*/
|
|
155
168
|
get payload(): Payload {
|
|
156
|
-
return
|
|
169
|
+
return payloadZ.parse({
|
|
157
170
|
key: this.key,
|
|
158
171
|
name: this.name,
|
|
159
172
|
dataType: this.dataType.valueOf(),
|
|
@@ -164,6 +177,7 @@ export class Channel {
|
|
|
164
177
|
virtual: this.virtual,
|
|
165
178
|
expression: this.expression,
|
|
166
179
|
requires: this.requires,
|
|
180
|
+
status: this.status,
|
|
167
181
|
});
|
|
168
182
|
}
|
|
169
183
|
|
|
@@ -200,7 +214,7 @@ export class Channel {
|
|
|
200
214
|
}
|
|
201
215
|
}
|
|
202
216
|
|
|
203
|
-
export const
|
|
217
|
+
export const CALCULATION_STATUS_CHANNEL_NAME = "sy_calculation_status";
|
|
204
218
|
|
|
205
219
|
const RETRIEVE_GROUP_ENDPOINT = "/channel/retrieve-group";
|
|
206
220
|
|
|
@@ -213,8 +227,8 @@ const retrieveGroupResZ = z.object({ group: group.groupZ });
|
|
|
213
227
|
* cluster. This class should not be instantiated directly, and instead should be used
|
|
214
228
|
* through the `channels` property of an {@link Synnax} client.
|
|
215
229
|
*/
|
|
216
|
-
export class Client
|
|
217
|
-
readonly type =
|
|
230
|
+
export class Client {
|
|
231
|
+
readonly type = "channel";
|
|
218
232
|
private readonly frameClient: framer.Client;
|
|
219
233
|
private readonly client: UnaryClient;
|
|
220
234
|
readonly retriever: Retriever;
|
|
@@ -315,7 +329,7 @@ export class Client implements AsyncTermSearcher<string, Key, Channel> {
|
|
|
315
329
|
/**
|
|
316
330
|
* Retrieves a channel from the database using the given key or name.
|
|
317
331
|
*
|
|
318
|
-
* @param
|
|
332
|
+
* @param params - The key or name of the channel to retrieve.
|
|
319
333
|
* @param options - Optional parameters to control the retrieval process.
|
|
320
334
|
* @param options.dataTypes - Limits the query to only channels with the specified data
|
|
321
335
|
* type.
|
|
@@ -334,13 +348,13 @@ export class Client implements AsyncTermSearcher<string, Key, Channel> {
|
|
|
334
348
|
* const channel = await client.channels.retrieve(1);
|
|
335
349
|
* ```
|
|
336
350
|
*/
|
|
337
|
-
async retrieve(
|
|
351
|
+
async retrieve(params: KeyOrName, options?: RetrieveOptions): Promise<Channel>;
|
|
338
352
|
|
|
339
353
|
/**
|
|
340
354
|
* Retrieves multiple channels from the database using the provided keys or the
|
|
341
355
|
* provided names.
|
|
342
356
|
*
|
|
343
|
-
* @param
|
|
357
|
+
* @param params - The keys or the names of the channels to retrieve. Note that
|
|
344
358
|
* this method does not support mixing keys and names in the same call.
|
|
345
359
|
* @param options - Optional parameters to control the retrieval process.
|
|
346
360
|
* @param options.dataTypes - Limits the query to only channels with the specified data
|
|
@@ -348,7 +362,9 @@ export class Client implements AsyncTermSearcher<string, Key, Channel> {
|
|
|
348
362
|
* @param options.notDataTypes - Limits the query to only channels without the specified
|
|
349
363
|
*
|
|
350
364
|
*/
|
|
351
|
-
async retrieve(
|
|
365
|
+
async retrieve(params: Params, options?: RetrieveOptions): Promise<Channel[]>;
|
|
366
|
+
|
|
367
|
+
async retrieve(params: RetrieveRequest): Promise<Channel[]>;
|
|
352
368
|
|
|
353
369
|
/**
|
|
354
370
|
* Retrieves a channel from the database using the given parameters.
|
|
@@ -358,25 +374,24 @@ export class Client implements AsyncTermSearcher<string, Key, Channel> {
|
|
|
358
374
|
* @raises {QueryError} If the channel does not exist or if multiple results are returned.
|
|
359
375
|
*/
|
|
360
376
|
async retrieve(
|
|
361
|
-
|
|
377
|
+
params: Params | RetrieveRequest,
|
|
362
378
|
options?: RetrieveOptions,
|
|
363
379
|
): Promise<Channel | Channel[]> {
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
checkForMultipleOrNoResults("channel", channels, res, isSingle);
|
|
367
|
-
return isSingle ? res[0] : res;
|
|
368
|
-
}
|
|
380
|
+
if (typeof params === "object" && !Array.isArray(params))
|
|
381
|
+
return this.sugar(await this.retriever.retrieve(params));
|
|
369
382
|
|
|
370
|
-
|
|
371
|
-
|
|
383
|
+
const isSingle = !Array.isArray(params);
|
|
384
|
+
const res = this.sugar(await this.retriever.retrieve(params, options));
|
|
385
|
+
checkForMultipleOrNoResults<Params, Channel>("channel", params, res, isSingle);
|
|
386
|
+
return isSingle ? res[0] : res;
|
|
372
387
|
}
|
|
373
388
|
|
|
374
389
|
/***
|
|
375
390
|
* Deletes channels from the database using the given keys or names.
|
|
376
|
-
* @param
|
|
391
|
+
* @param params - The keys or names of the channels to delete.
|
|
377
392
|
*/
|
|
378
|
-
async delete(
|
|
379
|
-
const { normalized, variant } = analyzeParams(
|
|
393
|
+
async delete(params: Params): Promise<void> {
|
|
394
|
+
const { normalized, variant } = analyzeParams(params);
|
|
380
395
|
if (variant === "keys")
|
|
381
396
|
return await this.writer.delete({ keys: normalized as Key[] });
|
|
382
397
|
return await this.writer.delete({ names: normalized as string[] });
|
|
@@ -388,35 +403,19 @@ export class Client implements AsyncTermSearcher<string, Key, Channel> {
|
|
|
388
403
|
return await this.writer.rename(array.toArray(keys), array.toArray(names));
|
|
389
404
|
}
|
|
390
405
|
|
|
391
|
-
newSearcherWithOptions(
|
|
392
|
-
options: RetrieveOptions,
|
|
393
|
-
): AsyncTermSearcher<string, Key, Channel> {
|
|
394
|
-
return {
|
|
395
|
-
type: this.type,
|
|
396
|
-
search: async (term: string) => await this.search(term, options),
|
|
397
|
-
retrieve: async (keys: Key[]) => await this.retrieve(keys, options),
|
|
398
|
-
page: async (offset: number, limit: number) =>
|
|
399
|
-
await this.page(offset, limit, options),
|
|
400
|
-
};
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
async page(
|
|
404
|
-
offset: number,
|
|
405
|
-
limit: number,
|
|
406
|
-
options?: Omit<RetrieveOptions, "limit" | "offset">,
|
|
407
|
-
): Promise<Channel[]> {
|
|
408
|
-
return this.sugar(await this.retriever.page(offset, limit, options));
|
|
409
|
-
}
|
|
410
|
-
|
|
411
406
|
createDebouncedBatchRetriever(deb: number = 10): Retriever {
|
|
412
407
|
return new CacheRetriever(
|
|
413
408
|
new DebouncedBatchRetriever(new ClusterRetriever(this.client), deb),
|
|
414
409
|
);
|
|
415
410
|
}
|
|
416
411
|
|
|
417
|
-
|
|
412
|
+
sugar(payload: Payload): Channel;
|
|
413
|
+
sugar(payloads: Payload[]): Channel[];
|
|
414
|
+
sugar(payloads: Payload | Payload[]): Channel | Channel[] {
|
|
418
415
|
const { frameClient } = this;
|
|
419
|
-
|
|
416
|
+
if (Array.isArray(payloads))
|
|
417
|
+
return payloads.map((p) => new Channel({ ...p, frameClient }));
|
|
418
|
+
return new Channel({ ...payloads, frameClient });
|
|
420
419
|
}
|
|
421
420
|
|
|
422
421
|
async retrieveGroup(): Promise<group.Group> {
|
|
@@ -455,5 +454,7 @@ export const resolveCalculatedIndex = async (
|
|
|
455
454
|
return null;
|
|
456
455
|
};
|
|
457
456
|
|
|
458
|
-
export const ontologyID = (key: Key): ontology.ID =>
|
|
459
|
-
|
|
457
|
+
export const ontologyID = (key: Key): ontology.ID => ({
|
|
458
|
+
type: "channel",
|
|
459
|
+
key: key.toString(),
|
|
460
|
+
});
|
package/src/channel/payload.ts
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
8
|
// included in the file licenses/APL.txt.
|
|
9
9
|
|
|
10
|
-
import { type CrudeDataType, DataType, status } from "@synnaxlabs/x";
|
|
11
|
-
import { z } from "zod
|
|
10
|
+
import { type CrudeDataType, DataType, status, zod } from "@synnaxlabs/x";
|
|
11
|
+
import { z } from "zod";
|
|
12
12
|
|
|
13
13
|
import { nullableArrayZ } from "@/util/zod";
|
|
14
14
|
|
|
@@ -21,9 +21,10 @@ export type Names = Name[];
|
|
|
21
21
|
export type KeyOrName = Key | Name;
|
|
22
22
|
export type KeysOrNames = Keys | Names;
|
|
23
23
|
export type PrimitiveParams = Key | Name | Keys | Names;
|
|
24
|
-
export type Params = Key | Name | Keys | Names | Payload | Payload[];
|
|
25
24
|
|
|
26
|
-
export const
|
|
25
|
+
export const statusZ = status.statusZ();
|
|
26
|
+
export type Status = z.infer<typeof statusZ>;
|
|
27
|
+
export const payloadZ = z.object({
|
|
27
28
|
name: nameZ,
|
|
28
29
|
key: keyZ,
|
|
29
30
|
dataType: DataType.z,
|
|
@@ -35,10 +36,11 @@ export const channelZ = z.object({
|
|
|
35
36
|
alias: z.string().optional(),
|
|
36
37
|
expression: z.string().default(""),
|
|
37
38
|
requires: nullableArrayZ(keyZ),
|
|
39
|
+
status: statusZ.optional(),
|
|
38
40
|
});
|
|
39
|
-
export interface Payload extends z.infer<typeof
|
|
41
|
+
export interface Payload extends z.infer<typeof payloadZ> {}
|
|
40
42
|
|
|
41
|
-
export const newZ =
|
|
43
|
+
export const newZ = payloadZ.extend({
|
|
42
44
|
key: keyZ.optional(),
|
|
43
45
|
leaseholder: z.number().optional(),
|
|
44
46
|
index: keyZ.optional(),
|
|
@@ -49,16 +51,13 @@ export const newZ = channelZ.extend({
|
|
|
49
51
|
requires: nullableArrayZ(keyZ).optional().default([]),
|
|
50
52
|
});
|
|
51
53
|
|
|
52
|
-
export interface New extends Omit<z.input<typeof newZ>, "dataType"> {
|
|
54
|
+
export interface New extends Omit<z.input<typeof newZ>, "dataType" | "status"> {
|
|
53
55
|
dataType: CrudeDataType;
|
|
54
56
|
}
|
|
55
57
|
|
|
56
|
-
export const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
message: z.string(),
|
|
63
|
-
});
|
|
64
|
-
export interface CalculationState extends z.infer<typeof calculationStateZ> {}
|
|
58
|
+
export const paramsZ = z.union([
|
|
59
|
+
zod.toArray(keyZ),
|
|
60
|
+
zod.toArray(nameZ),
|
|
61
|
+
zod.toArray(payloadZ).transform((p) => p.map((c) => c.key)),
|
|
62
|
+
]);
|
|
63
|
+
export type Params = Key | Name | Keys | Names | Payload | Payload[];
|
package/src/channel/retriever.ts
CHANGED
|
@@ -11,10 +11,9 @@ import { type UnaryClient } from "@synnaxlabs/freighter";
|
|
|
11
11
|
import { debounce } from "@synnaxlabs/x/debounce";
|
|
12
12
|
import { DataType } from "@synnaxlabs/x/telem";
|
|
13
13
|
import { Mutex } from "async-mutex";
|
|
14
|
-
import { z } from "zod
|
|
14
|
+
import { z } from "zod";
|
|
15
15
|
|
|
16
16
|
import {
|
|
17
|
-
channelZ,
|
|
18
17
|
type Key,
|
|
19
18
|
type KeyOrName,
|
|
20
19
|
type Keys,
|
|
@@ -24,6 +23,7 @@ import {
|
|
|
24
23
|
type Names,
|
|
25
24
|
type Params,
|
|
26
25
|
type Payload,
|
|
26
|
+
payloadZ,
|
|
27
27
|
} from "@/channel/payload";
|
|
28
28
|
import { QueryError } from "@/errors";
|
|
29
29
|
import {
|
|
@@ -36,7 +36,7 @@ const reqZ = z.object({
|
|
|
36
36
|
leaseholder: z.number().optional(),
|
|
37
37
|
keys: keyZ.array().optional(),
|
|
38
38
|
names: z.string().array().optional(),
|
|
39
|
-
|
|
39
|
+
searchTerm: z.string().optional(),
|
|
40
40
|
rangeKey: z.string().optional(),
|
|
41
41
|
limit: z.number().optional(),
|
|
42
42
|
offset: z.number().optional(),
|
|
@@ -45,13 +45,15 @@ const reqZ = z.object({
|
|
|
45
45
|
virtual: z.boolean().optional(),
|
|
46
46
|
isIndex: z.boolean().optional(),
|
|
47
47
|
internal: z.boolean().optional(),
|
|
48
|
+
calculated: z.boolean().optional(),
|
|
48
49
|
});
|
|
49
|
-
interface
|
|
50
|
+
export interface RetrieveRequest extends z.input<typeof reqZ> {}
|
|
50
51
|
|
|
51
|
-
export interface RetrieveOptions
|
|
52
|
+
export interface RetrieveOptions
|
|
53
|
+
extends Omit<RetrieveRequest, "keys" | "names" | "search"> {}
|
|
52
54
|
export interface PageOptions extends Omit<RetrieveOptions, "offset" | "limit"> {}
|
|
53
55
|
|
|
54
|
-
const resZ = z.object({ channels: nullableArrayZ(
|
|
56
|
+
const resZ = z.object({ channels: nullableArrayZ(payloadZ) });
|
|
55
57
|
|
|
56
58
|
export const analyzeParams = (
|
|
57
59
|
channels: Params,
|
|
@@ -66,9 +68,8 @@ export const analyzeParams = (
|
|
|
66
68
|
};
|
|
67
69
|
|
|
68
70
|
export interface Retriever {
|
|
69
|
-
retrieve: (channels: Params, opts?: RetrieveOptions) => Promise<Payload[]
|
|
70
|
-
|
|
71
|
-
page: (offset: number, limit: number, opts?: PageOptions) => Promise<Payload[]>;
|
|
71
|
+
retrieve: ((channels: Params, opts?: RetrieveOptions) => Promise<Payload[]>) &
|
|
72
|
+
((request: RetrieveRequest) => Promise<Payload[]>);
|
|
72
73
|
}
|
|
73
74
|
|
|
74
75
|
export class ClusterRetriever implements Retriever {
|
|
@@ -79,11 +80,12 @@ export class ClusterRetriever implements Retriever {
|
|
|
79
80
|
this.client = client;
|
|
80
81
|
}
|
|
81
82
|
|
|
82
|
-
async
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
83
|
+
async retrieve(
|
|
84
|
+
channels: Params | RetrieveRequest,
|
|
85
|
+
options?: RetrieveOptions,
|
|
86
|
+
): Promise<Payload[]> {
|
|
87
|
+
if (!Array.isArray(channels) && typeof channels === "object")
|
|
88
|
+
return await this.execute(channels);
|
|
87
89
|
const res = analyzeParams(channels);
|
|
88
90
|
const { variant } = res;
|
|
89
91
|
let { normalized } = res;
|
|
@@ -93,11 +95,7 @@ export class ClusterRetriever implements Retriever {
|
|
|
93
95
|
return await this.execute({ [variant]: normalized, ...options });
|
|
94
96
|
}
|
|
95
97
|
|
|
96
|
-
async
|
|
97
|
-
return await this.execute({ offset, limit, ...options });
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
private async execute(request: Request): Promise<Payload[]> {
|
|
98
|
+
private async execute(request: RetrieveRequest): Promise<Payload[]> {
|
|
101
99
|
const [res, err] = await this.client.send(
|
|
102
100
|
ClusterRetriever.ENDPOINT,
|
|
103
101
|
request,
|
|
@@ -120,15 +118,12 @@ export class CacheRetriever implements Retriever {
|
|
|
120
118
|
this.wrapped = wrapped;
|
|
121
119
|
}
|
|
122
120
|
|
|
123
|
-
async
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
async retrieve(channels: Params, options?: RetrieveOptions): Promise<Payload[]> {
|
|
121
|
+
async retrieve(
|
|
122
|
+
channels: Params | RetrieveRequest,
|
|
123
|
+
options?: RetrieveOptions,
|
|
124
|
+
): Promise<Payload[]> {
|
|
125
|
+
if (!Array.isArray(channels) && typeof channels === "object")
|
|
126
|
+
return await this.wrapped.retrieve(channels);
|
|
132
127
|
const { normalized } = analyzeParams(channels);
|
|
133
128
|
const results: Payload[] = [];
|
|
134
129
|
const toFetch: KeysOrNames = [];
|
|
@@ -226,19 +221,9 @@ export class DebouncedBatchRetriever implements Retriever {
|
|
|
226
221
|
}, deb);
|
|
227
222
|
}
|
|
228
223
|
|
|
229
|
-
async
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
async page(
|
|
234
|
-
offset: number,
|
|
235
|
-
limit: number,
|
|
236
|
-
options?: RetrieveOptions,
|
|
237
|
-
): Promise<Payload[]> {
|
|
238
|
-
return await this.wrapped.page(offset, limit, options);
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
async retrieve(channels: Params): Promise<Payload[]> {
|
|
224
|
+
async retrieve(channels: Params | RetrieveRequest): Promise<Payload[]> {
|
|
225
|
+
if (!Array.isArray(channels) && typeof channels === "object")
|
|
226
|
+
return await this.wrapped.retrieve(channels);
|
|
242
227
|
const { normalized, variant } = analyzeParams(channels);
|
|
243
228
|
// Bypass on name fetches for now.
|
|
244
229
|
if (variant === "names") return await this.wrapped.retrieve(normalized);
|
package/src/channel/writer.ts
CHANGED
|
@@ -9,21 +9,21 @@
|
|
|
9
9
|
|
|
10
10
|
import { sendRequired, type UnaryClient } from "@synnaxlabs/freighter";
|
|
11
11
|
import { type DataType } from "@synnaxlabs/x";
|
|
12
|
-
import { z } from "zod
|
|
12
|
+
import { z } from "zod";
|
|
13
13
|
|
|
14
14
|
import {
|
|
15
|
-
channelZ,
|
|
16
15
|
type Key,
|
|
17
16
|
keyZ,
|
|
18
17
|
nameZ,
|
|
19
18
|
type New,
|
|
20
19
|
newZ,
|
|
21
20
|
type Payload,
|
|
21
|
+
payloadZ,
|
|
22
22
|
} from "@/channel/payload";
|
|
23
23
|
import { type CacheRetriever } from "@/channel/retriever";
|
|
24
24
|
|
|
25
25
|
const createReqZ = z.object({ channels: newZ.array() });
|
|
26
|
-
const createResZ = z.object({ channels:
|
|
26
|
+
const createResZ = z.object({ channels: payloadZ.array() });
|
|
27
27
|
|
|
28
28
|
const deleteReqZ = z.object({
|
|
29
29
|
keys: keyZ.array().optional(),
|
|
@@ -58,7 +58,10 @@ export class Writer {
|
|
|
58
58
|
this.client,
|
|
59
59
|
CREATE_ENDPOINT,
|
|
60
60
|
{
|
|
61
|
-
channels: channels.map((c) => ({
|
|
61
|
+
channels: channels.map((c) => ({
|
|
62
|
+
...c,
|
|
63
|
+
dataType: c.dataType as DataType,
|
|
64
|
+
})),
|
|
62
65
|
},
|
|
63
66
|
createReqZ,
|
|
64
67
|
createResZ,
|
package/src/client.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import { breaker } from "@synnaxlabs/x";
|
|
11
11
|
import { TimeSpan, TimeStamp } from "@synnaxlabs/x/telem";
|
|
12
12
|
import { URL } from "@synnaxlabs/x/url";
|
|
13
|
-
import { z } from "zod
|
|
13
|
+
import { z } from "zod";
|
|
14
14
|
|
|
15
15
|
import { access } from "@/access";
|
|
16
16
|
import { auth } from "@/auth";
|
|
@@ -132,7 +132,7 @@ export default class Synnax extends framer.Client {
|
|
|
132
132
|
this.control = new control.Client(this);
|
|
133
133
|
this.ontology = new ontology.Client(transport.unary, this);
|
|
134
134
|
const rangeWriter = new ranger.Writer(this.transport.unary);
|
|
135
|
-
this.labels = new label.Client(this.transport.unary
|
|
135
|
+
this.labels = new label.Client(this.transport.unary);
|
|
136
136
|
this.ranges = new ranger.Client(
|
|
137
137
|
this,
|
|
138
138
|
rangeWriter,
|
|
@@ -144,14 +144,14 @@ export default class Synnax extends framer.Client {
|
|
|
144
144
|
this.access = new access.Client(this.transport.unary);
|
|
145
145
|
this.user = new user.Client(this.transport.unary);
|
|
146
146
|
this.workspaces = new workspace.Client(this.transport.unary);
|
|
147
|
-
const devices = new device.Client(this.transport.unary
|
|
147
|
+
const devices = new device.Client(this.transport.unary);
|
|
148
148
|
const tasks = new task.Client(
|
|
149
149
|
this.transport.unary,
|
|
150
150
|
this,
|
|
151
151
|
this.ontology,
|
|
152
152
|
this.ranges,
|
|
153
153
|
);
|
|
154
|
-
const racks = new rack.Client(this.transport.unary, tasks
|
|
154
|
+
const racks = new rack.Client(this.transport.unary, tasks);
|
|
155
155
|
this.hardware = new hardware.Client(tasks, racks, devices);
|
|
156
156
|
}
|
|
157
157
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import type { UnaryClient } from "@synnaxlabs/freighter";
|
|
11
11
|
import { migrate } from "@synnaxlabs/x";
|
|
12
12
|
import { TimeSpan } from "@synnaxlabs/x/telem";
|
|
13
|
-
import { z } from "zod
|
|
13
|
+
import { z } from "zod";
|
|
14
14
|
|
|
15
15
|
export const statusZ = z.enum(["disconnected", "connecting", "connected", "failed"]);
|
|
16
16
|
export type Status = z.infer<typeof statusZ>;
|
|
@@ -9,20 +9,22 @@
|
|
|
9
9
|
|
|
10
10
|
import { URL } from "@synnaxlabs/x/url";
|
|
11
11
|
import { describe, expect, it } from "vitest";
|
|
12
|
-
import { z } from "zod
|
|
12
|
+
import { z } from "zod";
|
|
13
13
|
|
|
14
14
|
import { auth } from "@/auth";
|
|
15
15
|
import { connection } from "@/connection";
|
|
16
|
-
import {
|
|
16
|
+
import { TEST_CLIENT_PROPS } from "@/testutil/client";
|
|
17
17
|
import { Transport } from "@/transport";
|
|
18
18
|
|
|
19
19
|
describe("connectivity", () => {
|
|
20
20
|
it("should connect to the server", async () => {
|
|
21
|
-
const transport = new Transport(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
const transport = new Transport(
|
|
22
|
+
new URL({
|
|
23
|
+
host: TEST_CLIENT_PROPS.host,
|
|
24
|
+
port: Number(TEST_CLIENT_PROPS.port),
|
|
25
|
+
}),
|
|
26
|
+
);
|
|
27
|
+
const client = new auth.Client(transport.unary, TEST_CLIENT_PROPS);
|
|
26
28
|
transport.use(client.middleware());
|
|
27
29
|
const connectivity = new connection.Checker(
|
|
28
30
|
transport.unary,
|
|
@@ -31,15 +33,17 @@ describe("connectivity", () => {
|
|
|
31
33
|
);
|
|
32
34
|
const state = await connectivity.check();
|
|
33
35
|
expect(state.status).toEqual("connected");
|
|
34
|
-
expect(z.
|
|
36
|
+
expect(z.uuid().safeParse(state.clusterKey).success).toBe(true);
|
|
35
37
|
});
|
|
36
38
|
describe("version compatibility", () => {
|
|
37
39
|
it("should pull the server and client versions", async () => {
|
|
38
|
-
const transport = new Transport(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
const transport = new Transport(
|
|
41
|
+
new URL({
|
|
42
|
+
host: TEST_CLIENT_PROPS.host,
|
|
43
|
+
port: Number(TEST_CLIENT_PROPS.port),
|
|
44
|
+
}),
|
|
45
|
+
);
|
|
46
|
+
const client = new auth.Client(transport.unary, TEST_CLIENT_PROPS);
|
|
43
47
|
transport.use(client.middleware());
|
|
44
48
|
const connectivity = new connection.Checker(
|
|
45
49
|
transport.unary,
|
|
@@ -51,11 +55,13 @@ describe("connectivity", () => {
|
|
|
51
55
|
expect(state.clientVersion).toBe(__VERSION__);
|
|
52
56
|
});
|
|
53
57
|
it("should adjust state if the server is too old", async () => {
|
|
54
|
-
const transport = new Transport(
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
const transport = new Transport(
|
|
59
|
+
new URL({
|
|
60
|
+
host: TEST_CLIENT_PROPS.host,
|
|
61
|
+
port: Number(TEST_CLIENT_PROPS.port),
|
|
62
|
+
}),
|
|
63
|
+
);
|
|
64
|
+
const client = new auth.Client(transport.unary, TEST_CLIENT_PROPS);
|
|
59
65
|
transport.use(client.middleware());
|
|
60
66
|
const connectivity = new connection.Checker(
|
|
61
67
|
transport.unary,
|
|
@@ -67,11 +73,13 @@ describe("connectivity", () => {
|
|
|
67
73
|
expect(state.clientVersion).toBe("50000.0.0");
|
|
68
74
|
});
|
|
69
75
|
it("should adjust state if the server is too new", async () => {
|
|
70
|
-
const transport = new Transport(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
76
|
+
const transport = new Transport(
|
|
77
|
+
new URL({
|
|
78
|
+
host: TEST_CLIENT_PROPS.host,
|
|
79
|
+
port: Number(TEST_CLIENT_PROPS.port),
|
|
80
|
+
}),
|
|
81
|
+
);
|
|
82
|
+
const client = new auth.Client(transport.unary, TEST_CLIENT_PROPS);
|
|
75
83
|
transport.use(client.middleware());
|
|
76
84
|
const connectivity = new connection.Checker(transport.unary, undefined, "0.0.0");
|
|
77
85
|
const state = await connectivity.check();
|
package/src/control/client.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import { StateTracker } from "@/control/state";
|
|
11
11
|
import { framer } from "@/framer";
|
|
12
12
|
|
|
13
|
-
const
|
|
13
|
+
export const CONTROL_STATE_CHANNEL_NAME = "sy_node_1_control";
|
|
14
14
|
|
|
15
15
|
export class Client {
|
|
16
16
|
private readonly framer: framer.Client;
|
|
@@ -22,7 +22,7 @@ export class Client {
|
|
|
22
22
|
async openStateTracker(): Promise<StateTracker> {
|
|
23
23
|
const stream = await framer.HardenedStreamer.open(
|
|
24
24
|
async (p) => await this.framer.openStreamer(p),
|
|
25
|
-
|
|
25
|
+
CONTROL_STATE_CHANNEL_NAME,
|
|
26
26
|
);
|
|
27
27
|
return new StateTracker(stream);
|
|
28
28
|
}
|
|
@@ -9,14 +9,14 @@
|
|
|
9
9
|
|
|
10
10
|
import { describe, expect, it } from "vitest";
|
|
11
11
|
|
|
12
|
-
import {
|
|
12
|
+
import { createTestClient } from "@/testutil/client";
|
|
13
13
|
|
|
14
|
-
const client =
|
|
14
|
+
const client = createTestClient();
|
|
15
15
|
|
|
16
16
|
describe("state", () => {
|
|
17
17
|
it("should receive the initial control state from the cluster", async () => {
|
|
18
18
|
const s = await client.control.openStateTracker();
|
|
19
|
-
await expect.poll(() => s.states.size > 0).
|
|
19
|
+
await expect.poll(() => s.states.size > 0).toBe(true);
|
|
20
20
|
await s.close();
|
|
21
21
|
});
|
|
22
22
|
});
|
package/src/control/state.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import { control } from "@synnaxlabs/x";
|
|
11
11
|
import { binary } from "@synnaxlabs/x/binary";
|
|
12
12
|
import { type observe } from "@synnaxlabs/x/observe";
|
|
13
|
-
import { z } from "zod
|
|
13
|
+
import { z } from "zod";
|
|
14
14
|
|
|
15
15
|
import { type channel } from "@/channel";
|
|
16
16
|
import { keyZ } from "@/channel/payload";
|