@synnaxlabs/client 0.2.0 → 0.2.1

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 (120) hide show
  1. package/.DS_Store +0 -0
  2. package/.editorconfig +0 -15
  3. package/.eslintrc.json +0 -33
  4. package/.gitignore +0 -9
  5. package/.nyc_output/20720f2d-6abe-420f-a3c5-304d52d60827.json +0 -1
  6. package/.nyc_output/4725921c-6f1b-4ae9-9819-e455f702d31c.json +0 -1
  7. package/.nyc_output/47478588-5ffd-4332-873c-facaa4a2fc38.json +0 -1
  8. package/.nyc_output/48180641-e0b2-49ab-a6eb-e7910e9eac2f.json +0 -1
  9. package/.nyc_output/cb0abf31-740f-47db-b94a-8e3f8f117cb8.json +0 -1
  10. package/.nyc_output/fc77fce2-dad0-49a8-8d4b-0a9014ecf8c5.json +0 -1
  11. package/.nyc_output/processinfo/20720f2d-6abe-420f-a3c5-304d52d60827.json +0 -1
  12. package/.nyc_output/processinfo/4725921c-6f1b-4ae9-9819-e455f702d31c.json +0 -1
  13. package/.nyc_output/processinfo/47478588-5ffd-4332-873c-facaa4a2fc38.json +0 -1
  14. package/.nyc_output/processinfo/48180641-e0b2-49ab-a6eb-e7910e9eac2f.json +0 -1
  15. package/.nyc_output/processinfo/cb0abf31-740f-47db-b94a-8e3f8f117cb8.json +0 -1
  16. package/.nyc_output/processinfo/fc77fce2-dad0-49a8-8d4b-0a9014ecf8c5.json +0 -1
  17. package/.nyc_output/processinfo/index.json +0 -1
  18. package/.prettierignore +0 -2
  19. package/build/tsconfig.module.tsbuildinfo +0 -1
  20. package/build/tsconfig.tsbuildinfo +0 -1
  21. package/coverage/base.css +0 -224
  22. package/coverage/block-navigation.js +0 -87
  23. package/coverage/favicon.png +0 -0
  24. package/coverage/index.html +0 -191
  25. package/coverage/lcov-report/base.css +0 -224
  26. package/coverage/lcov-report/block-navigation.js +0 -87
  27. package/coverage/lcov-report/favicon.png +0 -0
  28. package/coverage/lcov-report/index.html +0 -191
  29. package/coverage/lcov-report/prettify.css +0 -1
  30. package/coverage/lcov-report/prettify.js +0 -2
  31. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  32. package/coverage/lcov-report/sorter.js +0 -196
  33. package/coverage/lcov-report/src/index.html +0 -116
  34. package/coverage/lcov-report/src/lib/auth.ts.html +0 -340
  35. package/coverage/lcov-report/src/lib/channel/client.ts.html +0 -604
  36. package/coverage/lcov-report/src/lib/channel/creator.ts.html +0 -304
  37. package/coverage/lcov-report/src/lib/channel/index.html +0 -176
  38. package/coverage/lcov-report/src/lib/channel/payload.ts.html +0 -139
  39. package/coverage/lcov-report/src/lib/channel/registry.ts.html +0 -202
  40. package/coverage/lcov-report/src/lib/channel/retriever.ts.html +0 -244
  41. package/coverage/lcov-report/src/lib/client.ts.html +0 -244
  42. package/coverage/lcov-report/src/lib/errors.ts.html +0 -484
  43. package/coverage/lcov-report/src/lib/index.html +0 -176
  44. package/coverage/lcov-report/src/lib/segment/client.ts.html +0 -463
  45. package/coverage/lcov-report/src/lib/segment/index.html +0 -206
  46. package/coverage/lcov-report/src/lib/segment/iterator.ts.html +0 -928
  47. package/coverage/lcov-report/src/lib/segment/payload.ts.html +0 -139
  48. package/coverage/lcov-report/src/lib/segment/splitter.ts.html +0 -181
  49. package/coverage/lcov-report/src/lib/segment/typed.ts.html +0 -307
  50. package/coverage/lcov-report/src/lib/segment/validator.ts.html +0 -331
  51. package/coverage/lcov-report/src/lib/segment/writer.ts.html +0 -727
  52. package/coverage/lcov-report/src/lib/telem.ts.html +0 -2056
  53. package/coverage/lcov-report/src/lib/transport.ts.html +0 -196
  54. package/coverage/lcov-report/src/lib/user/index.html +0 -116
  55. package/coverage/lcov-report/src/lib/user/payload.ts.html +0 -109
  56. package/coverage/lcov-report/src/lib/util/index.html +0 -116
  57. package/coverage/lcov-report/src/lib/util/telem.ts.html +0 -124
  58. package/coverage/lcov-report/src/setupspecs.ts.html +0 -133
  59. package/coverage/lcov.info +0 -1230
  60. package/coverage/prettify.css +0 -1
  61. package/coverage/prettify.js +0 -2
  62. package/coverage/sort-arrow-sprite.png +0 -0
  63. package/coverage/sorter.js +0 -196
  64. package/coverage/src/index.html +0 -116
  65. package/coverage/src/lib/auth.ts.html +0 -340
  66. package/coverage/src/lib/channel/client.ts.html +0 -604
  67. package/coverage/src/lib/channel/creator.ts.html +0 -304
  68. package/coverage/src/lib/channel/index.html +0 -176
  69. package/coverage/src/lib/channel/payload.ts.html +0 -139
  70. package/coverage/src/lib/channel/registry.ts.html +0 -202
  71. package/coverage/src/lib/channel/retriever.ts.html +0 -244
  72. package/coverage/src/lib/client.ts.html +0 -244
  73. package/coverage/src/lib/errors.ts.html +0 -484
  74. package/coverage/src/lib/index.html +0 -176
  75. package/coverage/src/lib/segment/client.ts.html +0 -463
  76. package/coverage/src/lib/segment/index.html +0 -206
  77. package/coverage/src/lib/segment/iterator.ts.html +0 -928
  78. package/coverage/src/lib/segment/payload.ts.html +0 -139
  79. package/coverage/src/lib/segment/splitter.ts.html +0 -181
  80. package/coverage/src/lib/segment/typed.ts.html +0 -307
  81. package/coverage/src/lib/segment/validator.ts.html +0 -331
  82. package/coverage/src/lib/segment/writer.ts.html +0 -727
  83. package/coverage/src/lib/telem.ts.html +0 -2056
  84. package/coverage/src/lib/transport.ts.html +0 -196
  85. package/coverage/src/lib/user/index.html +0 -116
  86. package/coverage/src/lib/user/payload.ts.html +0 -109
  87. package/coverage/src/lib/util/index.html +0 -116
  88. package/coverage/src/lib/util/telem.ts.html +0 -124
  89. package/coverage/src/setupspecs.ts.html +0 -133
  90. package/src/index.ts +0 -13
  91. package/src/lib/.DS_Store +0 -0
  92. package/src/lib/auth.spec.ts +0 -36
  93. package/src/lib/auth.ts +0 -85
  94. package/src/lib/channel/channel.spec.ts +0 -49
  95. package/src/lib/channel/client.ts +0 -173
  96. package/src/lib/channel/creator.ts +0 -73
  97. package/src/lib/channel/payload.ts +0 -18
  98. package/src/lib/channel/registry.ts +0 -39
  99. package/src/lib/channel/retriever.ts +0 -53
  100. package/src/lib/client.ts +0 -53
  101. package/src/lib/errors.ts +0 -133
  102. package/src/lib/segment/client.ts +0 -126
  103. package/src/lib/segment/iterator.spec.ts +0 -78
  104. package/src/lib/segment/iterator.ts +0 -281
  105. package/src/lib/segment/payload.ts +0 -18
  106. package/src/lib/segment/splitter.ts +0 -32
  107. package/src/lib/segment/typed.ts +0 -74
  108. package/src/lib/segment/validator.ts +0 -82
  109. package/src/lib/segment/writer.spec.ts +0 -85
  110. package/src/lib/segment/writer.ts +0 -214
  111. package/src/lib/telem.spec.ts +0 -200
  112. package/src/lib/telem.ts +0 -657
  113. package/src/lib/transport.ts +0 -37
  114. package/src/lib/user/payload.ts +0 -8
  115. package/src/lib/util/telem.ts +0 -13
  116. package/src/setupspecs.ts +0 -16
  117. package/tsconfig.json +0 -47
  118. package/tsconfig.module.json +0 -9
  119. package/yarn-error.log +0 -5756
  120. package/yarn.lock +0 -5936
package/src/lib/client.ts DELETED
@@ -1,53 +0,0 @@
1
- import { URL } from '@synnaxlabs/freighter';
2
-
3
- import AuthenticationClient from './auth';
4
- import ChannelClient from './channel/client';
5
- import ChannelCreator from './channel/creator';
6
- import Registry from './channel/registry';
7
- import ChannelRetriever from './channel/retriever';
8
- import SegmentClient from './segment/client';
9
- import Transport from './transport';
10
-
11
- export type SynnaxProps = {
12
- host: string;
13
- port: number;
14
- username?: string;
15
- password?: string;
16
- };
17
-
18
- /**
19
- * Client to perform operations against a Synnax cluster.
20
- *
21
- * @property channel - Channel client for creating and retrieving channels.
22
- * @property data - Data client for reading and writing telemetry.
23
- */
24
- export default class Synnax {
25
- private transport: Transport;
26
- data: SegmentClient;
27
- channel: ChannelClient;
28
- auth: AuthenticationClient | undefined;
29
-
30
- /**
31
- * @param props.host - Hostname of a node in the cluster.
32
- * @param props.port - Port of the node in the cluster.
33
- * @param props.username - Username for authentication. Not required if the
34
- * cluster is insecure.
35
- * @param props.password - Password for authentication. Not required if the
36
- * cluster is insecure.
37
- */
38
- constructor({ host, port, username, password }: SynnaxProps) {
39
- this.transport = new Transport(new URL({ host, port }));
40
- if (username && password) {
41
- this.auth = new AuthenticationClient(this.transport.httpFactory, {
42
- username,
43
- password,
44
- });
45
- this.transport.use(this.auth.middleware());
46
- }
47
- const chRetriever = new ChannelRetriever(this.transport);
48
- const chCreator = new ChannelCreator(this.transport);
49
- const chRegistry = new Registry(chRetriever);
50
- this.data = new SegmentClient(this.transport, chRegistry);
51
- this.channel = new ChannelClient(this.data, chRetriever, chCreator);
52
- }
53
- }
package/src/lib/errors.ts DELETED
@@ -1,133 +0,0 @@
1
- import { BaseTypedError, registerError } from '@synnaxlabs/freighter';
2
- import { z } from 'zod';
3
-
4
- const _FREIGHTER_EXCEPTION_TYPE = 'synnax.api.errors';
5
-
6
- const APIErrorPayloadSchema = z.object({
7
- type: z.string(),
8
- error: z.record(z.unknown()),
9
- });
10
-
11
- type APIErrorPayload = z.infer<typeof APIErrorPayloadSchema>;
12
-
13
- enum APIErrorType {
14
- General = 'general',
15
- Nil = 'nil',
16
- Parse = 'parse',
17
- Auth = 'auth',
18
- Unexpected = 'unexpected',
19
- Validation = 'validation',
20
- Query = 'query',
21
- Route = 'route',
22
- }
23
-
24
- export type Field = {
25
- field: string;
26
- message: string;
27
- };
28
-
29
- class BaseError extends BaseTypedError {
30
- constructor(message: string) {
31
- super(message, _FREIGHTER_EXCEPTION_TYPE);
32
- }
33
- }
34
-
35
- /**
36
- * Raised when a validation error occurs.
37
- */
38
- export class ValidationError extends BaseError {
39
- fields: Field[];
40
-
41
- constructor(fieldsOrMessage: string | Field[] | Field) {
42
- if (typeof fieldsOrMessage === 'string') {
43
- super(fieldsOrMessage);
44
- this.fields = [];
45
- } else if (Array.isArray(fieldsOrMessage)) {
46
- super(
47
- fieldsOrMessage
48
- .map((field) => `${field.field}: ${field.message}`)
49
- .join('\n')
50
- );
51
- this.fields = fieldsOrMessage;
52
- } else {
53
- super(`${fieldsOrMessage.field}: ${fieldsOrMessage.message}`);
54
- this.fields = [fieldsOrMessage];
55
- }
56
- }
57
- }
58
-
59
- /**
60
- * GeneralError is raised when a general error occurs.
61
- */
62
- export class GeneralError extends BaseError {}
63
-
64
- /**
65
- * ParseError is raised when a parse error occurs.
66
- */
67
- export class ParseError extends BaseError {}
68
-
69
- /**
70
- * AuthError is raised when an authentication error occurs.
71
- */
72
- export class AuthError extends BaseError {}
73
-
74
- /**
75
- * UnexpectedError is raised when an unexpected error occurs.
76
- */
77
- export class UnexpectedError extends BaseError {}
78
-
79
- /**
80
- * QueryError is raised when a query error occurs.
81
- */
82
- export class QueryError extends BaseError {}
83
-
84
- /**
85
- * RouteError is raised when a routing error occurs.
86
- */
87
- export class RouteError extends BaseError {
88
- path: string;
89
-
90
- constructor(message: string, path: string) {
91
- super(message);
92
- this.path = path;
93
- }
94
- }
95
-
96
- /**
97
- * Raised when time-series data is not contiguous.
98
- */
99
- export class ContiguityError extends BaseError {}
100
-
101
- const parsePayload = (payload: APIErrorPayload): Error | undefined => {
102
- switch (payload.type) {
103
- case APIErrorType.General:
104
- return new GeneralError(payload.error.message as string);
105
- case APIErrorType.Parse:
106
- return new ParseError(payload.error.message as string);
107
- case APIErrorType.Auth:
108
- return new AuthError(payload.error.message as string);
109
- case APIErrorType.Unexpected:
110
- return new UnexpectedError(JSON.stringify(payload.error));
111
- case APIErrorType.Validation:
112
- return new ValidationError(payload.error.fields as string | Field[]);
113
- case APIErrorType.Query:
114
- return new QueryError(payload.error.message as string);
115
- case APIErrorType.Route:
116
- return new RouteError(
117
- payload.error.path as string,
118
- payload.error.message as string
119
- );
120
- default:
121
- return undefined;
122
- }
123
- };
124
-
125
- const decode = (encoded: string): Error | undefined => {
126
- return parsePayload(APIErrorPayloadSchema.parse(JSON.parse(encoded)));
127
- };
128
-
129
- const encode = (): string => {
130
- throw new Error('Not implemented');
131
- };
132
-
133
- registerError({ type: _FREIGHTER_EXCEPTION_TYPE, encode, decode });
@@ -1,126 +0,0 @@
1
- import Registry from '../channel/registry';
2
- import { TimeRange, TypedArray, UnparsedTimeStamp } from '../telem';
3
- import Transport from '../transport';
4
-
5
- import { TypedIterator } from './iterator';
6
- import TypedSegment from './typed';
7
- import { TypedWriter } from './writer';
8
-
9
- export default class SegmentClient {
10
- private transport: Transport;
11
- private channels: Registry;
12
-
13
- constructor(transport: Transport, channels: Registry) {
14
- this.transport = transport;
15
- this.channels = channels;
16
- }
17
-
18
- /**
19
- * Opens a new iterator over the given channels within the provided time range.
20
- *
21
- * @param tr - A time range to iterate over.
22
- * @param keys - A list of channel keys to iterate over.
23
- * @param aggregate - Whether to accumulate iteration results or reset them
24
- * on every iterator method call.
25
- * @returns a new {@link TypedIterator}.
26
- */
27
- async newIterator(
28
- tr: TimeRange,
29
- keys: string[],
30
- aggregate: boolean
31
- ): Promise<TypedIterator> {
32
- const iter = new TypedIterator(
33
- this.transport.streamClient,
34
- this.channels,
35
- aggregate
36
- );
37
- await iter.open(tr, keys);
38
- return iter;
39
- }
40
-
41
- /**
42
- * Opens a new writer on the given channels.
43
- *
44
- * @param keys - The keys of the channels to write to. A writer cannot write to
45
- * a channel that is not in this list. See the {@link TypedWriter} documentation
46
- * for more information.
47
- * @returns a new {@link TypedWriter}.
48
- */
49
- async newWriter(keys: string[]): Promise<TypedWriter> {
50
- const writer = new TypedWriter(this.transport.streamClient, this.channels);
51
- await writer.open(keys);
52
- return writer;
53
- }
54
-
55
- /**
56
- * Writes telemetry to the given channel starting at the given timestamp.
57
- *
58
- * @param to - The key of the channel to write to.
59
- * @param start - The starting timestamp of the first sample in data.
60
- * @param data - The telemetry to write. This telemetry must have the same
61
- * data type as the channel.
62
- * @throws if the channel does not exist.
63
- */
64
- async write(
65
- to: string,
66
- start: UnparsedTimeStamp,
67
- data: TypedArray
68
- ): Promise<boolean> {
69
- const writer = await this.newWriter([to]);
70
- try {
71
- return await writer.write(to, start, data);
72
- } finally {
73
- await writer.close();
74
- }
75
- }
76
-
77
- /**
78
- * Reads telemetry from the channel between the two timestamps.
79
- *
80
- * @param from - The key of the channel to read from.
81
- * @param start - The starting timestamp of the range to read from.
82
- * @param end - The ending timestamp of the range to read from.
83
- * @returns a typed array containing the retrieved telemetry.
84
- * @throws if the channel does not exist.
85
- * @throws if the telemetry between start and end is not contiguous.
86
- */
87
- async read(
88
- from: string,
89
- start: UnparsedTimeStamp,
90
- end: UnparsedTimeStamp
91
- ): Promise<TypedArray> {
92
- return (await this.readSegment(from, start, end)).view;
93
- }
94
-
95
- /**
96
- * Reads a segment from the channel between the two timestamps.
97
- *
98
- * @param from - The key of the channel to read from.
99
- * @param start - The starting timestamp of the range to read from.
100
- * @param end - The ending timestamp of the range to read from.
101
- * @returns a segment containing the retrieved telemetry.
102
- * @throws if the channel does not exist.
103
- * @throws if the telemetry between start and end is not contiguous.
104
- */
105
- async readSegment(
106
- from: string,
107
- start: UnparsedTimeStamp,
108
- end: UnparsedTimeStamp
109
- ): Promise<TypedSegment> {
110
- const iter = await this.newIterator(
111
- new TimeRange(start, end),
112
- [from],
113
- true
114
- );
115
- let seg: TypedSegment;
116
- try {
117
- await iter.first();
118
- // eslint-disable-next-line no-empty
119
- while (await iter.next()) {}
120
- seg = (await iter.value())[from];
121
- } finally {
122
- await iter.close();
123
- }
124
- return seg as TypedSegment;
125
- }
126
- }
@@ -1,78 +0,0 @@
1
- import test from 'ava';
2
-
3
- import { newClient } from '../../setupspecs';
4
- import { ContiguityError } from '../errors';
5
- import { DataType, Rate, TimeRange, TimeSpan } from '../telem';
6
- import { randomTypedArray } from '../util/telem';
7
-
8
- const client = newClient();
9
-
10
- const newChannel = async () => {
11
- return await client.channel.create({
12
- name: 'test',
13
- nodeId: 1,
14
- rate: Rate.Hz(25),
15
- dataType: DataType.Float64,
16
- });
17
- };
18
-
19
- test('TypedIterator - basic iteration', async (t) => {
20
- const ch = await newChannel();
21
- const writer = await client.data.newWriter([ch.key]);
22
- const data = randomTypedArray(25, ch.dataType);
23
- try {
24
- await writer.write(ch.key, TimeSpan.Second, data);
25
- await writer.write(ch.key, TimeSpan.Seconds(2), data);
26
- await writer.write(ch.key, TimeSpan.Seconds(3), data);
27
- } finally {
28
- await writer.close();
29
- }
30
- const iterator = await client.data.newIterator(
31
- new TimeRange(TimeSpan.Zero, TimeSpan.Seconds(4)),
32
- [ch.key],
33
- false
34
- );
35
- try {
36
- t.true(await iterator.first());
37
- t.true((await iterator.value())[ch.key].view.length === 25);
38
- let c = 1;
39
- while (await iterator.next()) {
40
- c++;
41
- t.true((await iterator.value())[ch.key].view.length === 25);
42
- }
43
- t.true(c === 3);
44
- } finally {
45
- await iterator.close();
46
- }
47
- });
48
-
49
- test('Client - basic read', async (t) => {
50
- const ch = await newChannel();
51
- const writer = await client.data.newWriter([ch.key]);
52
- const data = randomTypedArray(25, ch.dataType);
53
- try {
54
- await writer.write(ch.key, TimeSpan.Second, data);
55
- await writer.write(ch.key, TimeSpan.Seconds(2), data);
56
- await writer.write(ch.key, TimeSpan.Seconds(3), data);
57
- } finally {
58
- await writer.close();
59
- }
60
- const resData = await client.data.read(
61
- ch.key,
62
- TimeSpan.Zero,
63
- TimeSpan.Seconds(4)
64
- );
65
- resData.slice(0, 25).forEach((v, i) => t.true(v === data[i]));
66
- t.true(resData.length === 75);
67
- });
68
-
69
- test('Client - incontiguous read', async (t) => {
70
- const ch = await newChannel();
71
- const data = randomTypedArray(25, ch.dataType);
72
- await ch.write(TimeSpan.Zero, data);
73
- await ch.write(TimeSpan.Seconds(2), data);
74
- const err = await t.throwsAsync(async () => {
75
- await client.data.read(ch.key, TimeSpan.Zero, TimeSpan.Seconds(4));
76
- });
77
- t.true(err instanceof ContiguityError);
78
- });
@@ -1,281 +0,0 @@
1
- import {
2
- EOF,
3
- ErrorPayloadSchema,
4
- Stream,
5
- StreamClient,
6
- } from '@synnaxlabs/freighter';
7
- import { z } from 'zod';
8
-
9
- import { ChannelPayload } from '../channel/payload';
10
- import Registry from '../channel/registry';
11
- import { TimeRange } from '../telem';
12
-
13
- import { SegmentPayload, SegmentPayloadSchema } from './payload';
14
- import TypedSegment from './typed';
15
-
16
- enum Command {
17
- Open = 0,
18
- Next = 1,
19
- Prev = 2,
20
- First = 3,
21
- Last = 4,
22
- NextSpan = 5,
23
- PrevSpan = 6,
24
- NextRange = 7,
25
- Valid = 8,
26
- Error = 9,
27
- SeekFirst = 10,
28
- SeekLast = 11,
29
- SeekLT = 12,
30
- SeekGE = 13,
31
- }
32
-
33
- enum ResponseVariant {
34
- None = 0,
35
- Ack = 1,
36
- Data = 2,
37
- }
38
-
39
- const RequestSchema = z.object({
40
- command: z.nativeEnum(Command),
41
- span: z.number().optional(),
42
- range: z.instanceof(TimeRange).optional(),
43
- stamp: z.number().optional(),
44
- keys: z.string().array().optional(),
45
- });
46
-
47
- type Request = z.infer<typeof RequestSchema>;
48
-
49
- const ResponseSchema = z.object({
50
- variant: z.nativeEnum(ResponseVariant),
51
- ack: z.boolean(),
52
- command: z.nativeEnum(Command),
53
- error: ErrorPayloadSchema.optional(),
54
- segments: SegmentPayloadSchema.array().nullable(),
55
- });
56
-
57
- type Response = z.infer<typeof ResponseSchema>;
58
-
59
- /**
60
- * Used to iterate over a clusters telemetry in time-order. It should not be
61
- * instantiated directly, and should instead be instantiated via the SegmentClient.
62
- *
63
- * Using an iterator is ideal when querying/processing large ranges of data, but
64
- * is relatively complex and difficult to use. If you're looking to retrieve
65
- * telemetry between two timestamps, see the SegmentClient.read method.
66
- */
67
- export class CoreIterator {
68
- private static ENDPOINT = '/segment/iterate';
69
- private client: StreamClient;
70
- private stream: Stream<Request, Response> | undefined;
71
- private readonly aggregate: boolean = false;
72
- values: SegmentPayload[] = [];
73
-
74
- constructor(client: StreamClient, aggregate = false) {
75
- this.client = client;
76
- this.aggregate = aggregate;
77
- }
78
-
79
- /**
80
- * Opens the iterator, configuring it to iterate over the telemetry in the
81
- * channels with the given keys within the provided time range.
82
- *
83
- * @param tr - The time range to iterate over.
84
- * @param keys - The keys of the channels to iterate over.
85
- */
86
- async open(tr: TimeRange, keys: string[]) {
87
- this.stream = await this.client.stream(
88
- CoreIterator.ENDPOINT,
89
- RequestSchema,
90
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
91
- // @ts-ignore
92
- ResponseSchema
93
- );
94
- await this.execute({ command: Command.Open, keys, range: tr });
95
- this.values = [];
96
- }
97
-
98
- /**
99
- * Reads the next segment for each channel in the iterator.
100
- *
101
- * @returns false if the next segment can't be found for one or more channels or
102
- * the iterator has accumulated an error.
103
- */
104
- async next(): Promise<boolean> {
105
- return this.execute({ command: Command.Next });
106
- }
107
-
108
- /**
109
- * Reads the previous segment for each channel in the iterator.
110
- *
111
- * @returns false if the next segment can't be found for one or more channels or
112
- * the iterator has accumulated an error.
113
- */
114
- async prev(): Promise<boolean> {
115
- return this.execute({ command: Command.Prev });
116
- }
117
-
118
- /**
119
- * Seeks to the beginning of the time range and reads the first segment of each
120
- * channel in the iterator.
121
- *
122
- * @returns false if no segments exists in the time range for a particular channel
123
- * or the iterator has accumulated an error.
124
- */
125
- async first(): Promise<boolean> {
126
- return this.execute({ command: Command.First });
127
- }
128
-
129
- /**
130
- * Seeks to the end of the time range and reads the last segment of each channel
131
- * in the iterator.
132
- *
133
- * @returns false if no segments exists in the time range for a particular channel,
134
- * or the iterator has accumulated an error.
135
- */
136
- async last(): Promise<boolean> {
137
- return this.execute({ command: Command.Last });
138
- }
139
-
140
- /**
141
- * Reads the next time span of telemetry for each channel in the iterator.
142
- *
143
- * @returns false if a segment satisfying the request can't be found for a
144
- * particular channel or the iterator has accumulated an error.
145
- */
146
- async nextSpan(span: number): Promise<boolean> {
147
- return this.execute({ command: Command.NextSpan, span });
148
- }
149
-
150
- /**
151
- * Reads the previous time span of telemetry for each channel in the iterator.
152
- *
153
- * @returns false if a segment satisfying the request can't be found for a particular
154
- * channel or the iterator has accumulated an error.
155
- */
156
- async prevSpan(span: number): Promise<boolean> {
157
- return this.execute({ command: Command.PrevSpan, span });
158
- }
159
-
160
- /**
161
- * Seeks the iterator to the start of the time range and reads the telemetry within
162
- * the range for each channel.
163
- *
164
- * @returns: False if a segment satisfying the request can't be found for a particular
165
- * channel or the iterator has accumulated an error.
166
- */
167
- async nextRange(range: TimeRange): Promise<boolean> {
168
- return this.execute({ command: Command.NextRange, range });
169
- }
170
-
171
- /**
172
- * Seeks the iterator to the first segment in the time range, but does not read
173
- * it. Also invalidates the iterator. The iterator will not be considered valid
174
- * until a call to first, last, next, prev, prev_span, next_span, or next_range.
175
- *
176
- * @returns false if the iterator is not pointing to a valid segment for a particular
177
- * channel or has accumulated an error.
178
- */
179
- async seekFirst(): Promise<boolean> {
180
- return this.execute({ command: Command.SeekFirst });
181
- }
182
-
183
- /** Seeks the iterator to the last segment in the time range, but does not read it.
184
- * Also invalidates the iterator. The iterator will not be considered valid
185
- * until a call to first, last, next, prev, prev_span, next_span, or next_range.
186
- *
187
- * @returns false if the iterator is not pointing to a valid segment for a particular
188
- * channel or has accumulated an error.
189
- */
190
- async seekLast(): Promise<boolean> {
191
- return this.execute({ command: Command.SeekLast });
192
- }
193
-
194
- /**
195
- * Seeks the iterator to the first segment whose start is less than or equal to
196
- * the provided timestamp. Also invalidates the iterator. The iterator will not be
197
- * considered valid until a call to first, last, next, prev, prev_span, next_span, or next_range.
198
- *
199
- * @returns false if the iterator is not pointing to a valid segment for a particular
200
- * channel or has accumulated an error.
201
- */
202
- async seekLT(stamp: number): Promise<boolean> {
203
- return this.execute({ command: Command.SeekLT, stamp });
204
- }
205
-
206
- /**
207
- * Seeks the iterator to the first segment whose start is greater than or equal to
208
- * the provided timestamp. Also invalidates the iterator. The iterator will not be
209
- * considered valid until a call to first, last, next, prev, prev_span, next_span, or next_range.
210
- *
211
- * @returns false if the iterator is not pointing to a valid segment for a particular
212
- * channel or has accumulated an error.
213
- */
214
- async seekGE(stamp: number): Promise<boolean> {
215
- return this.execute({ command: Command.SeekGE, stamp });
216
- }
217
-
218
- /**
219
- * @returns true if the iterator value contains a valid segment, and fale otherwise.
220
- * valid most commonly returns false when the iterator is exhausted or has
221
- * accumulated an error.
222
- */
223
- async valid(): Promise<boolean> {
224
- return this.execute({ command: Command.Valid });
225
- }
226
-
227
- /**
228
- * Closes the iterator. An iterator MUST be closed after use, and this method
229
- * should probably be placed in a 'finally' block. If the iterator is not closed,
230
- * it may leak resources.
231
- */
232
- async close() {
233
- if (!this.stream)
234
- throw new Error('iterator.open() must be called before any other method');
235
- this.stream.closeSend();
236
- const [, exc] = await this.stream.receive();
237
- if (!(exc instanceof EOF)) throw exc;
238
- }
239
-
240
- private async execute(request: Request): Promise<boolean> {
241
- if (!this.stream)
242
- throw new Error('iterator.open() must be called before any other method');
243
- const err = this.stream.send(request);
244
- if (err) throw err;
245
- if (!this.aggregate) this.values = [];
246
- for (;;) {
247
- const [res, err] = await this.stream.receive();
248
- if (err || !res) throw err;
249
- if (res.variant == ResponseVariant.Ack) return res.ack;
250
- if (res.segments) this.values.push(...res.segments);
251
- }
252
- }
253
- }
254
-
255
- export class TypedIterator extends CoreIterator {
256
- channels: Registry;
257
-
258
- constructor(client: StreamClient, channels: Registry, aggregate = false) {
259
- super(client, aggregate);
260
- this.channels = channels;
261
- }
262
-
263
- async value(): Promise<Record<string, TypedSegment>> {
264
- const result: Record<string, TypedSegment> = {};
265
- this.values.sort((a, b) => a.start.valueOf() - b.start.valueOf());
266
- const keys = this.values.map((v) => v.channelKey);
267
- const channels = await this.channels.getN(...keys);
268
- this.values.forEach((v) => {
269
- const sugared = new TypedSegment(
270
- channels.find((c) => c.key == v.channelKey) as ChannelPayload,
271
- v
272
- );
273
- if (v.channelKey in result) {
274
- result[v.channelKey].extend(sugared);
275
- } else {
276
- result[v.channelKey] = sugared;
277
- }
278
- });
279
- return result;
280
- }
281
- }
@@ -1,18 +0,0 @@
1
- import { z } from 'zod';
2
-
3
- import { TimeStamp } from '../telem';
4
-
5
- export const SegmentPayloadSchema = z.object({
6
- channelKey: z.string(),
7
- start: z.number().transform((n) => new TimeStamp(n)),
8
- data: z.string().transform(
9
- (s) =>
10
- new Uint8Array(
11
- atob(s)
12
- .split('')
13
- .map((c) => c.charCodeAt(0))
14
- )
15
- ),
16
- });
17
-
18
- export type SegmentPayload = z.infer<typeof SegmentPayloadSchema>;