@synnaxlabs/client 0.17.3 → 0.17.5

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.
@@ -7,12 +7,20 @@
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 Key, type Name, type Params } from "@/channel/payload";
11
- import { type Retriever, analyzeParams } from "@/channel/retriever";
10
+ import { type CrudeSeries, Series } from "@synnaxlabs/x";
11
+
12
+ import {
13
+ type Key,
14
+ type Name,
15
+ type Params,
16
+ type KeyOrName,
17
+ type Payload,
18
+ } from "@/channel/payload";
19
+ import { type Retriever, analyzeParams, retrieveRequired } from "@/channel/retriever";
12
20
  import { ValidationError } from "@/errors";
13
- import { type Frame } from "@/framer/frame";
21
+ import { type CrudeFrame, Frame } from "@/framer/frame";
14
22
 
15
- export class BackwardFrameAdapter {
23
+ export class ReadFrameAdapter {
16
24
  private adapter: Map<Key, Name> | null;
17
25
  retriever: Retriever;
18
26
  keys: Key[];
@@ -23,11 +31,8 @@ export class BackwardFrameAdapter {
23
31
  this.keys = [];
24
32
  }
25
33
 
26
- static async open(
27
- retriever: Retriever,
28
- channels: Params,
29
- ): Promise<BackwardFrameAdapter> {
30
- const adapter = new BackwardFrameAdapter(retriever);
34
+ static async open(retriever: Retriever, channels: Params): Promise<ReadFrameAdapter> {
35
+ const adapter = new ReadFrameAdapter(retriever);
31
36
  await adapter.update(channels);
32
37
  return adapter;
33
38
  }
@@ -50,10 +55,10 @@ export class BackwardFrameAdapter {
50
55
  this.keys = Array.from(this.adapter.keys());
51
56
  }
52
57
 
53
- adapt(fr: Frame): Frame {
54
- if (this.adapter == null) return fr;
58
+ adapt(columnsOrData: Frame): Frame {
59
+ if (this.adapter == null) return columnsOrData;
55
60
  const a = this.adapter;
56
- return fr.map((k, arr) => {
61
+ return columnsOrData.map((k, arr) => {
57
62
  if (typeof k === "number") {
58
63
  const name = a.get(k);
59
64
  if (name == null) throw new Error(`Channel ${k} not found`);
@@ -64,7 +69,7 @@ export class BackwardFrameAdapter {
64
69
  }
65
70
  }
66
71
 
67
- export class ForwardFrameAdapter {
72
+ export class WriteFrameAdapter {
68
73
  private adapter: Map<Name, Key> | null;
69
74
  retriever: Retriever;
70
75
  keys: Key[];
@@ -78,46 +83,100 @@ export class ForwardFrameAdapter {
78
83
  static async open(
79
84
  retriever: Retriever,
80
85
  channels: Params,
81
- ): Promise<ForwardFrameAdapter> {
82
- const adapter = new ForwardFrameAdapter(retriever);
86
+ ): Promise<WriteFrameAdapter> {
87
+ const adapter = new WriteFrameAdapter(retriever);
83
88
  await adapter.update(channels);
84
89
  return adapter;
85
90
  }
86
91
 
87
92
  async update(channels: Params): Promise<void> {
88
- const { variant, normalized } = analyzeParams(channels);
89
- if (variant === "keys") {
90
- this.adapter = null;
91
- this.keys = normalized;
92
- return;
93
- }
94
- const fetched = await this.retriever.retrieve(normalized);
95
- const a = new Map<Name, Key>();
96
- this.adapter = a;
97
- normalized.forEach((name) => {
98
- const channel = fetched.find((channel) => channel.name === name);
99
- if (channel == null) throw new ValidationError(`Channel ${name} was not provided in the list of channels when opening the writer`);
100
- a.set(channel.name, channel.key);
101
- });
102
- this.keys = fetched.map((c) => c.key);
93
+ const results = await retrieveRequired(this.retriever, channels);
94
+ this.adapter = new Map<Name, Key>(results.map((c) => [c.name, c.key]));
95
+ this.keys = results.map((c) => c.key);
103
96
  }
104
97
 
105
- adapt(fr: Frame): Frame {
106
- if (this.adapter == null) {
107
- // assert that every col if of type number
108
- fr.columns.forEach((col) => {
109
- if (typeof col !== "number") throw new ValidationError(`Channel ${col} was not provided in the list of channels when opening the writer`);
110
- });
111
- return fr;
98
+ private async fetchChannel(ch: Key | Name): Promise<Payload> {
99
+ const res = await this.retriever.retrieve(ch);
100
+ if (res.length === 0) throw new Error(`Channel ${ch} not found`);
101
+ return res[0];
102
+ }
103
+
104
+ async adapt(
105
+ columnsOrData: Params | Record<KeyOrName, CrudeSeries> | CrudeFrame,
106
+ series?: CrudeSeries | CrudeSeries[],
107
+ ): Promise<Frame> {
108
+ if (typeof columnsOrData === "string" || typeof columnsOrData === "number") {
109
+ if (series == null)
110
+ throw new ValidationError(`
111
+ Received a single channel name or key but no series.
112
+ `);
113
+ if (Array.isArray(series)) {
114
+ if (series.length > 1) {
115
+ throw new ValidationError(`
116
+ Received a single channel name or key but multiple series.
117
+ `);
118
+ }
119
+ series = series[0] as CrudeSeries;
120
+ }
121
+ const pld = await this.fetchChannel(columnsOrData);
122
+ const s = new Series({ data: series as CrudeSeries, dataType: pld.dataType });
123
+ return new Frame(pld.key, s);
112
124
  }
113
- const a = this.adapter;
114
- return fr.map((col, arr) => {
115
- if (typeof col === "string") {
116
- const key = a.get(col);
117
- if (key == null) throw new Error(`Channel ${col} not found`);
118
- return [key, arr];
125
+
126
+ if (Array.isArray(columnsOrData)) {
127
+ if (series == null)
128
+ throw new ValidationError(`
129
+ Received an array of channel names or keys but no series.
130
+ `);
131
+ if (!Array.isArray(series))
132
+ throw new ValidationError(`
133
+ Received an array of channel names or keys but no array of series.
134
+ `);
135
+ const cols = [];
136
+ const data = [];
137
+ for (let i = 0; i < columnsOrData.length; i++) {
138
+ const pld = await this.fetchChannel(columnsOrData[i]);
139
+ if (i >= series.length) {
140
+ throw new ValidationError(`
141
+ Received an array of channel names or keys but not enough series.
142
+ `);
143
+ }
144
+ const s = new Series({
145
+ data: series[i] as CrudeSeries,
146
+ dataType: pld.dataType,
147
+ });
148
+ cols.push(pld.key);
149
+ data.push(s);
119
150
  }
120
- return [col, arr];
121
- });
151
+ return new Frame(cols, data);
152
+ }
153
+
154
+ if (columnsOrData instanceof Frame || columnsOrData instanceof Map) {
155
+ const fr = new Frame(columnsOrData);
156
+ if (this.adapter == null) return fr;
157
+ let cols: Key[] = [];
158
+ cols = fr.columns.map((col_) => {
159
+ const col = typeof col_ === "string" ? this.adapter?.get(col_) : col_;
160
+ if (col == null)
161
+ throw new ValidationError(`
162
+ Channel ${col_} was not provided in the list of channels when opening the writer
163
+ `);
164
+ return col;
165
+ });
166
+ return new Frame(cols, fr.series);
167
+ }
168
+
169
+ const cols = [];
170
+ const data = [];
171
+ const kvs = Object.entries(columnsOrData);
172
+ for (let i = 0; i < kvs.length; i++) {
173
+ const [k, v] = kvs[i];
174
+ const pld = await this.fetchChannel(k);
175
+ const s = new Series({ data: v, dataType: pld.dataType });
176
+ cols.push(pld.key);
177
+ data.push(s);
178
+ }
179
+
180
+ return new Frame(cols, data);
122
181
  }
123
182
  }
@@ -9,7 +9,7 @@
9
9
 
10
10
  import { type StreamClient } from "@synnaxlabs/freighter";
11
11
  import {
12
- type NativeTypedArray,
12
+ type TypedArray,
13
13
  type Series,
14
14
  type TimeRange,
15
15
  type CrudeTimeStamp,
@@ -84,11 +84,7 @@ export class Client {
84
84
  * data type as the channel.
85
85
  * @throws if the channel does not exist.
86
86
  */
87
- async write(
88
- to: KeyOrName,
89
- start: CrudeTimeStamp,
90
- data: NativeTypedArray,
91
- ): Promise<void> {
87
+ async write(to: KeyOrName, start: CrudeTimeStamp, data: TypedArray): Promise<void> {
92
88
  const w = await this.newWriter({
93
89
  start,
94
90
  channels: to,
@@ -19,9 +19,9 @@ describe("framer.Frame", () => {
19
19
  const f = new framer.Frame(
20
20
  ["a", "b", "c"],
21
21
  [
22
- new Series({data: new Float32Array([1, 2, 3])}),
23
- new Series({data: new Float32Array([1, 2, 3])}),
24
- new Series({data: new Float32Array([1, 2, 3])}),
22
+ new Series({ data: new Float32Array([1, 2, 3]) }),
23
+ new Series({ data: new Float32Array([1, 2, 3]) }),
24
+ new Series({ data: new Float32Array([1, 2, 3]) }),
25
25
  ],
26
26
  );
27
27
  expect(f.length).toEqual(9);
@@ -32,9 +32,9 @@ describe("framer.Frame", () => {
32
32
  const f = new framer.Frame(
33
33
  [12, 13, 14],
34
34
  [
35
- new Series({data: new Float32Array([1, 2, 3])}),
36
- new Series({data: new Float32Array([1, 2, 3])}),
37
- new Series({data: new Float32Array([1, 2, 3])}),
35
+ new Series({ data: new Float32Array([1, 2, 3]) }),
36
+ new Series({ data: new Float32Array([1, 2, 3]) }),
37
+ new Series({ data: new Float32Array([1, 2, 3]) }),
38
38
  ],
39
39
  );
40
40
  expect(f.length).toEqual(9);
@@ -42,25 +42,35 @@ describe("framer.Frame", () => {
42
42
  });
43
43
 
44
44
  test("from a single name and an array of arrays", () => {
45
- const f = new framer.Frame("a", [new Series({data: new Float32Array([1, 2, 3])})]);
45
+ const f = new framer.Frame("a", [
46
+ new Series({ data: new Float32Array([1, 2, 3]) }),
47
+ ]);
46
48
  expect(f.length).toEqual(3);
47
49
  expect(f.colType).toEqual("name");
48
50
  });
49
51
 
50
52
  test("from a single key and an array of arrays", () => {
51
- const f = new framer.Frame(12, [new Series({data: new Float32Array([1, 2, 3])})]);
53
+ const f = new framer.Frame(12, [
54
+ new Series({ data: new Float32Array([1, 2, 3]) }),
55
+ ]);
52
56
  expect(f.length).toEqual(3);
53
57
  expect(f.colType).toEqual("key");
54
58
  });
55
59
 
56
60
  test("from a single key and a single array", () => {
57
- const f = new framer.Frame(12, new Series({data: new Float32Array([1, 2, 3])}));
61
+ const f = new framer.Frame(
62
+ 12,
63
+ new Series({ data: new Float32Array([1, 2, 3]) }),
64
+ );
58
65
  expect(f.length).toEqual(3);
59
66
  expect(f.colType).toEqual("key");
60
67
  });
61
68
 
62
69
  test("from a single name and a single array", () => {
63
- const f = new framer.Frame("a", new Series({data: new Float32Array([1, 2, 3])}));
70
+ const f = new framer.Frame(
71
+ "a",
72
+ new Series({ data: new Float32Array([1, 2, 3]) }),
73
+ );
64
74
  expect(f.length).toEqual(3);
65
75
  expect(f.colType).toEqual("name");
66
76
  });
@@ -82,7 +92,7 @@ describe("framer.Frame", () => {
82
92
 
83
93
  test("from record", () => {
84
94
  const f = new framer.Frame({
85
- a: new Series({data: new Float32Array([1, 2, 3])}),
95
+ a: new Series({ data: new Float32Array([1, 2, 3]) }),
86
96
  });
87
97
  expect(f.length.valueOf()).toEqual(3);
88
98
  expect(f.columns.length).toEqual(1);
@@ -91,7 +101,7 @@ describe("framer.Frame", () => {
91
101
 
92
102
  test("from map", () => {
93
103
  const f = new framer.Frame(
94
- new Map([[12, new Series({data: new Float32Array([1, 2, 3])})]]),
104
+ new Map([[12, new Series({ data: new Float32Array([1, 2, 3]) })]]),
95
105
  );
96
106
  expect(f.length).toEqual(3);
97
107
  expect(f.columns.length).toEqual(1);
@@ -106,8 +116,8 @@ describe("framer.Frame", () => {
106
116
  new framer.Frame(
107
117
  ["a", "b", "c"],
108
118
  [
109
- new Series({data: new Float32Array([1, 2, 3])}),
110
- new Series({data: new Float32Array([1, 2, 3])}),
119
+ new Series({ data: new Float32Array([1, 2, 3]) }),
120
+ new Series({ data: new Float32Array([1, 2, 3]) }),
111
121
  ],
112
122
  ),
113
123
  ).toThrow();
@@ -119,12 +129,12 @@ describe("framer.Frame", () => {
119
129
  it("should return false if a key has more than one array", () => {
120
130
  const f = new framer.Frame(
121
131
  new Map([
122
- [12, [new Series({data: new Float32Array([1, 2, 3])})]],
132
+ [12, [new Series({ data: new Float32Array([1, 2, 3]) })]],
123
133
  [
124
134
  13,
125
135
  [
126
- new Series({data: new Float32Array([1, 2, 3])}),
127
- new Series({data: new Float32Array([1, 2, 3])}),
136
+ new Series({ data: new Float32Array([1, 2, 3]) }),
137
+ new Series({ data: new Float32Array([1, 2, 3]) }),
128
138
  ],
129
139
  ],
130
140
  ]),
@@ -137,8 +147,8 @@ describe("framer.Frame", () => {
137
147
  it("should return false if there is more than one key", () => {
138
148
  const f = new framer.Frame(
139
149
  new Map([
140
- [12, [new Series({data: new Float32Array([1, 2, 3])})]],
141
- [13, [new Series({data: new Float32Array([1, 2, 3])})]],
150
+ [12, [new Series({ data: new Float32Array([1, 2, 3]) })]],
151
+ [13, [new Series({ data: new Float32Array([1, 2, 3]) })]],
142
152
  ]),
143
153
  );
144
154
  expect(f.isHorizontal).toEqual(false);
@@ -164,7 +174,7 @@ describe("framer.Frame", () => {
164
174
  new Series({
165
175
  data: new Float32Array([1, 2, 3]),
166
176
  timeRange: new TimeRange(500, 50000),
167
- }),
177
+ }),
168
178
  ],
169
179
  ],
170
180
  ]),
@@ -181,7 +191,7 @@ describe("framer.Frame", () => {
181
191
  new Series({
182
192
  data: new Float32Array([1, 2, 3]),
183
193
  timeRange: new TimeRange(500, 50000),
184
- }),
194
+ }),
185
195
  ],
186
196
  ],
187
197
  [
@@ -190,7 +200,7 @@ describe("framer.Frame", () => {
190
200
  new Series({
191
201
  data: new Float32Array([1, 2, 3]),
192
202
  timeRange: new TimeRange(500, 50001),
193
- }),
203
+ }),
194
204
  ],
195
205
  ],
196
206
  ]),
@@ -201,7 +211,7 @@ describe("framer.Frame", () => {
201
211
 
202
212
  describe("timeRange", () => {
203
213
  describe("no key provided", () => {
204
- it("should return the maxium time range of the frame", () => {
214
+ it("should return the maximum time range of the frame", () => {
205
215
  const f = new framer.Frame(
206
216
  new Map([
207
217
  [
@@ -210,7 +220,7 @@ describe("framer.Frame", () => {
210
220
  new Series({
211
221
  data: new Float32Array([1, 2, 3]),
212
222
  timeRange: new TimeRange(40, 50000),
213
- }),
223
+ }),
214
224
  ],
215
225
  ],
216
226
  [
@@ -219,7 +229,7 @@ describe("framer.Frame", () => {
219
229
  new Series({
220
230
  data: new Float32Array([1, 2, 3]),
221
231
  timeRange: new TimeRange(500, 50001),
222
- }),
232
+ }),
223
233
  ],
224
234
  ],
225
235
  ]),
@@ -234,11 +244,11 @@ describe("framer.Frame", () => {
234
244
  a: new Series({
235
245
  data: new Float32Array([1, 2, 3]),
236
246
  timeRange: new TimeRange(40, 50000),
237
- }),
247
+ }),
238
248
  b: new Series({
239
249
  data: new Float32Array([1, 2, 3]),
240
250
  timeRange: new TimeRange(500, 50001),
241
- }),
251
+ }),
242
252
  });
243
253
  expect(f.timeRange("a")).toEqual(new TimeRange(40, 50000));
244
254
  });
@@ -254,7 +264,7 @@ describe("framer.Frame", () => {
254
264
  new Series({
255
265
  data: new Float32Array([1, 2, 3]),
256
266
  timeRange: new TimeRange(40, 50000),
257
- }),
267
+ }),
258
268
  ],
259
269
  ],
260
270
  [
@@ -263,7 +273,7 @@ describe("framer.Frame", () => {
263
273
  new Series({
264
274
  data: new Float32Array([1, 2, 3]),
265
275
  timeRange: new TimeRange(500, 50001),
266
- }),
276
+ }),
267
277
  ],
268
278
  ],
269
279
  ]),
@@ -283,7 +293,7 @@ describe("framer.Frame", () => {
283
293
  new Series({
284
294
  data: new Float32Array([1, 2, 3]),
285
295
  timeRange: new TimeRange(40, 50000),
286
- }),
296
+ }),
287
297
  ],
288
298
  ],
289
299
  [
@@ -292,7 +302,7 @@ describe("framer.Frame", () => {
292
302
  new Series({
293
303
  data: new Float32Array([1, 2, 3]),
294
304
  timeRange: new TimeRange(500, 50001),
295
- }),
305
+ }),
296
306
  ],
297
307
  ],
298
308
  ]),
@@ -302,4 +312,65 @@ describe("framer.Frame", () => {
302
312
  expect(pld.series?.[0].data.byteLength).toEqual(12);
303
313
  });
304
314
  });
315
+
316
+ describe("latest", () => {
317
+ it("should return the latest sample from each column in the frame", () => {
318
+ const f = new framer.Frame(
319
+ new Map([
320
+ [
321
+ 12,
322
+ [
323
+ new Series({
324
+ data: new Float32Array([1, 2, 3]),
325
+ timeRange: new TimeRange(40, 50000),
326
+ }),
327
+ ],
328
+ ],
329
+ [
330
+ 13,
331
+ [
332
+ new Series({
333
+ data: new Float32Array([1, 2, 3]),
334
+ timeRange: new TimeRange(500, 50001),
335
+ }),
336
+ ],
337
+ ],
338
+ ]),
339
+ );
340
+ expect(f.latest()).toEqual({ 12: 3, 13: 3 });
341
+ });
342
+ it("should return the latest sample for each col in the frame - even with multiple series per col", () => {
343
+ const f = new framer.Frame(
344
+ new Map([
345
+ [
346
+ 12,
347
+ [
348
+ new Series({
349
+ data: new Float32Array([1, 2, 3]),
350
+ timeRange: new TimeRange(40, 50000),
351
+ }),
352
+ new Series({
353
+ data: new Float32Array([4, 5, 6]),
354
+ timeRange: new TimeRange(40, 50000),
355
+ }),
356
+ ],
357
+ ],
358
+ [
359
+ 13,
360
+ [
361
+ new Series({
362
+ data: new Float32Array([1, 2, 3]),
363
+ timeRange: new TimeRange(500, 50001),
364
+ }),
365
+ new Series({
366
+ data: new Float32Array([4, 5, 7]),
367
+ timeRange: new TimeRange(500, 50001),
368
+ }),
369
+ ],
370
+ ],
371
+ ]),
372
+ );
373
+ expect(f.latest()).toEqual({ 12: 6, 13: 7 });
374
+ });
375
+ });
305
376
  });
@@ -7,7 +7,16 @@
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 { Size, Series, TimeRange, toArray, DataType, unique, TimeStamp } from "@synnaxlabs/x";
10
+ import {
11
+ Size,
12
+ Series,
13
+ TimeRange,
14
+ toArray,
15
+ DataType,
16
+ unique,
17
+ TimeStamp,
18
+ type TelemValue,
19
+ } from "@synnaxlabs/x";
11
20
  import { z } from "zod";
12
21
 
13
22
  import {
@@ -59,7 +68,7 @@ export type CrudeFrame =
59
68
  *
60
69
  * - A frame is weakly aligned if it meets the time range occupied by all arrays of a
61
70
  * particular channel is the same for all channels in the frame. This means that the
62
- * arrays for a particular channel can have gaps betwen them.
71
+ * arrays for a particular channel can have gaps between them.
63
72
  *
64
73
  * - A strongly aligned frame means that all channels share the same rate/index and
65
74
  * there are no gaps in time between arrays. Strongly aligned frames are natural
@@ -113,7 +122,7 @@ export class Frame {
113
122
  Object.entries(columnsOrData).forEach(([k, v]) => {
114
123
  const key = parseInt(k);
115
124
  if (!isNaN(key)) return this.push(key, ...toArray(v));
116
- else this.push(k, ...toArray(v))
125
+ else this.push(k, ...toArray(v));
117
126
  });
118
127
  return;
119
128
  }
@@ -249,6 +258,14 @@ export class Frame {
249
258
  );
250
259
  }
251
260
 
261
+ latest(): Record<string, TelemValue> {
262
+ return Object.fromEntries(
263
+ this.columns
264
+ .map((c, i) => [c, this.series[i].at(-1)])
265
+ .filter(([_, v]) => v != null),
266
+ );
267
+ }
268
+
252
269
  get timeRanges(): TimeRange[] {
253
270
  return this.uniqueColumns.map((col) => this.timeRange(col));
254
271
  }
@@ -403,7 +420,7 @@ export type FramePayload = z.infer<typeof frameZ>;
403
420
 
404
421
  export const seriesFromPayload = (series: SeriesPayload): Series => {
405
422
  const { dataType, data, timeRange, alignment } = series;
406
- return new Series({data, dataType, timeRange, glBufferUsage: "static", alignment});
423
+ return new Series({ data, dataType, timeRange, glBufferUsage: "static", alignment });
407
424
  };
408
425
 
409
426
  export const seriesToPayload = (series: Series): SeriesPayload => {
@@ -19,7 +19,7 @@ import { z } from "zod";
19
19
 
20
20
  import { type Params } from "@/channel/payload";
21
21
  import { type Retriever } from "@/channel/retriever";
22
- import { BackwardFrameAdapter } from "@/framer/adapter";
22
+ import { ReadFrameAdapter } from "@/framer/adapter";
23
23
  import { Frame, frameZ } from "@/framer/frame";
24
24
  import { StreamProxy } from "@/framer/streamProxy";
25
25
 
@@ -72,12 +72,12 @@ const resZ = z.object({
72
72
  export class Iterator {
73
73
  private static readonly ENDPOINT = "/frame/iterate";
74
74
  private readonly stream: StreamProxy<typeof reqZ, typeof resZ>;
75
- private readonly adapter: BackwardFrameAdapter;
75
+ private readonly adapter: ReadFrameAdapter;
76
76
  value: Frame;
77
77
 
78
78
  private constructor(
79
79
  stream: Stream<typeof reqZ, typeof resZ>,
80
- adapter: BackwardFrameAdapter,
80
+ adapter: ReadFrameAdapter,
81
81
  ) {
82
82
  this.stream = new StreamProxy("Iterator", stream);
83
83
  this.value = new Frame();
@@ -97,7 +97,7 @@ export class Iterator {
97
97
  retriever: Retriever,
98
98
  client: StreamClient,
99
99
  ): Promise<Iterator> {
100
- const adapter = await BackwardFrameAdapter.open(retriever, channels);
100
+ const adapter = await ReadFrameAdapter.open(retriever, channels);
101
101
  const stream = await client.stream(Iterator.ENDPOINT, reqZ, resZ);
102
102
  const iter = new Iterator(stream, adapter);
103
103
  await iter.execute({ command: Command.Open, keys: adapter.keys, bounds: tr });
@@ -13,7 +13,7 @@ import { z } from "zod";
13
13
 
14
14
  import { type Key, type Params } from "@/channel/payload";
15
15
  import { type Retriever } from "@/channel/retriever";
16
- import { BackwardFrameAdapter } from "@/framer/adapter";
16
+ import { ReadFrameAdapter } from "@/framer/adapter";
17
17
  import { Frame, frameZ } from "@/framer/frame";
18
18
  import { StreamProxy } from "@/framer/streamProxy";
19
19
 
@@ -31,11 +31,11 @@ const ENDPOINT = "/frame/stream";
31
31
 
32
32
  export class Streamer implements AsyncIterator<Frame>, AsyncIterable<Frame> {
33
33
  private readonly stream: StreamProxy<typeof reqZ, typeof resZ>;
34
- private readonly adapter: BackwardFrameAdapter;
34
+ private readonly adapter: ReadFrameAdapter;
35
35
 
36
36
  private constructor(
37
37
  stream: Stream<typeof reqZ, typeof resZ>,
38
- adapter: BackwardFrameAdapter,
38
+ adapter: ReadFrameAdapter,
39
39
  ) {
40
40
  this.stream = new StreamProxy("Streamer", stream);
41
41
  this.adapter = adapter;
@@ -51,7 +51,7 @@ export class Streamer implements AsyncIterator<Frame>, AsyncIterable<Frame> {
51
51
  retriever: Retriever,
52
52
  client: StreamClient,
53
53
  ): Promise<Streamer> {
54
- const adapter = await BackwardFrameAdapter.open(retriever, channels);
54
+ const adapter = await ReadFrameAdapter.open(retriever, channels);
55
55
  const stream = await client.stream(ENDPOINT, reqZ, resZ);
56
56
  const streamer = new Streamer(stream, adapter);
57
57
  stream.send({ start: new TimeStamp(start), keys: adapter.keys });
@@ -43,7 +43,7 @@ describe("Writer", () => {
43
43
  const writer = await client.telem.newWriter({ start: 0, channels: ch.key });
44
44
  await expect(
45
45
  writer.write("billy bob", randomSeries(10, DataType.FLOAT64)),
46
- ).rejects.toThrow("Channel billy bob was not provided");
46
+ ).rejects.toThrow("Channel billy bob not found");
47
47
  await writer.close();
48
48
  });
49
49
  test("stream when mode is set ot persist only", async () => {