@synnaxlabs/client 0.26.7 → 0.28.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 (140) hide show
  1. package/.turbo/turbo-build.log +7 -7
  2. package/README.md +36 -10
  3. package/api/client.api.md +3121 -0
  4. package/api-extractor.json +7 -0
  5. package/dist/access/client.d.ts +0 -1
  6. package/dist/access/payload.d.ts +0 -1
  7. package/dist/auth/auth.d.ts +0 -1
  8. package/dist/channel/client.d.ts +6 -2
  9. package/dist/channel/client.d.ts.map +1 -1
  10. package/dist/channel/creator.d.ts +0 -1
  11. package/dist/channel/payload.d.ts +4 -1
  12. package/dist/channel/payload.d.ts.map +1 -1
  13. package/dist/channel/retriever.d.ts +0 -1
  14. package/dist/channel/writer.d.ts +0 -1
  15. package/dist/client.cjs +23 -19
  16. package/dist/client.d.ts +10 -7
  17. package/dist/client.d.ts.map +1 -1
  18. package/dist/client.js +2326 -1904
  19. package/dist/connection/checker.d.ts +21 -2
  20. package/dist/connection/checker.d.ts.map +1 -1
  21. package/dist/control/client.d.ts +0 -1
  22. package/dist/control/client.d.ts.map +1 -1
  23. package/dist/control/state.d.ts +0 -1
  24. package/dist/errors.d.ts +0 -1
  25. package/dist/framer/adapter.d.ts +0 -1
  26. package/dist/framer/client.d.ts +0 -1
  27. package/dist/framer/client.d.ts.map +1 -1
  28. package/dist/framer/deleter.d.ts +0 -1
  29. package/dist/framer/frame.d.ts +11 -12
  30. package/dist/framer/iterator.d.ts +0 -1
  31. package/dist/framer/streamProxy.d.ts +0 -1
  32. package/dist/framer/streamer.d.ts +0 -1
  33. package/dist/framer/writer.d.ts +0 -1
  34. package/dist/framer/writer.d.ts.map +1 -1
  35. package/dist/hardware/client.d.ts +0 -1
  36. package/dist/hardware/device/client.d.ts +0 -1
  37. package/dist/hardware/device/payload.d.ts +0 -1
  38. package/dist/hardware/device/payload.d.ts.map +1 -1
  39. package/dist/hardware/rack/client.d.ts +0 -1
  40. package/dist/hardware/rack/payload.d.ts +0 -1
  41. package/dist/hardware/rack/payload.d.ts.map +1 -1
  42. package/dist/hardware/task/client.d.ts +12 -3
  43. package/dist/hardware/task/client.d.ts.map +1 -1
  44. package/dist/hardware/task/ni/types.d.ts +14495 -0
  45. package/dist/hardware/task/ni/types.d.ts.map +1 -0
  46. package/dist/hardware/task/payload.d.ts +6 -1
  47. package/dist/hardware/task/payload.d.ts.map +1 -1
  48. package/dist/label/client.d.ts +8 -6
  49. package/dist/label/client.d.ts.map +1 -1
  50. package/dist/label/payload.d.ts +0 -1
  51. package/dist/label/retriever.d.ts +0 -1
  52. package/dist/label/retriever.d.ts.map +1 -1
  53. package/dist/label/writer.d.ts +32 -2
  54. package/dist/label/writer.d.ts.map +1 -1
  55. package/dist/ontology/client.d.ts +136 -12
  56. package/dist/ontology/client.d.ts.map +1 -1
  57. package/dist/ontology/group/client.d.ts +0 -1
  58. package/dist/ontology/group/group.d.ts +0 -1
  59. package/dist/ontology/group/payload.d.ts +0 -1
  60. package/dist/ontology/group/writer.d.ts +0 -1
  61. package/dist/ontology/group/writer.d.ts.map +1 -1
  62. package/dist/ontology/payload.d.ts +6 -3
  63. package/dist/ontology/payload.d.ts.map +1 -1
  64. package/dist/ontology/writer.d.ts +4 -5
  65. package/dist/ontology/writer.d.ts.map +1 -1
  66. package/dist/ranger/alias.d.ts +0 -1
  67. package/dist/ranger/client.d.ts +57 -14
  68. package/dist/ranger/client.d.ts.map +1 -1
  69. package/dist/ranger/external.d.ts +1 -1
  70. package/dist/ranger/external.d.ts.map +1 -1
  71. package/dist/ranger/kv.d.ts +42 -5
  72. package/dist/ranger/kv.d.ts.map +1 -1
  73. package/dist/ranger/payload.d.ts +5 -2
  74. package/dist/ranger/payload.d.ts.map +1 -1
  75. package/dist/ranger/writer.d.ts +107 -2
  76. package/dist/ranger/writer.d.ts.map +1 -1
  77. package/dist/setupspecs.d.ts +0 -1
  78. package/dist/signals/observable.d.ts +0 -1
  79. package/dist/transport.d.ts +0 -1
  80. package/dist/user/client.d.ts +0 -1
  81. package/dist/user/payload.d.ts +0 -1
  82. package/dist/util/retrieve.d.ts +0 -1
  83. package/dist/util/telem.d.ts +0 -1
  84. package/dist/util/zod.d.ts +0 -1
  85. package/dist/workspace/client.d.ts +0 -1
  86. package/dist/workspace/lineplot/client.d.ts +0 -1
  87. package/dist/workspace/lineplot/payload.d.ts +0 -1
  88. package/dist/workspace/lineplot/retriever.d.ts +0 -1
  89. package/dist/workspace/lineplot/writer.d.ts +0 -1
  90. package/dist/workspace/payload.d.ts +0 -1
  91. package/dist/workspace/retriever.d.ts +0 -1
  92. package/dist/workspace/schematic/client.d.ts +0 -1
  93. package/dist/workspace/schematic/payload.d.ts +0 -1
  94. package/dist/workspace/schematic/retriever.d.ts +0 -1
  95. package/dist/workspace/schematic/writer.d.ts +0 -1
  96. package/dist/workspace/writer.d.ts +0 -1
  97. package/package.json +14 -12
  98. package/src/access/access.spec.ts +11 -11
  99. package/src/channel/batchRetriever.spec.ts +2 -0
  100. package/src/channel/channel.spec.ts +51 -31
  101. package/src/channel/client.ts +7 -0
  102. package/src/channel/payload.ts +1 -0
  103. package/src/client.ts +17 -8
  104. package/src/connection/checker.ts +58 -1
  105. package/src/connection/connection.spec.ts +43 -3
  106. package/src/control/client.ts +9 -0
  107. package/src/errors.spec.ts +9 -0
  108. package/src/framer/client.ts +0 -1
  109. package/src/framer/frame.spec.ts +2 -2
  110. package/src/framer/frame.ts +22 -22
  111. package/src/framer/writer.ts +2 -1
  112. package/src/hardware/device/payload.ts +9 -0
  113. package/src/hardware/rack/payload.ts +9 -0
  114. package/src/hardware/task/client.ts +82 -6
  115. package/src/hardware/task/ni/types.ts +1716 -0
  116. package/src/hardware/task/payload.ts +10 -0
  117. package/src/hardware/task/task.spec.ts +45 -30
  118. package/src/label/client.ts +49 -19
  119. package/src/label/label.spec.ts +9 -0
  120. package/src/label/retriever.ts +2 -1
  121. package/src/label/writer.ts +11 -3
  122. package/src/ontology/client.ts +227 -14
  123. package/src/ontology/group/writer.ts +10 -12
  124. package/src/ontology/ontology.spec.ts +3 -5
  125. package/src/ontology/payload.ts +5 -1
  126. package/src/ontology/writer.ts +26 -12
  127. package/src/ranger/client.ts +223 -41
  128. package/src/ranger/external.ts +1 -1
  129. package/src/ranger/kv.ts +50 -11
  130. package/src/ranger/payload.ts +9 -5
  131. package/src/ranger/ranger.spec.ts +114 -49
  132. package/src/ranger/writer.ts +7 -2
  133. package/src/vite-env.d.ts +1 -1
  134. package/vite.config.ts +6 -1
  135. package/dist/ranger/active.d.ts +0 -11
  136. package/dist/ranger/active.d.ts.map +0 -1
  137. package/dist/ranger/range.d.ts +0 -32
  138. package/dist/ranger/range.d.ts.map +0 -1
  139. package/src/ranger/active.ts +0 -74
  140. package/src/ranger/range.ts +0 -98
@@ -39,17 +39,17 @@ const columnType = (columns: Params): ColumnType => {
39
39
  return "name";
40
40
  };
41
41
 
42
- const validateMatchedColsAndArrays = (columns: Params, arrays: Series[]): void => {
42
+ const validateMatchedColsAndSeries = (columns: Params, series: Series[]): void => {
43
43
  const colsArr = toArray(columns);
44
- if (colsArr.length === arrays.length) return;
44
+ if (colsArr.length === series.length) return;
45
45
  const colType = columnType(columns);
46
46
  if (columnType === null)
47
47
  throw new ValidationError(
48
48
  "[Frame] - channel keys or names must be provided when constructing a frame.",
49
49
  );
50
50
  throw new ValidationError(
51
- `[Frame] - ${colType as string}s and arrays must be the same length.
52
- Got ${colsArr.length} ${colType as string}s and ${arrays.length} arrays.`,
51
+ `[Frame] - ${colType as string}s and series must be the same length.
52
+ Got ${colsArr.length} ${colType as string}s and ${series.length} series.`,
53
53
  );
54
54
  };
55
55
 
@@ -65,15 +65,15 @@ export type CrudeFrame =
65
65
  *
66
66
  * Frames have two important characteristics: alignment and orientation.
67
67
  *
68
- * A frame's alignment defines how correlated the arrays for different channels in the
68
+ * A frame's alignment defines how correlated the series for different channels in the
69
69
  * frame are:
70
70
  *
71
- * - A frame is weakly aligned if it meets the time range occupied by all arrays of a
71
+ * - A frame is weakly aligned if the time range occupied by all series of a
72
72
  * particular channel is the same for all channels in the frame. This means that the
73
- * arrays for a particular channel can have gaps between them.
73
+ * series for a particular channel can have gaps between them.
74
74
  *
75
75
  * - A strongly aligned frame means that all channels share the same rate/index and
76
- * there are no gaps in time between arrays. Strongly aligned frames are natural
76
+ * there are no gaps in time between series. Strongly aligned frames are natural
77
77
  * to interpret, as the values in a particular 'row' of the frame share the same
78
78
  * timestamp. All frames written to Synnax must be strongly aligned.
79
79
  *
@@ -85,7 +85,7 @@ export type CrudeFrame =
85
85
  *
86
86
  * - Horizontal frames have a single channel, and are strongly aligned by default.
87
87
  * A horizontal frame typically has a single array (in which case, it's also 'square'),
88
- * although it can have multiple arrays if all the arrays are continuous in time.
88
+ * although it can have multiple series if all the series are continuous in time.
89
89
  *
90
90
  * - Vertical frames are strongly aligned and have on or more channels, but ONLY a single
91
91
  * array per channel. Synnax requires that all frames written to the database are
@@ -98,7 +98,7 @@ export class Frame {
98
98
  readonly columns: Keys | Names = [];
99
99
  readonly series: Series[] = [];
100
100
 
101
- constructor(columnsOrData: Params | CrudeFrame = [], arrays: Series | Series[] = []) {
101
+ constructor(columnsOrData: Params | CrudeFrame = [], series: Series | Series[] = []) {
102
102
  if (columnsOrData instanceof Frame) {
103
103
  this.columns = columnsOrData.columns;
104
104
  this.series = columnsOrData.series;
@@ -117,9 +117,9 @@ export class Frame {
117
117
  if (isObject) {
118
118
  if ("keys" in columnsOrData && "series" in columnsOrData) {
119
119
  const data_ = columnsOrData as FramePayload;
120
- const arrays = data_.series.map((a) => seriesFromPayload(a));
121
- validateMatchedColsAndArrays(data_.keys, arrays);
122
- data_.keys.forEach((key, i) => this.push(key, arrays[i]));
120
+ const series = data_.series.map((a) => seriesFromPayload(a));
121
+ validateMatchedColsAndSeries(data_.keys, series);
122
+ data_.keys.forEach((key, i) => this.push(key, series[i]));
123
123
  } else
124
124
  Object.entries(columnsOrData).forEach(([k, v]) => {
125
125
  const key = parseInt(k);
@@ -129,21 +129,21 @@ export class Frame {
129
129
  return;
130
130
  }
131
131
 
132
- // Construction from a set of arrays and columns.
132
+ // Construction from a set of series and columns.
133
133
  if (
134
134
  Array.isArray(columnsOrData) ||
135
135
  ["string", "number"].includes(typeof columnsOrData)
136
136
  ) {
137
- const data_ = toArray(arrays);
137
+ const data_ = toArray(series);
138
138
  const cols = toArray(columnsOrData) as Keys | Names;
139
- validateMatchedColsAndArrays(cols, data_);
139
+ validateMatchedColsAndSeries(cols, data_);
140
140
  data_.forEach((d, i) => this.push(cols[i], d));
141
141
  return;
142
142
  }
143
143
 
144
144
  throw new ValidationError(
145
145
  `[Frame] - invalid frame construction parameters. data parameter ust be a frame
146
- payload, a list of lazy arrays, a lazy array, a map, or a record keyed by channel
146
+ payload, a list of lazy series, a lazy array, a map, or a record keyed by channel
147
147
  name. keys parameter must be a set of channel keys or channel names.`,
148
148
  );
149
149
  }
@@ -218,8 +218,8 @@ export class Frame {
218
218
  /**
219
219
  * @returns true if the frame is horizontal. Horizontal frames have a single channel,
220
220
  * and are strongly aligned by default.A horizontal frame typically has a single array
221
- * (in which case, it's also 'square'), although it can have multiple arrays if all
222
- * the arrays are continuous in time.
221
+ * (in which case, it's also 'square'), although it can have multiple series if all
222
+ * the series are continuous in time.
223
223
  */
224
224
  get isHorizontal(): boolean {
225
225
  return this.uniqueColumns.length === 1;
@@ -235,8 +235,8 @@ export class Frame {
235
235
 
236
236
  /**
237
237
  * @returns true if the frame is weakly aligned. A frame is weakly aligned if it meets
238
- * the time range occupied by all arrays of a particular channel is the same for all
239
- * channels in the frame. This means that the arrays for a particular channel can have
238
+ * the time range occupied by all series of a particular channel is the same for all
239
+ * channels in the frame. This means that the series for a particular channel can have
240
240
  * gaps between them.
241
241
  */
242
242
  get isWeaklyAligned(): boolean {
@@ -266,7 +266,7 @@ export class Frame {
266
266
  }
267
267
 
268
268
  /**
269
- * @returns lazy arrays matching the given channel key or name.
269
+ * @returns lazy series matching the given channel key or name.
270
270
  * @param key the channel key or name.
271
271
  */
272
272
  get(key: KeyOrName): MultiSeries;
@@ -54,7 +54,8 @@ const constructWriterMode = (mode: CrudeWriterMode): WriterMode => {
54
54
  case "persistStream":
55
55
  return WriterMode.PersistStream;
56
56
  default:
57
- return mode;
57
+ if (typeof mode === "number" && mode in WriterMode) return mode;
58
+ throw new Error(`invalid writer mode: ${mode}`);
58
59
  }
59
60
  };
60
61
 
@@ -1,3 +1,12 @@
1
+ // Copyright 2024 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
+
1
10
  import { binary, UnknownRecord } from "@synnaxlabs/x";
2
11
  import { z } from "zod";
3
12
 
@@ -1,3 +1,12 @@
1
+ // Copyright 2024 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
+
1
10
  import { z } from "zod";
2
11
 
3
12
  import { ontology } from "@/ontology";
@@ -18,7 +18,19 @@ import { z } from "zod";
18
18
  import { framer } from "@/framer";
19
19
  import { type Frame } from "@/framer/frame";
20
20
  import { rack } from "@/hardware/rack";
21
- import { NewTask, newTaskZ, Payload, State, StateObservable, stateZ, TaskKey, taskKeyZ, taskZ } from "@/hardware/task/payload";
21
+ import {
22
+ NewTask,
23
+ newTaskZ,
24
+ Payload,
25
+ State,
26
+ StateObservable,
27
+ stateZ,
28
+ TaskKey,
29
+ taskKeyZ,
30
+ taskZ,
31
+ } from "@/hardware/task/payload";
32
+ import { ontology } from "@/ontology";
33
+ import { ranger } from "@/ranger";
22
34
  import { signals } from "@/signals";
23
35
  import { analyzeParams, checkForMultipleOrNoResults } from "@/util/retrieve";
24
36
  import { nullableArrayZ } from "@/util/zod";
@@ -26,6 +38,8 @@ import { nullableArrayZ } from "@/util/zod";
26
38
  const TASK_STATE_CHANNEL = "sy_task_state";
27
39
  const TASK_CMD_CHANNEL = "sy_task_cmd";
28
40
 
41
+ const TASK_NOT_CREATED = new Error("Task not created");
42
+
29
43
  export class Task<
30
44
  C extends UnknownRecord = UnknownRecord,
31
45
  D extends {} = UnknownRecord,
@@ -36,25 +50,34 @@ export class Task<
36
50
  readonly internal: boolean;
37
51
  readonly type: T;
38
52
  readonly config: C;
53
+ readonly snapshot: boolean;
39
54
  state?: State<D>;
40
- private readonly frameClient: framer.Client;
55
+ private readonly frameClient: framer.Client | null;
56
+ private readonly ontologyClient: ontology.Client | null;
57
+ private readonly rangeClient: ranger.Client | null;
41
58
 
42
59
  constructor(
43
60
  key: TaskKey,
44
61
  name: string,
45
62
  type: T,
46
63
  config: C,
47
- frameClient: framer.Client,
48
64
  internal: boolean = false,
65
+ snapshot: boolean = false,
49
66
  state?: State<D> | null,
67
+ frameClient: framer.Client | null = null,
68
+ ontologyClient: ontology.Client | null = null,
69
+ rangeClient: ranger.Client | null = null,
50
70
  ) {
51
71
  this.key = key;
52
72
  this.name = name;
53
73
  this.type = type;
54
74
  this.config = config;
55
75
  this.internal = internal;
76
+ this.snapshot = snapshot;
56
77
  if (state !== null) this.state = state;
57
78
  this.frameClient = frameClient;
79
+ this.ontologyClient = ontologyClient;
80
+ this.rangeClient = rangeClient;
58
81
  }
59
82
 
60
83
  get payload(): Payload<C, D> {
@@ -68,7 +91,12 @@ export class Task<
68
91
  };
69
92
  }
70
93
 
94
+ get ontologyID(): ontology.ID {
95
+ return new ontology.ID({ type: "task", key: this.key });
96
+ }
97
+
71
98
  async executeCommand(type: string, args?: UnknownRecord): Promise<string> {
99
+ if (this.frameClient == null) throw TASK_NOT_CREATED;
72
100
  const writer = await this.frameClient.openWriter(TASK_CMD_CHANNEL);
73
101
  const key = id.id();
74
102
  await writer.write(TASK_CMD_CHANNEL, [{ task: this.key, type, key, args }]);
@@ -81,6 +109,7 @@ export class Task<
81
109
  args: UnknownRecord,
82
110
  timeout: CrudeTimeSpan,
83
111
  ): Promise<State<D>> {
112
+ if (this.frameClient == null) throw TASK_NOT_CREATED;
84
113
  const streamer = await this.frameClient.openStreamer(TASK_STATE_CHANNEL);
85
114
  const cmdKey = await this.executeCommand(type, args);
86
115
  let res: State<D>;
@@ -105,6 +134,7 @@ export class Task<
105
134
  async openStateObserver<D extends UnknownRecord = UnknownRecord>(): Promise<
106
135
  StateObservable<D>
107
136
  > {
137
+ if (this.frameClient == null) throw TASK_NOT_CREATED;
108
138
  return new framer.ObservableStreamer<State<D>>(
109
139
  await this.frameClient.openStreamer(TASK_STATE_CHANNEL),
110
140
  (frame) => {
@@ -118,6 +148,14 @@ export class Task<
118
148
  },
119
149
  );
120
150
  }
151
+
152
+ async snapshottedTo(): Promise<ontology.Resource | null> {
153
+ if (this.ontologyClient == null || this.rangeClient == null) throw TASK_NOT_CREATED;
154
+ if (!this.snapshot) return null;
155
+ const parents = await this.ontologyClient.retrieveParents(this.ontologyID);
156
+ if (parents.length == 0) return null;
157
+ return parents[0];
158
+ }
121
159
  }
122
160
 
123
161
  const retrieveReqZ = z.object({
@@ -143,20 +181,36 @@ export type RetrieveOptions = Pick<
143
181
  const RETRIEVE_ENDPOINT = "/hardware/task/retrieve";
144
182
  const CREATE_ENDPOINT = "/hardware/task/create";
145
183
  const DELETE_ENDPOINT = "/hardware/task/delete";
184
+ const COPY_ENDPOINT = "/hardware/task/copy";
146
185
 
147
186
  const createReqZ = z.object({ tasks: newTaskZ.array() });
148
187
  const createResZ = z.object({ tasks: taskZ.array() });
149
188
  const deleteReqZ = z.object({ keys: taskKeyZ.array() });
150
189
  const deleteResZ = z.object({});
190
+ const copyReqZ = z.object({
191
+ key: taskKeyZ,
192
+ name: z.string(),
193
+ snapshot: z.boolean(),
194
+ });
195
+ const copyResZ = z.object({ task: taskZ });
151
196
 
152
197
  export class Client implements AsyncTermSearcher<string, TaskKey, Payload> {
153
198
  readonly type: string = "task";
154
199
  private readonly client: UnaryClient;
155
200
  private readonly frameClient: framer.Client;
201
+ private readonly ontologyClient: ontology.Client;
202
+ private readonly rangeClient: ranger.Client;
156
203
 
157
- constructor(client: UnaryClient, frameClient: framer.Client) {
204
+ constructor(
205
+ client: UnaryClient,
206
+ frameClient: framer.Client,
207
+ ontologyClient: ontology.Client,
208
+ rangeClient: ranger.Client,
209
+ ) {
158
210
  this.client = client;
159
211
  this.frameClient = frameClient;
212
+ this.ontologyClient = ontologyClient;
213
+ this.rangeClient = rangeClient;
160
214
  }
161
215
 
162
216
  async create<
@@ -251,6 +305,17 @@ export class Client implements AsyncTermSearcher<string, TaskKey, Payload> {
251
305
  return single && variant !== "rack" ? sugared[0] : sugared;
252
306
  }
253
307
 
308
+ async copy(key: string, name: string, snapshot: boolean): Promise<Task> {
309
+ const res = await sendRequired(
310
+ this.client,
311
+ COPY_ENDPOINT,
312
+ { key, name, snapshot },
313
+ copyReqZ,
314
+ copyResZ,
315
+ );
316
+ return this.sugar([res.task])[0];
317
+ }
318
+
254
319
  async retrieveByName(name: string, rack?: number): Promise<Task> {
255
320
  const tasks = await this.execRetrieve({ names: [name], rack });
256
321
  checkForMultipleOrNoResults("Task", name, tasks, true);
@@ -270,8 +335,19 @@ export class Client implements AsyncTermSearcher<string, TaskKey, Payload> {
270
335
 
271
336
  private sugar(payloads: Payload[]): Task[] {
272
337
  return payloads.map(
273
- ({ key, name, type, config, state, internal }) =>
274
- new Task(key, name, type, config, this.frameClient, internal, state),
338
+ ({ key, name, type, config, state, internal, snapshot }) =>
339
+ new Task(
340
+ key,
341
+ name,
342
+ type,
343
+ config,
344
+ internal,
345
+ snapshot,
346
+ state,
347
+ this.frameClient,
348
+ this.ontologyClient,
349
+ this.rangeClient,
350
+ ),
275
351
  );
276
352
  }
277
353