@synnaxlabs/client 0.54.2 → 0.56.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 (222) hide show
  1. package/.turbo/turbo-build.log +10 -13
  2. package/dist/client.cjs +60 -42
  3. package/dist/client.js +8037 -6265
  4. package/dist/src/access/policy/client.d.ts +70 -80
  5. package/dist/src/access/policy/client.d.ts.map +1 -1
  6. package/dist/src/access/policy/types.gen.d.ts +18 -20
  7. package/dist/src/access/policy/types.gen.d.ts.map +1 -1
  8. package/dist/src/access/role/client.d.ts.map +1 -1
  9. package/dist/src/access/role/types.gen.d.ts +2 -2
  10. package/dist/src/actions/actions.d.ts +68 -0
  11. package/dist/src/actions/actions.d.ts.map +1 -0
  12. package/dist/src/actions/actions.spec.d.ts +2 -0
  13. package/dist/src/actions/actions.spec.d.ts.map +1 -0
  14. package/dist/src/actions/external.d.ts +2 -0
  15. package/dist/src/actions/external.d.ts.map +1 -0
  16. package/dist/src/actions/index.d.ts +2 -0
  17. package/dist/src/actions/index.d.ts.map +1 -0
  18. package/dist/src/arc/arc.spec.d.ts +2 -0
  19. package/dist/src/arc/arc.spec.d.ts.map +1 -0
  20. package/dist/src/arc/client.d.ts.map +1 -1
  21. package/dist/src/arc/compiler/types.gen.d.ts +1 -1
  22. package/dist/src/arc/compiler/types.gen.d.ts.map +1 -1
  23. package/dist/src/arc/graph/types.gen.d.ts +40 -40
  24. package/dist/src/arc/graph/types.gen.d.ts.map +1 -1
  25. package/dist/src/arc/ir/types.gen.d.ts +202 -233
  26. package/dist/src/arc/ir/types.gen.d.ts.map +1 -1
  27. package/dist/src/arc/module/types.gen.d.ts +63 -82
  28. package/dist/src/arc/module/types.gen.d.ts.map +1 -1
  29. package/dist/src/arc/program/types.gen.d.ts +63 -82
  30. package/dist/src/arc/program/types.gen.d.ts.map +1 -1
  31. package/dist/src/arc/types/types.gen.d.ts +11 -11
  32. package/dist/src/arc/types/types.gen.d.ts.map +1 -1
  33. package/dist/src/arc/types.gen.d.ts +139 -158
  34. package/dist/src/arc/types.gen.d.ts.map +1 -1
  35. package/dist/src/auth/auth.d.ts +3 -3
  36. package/dist/src/auth/auth.d.ts.map +1 -1
  37. package/dist/src/channel/client.d.ts +2 -2
  38. package/dist/src/channel/client.d.ts.map +1 -1
  39. package/dist/src/channel/retriever.d.ts +5 -8
  40. package/dist/src/channel/retriever.d.ts.map +1 -1
  41. package/dist/src/channel/types.gen.d.ts +3 -3
  42. package/dist/src/channel/types.gen.d.ts.map +1 -1
  43. package/dist/src/channel/writer.d.ts.map +1 -1
  44. package/dist/src/client.d.ts +5 -0
  45. package/dist/src/client.d.ts.map +1 -1
  46. package/dist/src/connection/checker.d.ts +17 -2
  47. package/dist/src/connection/checker.d.ts.map +1 -1
  48. package/dist/src/control/state.d.ts.map +1 -1
  49. package/dist/src/device/client.d.ts.map +1 -1
  50. package/dist/src/device/types.gen.d.ts +6 -8
  51. package/dist/src/device/types.gen.d.ts.map +1 -1
  52. package/dist/src/errors.d.ts +2 -0
  53. package/dist/src/errors.d.ts.map +1 -1
  54. package/dist/src/framer/adapter.d.ts.map +1 -1
  55. package/dist/src/framer/client.d.ts +2 -2
  56. package/dist/src/framer/client.d.ts.map +1 -1
  57. package/dist/src/framer/codec.d.ts +9 -1
  58. package/dist/src/framer/codec.d.ts.map +1 -1
  59. package/dist/src/framer/deleter.d.ts.map +1 -1
  60. package/dist/src/framer/frame.d.ts +1 -1
  61. package/dist/src/framer/iterator.d.ts +84 -3
  62. package/dist/src/framer/iterator.d.ts.map +1 -1
  63. package/dist/src/framer/streamProxy.d.ts.map +1 -1
  64. package/dist/src/framer/streamer.d.ts +1 -3
  65. package/dist/src/framer/streamer.d.ts.map +1 -1
  66. package/dist/src/framer/types.gen.d.ts +18 -0
  67. package/dist/src/framer/types.gen.d.ts.map +1 -1
  68. package/dist/src/framer/writer.d.ts +8 -8
  69. package/dist/src/framer/writer.d.ts.map +1 -1
  70. package/dist/src/group/client.d.ts +1 -2
  71. package/dist/src/group/client.d.ts.map +1 -1
  72. package/dist/src/group/types.gen.d.ts +2 -2
  73. package/dist/src/index.d.ts +2 -1
  74. package/dist/src/index.d.ts.map +1 -1
  75. package/dist/src/label/client.d.ts +5 -8
  76. package/dist/src/label/client.d.ts.map +1 -1
  77. package/dist/src/lineplot/client.d.ts.map +1 -1
  78. package/dist/src/lineplot/types.gen.d.ts +2 -2
  79. package/dist/src/log/client.d.ts.map +1 -1
  80. package/dist/src/log/types.gen.d.ts +2 -2
  81. package/dist/src/ontology/client.d.ts +1 -3
  82. package/dist/src/ontology/client.d.ts.map +1 -1
  83. package/dist/src/ontology/payload.d.ts +12 -16
  84. package/dist/src/ontology/payload.d.ts.map +1 -1
  85. package/dist/src/ontology/types.gen.d.ts +1 -2
  86. package/dist/src/ontology/types.gen.d.ts.map +1 -1
  87. package/dist/src/ontology/writer.d.ts +5 -10
  88. package/dist/src/ontology/writer.d.ts.map +1 -1
  89. package/dist/src/rack/client.d.ts.map +1 -1
  90. package/dist/src/rack/types.gen.d.ts +3 -3
  91. package/dist/src/ranger/alias/client.d.ts.map +1 -1
  92. package/dist/src/ranger/client.d.ts.map +1 -1
  93. package/dist/src/ranger/kv/client.d.ts.map +1 -1
  94. package/dist/src/ranger/types.gen.d.ts +6 -6
  95. package/dist/src/ranger/types.gen.d.ts.map +1 -1
  96. package/dist/src/ranger/writer.d.ts +2 -3
  97. package/dist/src/ranger/writer.d.ts.map +1 -1
  98. package/dist/src/schematic/actions.d.ts +147 -0
  99. package/dist/src/schematic/actions.d.ts.map +1 -0
  100. package/dist/src/schematic/actions.gen.d.ts +484 -0
  101. package/dist/src/schematic/actions.gen.d.ts.map +1 -0
  102. package/dist/src/schematic/actions.spec.d.ts +2 -0
  103. package/dist/src/schematic/actions.spec.d.ts.map +1 -0
  104. package/dist/src/schematic/client.d.ts +53 -2
  105. package/dist/src/schematic/client.d.ts.map +1 -1
  106. package/dist/src/schematic/external.d.ts +2 -0
  107. package/dist/src/schematic/external.d.ts.map +1 -1
  108. package/dist/src/schematic/symbol/client.d.ts.map +1 -1
  109. package/dist/src/schematic/symbol/types.gen.d.ts +48 -58
  110. package/dist/src/schematic/symbol/types.gen.d.ts.map +1 -1
  111. package/dist/src/schematic/types.gen.d.ts +131 -5
  112. package/dist/src/schematic/types.gen.d.ts.map +1 -1
  113. package/dist/src/status/client.d.ts.map +1 -1
  114. package/dist/src/status/payload.d.ts +3 -3
  115. package/dist/src/table/actions.d.ts +156 -0
  116. package/dist/src/table/actions.d.ts.map +1 -0
  117. package/dist/src/table/actions.gen.d.ts +587 -0
  118. package/dist/src/table/actions.gen.d.ts.map +1 -0
  119. package/dist/src/table/client.d.ts +28 -2
  120. package/dist/src/table/client.d.ts.map +1 -1
  121. package/dist/src/table/external.d.ts +2 -0
  122. package/dist/src/table/external.d.ts.map +1 -1
  123. package/dist/src/table/types.gen.d.ts +71 -4
  124. package/dist/src/table/types.gen.d.ts.map +1 -1
  125. package/dist/src/task/client.d.ts.map +1 -1
  126. package/dist/src/task/types.gen.d.ts +7 -7
  127. package/dist/src/task/types.gen.d.ts.map +1 -1
  128. package/dist/src/user/client.d.ts +2 -2
  129. package/dist/src/user/client.d.ts.map +1 -1
  130. package/dist/src/user/types.gen.d.ts +2 -2
  131. package/dist/src/view/client.d.ts.map +1 -1
  132. package/dist/src/view/types.gen.d.ts +2 -2
  133. package/dist/src/workspace/client.d.ts.map +1 -1
  134. package/dist/src/workspace/types.gen.d.ts +3 -3
  135. package/dist/src/workspace/types.gen.d.ts.map +1 -1
  136. package/package.json +12 -11
  137. package/src/access/policy/client.ts +4 -7
  138. package/src/access/role/client.ts +6 -26
  139. package/src/actions/actions.spec.ts +229 -0
  140. package/src/actions/actions.ts +104 -0
  141. package/src/actions/external.ts +10 -0
  142. package/src/actions/index.ts +10 -0
  143. package/src/arc/arc.spec.ts +44 -0
  144. package/src/arc/client.ts +3 -7
  145. package/src/arc/compiler/types.gen.ts +2 -1
  146. package/src/arc/ir/types.gen.ts +102 -48
  147. package/src/arc/lsp.spec.ts +3 -7
  148. package/src/arc/types/types.gen.ts +3 -3
  149. package/src/auth/auth.spec.ts +12 -13
  150. package/src/auth/auth.ts +48 -34
  151. package/src/channel/batchRetriever.spec.ts +13 -4
  152. package/src/channel/channel.spec.ts +13 -0
  153. package/src/channel/client.ts +8 -6
  154. package/src/channel/retriever.ts +7 -16
  155. package/src/channel/types.gen.ts +1 -2
  156. package/src/channel/writer.ts +4 -20
  157. package/src/client.ts +3 -0
  158. package/src/connection/checker.ts +48 -10
  159. package/src/connection/connection.spec.ts +64 -2
  160. package/src/control/state.ts +5 -4
  161. package/src/device/client.ts +5 -8
  162. package/src/device/device.spec.ts +7 -5
  163. package/src/device/types.gen.ts +4 -4
  164. package/src/errors.ts +8 -9
  165. package/src/framer/adapter.ts +2 -4
  166. package/src/framer/client.ts +12 -0
  167. package/src/framer/codec.spec.ts +53 -3
  168. package/src/framer/codec.ts +58 -25
  169. package/src/framer/deleter.ts +2 -8
  170. package/src/framer/iterator.ts +42 -39
  171. package/src/framer/streamProxy.ts +11 -12
  172. package/src/framer/streamer.spec.ts +1 -1
  173. package/src/framer/streamer.ts +2 -7
  174. package/src/framer/types.gen.ts +20 -0
  175. package/src/framer/writer.spec.ts +221 -1
  176. package/src/framer/writer.ts +53 -28
  177. package/src/group/client.ts +4 -7
  178. package/src/index.ts +3 -2
  179. package/src/label/client.ts +6 -16
  180. package/src/label/label.spec.ts +12 -0
  181. package/src/lineplot/client.ts +6 -21
  182. package/src/log/client.ts +6 -21
  183. package/src/ontology/client.ts +2 -3
  184. package/src/ontology/ontology.spec.ts +10 -0
  185. package/src/ontology/types.gen.ts +0 -1
  186. package/src/ontology/writer.ts +4 -7
  187. package/src/rack/client.ts +4 -7
  188. package/src/rack/rack.spec.ts +12 -1
  189. package/src/ranger/alias/client.ts +6 -11
  190. package/src/ranger/client.ts +2 -3
  191. package/src/ranger/kv/client.ts +4 -7
  192. package/src/ranger/ranger.spec.ts +12 -0
  193. package/src/ranger/writer.ts +4 -17
  194. package/src/schematic/access.spec.ts +6 -6
  195. package/src/schematic/actions.gen.ts +200 -0
  196. package/src/schematic/actions.spec.ts +699 -0
  197. package/src/schematic/actions.ts +168 -0
  198. package/src/schematic/client.ts +34 -30
  199. package/src/schematic/external.ts +2 -0
  200. package/src/schematic/schematic.spec.ts +233 -69
  201. package/src/schematic/symbol/client.spec.ts +33 -9
  202. package/src/schematic/symbol/client.ts +6 -11
  203. package/src/schematic/symbol/types.gen.ts +1 -10
  204. package/src/schematic/types.gen.ts +55 -6
  205. package/src/status/client.ts +4 -10
  206. package/src/status/status.spec.ts +7 -6
  207. package/src/table/access.spec.ts +0 -6
  208. package/src/table/actions.gen.ts +243 -0
  209. package/src/table/actions.ts +255 -0
  210. package/src/table/client.ts +21 -25
  211. package/src/table/external.ts +2 -0
  212. package/src/table/table.spec.ts +588 -43
  213. package/src/table/types.gen.ts +58 -5
  214. package/src/task/client.ts +14 -20
  215. package/src/task/task.spec.ts +15 -1
  216. package/src/task/types.gen.ts +8 -6
  217. package/src/user/client.ts +6 -11
  218. package/src/view/client.ts +4 -7
  219. package/src/view/view.spec.ts +9 -5
  220. package/src/workspace/client.ts +6 -16
  221. package/src/workspace/types.gen.ts +2 -1
  222. package/src/workspace/workspace.spec.ts +14 -1
@@ -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 Stream, type StreamClient } from "@synnaxlabs/freighter";
10
+ import { type Stream, type WebSocketClient } from "@synnaxlabs/freighter";
11
11
  import {
12
12
  type CrudeTimeRange,
13
13
  type CrudeTimeSpan,
@@ -21,31 +21,15 @@ import { z } from "zod";
21
21
 
22
22
  import { channel } from "@/channel";
23
23
  import { ReadAdapter } from "@/framer/adapter";
24
+ import { WSIteratorCodec } from "@/framer/codec";
24
25
  import { Frame, frameZ } from "@/framer/frame";
25
26
  import { StreamProxy } from "@/framer/streamProxy";
27
+ import { IteratorCommand, IteratorResponseVariant } from "@/framer/types.gen";
26
28
 
27
29
  export const AUTO_SPAN = new TimeSpan(-1);
28
30
 
29
- enum Command {
30
- Open = 0,
31
- Next = 1,
32
- Prev = 2,
33
- SeekFirst = 3,
34
- SeekLast = 4,
35
- SeekLE = 5,
36
- SeekGE = 6,
37
- Valid = 7,
38
- Error = 8,
39
- }
40
-
41
- enum ResponseVariant {
42
- None = 0,
43
- Ack = 1,
44
- Data = 2,
45
- }
46
-
47
- const reqZ = z.object({
48
- command: z.enum(Command),
31
+ export const iteratorReqZ = z.object({
32
+ command: z.enum(IteratorCommand),
49
33
  span: TimeSpan.z.optional(),
50
34
  bounds: TimeRange.z.optional(),
51
35
  stamp: TimeStamp.z.optional(),
@@ -53,16 +37,19 @@ const reqZ = z.object({
53
37
  chunkSize: z.number().optional(),
54
38
  downsampleFactor: z.int().optional(),
55
39
  });
56
- interface Request extends z.infer<typeof reqZ> {}
57
40
 
58
- const resZ = z.object({
59
- variant: z.enum(ResponseVariant),
41
+ export interface IteratorRequest extends z.infer<typeof iteratorReqZ> {}
42
+
43
+ export const iteratorResZ = z.object({
44
+ variant: z.enum(IteratorResponseVariant),
60
45
  ack: z.boolean(),
61
- command: z.enum(Command),
46
+ command: z.enum(IteratorCommand),
62
47
  error: errors.payloadZ.optional().nullable(),
63
48
  frame: frameZ.optional(),
64
49
  });
65
50
 
51
+ export interface IteratorResponse extends z.infer<typeof iteratorResZ> {}
52
+
66
53
  export interface IteratorConfig {
67
54
  /** chunkSize is the maximum number of samples contained per channel in the frame
68
55
  * resulting from a call to next with {@link AUTO_SPAN}.
@@ -84,11 +71,14 @@ export interface IteratorConfig {
84
71
  * telemetry between two timestamps, see the SegmentClient.read method.
85
72
  */
86
73
  export class Iterator {
87
- private readonly stream: StreamProxy<typeof reqZ, typeof resZ>;
74
+ private readonly stream: StreamProxy<typeof iteratorReqZ, typeof iteratorResZ>;
88
75
  private readonly adapter: ReadAdapter;
89
76
  value: Frame;
90
77
 
91
- private constructor(stream: Stream<typeof reqZ, typeof resZ>, adapter: ReadAdapter) {
78
+ private constructor(
79
+ stream: Stream<typeof iteratorReqZ, typeof iteratorResZ>,
80
+ adapter: ReadAdapter,
81
+ ) {
92
82
  this.stream = new StreamProxy("Iterator", stream);
93
83
  this.value = new Frame();
94
84
  this.adapter = adapter;
@@ -109,14 +99,15 @@ export class Iterator {
109
99
  tr: CrudeTimeRange,
110
100
  channels: channel.Params,
111
101
  retriever: channel.Retriever,
112
- client: StreamClient,
102
+ client: WebSocketClient,
113
103
  opts: IteratorConfig = {},
114
104
  ): Promise<Iterator> {
115
105
  const adapter = await ReadAdapter.open(retriever, channels);
116
- const stream = await client.stream("/frame/iterate", reqZ, resZ);
106
+ client = client.withCodec(new WSIteratorCodec(adapter.codec));
107
+ const stream = await client.stream("/frame/iterate", iteratorReqZ, iteratorResZ);
117
108
  const iter = new Iterator(stream, adapter);
118
109
  await iter.execute({
119
- command: Command.Open,
110
+ command: IteratorCommand.Open,
120
111
  keys: Array.from(adapter.keys),
121
112
  bounds: new TimeRange(tr),
122
113
  chunkSize: opts.chunkSize ?? 1e5,
@@ -137,7 +128,10 @@ export class Iterator {
137
128
  * particular channel or the iterator has accumulated an error.
138
129
  */
139
130
  async next(span: CrudeTimeSpan = AUTO_SPAN): Promise<boolean> {
140
- return await this.execute({ command: Command.Next, span: new TimeSpan(span) });
131
+ return await this.execute({
132
+ command: IteratorCommand.Next,
133
+ span: new TimeSpan(span),
134
+ });
141
135
  }
142
136
 
143
137
  /**
@@ -152,7 +146,10 @@ export class Iterator {
152
146
  * channel or the iterator has accumulated an error.
153
147
  */
154
148
  async prev(span: CrudeTimeSpan = AUTO_SPAN): Promise<boolean> {
155
- return await this.execute({ command: Command.Prev, span: new TimeSpan(span) });
149
+ return await this.execute({
150
+ command: IteratorCommand.Prev,
151
+ span: new TimeSpan(span),
152
+ });
156
153
  }
157
154
 
158
155
  /**
@@ -164,7 +161,7 @@ export class Iterator {
164
161
  * channel or has accumulated an error.
165
162
  */
166
163
  async seekFirst(): Promise<boolean> {
167
- return await this.execute({ command: Command.SeekFirst });
164
+ return await this.execute({ command: IteratorCommand.SeekFirst });
168
165
  }
169
166
 
170
167
  /** Seeks the iterator to the last segment in the time range, but does not read it.
@@ -175,7 +172,7 @@ export class Iterator {
175
172
  * channel or has accumulated an error.
176
173
  */
177
174
  async seekLast(): Promise<boolean> {
178
- return await this.execute({ command: Command.SeekLast });
175
+ return await this.execute({ command: IteratorCommand.SeekLast });
179
176
  }
180
177
 
181
178
  /**
@@ -187,7 +184,10 @@ export class Iterator {
187
184
  * channel or has accumulated an error.
188
185
  */
189
186
  async seekLE(stamp: CrudeTimeStamp): Promise<boolean> {
190
- return await this.execute({ command: Command.SeekLE, stamp: new TimeStamp(stamp) });
187
+ return await this.execute({
188
+ command: IteratorCommand.SeekLE,
189
+ stamp: new TimeStamp(stamp),
190
+ });
191
191
  }
192
192
 
193
193
  /**
@@ -199,7 +199,10 @@ export class Iterator {
199
199
  * channel or has accumulated an error.
200
200
  */
201
201
  async seekGE(stamp: CrudeTimeStamp): Promise<boolean> {
202
- return await this.execute({ command: Command.SeekGE, stamp: new TimeStamp(stamp) });
202
+ return await this.execute({
203
+ command: IteratorCommand.SeekGE,
204
+ stamp: new TimeStamp(stamp),
205
+ });
203
206
  }
204
207
 
205
208
  /**
@@ -208,7 +211,7 @@ export class Iterator {
208
211
  * an error.
209
212
  */
210
213
  async valid(): Promise<boolean> {
211
- return await this.execute({ command: Command.Valid });
214
+ return await this.execute({ command: IteratorCommand.Valid });
212
215
  }
213
216
 
214
217
  /**
@@ -224,12 +227,12 @@ export class Iterator {
224
227
  return new IteratorIterator(this);
225
228
  }
226
229
 
227
- private async execute(request: Request): Promise<boolean> {
230
+ private async execute(request: IteratorRequest): Promise<boolean> {
228
231
  this.stream.send(request);
229
232
  this.value = new Frame();
230
233
  while (true) {
231
234
  const res = await this.stream.receive();
232
- if (res.variant === ResponseVariant.Ack) return res.ack;
235
+ if (res.variant === IteratorResponseVariant.Ack) return res.ack;
233
236
  this.value.push(this.adapter.adapt(new Frame(res.frame)));
234
237
  }
235
238
  }
@@ -10,6 +10,8 @@
10
10
  import { EOF, type Stream } from "@synnaxlabs/freighter";
11
11
  import { type z } from "zod";
12
12
 
13
+ import { UnexpectedError } from "@/errors";
14
+
13
15
  export class StreamProxy<RQ extends z.ZodType, RS extends z.ZodType> {
14
16
  readonly name: string;
15
17
  private readonly stream: Stream<RQ, RS>;
@@ -20,9 +22,7 @@ export class StreamProxy<RQ extends z.ZodType, RS extends z.ZodType> {
20
22
  }
21
23
 
22
24
  async receive(): Promise<z.infer<RS>> {
23
- const [res, err] = await this.stream.receive();
24
- if (err != null) throw err;
25
- return res;
25
+ return await this.stream.receive();
26
26
  }
27
27
 
28
28
  received(): boolean {
@@ -32,16 +32,16 @@ export class StreamProxy<RQ extends z.ZodType, RS extends z.ZodType> {
32
32
  async closeAndAck(): Promise<void> {
33
33
  this.stream.closeSend();
34
34
  while (true) {
35
- const [res, err] = await this.stream.receive();
36
- if (res != null)
37
- console.warn(
38
- `${this.name} received unexpected response on ${JSON.stringify(res)} closure.
39
- Please report this error to the Synnax team.`,
40
- );
41
- if (err != null) {
35
+ let res: z.infer<RS>;
36
+ try {
37
+ res = await this.stream.receive();
38
+ } catch (err) {
42
39
  if (EOF.matches(err)) return;
43
40
  throw err;
44
41
  }
42
+ throw new UnexpectedError(
43
+ `${this.name} received unexpected response ${JSON.stringify(res)} on closure.`,
44
+ );
45
45
  }
46
46
  }
47
47
 
@@ -50,7 +50,6 @@ export class StreamProxy<RQ extends z.ZodType, RS extends z.ZodType> {
50
50
  }
51
51
 
52
52
  send(req: z.input<RQ>): void {
53
- const err = this.stream.send(req);
54
- if (err != null) throw err;
53
+ this.stream.send(req);
55
54
  }
56
55
  }
@@ -565,7 +565,7 @@ describe("Streamer", () => {
565
565
  it("should correctly call the underlying streamer methods", async () => {
566
566
  const streamer = new MockStreamer();
567
567
  const openMock = vi.fn();
568
- const config = { channels: [1, 2, 3], useHighPerformanceCodec: true };
568
+ const config = { channels: [1, 2, 3] };
569
569
  const fr = new Frame({ 1: new Series([1]) });
570
570
  const hardened = await HardenedStreamer.open(
571
571
  async (cfg) => {
@@ -46,9 +46,6 @@ const intermediateStreamerConfigZ = z.object({
46
46
  downsampleFactor: z.int().default(1),
47
47
  /** Optional throttle rate in Hz to limit the rate of frames sent to the client. Defaults to 0 (no throttling). */
48
48
  throttleRate: Rate.z.default(new Rate(0)),
49
- /** useHighPerformanceCodec sets whether the writer will use the Synnax frame encoder
50
- as opposed to the standard JSON encoding mechanisms for frames. */
51
- useHighPerformanceCodec: z.boolean().default(true),
52
49
  /** excludeGroups sets writer group IDs whose frames should be filtered out by the
53
50
  Core. Used for telemetry bypass deduplication. */
54
51
  excludeGroups: z.uint32().array().default([]),
@@ -112,8 +109,7 @@ export const createStreamOpener =
112
109
  async (config) => {
113
110
  const cfg = streamerConfigZ.parse(config);
114
111
  const adapter = await ReadAdapter.open(retriever, cfg.channels);
115
- if (cfg.useHighPerformanceCodec)
116
- client = client.withCodec(new WSStreamerCodec(adapter.codec));
112
+ client = client.withCodec(new WSStreamerCodec(adapter.codec));
117
113
  const stream = await client.stream("/frame/stream", reqZ, resZ);
118
114
  const streamer = new BaseStreamer(
119
115
  stream,
@@ -128,8 +124,7 @@ export const createStreamOpener =
128
124
  throttleRate: cfg.throttleRate,
129
125
  excludeGroups: cfg.excludeGroups,
130
126
  });
131
- const [, err] = await stream.receive();
132
- if (err != null) throw err;
127
+ await stream.receive();
133
128
  return streamer;
134
129
  };
135
130
 
@@ -18,3 +18,23 @@ export enum WriterCommand {
18
18
  SetAuthority = 3,
19
19
  }
20
20
  export const writerCommandZ = z.enum(WriterCommand);
21
+
22
+ export enum IteratorCommand {
23
+ Open = 0,
24
+ Next = 1,
25
+ Prev = 2,
26
+ SeekFirst = 3,
27
+ SeekLast = 4,
28
+ SeekLE = 5,
29
+ SeekGE = 6,
30
+ Valid = 7,
31
+ Error = 8,
32
+ }
33
+ export const iteratorCommandZ = z.enum(IteratorCommand);
34
+
35
+ export enum IteratorResponseVariant {
36
+ None = 0,
37
+ Ack = 1,
38
+ Data = 2,
39
+ }
40
+ export const iteratorResponseVariantZ = z.enum(IteratorResponseVariant);
@@ -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 { DataType, id, TimeRange, TimeSpan, TimeStamp } from "@synnaxlabs/x";
10
+ import { DataType, id, Series, TimeRange, TimeSpan, TimeStamp } from "@synnaxlabs/x";
11
11
  import { describe, expect, it, test } from "vitest";
12
12
 
13
13
  import { UnauthorizedError, ValidationError } from "@/errors";
@@ -115,6 +115,83 @@ describe("Writer", () => {
115
115
  expect(true).toBe(true);
116
116
  });
117
117
 
118
+ test("auto-index generates server-side timestamps for data-only writes", async () => {
119
+ const [index, data] = await newIndexedPair(client);
120
+ const before = TimeStamp.now();
121
+ const writer = await client.openWriter({
122
+ start: before,
123
+ channels: [data.key],
124
+ autoIndex: true,
125
+ });
126
+ try {
127
+ await writer.write(data.key, randomSeries(5, data.dataType));
128
+ await writer.commit();
129
+ } finally {
130
+ await writer.close();
131
+ }
132
+ const f = await client.read(
133
+ new TimeRange(before, TimeStamp.now().add(TimeSpan.seconds(1))),
134
+ index.key,
135
+ );
136
+ expect(f.length).toEqual(5);
137
+ });
138
+
139
+ test("auto-index mixes user-provided and generated timestamps in one writer", async () => {
140
+ const [index, data] = await newIndexedPair(client);
141
+ const userStamps = secondsLinspace(200, 2);
142
+ const beforeAuto = TimeStamp.now();
143
+ const writer = await client.openWriter({
144
+ start: TimeStamp.seconds(200),
145
+ channels: [index.key, data.key],
146
+ autoIndex: true,
147
+ });
148
+ try {
149
+ await writer.write({
150
+ [index.key]: userStamps,
151
+ [data.key]: randomSeries(2, data.dataType),
152
+ });
153
+ await writer.write(data.key, randomSeries(3, data.dataType));
154
+ await writer.commit();
155
+ } finally {
156
+ await writer.close();
157
+ }
158
+ const userF = await client.read(
159
+ new TimeRange(TimeStamp.seconds(200), TimeStamp.seconds(202)),
160
+ index.key,
161
+ );
162
+ expect(userF.data).toEqual(new BigInt64Array(userStamps.map((v) => v.valueOf())));
163
+ const autoF = await client.read(
164
+ new TimeRange(beforeAuto, TimeStamp.now().add(TimeSpan.seconds(1))),
165
+ index.key,
166
+ );
167
+ expect(autoF.length).toEqual(3);
168
+ });
169
+
170
+ test("auto-index leaves user-provided index data untouched", async () => {
171
+ const [index, data] = await newIndexedPair(client);
172
+ const writer = await client.openWriter({
173
+ start: TimeStamp.seconds(200),
174
+ channels: [index.key, data.key],
175
+ autoIndex: true,
176
+ });
177
+ try {
178
+ await writer.write({
179
+ [index.key]: secondsLinspace(200, 3),
180
+ [data.key]: randomSeries(3, data.dataType),
181
+ });
182
+ await writer.commit();
183
+ } finally {
184
+ await writer.close();
185
+ }
186
+ const f = await client.read(
187
+ new TimeRange(TimeStamp.seconds(200), TimeStamp.seconds(203)),
188
+ index.key,
189
+ );
190
+ expect(f.data).toEqual(
191
+ new BigInt64Array(secondsLinspace(200, 3).map((v) => v.valueOf())),
192
+ );
193
+ });
194
+
118
195
  test("write with auto commit and a set interval", async () => {
119
196
  const channels = await newIndexedPair(client);
120
197
  const writer = await client.openWriter({
@@ -263,4 +340,147 @@ describe("Writer", () => {
263
340
  expect(f.length).toEqual(10);
264
341
  });
265
342
  });
343
+
344
+ describe("Variable Channels", () => {
345
+ test("write and read string data", async () => {
346
+ const index = await client.channels.create({
347
+ name: id.create(),
348
+ isIndex: true,
349
+ dataType: DataType.TIMESTAMP,
350
+ leaseholder: 1,
351
+ });
352
+ const data = await client.channels.create({
353
+ name: id.create(),
354
+ index: index.key,
355
+ dataType: DataType.STRING,
356
+ leaseholder: 1,
357
+ });
358
+ const writer = await client.openWriter({
359
+ start: TimeStamp.seconds(1),
360
+ channels: [index, data],
361
+ });
362
+ try {
363
+ await writer.write({
364
+ [index.key]: secondsLinspace(1, 3),
365
+ [data.key]: new Series({
366
+ data: ["hello", "world", "foo"],
367
+ dataType: DataType.STRING,
368
+ }),
369
+ });
370
+ await writer.commit();
371
+ } finally {
372
+ await writer.close();
373
+ }
374
+ const f = await data.read(TimeRange.MAX);
375
+ expect(f.toStrings()).toEqual(["hello", "world", "foo"]);
376
+ });
377
+
378
+ test("write and read JSON data", async () => {
379
+ const index = await client.channels.create({
380
+ name: id.create(),
381
+ isIndex: true,
382
+ dataType: DataType.TIMESTAMP,
383
+ leaseholder: 1,
384
+ });
385
+ const data = await client.channels.create({
386
+ name: id.create(),
387
+ index: index.key,
388
+ dataType: DataType.JSON,
389
+ leaseholder: 1,
390
+ });
391
+ const writer = await client.openWriter({
392
+ start: TimeStamp.seconds(1),
393
+ channels: [index, data],
394
+ });
395
+ try {
396
+ await writer.write({
397
+ [index.key]: secondsLinspace(1, 2),
398
+ [data.key]: new Series({
399
+ data: [{ key: "value" }, { num: 42 }],
400
+ dataType: DataType.JSON,
401
+ }),
402
+ });
403
+ await writer.commit();
404
+ } finally {
405
+ await writer.close();
406
+ }
407
+ const f = await data.read(TimeRange.MAX);
408
+ expect(f.length).toEqual(2);
409
+ });
410
+
411
+ test("write mixed fixed and variable channels", async () => {
412
+ const index = await client.channels.create({
413
+ name: id.create(),
414
+ isIndex: true,
415
+ dataType: DataType.TIMESTAMP,
416
+ leaseholder: 1,
417
+ });
418
+ const floatCh = await client.channels.create({
419
+ name: id.create(),
420
+ index: index.key,
421
+ dataType: DataType.FLOAT64,
422
+ leaseholder: 1,
423
+ });
424
+ const strCh = await client.channels.create({
425
+ name: id.create(),
426
+ index: index.key,
427
+ dataType: DataType.STRING,
428
+ leaseholder: 1,
429
+ });
430
+ const writer = await client.openWriter({
431
+ start: TimeStamp.seconds(1),
432
+ channels: [index, floatCh, strCh],
433
+ });
434
+ try {
435
+ await writer.write({
436
+ [index.key]: secondsLinspace(1, 3),
437
+ [floatCh.key]: new Float64Array([1.1, 2.2, 3.3]),
438
+ [strCh.key]: new Series({
439
+ data: ["a", "b", "c"],
440
+ dataType: DataType.STRING,
441
+ }),
442
+ });
443
+ await writer.commit();
444
+ } finally {
445
+ await writer.close();
446
+ }
447
+ const floatData = await floatCh.read(TimeRange.MAX);
448
+ expect(floatData.length).toEqual(3);
449
+ const strData = await strCh.read(TimeRange.MAX);
450
+ expect(strData.toStrings()).toEqual(["a", "b", "c"]);
451
+ });
452
+
453
+ test("write strings with embedded newlines", async () => {
454
+ const index = await client.channels.create({
455
+ name: id.create(),
456
+ isIndex: true,
457
+ dataType: DataType.TIMESTAMP,
458
+ leaseholder: 1,
459
+ });
460
+ const data = await client.channels.create({
461
+ name: id.create(),
462
+ index: index.key,
463
+ dataType: DataType.STRING,
464
+ leaseholder: 1,
465
+ });
466
+ const writer = await client.openWriter({
467
+ start: TimeStamp.seconds(1),
468
+ channels: [index, data],
469
+ });
470
+ try {
471
+ await writer.write({
472
+ [index.key]: secondsLinspace(1, 2),
473
+ [data.key]: new Series({
474
+ data: ["line1\nline2", "no newline"],
475
+ dataType: DataType.STRING,
476
+ }),
477
+ });
478
+ await writer.commit();
479
+ } finally {
480
+ await writer.close();
481
+ }
482
+ const f = await data.read(TimeRange.MAX);
483
+ expect(f.toStrings()).toEqual(["line1\nline2", "no newline"]);
484
+ });
485
+ });
266
486
  });