@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.
Files changed (245) hide show
  1. package/.turbo/turbo-build.log +7 -7
  2. package/dist/access/payload.d.ts +1 -1
  3. package/dist/access/payload.d.ts.map +1 -1
  4. package/dist/access/policy/client.d.ts +263 -6
  5. package/dist/access/policy/client.d.ts.map +1 -1
  6. package/dist/access/policy/external.d.ts +0 -1
  7. package/dist/access/policy/external.d.ts.map +1 -1
  8. package/dist/access/policy/payload.d.ts +105 -93
  9. package/dist/access/policy/payload.d.ts.map +1 -1
  10. package/dist/auth/auth.d.ts +1 -1
  11. package/dist/auth/auth.d.ts.map +1 -1
  12. package/dist/channel/client.d.ts +23 -17
  13. package/dist/channel/client.d.ts.map +1 -1
  14. package/dist/channel/payload.d.ts +151 -21
  15. package/dist/channel/payload.d.ts.map +1 -1
  16. package/dist/channel/retriever.d.ts +9 -16
  17. package/dist/channel/retriever.d.ts.map +1 -1
  18. package/dist/channel/writer.d.ts +1 -1
  19. package/dist/channel/writer.d.ts.map +1 -1
  20. package/dist/client.cjs +27 -135
  21. package/dist/client.d.ts +3 -3
  22. package/dist/client.d.ts.map +1 -1
  23. package/dist/client.js +8657 -28963
  24. package/dist/connection/checker.d.ts +1 -1
  25. package/dist/connection/checker.d.ts.map +1 -1
  26. package/dist/control/client.d.ts +1 -0
  27. package/dist/control/client.d.ts.map +1 -1
  28. package/dist/control/state.d.ts +6 -6
  29. package/dist/control/state.d.ts.map +1 -1
  30. package/dist/errors.d.ts +18 -5
  31. package/dist/errors.d.ts.map +1 -1
  32. package/dist/framer/adapter.d.ts +3 -3
  33. package/dist/framer/adapter.d.ts.map +1 -1
  34. package/dist/framer/client.d.ts +4 -13
  35. package/dist/framer/client.d.ts.map +1 -1
  36. package/dist/framer/codec.d.ts +1 -1
  37. package/dist/framer/codec.d.ts.map +1 -1
  38. package/dist/framer/deleter.d.ts +5 -5
  39. package/dist/framer/deleter.d.ts.map +1 -1
  40. package/dist/framer/frame.d.ts +5 -7
  41. package/dist/framer/frame.d.ts.map +1 -1
  42. package/dist/framer/streamProxy.d.ts +1 -1
  43. package/dist/framer/streamProxy.d.ts.map +1 -1
  44. package/dist/framer/streamer.d.ts +235 -20
  45. package/dist/framer/streamer.d.ts.map +1 -1
  46. package/dist/framer/writer.d.ts +302 -33
  47. package/dist/framer/writer.d.ts.map +1 -1
  48. package/dist/hardware/device/client.d.ts +49 -28
  49. package/dist/hardware/device/client.d.ts.map +1 -1
  50. package/dist/hardware/device/payload.d.ts +126 -46
  51. package/dist/hardware/device/payload.d.ts.map +1 -1
  52. package/dist/hardware/rack/client.d.ts +78 -22
  53. package/dist/hardware/rack/client.d.ts.map +1 -1
  54. package/dist/hardware/rack/payload.d.ts +99 -56
  55. package/dist/hardware/rack/payload.d.ts.map +1 -1
  56. package/dist/hardware/task/client.d.ts +100 -41
  57. package/dist/hardware/task/client.d.ts.map +1 -1
  58. package/dist/hardware/task/payload.d.ts +83 -61
  59. package/dist/hardware/task/payload.d.ts.map +1 -1
  60. package/dist/index.d.ts +2 -2
  61. package/dist/index.d.ts.map +1 -1
  62. package/dist/label/client.d.ts +138 -20
  63. package/dist/label/client.d.ts.map +1 -1
  64. package/dist/label/external.d.ts +0 -2
  65. package/dist/label/external.d.ts.map +1 -1
  66. package/dist/label/payload.d.ts +4 -5
  67. package/dist/label/payload.d.ts.map +1 -1
  68. package/dist/ontology/client.d.ts +45 -135
  69. package/dist/ontology/client.d.ts.map +1 -1
  70. package/dist/ontology/group/group.d.ts +3 -3
  71. package/dist/ontology/group/group.d.ts.map +1 -1
  72. package/dist/ontology/group/payload.d.ts +3 -27
  73. package/dist/ontology/group/payload.d.ts.map +1 -1
  74. package/dist/ontology/payload.d.ts +114 -243
  75. package/dist/ontology/payload.d.ts.map +1 -1
  76. package/dist/ontology/writer.d.ts +4 -4
  77. package/dist/ontology/writer.d.ts.map +1 -1
  78. package/dist/ranger/alias.d.ts +15 -5
  79. package/dist/ranger/alias.d.ts.map +1 -1
  80. package/dist/ranger/client.d.ts +91 -30
  81. package/dist/ranger/client.d.ts.map +1 -1
  82. package/dist/ranger/external.d.ts +1 -1
  83. package/dist/ranger/external.d.ts.map +1 -1
  84. package/dist/ranger/kv.d.ts +11 -12
  85. package/dist/ranger/kv.d.ts.map +1 -1
  86. package/dist/ranger/payload.d.ts +19 -44
  87. package/dist/ranger/payload.d.ts.map +1 -1
  88. package/dist/ranger/writer.d.ts +22 -19
  89. package/dist/ranger/writer.d.ts.map +1 -1
  90. package/dist/testutil/client.d.ts +4 -0
  91. package/dist/testutil/client.d.ts.map +1 -0
  92. package/dist/user/client.d.ts +59 -6
  93. package/dist/user/client.d.ts.map +1 -1
  94. package/dist/user/payload.d.ts +4 -6
  95. package/dist/user/payload.d.ts.map +1 -1
  96. package/dist/user/retriever.d.ts +2 -2
  97. package/dist/user/retriever.d.ts.map +1 -1
  98. package/dist/util/decodeJSONString.d.ts +2 -2
  99. package/dist/util/decodeJSONString.d.ts.map +1 -1
  100. package/dist/util/parseWithoutKeyConversion.d.ts +2 -2
  101. package/dist/util/parseWithoutKeyConversion.d.ts.map +1 -1
  102. package/dist/util/retrieve.d.ts +1 -1
  103. package/dist/util/retrieve.d.ts.map +1 -1
  104. package/dist/util/zod.d.ts +1 -1
  105. package/dist/util/zod.d.ts.map +1 -1
  106. package/dist/workspace/client.d.ts +17 -6
  107. package/dist/workspace/client.d.ts.map +1 -1
  108. package/dist/workspace/lineplot/client.d.ts +2 -2
  109. package/dist/workspace/lineplot/client.d.ts.map +1 -1
  110. package/dist/workspace/lineplot/payload.d.ts +8 -9
  111. package/dist/workspace/lineplot/payload.d.ts.map +1 -1
  112. package/dist/workspace/log/client.d.ts +2 -2
  113. package/dist/workspace/log/client.d.ts.map +1 -1
  114. package/dist/workspace/log/payload.d.ts +8 -9
  115. package/dist/workspace/log/payload.d.ts.map +1 -1
  116. package/dist/workspace/payload.d.ts +10 -11
  117. package/dist/workspace/payload.d.ts.map +1 -1
  118. package/dist/workspace/schematic/client.d.ts +2 -2
  119. package/dist/workspace/schematic/client.d.ts.map +1 -1
  120. package/dist/workspace/schematic/payload.d.ts +10 -11
  121. package/dist/workspace/schematic/payload.d.ts.map +1 -1
  122. package/dist/workspace/table/client.d.ts +2 -2
  123. package/dist/workspace/table/client.d.ts.map +1 -1
  124. package/dist/workspace/table/payload.d.ts +10 -11
  125. package/dist/workspace/table/payload.d.ts.map +1 -1
  126. package/examples/node/package-lock.json +47 -39
  127. package/examples/node/package.json +2 -1
  128. package/examples/node/streamWrite.js +5 -11
  129. package/package.json +14 -13
  130. package/src/access/payload.ts +1 -1
  131. package/src/access/policy/client.ts +87 -32
  132. package/src/access/policy/external.ts +0 -1
  133. package/src/access/policy/payload.ts +4 -4
  134. package/src/access/policy/policy.spec.ts +86 -83
  135. package/src/auth/auth.spec.ts +29 -18
  136. package/src/auth/auth.ts +1 -1
  137. package/src/channel/batchRetriever.spec.ts +4 -9
  138. package/src/channel/channel.spec.ts +24 -6
  139. package/src/channel/client.ts +52 -51
  140. package/src/channel/payload.ts +15 -16
  141. package/src/channel/retriever.ts +26 -41
  142. package/src/channel/writer.ts +7 -4
  143. package/src/client.ts +4 -4
  144. package/src/connection/checker.ts +1 -1
  145. package/src/connection/connection.spec.ts +31 -23
  146. package/src/control/client.ts +2 -2
  147. package/src/control/state.spec.ts +3 -3
  148. package/src/control/state.ts +1 -1
  149. package/src/errors.spec.ts +9 -5
  150. package/src/errors.ts +28 -15
  151. package/src/framer/adapter.spec.ts +118 -9
  152. package/src/framer/adapter.ts +24 -11
  153. package/src/framer/client.spec.ts +125 -2
  154. package/src/framer/client.ts +41 -47
  155. package/src/framer/codec.ts +1 -1
  156. package/src/framer/deleter.spec.ts +2 -2
  157. package/src/framer/deleter.ts +1 -1
  158. package/src/framer/frame.ts +1 -4
  159. package/src/framer/iterator.spec.ts +8 -8
  160. package/src/framer/iterator.ts +1 -1
  161. package/src/framer/streamProxy.ts +1 -1
  162. package/src/framer/streamer.spec.ts +185 -36
  163. package/src/framer/streamer.ts +28 -36
  164. package/src/framer/writer.spec.ts +7 -6
  165. package/src/framer/writer.ts +97 -111
  166. package/src/hardware/device/client.ts +45 -131
  167. package/src/hardware/device/device.spec.ts +163 -52
  168. package/src/hardware/device/payload.ts +10 -21
  169. package/src/hardware/rack/client.ts +87 -105
  170. package/src/hardware/rack/payload.ts +4 -13
  171. package/src/hardware/rack/rack.spec.ts +28 -35
  172. package/src/hardware/task/client.ts +335 -291
  173. package/src/hardware/task/payload.ts +86 -62
  174. package/src/hardware/task/task.spec.ts +208 -32
  175. package/src/index.ts +2 -1
  176. package/src/label/client.ts +100 -95
  177. package/src/label/external.ts +0 -2
  178. package/src/label/label.spec.ts +8 -6
  179. package/src/label/payload.ts +3 -4
  180. package/src/ontology/client.ts +41 -324
  181. package/src/ontology/group/group.spec.ts +2 -2
  182. package/src/ontology/group/group.ts +4 -5
  183. package/src/ontology/group/payload.ts +2 -25
  184. package/src/ontology/group/writer.ts +1 -1
  185. package/src/ontology/ontology.spec.ts +355 -41
  186. package/src/ontology/payload.ts +77 -112
  187. package/src/ontology/writer.ts +8 -17
  188. package/src/ranger/alias.ts +45 -37
  189. package/src/ranger/client.ts +144 -149
  190. package/src/ranger/external.ts +1 -1
  191. package/src/ranger/kv.ts +9 -27
  192. package/src/ranger/payload.ts +23 -37
  193. package/src/ranger/ranger.spec.ts +37 -56
  194. package/src/ranger/writer.ts +1 -1
  195. package/src/{signals/index.ts → testutil/client.ts} +11 -1
  196. package/src/user/client.ts +122 -47
  197. package/src/user/payload.ts +2 -5
  198. package/src/user/retriever.ts +1 -1
  199. package/src/user/user.spec.ts +31 -31
  200. package/src/user/writer.ts +1 -1
  201. package/src/util/decodeJSONString.ts +3 -3
  202. package/src/util/parseWithoutKeyConversion.ts +2 -2
  203. package/src/util/retrieve.ts +1 -1
  204. package/src/util/zod.ts +1 -1
  205. package/src/workspace/client.ts +20 -36
  206. package/src/workspace/lineplot/client.ts +5 -7
  207. package/src/workspace/lineplot/lineplot.spec.ts +2 -2
  208. package/src/workspace/lineplot/payload.ts +4 -7
  209. package/src/workspace/log/client.ts +5 -7
  210. package/src/workspace/log/log.spec.ts +2 -2
  211. package/src/workspace/log/payload.ts +4 -7
  212. package/src/workspace/payload.ts +4 -7
  213. package/src/workspace/schematic/client.ts +5 -7
  214. package/src/workspace/schematic/payload.ts +4 -7
  215. package/src/workspace/schematic/schematic.spec.ts +2 -2
  216. package/src/workspace/table/client.ts +5 -7
  217. package/src/workspace/table/payload.ts +4 -7
  218. package/src/workspace/table/table.spec.ts +2 -2
  219. package/src/workspace/workspace.spec.ts +2 -2
  220. package/dist/access/policy/ontology.d.ts +0 -5
  221. package/dist/access/policy/ontology.d.ts.map +0 -1
  222. package/dist/access/policy/retriever.d.ts +0 -40
  223. package/dist/access/policy/retriever.d.ts.map +0 -1
  224. package/dist/access/policy/writer.d.ts +0 -9
  225. package/dist/access/policy/writer.d.ts.map +0 -1
  226. package/dist/label/retriever.d.ts +0 -14
  227. package/dist/label/retriever.d.ts.map +0 -1
  228. package/dist/label/writer.d.ts +0 -54
  229. package/dist/label/writer.d.ts.map +0 -1
  230. package/dist/setupspecs.d.ts +0 -5
  231. package/dist/setupspecs.d.ts.map +0 -1
  232. package/dist/signals/external.d.ts +0 -2
  233. package/dist/signals/external.d.ts.map +0 -1
  234. package/dist/signals/index.d.ts +0 -2
  235. package/dist/signals/index.d.ts.map +0 -1
  236. package/dist/signals/observable.d.ts +0 -12
  237. package/dist/signals/observable.d.ts.map +0 -1
  238. package/src/access/policy/ontology.ts +0 -17
  239. package/src/access/policy/retriever.ts +0 -44
  240. package/src/access/policy/writer.ts +0 -65
  241. package/src/label/retriever.ts +0 -63
  242. package/src/label/writer.ts +0 -95
  243. package/src/setupspecs.ts +0 -27
  244. package/src/signals/external.ts +0 -10
  245. package/src/signals/observable.ts +0 -42
@@ -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/v4";
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
- readonly alias: string | undefined;
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 & { frameClient?: framer.Client; density?: CrudeDensity }) {
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 channelZ.parse({
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 CALCULATION_STATE_CHANNEL_NAME = "sy_calculation_state";
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 implements AsyncTermSearcher<string, Key, Channel> {
217
- readonly type = ONTOLOGY_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 channel - The key or name of the channel to retrieve.
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(channel: KeyOrName, options?: RetrieveOptions): Promise<Channel>;
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 channels - The keys or the names of the channels to retrieve. Note that
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(channels: Params, options?: RetrieveOptions): Promise<Channel[]>;
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
- channels: Params,
377
+ params: Params | RetrieveRequest,
362
378
  options?: RetrieveOptions,
363
379
  ): Promise<Channel | Channel[]> {
364
- const isSingle = !Array.isArray(channels);
365
- const res = this.sugar(await this.retriever.retrieve(channels, options));
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
- async search(term: string, options?: RetrieveOptions): Promise<Channel[]> {
371
- return this.sugar(await this.retriever.search(term, options));
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 channels - The keys or names of the channels to delete.
391
+ * @param params - The keys or names of the channels to delete.
377
392
  */
378
- async delete(channels: Params): Promise<void> {
379
- const { normalized, variant } = analyzeParams(channels);
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
- private sugar(payloads: Payload[]): Channel[] {
412
+ sugar(payload: Payload): Channel;
413
+ sugar(payloads: Payload[]): Channel[];
414
+ sugar(payloads: Payload | Payload[]): Channel | Channel[] {
418
415
  const { frameClient } = this;
419
- return payloads.map((p) => new Channel({ ...p, frameClient }));
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
- new ontology.ID({ type: ONTOLOGY_TYPE, key: key.toString() });
457
+ export const ontologyID = (key: Key): ontology.ID => ({
458
+ type: "channel",
459
+ key: key.toString(),
460
+ });
@@ -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/v4";
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 channelZ = z.object({
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 channelZ> {}
41
+ export interface Payload extends z.infer<typeof payloadZ> {}
40
42
 
41
- export const newZ = channelZ.extend({
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 ONTOLOGY_TYPE = "channel";
57
- export type OntologyType = typeof ONTOLOGY_TYPE;
58
-
59
- export const calculationStateZ = z.object({
60
- key: keyZ,
61
- variant: status.variantZ,
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[];
@@ -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/v4";
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
- search: z.string().optional(),
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 Request extends z.input<typeof reqZ> {}
50
+ export interface RetrieveRequest extends z.input<typeof reqZ> {}
50
51
 
51
- export interface RetrieveOptions extends Omit<Request, "keys" | "names" | "search"> {}
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(channelZ) });
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
- search: (term: string, opts?: RetrieveOptions) => Promise<Payload[]>;
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 search(term: string, options?: RetrieveOptions): Promise<Payload[]> {
83
- return await this.execute({ search: term, ...options });
84
- }
85
-
86
- async retrieve(channels: Params, options?: RetrieveOptions): Promise<Payload[]> {
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 page(offset: number, limit: number, options?: PageOptions): Promise<Payload[]> {
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 search(term: string, options?: RetrieveOptions): Promise<Payload[]> {
124
- return await this.wrapped.search(term, options);
125
- }
126
-
127
- async page(offset: number, limit: number, options?: PageOptions): Promise<Payload[]> {
128
- return await this.wrapped.page(offset, limit, options);
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 search(term: string, options?: RetrieveOptions): Promise<Payload[]> {
230
- return await this.wrapped.search(term, options);
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);
@@ -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/v4";
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: channelZ.array() });
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) => ({ ...c, dataType: c.dataType as DataType })),
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/v4";
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, this, this.ontology);
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, this);
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, this);
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/v4";
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/v4";
12
+ import { z } from "zod";
13
13
 
14
14
  import { auth } from "@/auth";
15
15
  import { connection } from "@/connection";
16
- import { HOST, PORT } from "@/setupspecs";
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(new URL({ host: HOST, port: PORT }));
22
- const client = new auth.Client(transport.unary, {
23
- username: "synnax",
24
- password: "seldon",
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.string().uuid().safeParse(state.clusterKey).success).toBe(true);
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(new URL({ host: HOST, port: PORT }));
39
- const client = new auth.Client(transport.unary, {
40
- username: "synnax",
41
- password: "seldon",
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(new URL({ host: HOST, port: PORT }));
55
- const client = new auth.Client(transport.unary, {
56
- username: "synnax",
57
- password: "seldon",
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(new URL({ host: HOST, port: PORT }));
71
- const client = new auth.Client(transport.unary, {
72
- username: "synnax",
73
- password: "seldon",
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();
@@ -10,7 +10,7 @@
10
10
  import { StateTracker } from "@/control/state";
11
11
  import { framer } from "@/framer";
12
12
 
13
- const CONTROL_STATE_KEY = "sy_node_1_control";
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
- CONTROL_STATE_KEY,
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 { newClient } from "@/setupspecs";
12
+ import { createTestClient } from "@/testutil/client";
13
13
 
14
- const client = newClient();
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).toBeTruthy();
19
+ await expect.poll(() => s.states.size > 0).toBe(true);
20
20
  await s.close();
21
21
  });
22
22
  });
@@ -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/v4";
13
+ import { z } from "zod";
14
14
 
15
15
  import { type channel } from "@/channel";
16
16
  import { keyZ } from "@/channel/payload";