@synnaxlabs/client 0.40.0 → 0.42.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.
Files changed (142) hide show
  1. package/.turbo/turbo-build.log +7 -7
  2. package/dist/access/payload.d.ts +7 -1
  3. package/dist/access/payload.d.ts.map +1 -1
  4. package/dist/access/policy/payload.d.ts +182 -142
  5. package/dist/access/policy/payload.d.ts.map +1 -1
  6. package/dist/access/policy/retriever.d.ts +25 -22
  7. package/dist/access/policy/retriever.d.ts.map +1 -1
  8. package/dist/auth/auth.d.ts +1 -7
  9. package/dist/auth/auth.d.ts.map +1 -1
  10. package/dist/channel/client.d.ts +2 -7
  11. package/dist/channel/client.d.ts.map +1 -1
  12. package/dist/channel/payload.d.ts +13 -74
  13. package/dist/channel/payload.d.ts.map +1 -1
  14. package/dist/channel/retriever.d.ts +5 -31
  15. package/dist/channel/retriever.d.ts.map +1 -1
  16. package/dist/channel/writer.d.ts +6 -18
  17. package/dist/channel/writer.d.ts.map +1 -1
  18. package/dist/client.cjs +35 -30
  19. package/dist/client.d.ts +8 -56
  20. package/dist/client.d.ts.map +1 -1
  21. package/dist/client.js +6391 -3850
  22. package/dist/connection/checker.d.ts +22 -39
  23. package/dist/connection/checker.d.ts.map +1 -1
  24. package/dist/control/client.d.ts.map +1 -1
  25. package/dist/control/state.d.ts +6 -26
  26. package/dist/control/state.d.ts.map +1 -1
  27. package/dist/errors.d.ts +31 -56
  28. package/dist/errors.d.ts.map +1 -1
  29. package/dist/framer/adapter.d.ts +4 -0
  30. package/dist/framer/adapter.d.ts.map +1 -1
  31. package/dist/framer/client.d.ts +2 -2
  32. package/dist/framer/client.d.ts.map +1 -1
  33. package/dist/framer/codec.d.ts +34 -0
  34. package/dist/framer/codec.d.ts.map +1 -0
  35. package/dist/framer/codec.spec.d.ts +2 -0
  36. package/dist/framer/codec.spec.d.ts.map +1 -0
  37. package/dist/framer/deleter.d.ts +12 -49
  38. package/dist/framer/deleter.d.ts.map +1 -1
  39. package/dist/framer/frame.d.ts +26 -88
  40. package/dist/framer/frame.d.ts.map +1 -1
  41. package/dist/framer/iterator.d.ts.map +1 -1
  42. package/dist/framer/streamer.d.ts +69 -11
  43. package/dist/framer/streamer.d.ts.map +1 -1
  44. package/dist/framer/writer.d.ts +60 -257
  45. package/dist/framer/writer.d.ts.map +1 -1
  46. package/dist/hardware/device/client.d.ts +13 -24
  47. package/dist/hardware/device/client.d.ts.map +1 -1
  48. package/dist/hardware/device/payload.d.ts +25 -44
  49. package/dist/hardware/device/payload.d.ts.map +1 -1
  50. package/dist/hardware/rack/client.d.ts +12 -5
  51. package/dist/hardware/rack/client.d.ts.map +1 -1
  52. package/dist/hardware/rack/payload.d.ts +36 -15
  53. package/dist/hardware/rack/payload.d.ts.map +1 -1
  54. package/dist/hardware/task/client.d.ts +4 -20
  55. package/dist/hardware/task/client.d.ts.map +1 -1
  56. package/dist/hardware/task/payload.d.ts +41 -116
  57. package/dist/hardware/task/payload.d.ts.map +1 -1
  58. package/dist/index.d.ts +0 -2
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/label/payload.d.ts +1 -9
  61. package/dist/label/payload.d.ts.map +1 -1
  62. package/dist/label/writer.d.ts +27 -36
  63. package/dist/label/writer.d.ts.map +1 -1
  64. package/dist/ontology/client.d.ts +46 -36
  65. package/dist/ontology/client.d.ts.map +1 -1
  66. package/dist/ontology/group/payload.d.ts +1 -7
  67. package/dist/ontology/group/payload.d.ts.map +1 -1
  68. package/dist/ontology/payload.d.ts +239 -146
  69. package/dist/ontology/payload.d.ts.map +1 -1
  70. package/dist/ranger/client.d.ts +13 -55
  71. package/dist/ranger/client.d.ts.map +1 -1
  72. package/dist/ranger/kv.d.ts +7 -49
  73. package/dist/ranger/kv.d.ts.map +1 -1
  74. package/dist/ranger/payload.d.ts +21 -99
  75. package/dist/ranger/payload.d.ts.map +1 -1
  76. package/dist/ranger/writer.d.ts +35 -88
  77. package/dist/ranger/writer.d.ts.map +1 -1
  78. package/dist/testutil/indexedPair.d.ts +5 -0
  79. package/dist/testutil/indexedPair.d.ts.map +1 -0
  80. package/dist/testutil/telem.d.ts +3 -0
  81. package/dist/testutil/telem.d.ts.map +1 -0
  82. package/dist/transport.d.ts +2 -2
  83. package/dist/transport.d.ts.map +1 -1
  84. package/dist/user/payload.d.ts +3 -29
  85. package/dist/user/payload.d.ts.map +1 -1
  86. package/dist/user/retriever.d.ts +3 -9
  87. package/dist/user/retriever.d.ts.map +1 -1
  88. package/dist/util/decodeJSONString.d.ts.map +1 -1
  89. package/dist/util/zod.d.ts +1 -1
  90. package/dist/util/zod.d.ts.map +1 -1
  91. package/dist/workspace/lineplot/payload.d.ts +10 -26
  92. package/dist/workspace/lineplot/payload.d.ts.map +1 -1
  93. package/dist/workspace/log/payload.d.ts +10 -26
  94. package/dist/workspace/log/payload.d.ts.map +1 -1
  95. package/dist/workspace/payload.d.ts +14 -40
  96. package/dist/workspace/payload.d.ts.map +1 -1
  97. package/dist/workspace/schematic/payload.d.ts +13 -45
  98. package/dist/workspace/schematic/payload.d.ts.map +1 -1
  99. package/dist/workspace/table/payload.d.ts +13 -39
  100. package/dist/workspace/table/payload.d.ts.map +1 -1
  101. package/package.json +8 -8
  102. package/src/channel/channel.spec.ts +26 -27
  103. package/src/channel/client.ts +0 -9
  104. package/src/channel/payload.ts +22 -5
  105. package/src/channel/retriever.ts +12 -6
  106. package/src/client.ts +4 -4
  107. package/src/control/client.ts +5 -2
  108. package/src/control/state.spec.ts +1 -2
  109. package/src/control/state.ts +8 -3
  110. package/src/errors.spec.ts +5 -4
  111. package/src/errors.ts +21 -82
  112. package/src/framer/adapter.ts +22 -3
  113. package/src/framer/client.ts +38 -21
  114. package/src/framer/codec.spec.ts +303 -0
  115. package/src/framer/codec.ts +396 -0
  116. package/src/framer/deleter.spec.ts +51 -63
  117. package/src/framer/frame.ts +16 -5
  118. package/src/framer/iterator.spec.ts +45 -28
  119. package/src/framer/iterator.ts +6 -5
  120. package/src/framer/streamProxy.ts +1 -1
  121. package/src/framer/streamer.spec.ts +10 -27
  122. package/src/framer/streamer.ts +138 -22
  123. package/src/framer/writer.spec.ts +125 -150
  124. package/src/framer/writer.ts +74 -68
  125. package/src/hardware/device/client.ts +42 -10
  126. package/src/hardware/device/device.spec.ts +109 -1
  127. package/src/hardware/device/payload.ts +17 -3
  128. package/src/hardware/rack/client.ts +48 -8
  129. package/src/hardware/rack/payload.ts +16 -1
  130. package/src/hardware/rack/rack.spec.ts +36 -0
  131. package/src/hardware/task/payload.ts +9 -6
  132. package/src/hardware/task/task.spec.ts +9 -6
  133. package/src/index.ts +0 -2
  134. package/src/ontology/group/group.spec.ts +2 -2
  135. package/src/ontology/payload.ts +3 -3
  136. package/src/ranger/client.ts +3 -2
  137. package/src/ranger/ranger.spec.ts +9 -7
  138. package/src/testutil/indexedPair.ts +40 -0
  139. package/src/testutil/telem.ts +13 -0
  140. package/src/transport.ts +1 -2
  141. package/src/util/decodeJSONString.ts +2 -2
  142. package/src/util/retrieve.spec.ts +1 -1
@@ -13,6 +13,7 @@ import { type AsyncTermSearcher } from "@synnaxlabs/x/search";
13
13
  import { toArray } from "@synnaxlabs/x/toArray";
14
14
  import { z } from "zod";
15
15
 
16
+ import { framer } from "@/framer";
16
17
  import {
17
18
  type Key,
18
19
  keyZ,
@@ -21,6 +22,8 @@ import {
21
22
  ONTOLOGY_TYPE,
22
23
  type Payload,
23
24
  rackZ,
25
+ type State,
26
+ stateZ,
24
27
  } from "@/hardware/rack/payload";
25
28
  import { type task } from "@/hardware/task";
26
29
  import { ontology } from "@/ontology";
@@ -31,12 +34,17 @@ const RETRIEVE_ENDPOINT = "/hardware/rack/retrieve";
31
34
  const CREATE_ENDPOINT = "/hardware/rack/create";
32
35
  const DELETE_ENDPOINT = "/hardware/rack/delete";
33
36
 
37
+ const STATE_CHANNEL_NAME = "sy_rack_state";
38
+
34
39
  const retrieveReqZ = z.object({
35
40
  keys: keyZ.array().optional(),
36
41
  names: z.string().array().optional(),
37
42
  search: z.string().optional(),
38
- offset: z.number().optional(),
43
+ embedded: z.boolean().optional(),
44
+ hostIsNode: z.boolean().optional(),
39
45
  limit: z.number().optional(),
46
+ offset: z.number().optional(),
47
+ includeState: z.boolean().optional(),
40
48
  });
41
49
 
42
50
  const retrieveResZ = z.object({ racks: nullableArrayZ(rackZ) });
@@ -49,14 +57,24 @@ const deleteReqZ = z.object({ keys: keyZ.array() });
49
57
 
50
58
  const deleteResZ = z.object({});
51
59
 
60
+ export interface RetrieveOptions {
61
+ includeState?: boolean;
62
+ }
63
+
52
64
  export class Client implements AsyncTermSearcher<string, Key, Payload> {
53
65
  readonly type = ONTOLOGY_TYPE;
54
66
  private readonly client: UnaryClient;
55
67
  private readonly tasks: task.Client;
68
+ private readonly frameClient: framer.Client;
56
69
 
57
- constructor(client: UnaryClient, taskClient: task.Client) {
70
+ constructor(
71
+ client: UnaryClient,
72
+ taskClient: task.Client,
73
+ frameClient: framer.Client,
74
+ ) {
58
75
  this.client = client;
59
76
  this.tasks = taskClient;
77
+ this.frameClient = frameClient;
60
78
  }
61
79
 
62
80
  async delete(keys: Key | Key[]): Promise<void> {
@@ -107,9 +125,12 @@ export class Client implements AsyncTermSearcher<string, Key, Payload> {
107
125
  return this.sugar(res.racks);
108
126
  }
109
127
 
110
- async retrieve(key: string | Key): Promise<Rack>;
111
- async retrieve(keys: Key[]): Promise<Rack[]>;
112
- async retrieve(racks: string | Key | Key[]): Promise<Rack | Rack[]> {
128
+ async retrieve(key: string | Key, options?: RetrieveOptions): Promise<Rack>;
129
+ async retrieve(keys: Key[], options?: RetrieveOptions): Promise<Rack[]>;
130
+ async retrieve(
131
+ racks: string | Key | Key[],
132
+ options?: RetrieveOptions,
133
+ ): Promise<Rack | Rack[]> {
113
134
  const { variant, normalized, single } = analyzeParams(racks, {
114
135
  string: "names",
115
136
  number: "keys",
@@ -117,7 +138,10 @@ export class Client implements AsyncTermSearcher<string, Key, Payload> {
117
138
  const res = await sendRequired<typeof retrieveReqZ, typeof retrieveResZ>(
118
139
  this.client,
119
140
  RETRIEVE_ENDPOINT,
120
- { [variant]: normalized },
141
+ {
142
+ [variant]: normalized,
143
+ includeState: options?.includeState,
144
+ },
121
145
  retrieveReqZ,
122
146
  retrieveResZ,
123
147
  );
@@ -126,20 +150,36 @@ export class Client implements AsyncTermSearcher<string, Key, Payload> {
126
150
  return single ? sugared[0] : sugared;
127
151
  }
128
152
 
153
+ async openStateObserver(): Promise<framer.ObservableStreamer<State[]>> {
154
+ return new framer.ObservableStreamer<State[]>(
155
+ await this.frameClient.openStreamer(STATE_CHANNEL_NAME),
156
+ (fr) => {
157
+ const data = fr.get(STATE_CHANNEL_NAME);
158
+ if (data.length === 0) return [[], false];
159
+ const states = data.parseJSON(stateZ);
160
+ return [states, true];
161
+ },
162
+ );
163
+ }
164
+
129
165
  private sugar(payloads: Payload[]): Rack[] {
130
- return payloads.map(({ key, name }) => new Rack(key, name, this.tasks));
166
+ return payloads.map(
167
+ ({ key, name, state }) => new Rack(key, name, this.tasks, state),
168
+ );
131
169
  }
132
170
  }
133
171
 
134
172
  export class Rack {
135
173
  key: Key;
136
174
  name: string;
175
+ state?: State;
137
176
  private readonly tasks: task.Client;
138
177
 
139
- constructor(key: Key, name: string, taskClient: task.Client) {
178
+ constructor(key: Key, name: string, taskClient: task.Client, state?: State) {
140
179
  this.key = key;
141
180
  this.name = name;
142
181
  this.tasks = taskClient;
182
+ this.state = state;
143
183
  }
144
184
 
145
185
  async listTasks(): Promise<task.Task[]> {
@@ -8,12 +8,27 @@
8
8
  // included in the file licenses/APL.txt.
9
9
 
10
10
  import { zod } from "@synnaxlabs/x";
11
+ import { TimeStamp } from "@synnaxlabs/x/telem";
11
12
  import { z } from "zod";
12
13
 
13
14
  export const keyZ = zod.uint32;
14
15
  export type Key = z.infer<typeof keyZ>;
15
16
 
16
- export const rackZ = z.object({ key: keyZ, name: z.string() });
17
+ export const stateZ = z.object({
18
+ key: keyZ,
19
+ variant: z.string(),
20
+ message: z.string(),
21
+ lastReceived: TimeStamp.z.optional(),
22
+ });
23
+
24
+ export interface State extends z.infer<typeof stateZ> {}
25
+
26
+ export const rackZ = z.object({
27
+ key: keyZ,
28
+ name: z.string(),
29
+ state: stateZ.optional(),
30
+ });
31
+
17
32
  export interface Payload extends z.infer<typeof rackZ> {}
18
33
 
19
34
  export const newZ = rackZ.partial({ key: true });
@@ -7,6 +7,7 @@
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 { TimeStamp } from "@synnaxlabs/x";
10
11
  import { describe, expect, it } from "vitest";
11
12
  import { ZodError } from "zod";
12
13
 
@@ -66,4 +67,39 @@ describe("Rack", () => {
66
67
  ).rejects.toThrow(NotFoundError);
67
68
  });
68
69
  });
70
+ describe("state", () => {
71
+ it("should include state when includeState is true", async () => {
72
+ const r = await client.hardware.racks.create({ name: "test" });
73
+ await expect
74
+ .poll(async () => {
75
+ const retrieved = await client.hardware.racks.retrieve(r.key, {
76
+ includeState: true,
77
+ });
78
+ return (
79
+ retrieved.state !== undefined &&
80
+ retrieved.state.lastReceived instanceof TimeStamp &&
81
+ retrieved.state.key === r.key
82
+ );
83
+ })
84
+ .toBeTruthy();
85
+ });
86
+ it("should include state for multiple racks", async () => {
87
+ const r1 = await client.hardware.racks.create({ name: "test1" });
88
+ const r2 = await client.hardware.racks.create({ name: "test2" });
89
+
90
+ await expect
91
+ .poll(async () => {
92
+ const retrieved = await client.hardware.racks.retrieve([r1.key, r2.key], {
93
+ includeState: true,
94
+ });
95
+ return retrieved.every(
96
+ (rack) =>
97
+ rack.state !== undefined &&
98
+ rack.state.lastReceived instanceof TimeStamp &&
99
+ rack.state.key === rack.key,
100
+ );
101
+ })
102
+ .toBeTruthy();
103
+ });
104
+ });
69
105
  });
@@ -7,7 +7,12 @@
7
7
  // License, use of this software will be governed by the Apache License, Version 2.0,
8
8
  // included in the file licenses/APL.txt.
9
9
 
10
- import { binary, type observe, type UnknownRecord } from "@synnaxlabs/x";
10
+ import {
11
+ binary,
12
+ type observe,
13
+ type UnknownRecord,
14
+ unknownRecordZ,
15
+ } from "@synnaxlabs/x";
11
16
  import { z } from "zod";
12
17
 
13
18
  import { type Key as RackKey } from "@/hardware/rack/payload";
@@ -28,8 +33,7 @@ export const stateZ = z.object({
28
33
  task: keyZ,
29
34
  variant: statusZ,
30
35
  key: z.string().optional(),
31
- details: z
32
- .record(z.unknown())
36
+ details: unknownRecordZ
33
37
  .or(z.string().transform(parseWithoutKeyConversion))
34
38
  .or(z.array(z.unknown()))
35
39
  .or(z.null()) as z.ZodType<UnknownRecord | undefined>,
@@ -44,7 +48,7 @@ export const taskZ = z.object({
44
48
  name: z.string(),
45
49
  type: z.string(),
46
50
  internal: z.boolean().optional(),
47
- config: z.record(z.unknown()).or(z.string().transform(decodeJSONString)),
51
+ config: unknownRecordZ.or(z.string().transform(decodeJSONString)),
48
52
  state: stateZ.optional().nullable(),
49
53
  snapshot: z.boolean().optional(),
50
54
  });
@@ -74,8 +78,7 @@ export const commandZ = z.object({
74
78
  task: keyZ,
75
79
  type: z.string(),
76
80
  key: z.string(),
77
- args: z
78
- .record(z.unknown())
81
+ args: unknownRecordZ
79
82
  .or(z.string().transform(parseWithoutKeyConversion))
80
83
  .or(z.array(z.unknown()))
81
84
  .or(z.null())
@@ -98,13 +98,16 @@ describe("Task", async () => {
98
98
  task: t.key,
99
99
  variant: "success",
100
100
  };
101
- expect(await w.write("sy_task_state", [state])).toBeTruthy();
101
+ await w.write("sy_task_state", [state]);
102
102
  await w.close();
103
- const retrieved = await client.hardware.tasks.retrieve(t.key, {
104
- includeState: true,
105
- });
106
- expect(retrieved.state).not.toBeNull();
107
- expect(retrieved.state?.variant).toBe(state.variant);
103
+ await expect
104
+ .poll(async () => {
105
+ const retrieved = await client.hardware.tasks.retrieve(t.key, {
106
+ includeState: true,
107
+ });
108
+ return retrieved.state?.variant === state.variant;
109
+ })
110
+ .toBeTruthy();
108
111
  });
109
112
  });
110
113
  });
package/src/index.ts CHANGED
@@ -61,5 +61,3 @@ export {
61
61
  type TypedArray,
62
62
  type TZInfo,
63
63
  } from "@synnaxlabs/x/telem";
64
- import { control } from "@synnaxlabs/x";
65
- export const Authority = control.Authority;
@@ -9,7 +9,7 @@
9
9
 
10
10
  import { describe, expect, it } from "vitest";
11
11
 
12
- import { QueryError } from "@/errors";
12
+ import { NotFoundError } from "@/errors";
13
13
  import { ontology } from "@/ontology";
14
14
  import { newClient } from "@/setupspecs";
15
15
 
@@ -40,7 +40,7 @@ describe("Group", () => {
40
40
  await client.ontology.groups.delete(g.key);
41
41
  await expect(
42
42
  async () => await client.ontology.retrieve(g.ontologyID),
43
- ).rejects.toThrow(QueryError);
43
+ ).rejects.toThrowError(NotFoundError);
44
44
  });
45
45
  });
46
46
  });
@@ -7,7 +7,7 @@
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 change, type UnknownRecord } from "@synnaxlabs/x";
10
+ import { type change, type UnknownRecord, unknownRecordZ } from "@synnaxlabs/x";
11
11
  import { z } from "zod";
12
12
 
13
13
  import {
@@ -124,7 +124,7 @@ export interface SchemaField extends z.infer<typeof schemaFieldZ> {}
124
124
 
125
125
  export const schemaZ = z.object({
126
126
  type: resourceTypeZ,
127
- fields: z.record(schemaFieldZ),
127
+ fields: z.record(z.string(), schemaFieldZ),
128
128
  });
129
129
  export interface Schema extends z.infer<typeof schemaZ> {}
130
130
 
@@ -133,7 +133,7 @@ export const resourceZ = z
133
133
  id: ID.z,
134
134
  name: z.string(),
135
135
  schema: schemaZ.optional().nullable(),
136
- data: z.record(z.unknown()).optional().nullable(),
136
+ data: unknownRecordZ.optional().nullable(),
137
137
  })
138
138
  .transform((resource) => ({ key: resource.id.toString(), ...resource }));
139
139
  export interface Resource<T extends UnknownRecord = UnknownRecord>
@@ -17,7 +17,7 @@ import { z } from "zod";
17
17
  import { type channel } from "@/channel";
18
18
  import { MultipleFoundError, NotFoundError, QueryError } from "@/errors";
19
19
  import { type framer } from "@/framer";
20
- import { type label } from "@/label";
20
+ import { label } from "@/label";
21
21
  import { ontology } from "@/ontology";
22
22
  import { type Alias, Aliaser } from "@/ranger/alias";
23
23
  import { KV } from "@/ranger/kv";
@@ -195,6 +195,7 @@ const retrieveReqZ = z.object({
195
195
  overlapsWith: TimeRange.z.optional(),
196
196
  limit: z.number().int().optional(),
197
197
  offset: z.number().int().optional(),
198
+ hasLabels: label.keyZ.array().optional(),
198
199
  });
199
200
 
200
201
  export interface RetrieveRequest extends z.infer<typeof retrieveReqZ> {}
@@ -321,7 +322,7 @@ export class Client implements AsyncTermSearcher<string, Key, Range> {
321
322
  "sy_range_delete",
322
323
  (variant, data) => {
323
324
  if (variant === "delete")
324
- return data.toStrings().map((k) => ({ variant, key: k, value: undefined }));
325
+ return data.toUUIDs().map((k) => ({ variant, key: k, value: undefined }));
325
326
  const sugared = this.sugarMany(data.parseJSON(payloadZ));
326
327
  return sugared.map((r) => ({ variant, key: r.key, value: r }));
327
328
  },
@@ -8,10 +8,10 @@
8
8
  // included in the file licenses/APL.txt.
9
9
 
10
10
  import { type change } from "@synnaxlabs/x";
11
- import { DataType, Rate, TimeSpan, TimeStamp } from "@synnaxlabs/x/telem";
11
+ import { DataType, TimeSpan, TimeStamp } from "@synnaxlabs/x/telem";
12
12
  import { describe, expect, it } from "vitest";
13
13
 
14
- import { QueryError } from "@/errors";
14
+ import { NotFoundError } from "@/errors";
15
15
  import { type ranger } from "@/ranger";
16
16
  import { newClient } from "@/setupspecs";
17
17
 
@@ -74,7 +74,7 @@ describe("Ranger", () => {
74
74
  });
75
75
  await client.ranges.delete(range.key);
76
76
  await expect(async () => await client.ranges.retrieve(range.key)).rejects.toThrow(
77
- QueryError,
77
+ NotFoundError,
78
78
  );
79
79
  });
80
80
  });
@@ -172,7 +172,9 @@ describe("Ranger", () => {
172
172
  const val = await rng.kv.get("foo");
173
173
  expect(val).toEqual("bar");
174
174
  await rng.kv.delete("foo");
175
- await expect(async () => await rng.kv.get("foo")).rejects.toThrow(QueryError);
175
+ await expect(async () => await rng.kv.get("foo")).rejects.toThrowError(
176
+ NotFoundError,
177
+ );
176
178
  });
177
179
 
178
180
  it("should set and get multiple keys", async () => {
@@ -240,7 +242,7 @@ describe("Ranger", () => {
240
242
  const ch = await client.channels.create({
241
243
  name: "My New Channel",
242
244
  dataType: DataType.FLOAT32,
243
- rate: Rate.hz(1),
245
+ virtual: true,
244
246
  });
245
247
  const rng = await client.ranges.create({
246
248
  name: "My New One Second Range",
@@ -256,7 +258,7 @@ describe("Ranger", () => {
256
258
  const ch = await client.channels.create({
257
259
  name: "My New Channel",
258
260
  dataType: DataType.FLOAT32,
259
- rate: Rate.hz(1),
261
+ virtual: true,
260
262
  });
261
263
  const rng = await client.ranges.create({
262
264
  name: "My New One Second Range",
@@ -272,7 +274,7 @@ describe("Ranger", () => {
272
274
  const ch = await client.channels.create({
273
275
  name: "My New Channel",
274
276
  dataType: DataType.FLOAT32,
275
- rate: Rate.hz(1),
277
+ virtual: true,
276
278
  });
277
279
  const rng = await client.ranges.create({
278
280
  name: "My New One Second Range",
@@ -0,0 +1,40 @@
1
+ // Copyright 2025 Synnax Labs, Inc.
2
+ //
3
+ // Use of this software is governed by the Business Source License included in the file
4
+ // licenses/BSL.txt.
5
+ //
6
+ // As of the Change Date specified in that file, in accordance with the Business Source
7
+ // License, use of this software will be governed by the Apache License, Version 2.0,
8
+ // included in the file licenses/APL.txt.
9
+
10
+ import { DataType, id } from "@synnaxlabs/x";
11
+
12
+ import { type channel } from "@/channel";
13
+ import type Synnax from "@/client";
14
+
15
+ export const newIndexedPair = async (
16
+ client: Synnax,
17
+ ): Promise<[channel.Channel, channel.Channel]> => {
18
+ const index = await client.channels.create({
19
+ leaseholder: 1,
20
+ name: `test-${id.create()}`,
21
+ dataType: DataType.TIMESTAMP,
22
+ isIndex: true,
23
+ });
24
+ const data = await client.channels.create({
25
+ leaseholder: 1,
26
+ name: `test-${id.create()}`,
27
+ dataType: DataType.FLOAT64,
28
+ index: index.key,
29
+ });
30
+ return [index, data];
31
+ };
32
+
33
+ export const newVirtualChannel = async (client: Synnax): Promise<channel.Channel> => {
34
+ const ch = await client.channels.create({
35
+ name: `test-${id.create()}`,
36
+ dataType: DataType.FLOAT64,
37
+ virtual: true,
38
+ });
39
+ return ch;
40
+ };
@@ -0,0 +1,13 @@
1
+ // Copyright 2025 Synnax Labs, Inc.
2
+ //
3
+ // Use of this software is governed by the Business Source License included in the file
4
+ // licenses/BSL.txt.
5
+ //
6
+ // As of the Change Date specified in that file, in accordance with the Business Source
7
+ // License, use of this software will be governed by the Apache License, Version 2.0,
8
+ // included in the file licenses/APL.txt.
9
+
10
+ import { TimeStamp } from "@synnaxlabs/x";
11
+
12
+ export const secondsLinspace = (start: number, n: number): TimeStamp[] =>
13
+ Array.from({ length: n }, (_, i) => start + i).map((n) => TimeStamp.seconds(n));
package/src/transport.ts CHANGED
@@ -10,7 +10,6 @@
10
10
  import {
11
11
  HTTPClient,
12
12
  type Middleware,
13
- type StreamClient,
14
13
  type UnaryClient,
15
14
  unaryWithBreaker,
16
15
  WebSocketClient,
@@ -24,7 +23,7 @@ const baseAPIEndpoint = "/api/v1/";
24
23
  export class Transport {
25
24
  readonly url: URL;
26
25
  readonly unary: UnaryClient;
27
- readonly stream: StreamClient;
26
+ readonly stream: WebSocketClient;
28
27
  readonly secure: boolean;
29
28
 
30
29
  constructor(url: URL, breakerCfg: breaker.Config = {}, secure: boolean = false) {
@@ -7,7 +7,7 @@
7
7
  // License, use of this software will be governed by the Apache License, Version 2.0,
8
8
  // included in the file licenses/APL.txt.
9
9
 
10
- import { binary, type UnknownRecord } from "@synnaxlabs/x";
10
+ import { binary, type UnknownRecord, unknownRecordZ } from "@synnaxlabs/x";
11
11
 
12
12
  export const decodeJSONString = (s: string): UnknownRecord =>
13
- s ? binary.JSON_CODEC.decodeString(s) : {};
13
+ s ? binary.JSON_CODEC.decodeString(s, unknownRecordZ) : {};
@@ -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 Primitive } from "@synnaxlabs/x";
10
11
  import { describe, expect, it } from "vitest";
11
- import { type Primitive } from "zod";
12
12
 
13
13
  import {
14
14
  analyzeParams,