@synnaxlabs/client 0.26.0 → 0.26.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.
@@ -11,6 +11,6 @@
11
11
  "author": "",
12
12
  "license": "ISC",
13
13
  "dependencies": {
14
- "@synnaxlabs/client": "^0.23.0"
14
+ "@synnaxlabs/client": "^0.26.1"
15
15
  }
16
16
  }
@@ -21,13 +21,13 @@ series = new Series({ data: [1, 2, 3, 4, 5], dataType: "float32" });
21
21
  // automatically be of type string.
22
22
  series = new Series(["apple", "banana", "cherry"]);
23
23
 
24
- // Construct a series from a Float32Array. This is the most efficient way to
25
- // construct a series from a large amount of data.
24
+ // Construct a series from a Float32Array. This is the most efficient way to construct a
25
+ // series from a large amount of data.
26
26
  series = new Series(new Float32Array([1, 2, 3, 4, 5]));
27
27
 
28
- // Construct a series from a JSON object. This is useful when you have a series
29
- // that has been serialized to JSON.
30
- series = new Series([{ red: "cherry" }, { yellow: "banana" }, {orange: "orange" }]);
28
+ // Construct a series from a JSON object. This is useful when you have a series that has
29
+ // been serialized to JSON.
30
+ series = new Series([{ red: "cherry" }, { yellow: "banana" }, { orange: "orange" }]);
31
31
 
32
32
  series = new Series([1, "a", 3, "b", 5]);
33
33
 
@@ -60,16 +60,16 @@ series = new Series([{ red: "cherry", yellow: "banana", orange: "orange" }]);
60
60
  jsArray = [...series];
61
61
  console.log(jsArray); // [ { red: 'cherry', yellow: 'banana', orange: 'orange' } ]
62
62
 
63
- import { TimeRange, TimeStamp, TimeSpan } from "@synnaxlabs/client";
63
+ import { TimeRange, TimeSpan, TimeStamp } from "@synnaxlabs/client";
64
64
 
65
65
  const start = TimeStamp.now();
66
66
 
67
67
  const tr = new TimeRange(start, start.add(TimeSpan.seconds(5)));
68
68
 
69
69
  series = new Series({
70
- data: [1, 2, 3, 4, 5],
71
- dataType: "float64",
72
- timeRange: new TimeRange(start, start.add(TimeSpan.seconds(6)))
70
+ data: [1, 2, 3, 4, 5],
71
+ dataType: "float64",
72
+ timeRange: tr,
73
73
  });
74
74
 
75
75
  series = new Series([1, 2, 3, 4, 5]);
@@ -93,51 +93,52 @@ import { Frame } from "@synnaxlabs/client";
93
93
 
94
94
  // Construct a frame for the given channel names.
95
95
  let frame = new Frame({
96
- "channel1": new Series([1, 2, 3, 4, 5]),
97
- "channel2": new Series([5, 4, 3, 2, 1]),
98
- "channel3": new Series([1, 1, 1, 1, 1]),
96
+ channel1: new Series([1, 2, 3, 4, 5]),
97
+ channel2: new Series([5, 4, 3, 2, 1]),
98
+ channel3: new Series([1, 1, 1, 1, 1]),
99
99
  });
100
100
 
101
101
  // Construct a frame for the given channel keys
102
102
  frame = new Frame({
103
- 1: new Series([1, 2, 3, 4, 5]),
104
- 2: new Series([5, 4, 3, 2, 1]),
105
- // Notice that series do not need to be the same length.
106
- 3: new Series([1, 1, 1]),
103
+ 1: new Series([1, 2, 3, 4, 5]),
104
+ 2: new Series([5, 4, 3, 2, 1]),
105
+ // Notice that series do not need to be the same length.
106
+ 3: new Series([1, 1, 1]),
107
107
  });
108
108
 
109
109
  // Construct a frame from a map
110
- frame = new Frame(new Map([
111
- ["channel1", new Series([1, 2, 3, 4, 5])],
112
- ["channel2", new Series([5, 4, 3, 2, 1])],
113
- ["channel3", new Series([1, 1, 1, 1, 1])],
114
- ]));
110
+ frame = new Frame(
111
+ new Map([
112
+ ["channel1", new Series([1, 2, 3, 4, 5])],
113
+ ["channel2", new Series([5, 4, 3, 2, 1])],
114
+ ["channel3", new Series([1, 1, 1, 1, 1])],
115
+ ]),
116
+ );
115
117
 
116
118
  // Or from an array of keys and series
117
- frame = new Frame(["channel1", "channel2", "channel3"], [
118
- new Series([1, 2, 3, 4, 5]),
119
- new Series([5, 4, 3, 2, 1]),
120
- new Series([1, 1, 1, 1, 1]),
121
- ]);
119
+ frame = new Frame(
120
+ ["channel1", "channel2", "channel3"],
121
+ [
122
+ new Series([1, 2, 3, 4, 5]),
123
+ new Series([5, 4, 3, 2, 1]),
124
+ new Series([1, 1, 1, 1, 1]),
125
+ ],
126
+ );
122
127
 
123
128
  // Or construct a frame with multiple series for a single channel
124
129
  frame = new Frame({
125
- "channel1": [
126
- new Series([1, 2, 3, 4, 5]),
127
- new Series([5, 4, 3, 2, 1]),
128
- new Series([1, 1, 1, 1, 1]),
129
- ],
130
- "channel2": [
131
- new Series([1, 2, 3, 4, 5]),
132
- ],
130
+ channel1: [
131
+ new Series([1, 2, 3, 4, 5]),
132
+ new Series([5, 4, 3, 2, 1]),
133
+ new Series([1, 1, 1, 1, 1]),
134
+ ],
135
+ channel2: [new Series([1, 2, 3, 4, 5])],
133
136
  });
134
137
 
135
- import { MultiSeries } from "@synnaxlabs/client";
136
-
137
138
  frame = new Frame({
138
- "channel1": [new Series([1, 2]), new Series([3, 4, 5])],
139
- "channel2": new Series([5, 4, 3, 2, 1]),
140
- "channel3": new Series([1, 1, 1, 1, 1]),
139
+ channel1: [new Series([1, 2]), new Series([3, 4, 5])],
140
+ channel2: new Series([5, 4, 3, 2, 1]),
141
+ channel3: new Series([1, 1, 1, 1, 1]),
141
142
  });
142
143
 
143
144
  const multiSeries = frame.get("channel1");
@@ -152,21 +153,21 @@ jsArray = [...multiSeries];
152
153
  console.log(jsArray); // [ 1, 2, 3, 4, 5 ]
153
154
 
154
155
  frame = new Frame({
155
- "channel1": new Series([1, 2, 3, 4, 5]),
156
- "channel2": new Series([5, 4, 3, 2, 1]),
157
- "channel3": new Series([1, 1]),
156
+ channel1: new Series([1, 2, 3, 4, 5]),
157
+ channel2: new Series([5, 4, 3, 2, 1]),
158
+ channel3: new Series([1, 1]),
158
159
  });
159
160
 
160
161
  let obj = frame.at(3);
161
162
  console.log(obj); // { channel1: 1, channel2: 5, channel3: undefined }
162
163
 
163
164
  frame = new Frame({
164
- "channel1": new Series([1, 2, 3, 4, 5]),
165
- "channel2": new Series([5, 4, 3, 2, 1]),
166
- "channel3": new Series([1, 1]),
165
+ channel1: new Series([1, 2, 3, 4, 5]),
166
+ channel2: new Series([5, 4, 3, 2, 1]),
167
+ channel3: new Series([1, 1]),
167
168
  });
168
169
  try {
169
- obj = frame.at(3, true); // Throws an error
170
+ obj = frame.at(3, true); // Throws an error
170
171
  } catch (e) {
171
- console.log(e.message); // no value at index
172
+ console.log(e.message); // no value at index
172
173
  }
@@ -12,7 +12,7 @@
12
12
  // applications (such as data acquisition from a sensor) or for very large datasets that
13
13
  // cannot be written all at once.
14
14
 
15
- import { Rate, Series, Synnax, TimeStamp, framer } from "@synnaxlabs/client";
15
+ import { Rate, Synnax, TimeStamp } from "@synnaxlabs/client";
16
16
 
17
17
  // Connect to a locally running, insecure Synnax cluster. If your connection parameters
18
18
  // are different, enter them here.
@@ -24,51 +24,58 @@ const client = new Synnax({
24
24
  });
25
25
 
26
26
  // Create an index channel that will be used to store our timestamps.
27
- const timeChannel = await client.channels.create({
28
- name: "stream_write_example_time",
29
- isIndex: true,
30
- dataType: "timestamp"
31
- }, { retrieveIfNameExists: true });
27
+ const timeChannel = await client.channels.create(
28
+ {
29
+ name: "stream_write_example_time",
30
+ isIndex: true,
31
+ dataType: "timestamp",
32
+ },
33
+ { retrieveIfNameExists: true },
34
+ );
32
35
 
33
36
  // Create a data channel that will be used to store our fake sensor data.
34
- const dataChannel1 = await client.channels.create({
35
- name: "stream_write_example_data_1",
36
- dataType: "float32",
37
- index: timeChannel.key,
38
- }, { retrieveIfNameExists: true });
39
-
40
- const dataChannel2 = await client.channels.create({
41
- name: "stream_write_example_data_2",
42
- dataType: "int32",
43
- index: timeChannel.key,
44
- }, { retrieveIfNameExists: true });
37
+ const dataChannel1 = await client.channels.create(
38
+ {
39
+ name: "stream_write_example_data_1",
40
+ dataType: "float32",
41
+ index: timeChannel.key,
42
+ },
43
+ { retrieveIfNameExists: true },
44
+ );
45
45
 
46
+ const dataChannel2 = await client.channels.create(
47
+ {
48
+ name: "stream_write_example_data_2",
49
+ dataType: "int32",
50
+ index: timeChannel.key,
51
+ },
52
+ { retrieveIfNameExists: true },
53
+ );
46
54
 
47
55
  // We'll start our write at the current time. This timestamps should be the same as or
48
56
  // just before the first timestamp we write.
49
57
  const start = TimeStamp.now();
50
58
 
51
- // Set a rough rate of 20 Hz. This won't be exact because we're sleeping for a fixed
59
+ // Set a rough rate of 25 Hz. This won't be exact because we're sleeping for a fixed
52
60
  // amount of time, but it's close enough for demonstration purposes.
53
61
  const roughRate = Rate.hz(25);
54
62
 
55
- // Make the writer commit every 500 samples. This will make the data available for
56
- // historical reads every 500 samples.
57
- const commitInterval = 500;
58
-
59
63
  const writer = await client.openWriter({
60
64
  start,
61
65
  channels: [timeChannel.key, dataChannel1.key, dataChannel2.key],
66
+ enableAutoCommit: true,
62
67
  });
63
68
 
64
69
  try {
65
70
  let i = 0;
66
71
  while (true) {
67
- await new Promise(resolve => setTimeout(resolve, roughRate.period.milliseconds));
72
+ await new Promise((resolve) =>
73
+ setTimeout(resolve, roughRate.period.milliseconds),
74
+ );
68
75
  i++;
69
76
  const timestamp = TimeStamp.now();
70
- const data2= i % 2;
71
77
  const data1 = Math.sin(i / 10);
78
+ const data2 = i % 2;
72
79
  await writer.write({
73
80
  [timeChannel.key]: timestamp,
74
81
  [dataChannel1.key]: data1,
@@ -76,16 +83,10 @@ try {
76
83
  });
77
84
 
78
85
  if (i % 60 == 0)
79
- console.log(`Writing sample ${i} at ${timestamp.toISOString()}`)
80
-
81
- // Commit the writer. This method will return false if the commit fails i.e.
82
- // we've mad an invalid write or someone has already written to this region.
83
- if (i % commitInterval == 0 && !await writer.commit()) {
84
- console.error("Failed to commit data");
85
- break;
86
- }
86
+ console.log(`Writing sample ${i} at ${timestamp.toISOString()}`);
87
87
  }
88
88
  } finally {
89
+ // Close the writer and the client when you are done
89
90
  await writer.close();
91
+ client.close();
90
92
  }
91
-
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@synnaxlabs/client",
3
3
  "private": false,
4
- "version": "0.26.0",
4
+ "version": "0.26.1",
5
5
  "type": "module",
6
6
  "description": "The Client Library for Synnax",
7
7
  "repository": "https://github.com/synnaxlabs/synnax/tree/main/client/ts",
@@ -28,9 +28,9 @@
28
28
  "typescript": "^5.5.3",
29
29
  "vite": "5.3.3",
30
30
  "vitest": "^1.6.0",
31
- "@synnaxlabs/tsconfig": "0.0.2",
31
+ "@synnaxlabs/vite-plugin": "0.0.1",
32
32
  "eslint-config-synnaxlabs": "0.0.1",
33
- "@synnaxlabs/vite-plugin": "0.0.1"
33
+ "@synnaxlabs/tsconfig": "0.0.2"
34
34
  },
35
35
  "peerDependencies": {
36
36
  "zod": "^3.23.8"
@@ -156,4 +156,13 @@ describe("WriteFrameAdapter", () => {
156
156
  expect(res.get(jsonChannel.key)).toHaveLength(1);
157
157
  expect(res.get(jsonChannel.key).at(0)).toEqual({ dog: "blue" });
158
158
  });
159
+
160
+ it("should correctly adapt generic object keys", async () => {
161
+ const res = await adapter.adaptObjectKeys({
162
+ [timeCh.name]: 532,
163
+ [dataCh.name]: 123,
164
+ });
165
+ expect(res).toHaveProperty(timeCh.key.toString());
166
+ expect(res).toHaveProperty(dataCh.key.toString());
167
+ });
159
168
  });
@@ -93,6 +93,12 @@ export class WriteFrameAdapter {
93
93
  return adapter;
94
94
  }
95
95
 
96
+ async adaptObjectKeys<V>(data: Record<KeyOrName, V>): Promise<Record<Key, V>> {
97
+ const out: Record<Key, V> = {};
98
+ for (const [k, v] of Object.entries(data)) out[await this.adaptToKey(k)] = v;
99
+ return out;
100
+ }
101
+
96
102
  async update(channels: Params): Promise<void> {
97
103
  const results = await retrieveRequired(this.retriever, channels);
98
104
  this.adapter = new Map<Name, Key>(results.map((c) => [c.name, c.key]));
@@ -105,6 +111,12 @@ export class WriteFrameAdapter {
105
111
  return res[0];
106
112
  }
107
113
 
114
+ private async adaptToKey(k: KeyOrName): Promise<Key> {
115
+ if (typeof k === "number") return k;
116
+ const res = await this.fetchChannel(k);
117
+ return res.key;
118
+ }
119
+
108
120
  async adapt(
109
121
  columnsOrData: Params | Record<KeyOrName, CrudeSeries> | CrudeFrame,
110
122
  series?: CrudeSeries | CrudeSeries[],
@@ -134,7 +134,7 @@ export class Client {
134
134
  const w = await this.openWriter({
135
135
  start,
136
136
  channels: Object.keys(data_),
137
- mode: WriterMode.PersistOnly,
137
+ mode: WriterMode.Persist,
138
138
  });
139
139
  try {
140
140
  await w.write(data_);
@@ -147,7 +147,7 @@ export class Client {
147
147
  const w = await this.openWriter({
148
148
  start,
149
149
  channels: channels as Params,
150
- mode: WriterMode.PersistOnly,
150
+ mode: WriterMode.Persist,
151
151
  errOnUnauthorized: true,
152
152
  enableAutoCommit: true,
153
153
  autoIndexPersistInterval: TimeSpan.MAX,
@@ -7,6 +7,7 @@
7
7
  // License, use of this software will be governed by the Apache License, Version 2.0,
8
8
  // included in the file licenses/APL.txt.
9
9
 
10
+ import { id } from "@synnaxlabs/x";
10
11
  import { DataType, Rate, TimeRange, TimeSpan, TimeStamp } from "@synnaxlabs/x/telem";
11
12
  import { describe, expect, test } from "vitest";
12
13
 
@@ -20,8 +21,8 @@ const client = newClient();
20
21
 
21
22
  const newChannel = async (): Promise<channel.Channel> =>
22
23
  await client.channels.create({
23
- name: "test",
24
24
  leaseholder: 1,
25
+ name: `test-${id.id()}`,
25
26
  rate: Rate.hz(1),
26
27
  dataType: DataType.FLOAT64,
27
28
  });
@@ -53,7 +54,7 @@ describe("Writer", () => {
53
54
  const writer = await client.openWriter({
54
55
  start: 0,
55
56
  channels: ch.key,
56
- mode: WriterMode.PersistOnly,
57
+ mode: WriterMode.Persist,
57
58
  });
58
59
  try {
59
60
  await writer.write(ch.key, randomSeries(10, ch.dataType));
@@ -137,27 +138,111 @@ describe("Writer", () => {
137
138
  channels: ch.key,
138
139
  authorities: 10,
139
140
  enableAutoCommit: true,
140
- })
141
+ });
141
142
  const w2 = await client.openWriter({
142
143
  start: 0,
143
144
  channels: ch.key,
144
145
  authorities: 20,
145
146
  enableAutoCommit: true,
146
- })
147
+ });
147
148
 
148
- await w1.write(ch.key, randomSeries(10, ch.dataType))
149
- let f = await ch.read(TimeRange.MAX)
150
- expect(f.length).toEqual(0)
149
+ await w1.write(ch.key, randomSeries(10, ch.dataType));
150
+ let f = await ch.read(TimeRange.MAX);
151
+ expect(f.length).toEqual(0);
151
152
 
152
- await w1.setAuthority({[ch.key]: 100});
153
- await w1.write(ch.key, randomSeries(10, ch.dataType))
153
+ await w1.setAuthority({ [ch.key]: 100 });
154
+ await w1.write(ch.key, randomSeries(10, ch.dataType));
154
155
 
155
- f = await ch.read(TimeRange.MAX)
156
- expect(f.length).toEqual(10)
156
+ f = await ch.read(TimeRange.MAX);
157
+ expect(f.length).toEqual(10);
157
158
 
158
- await w1.close()
159
- await w2.close()
160
- })
159
+ await w1.close();
160
+ await w2.close();
161
+ });
162
+ test("setAuthority with name keys", async () => {
163
+ const ch = await newChannel();
164
+ const w1 = await client.openWriter({
165
+ start: 0,
166
+ channels: ch.key,
167
+ authorities: 10,
168
+ enableAutoCommit: true,
169
+ });
170
+ const w2 = await client.openWriter({
171
+ start: 0,
172
+ channels: ch.key,
173
+ authorities: 20,
174
+ enableAutoCommit: true,
175
+ });
176
+
177
+ await w1.write(ch.key, randomSeries(10, ch.dataType));
178
+ let f = await ch.read(TimeRange.MAX);
179
+ expect(f.length).toEqual(0);
180
+
181
+ await w1.setAuthority({ [ch.name]: 100 });
182
+ await w1.write(ch.key, randomSeries(10, ch.dataType));
183
+
184
+ f = await ch.read(TimeRange.MAX);
185
+ expect(f.length).toEqual(10);
186
+
187
+ await w1.close();
188
+ await w2.close();
189
+ });
190
+ test("setAuthority with name-value pair", async () => {
191
+ const ch = await newChannel();
192
+ const w1 = await client.openWriter({
193
+ start: 0,
194
+ channels: ch.key,
195
+ authorities: 10,
196
+ enableAutoCommit: true,
197
+ });
198
+ const w2 = await client.openWriter({
199
+ start: 0,
200
+ channels: ch.key,
201
+ authorities: 20,
202
+ enableAutoCommit: true,
203
+ });
204
+
205
+ await w1.write(ch.key, randomSeries(10, ch.dataType));
206
+ let f = await ch.read(TimeRange.MAX);
207
+ expect(f.length).toEqual(0);
208
+
209
+ await w1.setAuthority(ch.name, 100);
210
+ await w1.write(ch.key, randomSeries(10, ch.dataType));
211
+
212
+ f = await ch.read(TimeRange.MAX);
213
+ expect(f.length).toEqual(10);
214
+
215
+ await w1.close();
216
+ await w2.close();
217
+ });
218
+ test("setAuthority on all channels", async () => {
219
+ const ch = await newChannel();
220
+ const w1 = await client.openWriter({
221
+ start: 0,
222
+ channels: ch.key,
223
+ authorities: 10,
224
+ enableAutoCommit: true,
225
+ });
226
+ const w2 = await client.openWriter({
227
+ start: 0,
228
+ channels: ch.key,
229
+ authorities: 20,
230
+ enableAutoCommit: true,
231
+ });
232
+
233
+ await w1.write(ch.key, randomSeries(10, ch.dataType));
234
+ let f = await ch.read(TimeRange.MAX);
235
+ expect(f.length).toEqual(0);
236
+
237
+ await w1.setAuthority(ch.name, 255);
238
+ await w1.write(ch.key, randomSeries(10, ch.dataType));
239
+
240
+ f = await ch.read(TimeRange.MAX);
241
+ expect(f.length).toEqual(10);
242
+
243
+ await w1.close();
244
+ await w2.close();
245
+ });
161
246
  });
162
247
  describe("Client", () => {
163
248
  test("Client - basic write", async () => {
@@ -7,8 +7,12 @@
7
7
  // License, use of this software will be governed by the Apache License, Version 2.0,
8
8
  // included in the file licenses/APL.txt.
9
9
 
10
- import type { Stream, StreamClient } from "@synnaxlabs/freighter";
11
- import { decodeError, errorZ } from "@synnaxlabs/freighter";
10
+ import {
11
+ decodeError,
12
+ errorZ,
13
+ type Stream,
14
+ type StreamClient,
15
+ } from "@synnaxlabs/freighter";
12
16
  import { control } from "@synnaxlabs/x";
13
17
  import {
14
18
  type CrudeSeries,
@@ -19,12 +23,7 @@ import {
19
23
  import { toArray } from "@synnaxlabs/x/toArray";
20
24
  import { z } from "zod";
21
25
 
22
- import {
23
- type Key,
24
- type KeyOrName,
25
- type KeysOrNames,
26
- type Params,
27
- } from "@/channel/payload";
26
+ import { type KeyOrName, type KeysOrNames, type Params } from "@/channel/payload";
28
27
  import { type Retriever } from "@/channel/retriever";
29
28
  import { WriteFrameAdapter } from "@/framer/adapter";
30
29
  import { type CrudeFrame, frameZ } from "@/framer/frame";
@@ -40,10 +39,25 @@ enum Command {
40
39
 
41
40
  export enum WriterMode {
42
41
  PersistStream = 1,
43
- PersistOnly = 2,
44
- StreamOnly = 3,
42
+ Persist = 2,
43
+ Stream = 3,
45
44
  }
46
45
 
46
+ export type CrudeWriterMode = "persist" | "stream" | "persistStream" | WriterMode;
47
+
48
+ const constructWriterMode = (mode: CrudeWriterMode): WriterMode => {
49
+ switch (mode) {
50
+ case "persist":
51
+ return WriterMode.Persist;
52
+ case "stream":
53
+ return WriterMode.Stream;
54
+ case "persistStream":
55
+ return WriterMode.PersistStream;
56
+ default:
57
+ return mode;
58
+ }
59
+ };
60
+
47
61
  export const ALWAYS_INDEX_PERSIST_ON_AUTO_COMMIT: TimeSpan = new TimeSpan(-1);
48
62
 
49
63
  const netConfigZ = z.object({
@@ -57,6 +71,8 @@ const netConfigZ = z.object({
57
71
  autoIndexPersistInterval: TimeSpan.z.optional(),
58
72
  });
59
73
 
74
+ type Config = z.infer<typeof netConfigZ>;
75
+
60
76
  const reqZ = z.object({
61
77
  command: z.nativeEnum(Command),
62
78
  config: netConfigZ.optional(),
@@ -86,10 +102,10 @@ export interface WriterConfig {
86
102
  authorities?: control.Authority | control.Authority[];
87
103
  // mode sets the persistence and streaming mode of the writer. The default
88
104
  // mode is WriterModePersistStream.
89
- mode?: WriterMode;
105
+ mode?: CrudeWriterMode;
90
106
  // errOnUnauthorized sets whether the writer raises an error when it attempts to write
91
107
  // to a channel without permission.
92
- errOnUnauthorized?: boolean,
108
+ errOnUnauthorized?: boolean;
93
109
  // enableAutoCommit determines whether the writer will automatically commit.
94
110
  // If enableAutoCommit is true, then the writer will commit after each write, and
95
111
  // will flush that commit to index after the specified autoIndexPersistInterval.
@@ -175,7 +191,7 @@ export class Writer {
175
191
  keys: adapter.keys,
176
192
  controlSubject: subject,
177
193
  authorities: toArray(authorities),
178
- mode,
194
+ mode: constructWriterMode(mode),
179
195
  errOnUnauthorized,
180
196
  enableAutoCommit,
181
197
  autoIndexPersistInterval,
@@ -219,20 +235,37 @@ export class Writer {
219
235
  return true;
220
236
  }
221
237
 
222
- async setAuthority(value: Record<Key, control.Authority>): Promise<boolean> {
223
- const res = await this.execute({
224
- command: Command.SetAuthority,
225
- config: {
226
- keys: Object.keys(value).map((k) => Number(k)),
227
- authorities: Object.values(value),
228
- },
229
- });
230
- return res.ack;
238
+ async setAuthority(value: number): Promise<boolean>;
239
+
240
+ async setAuthority(key: KeyOrName, authority: control.Authority): Promise<boolean>;
241
+
242
+ async setAuthority(value: Record<KeyOrName, control.Authority>): Promise<boolean>;
243
+
244
+ async setAuthority(
245
+ value: Record<KeyOrName, control.Authority> | KeyOrName | number,
246
+ authority?: control.Authority,
247
+ ): Promise<boolean> {
248
+ let config: Config = { keys: [], authorities: [] };
249
+ if (typeof value === "number" && authority == null)
250
+ config = { keys: [], authorities: [value] };
251
+ else {
252
+ let oValue: Record<KeyOrName, control.Authority>;
253
+ if (typeof value === "string" || typeof value === "number")
254
+ oValue = { [value]: authority } as Record<KeyOrName, control.Authority>;
255
+ else oValue = value;
256
+ oValue = await this.adapter.adaptObjectKeys(oValue);
257
+ config = {
258
+ keys: Object.keys(oValue).map((k) => Number(k)),
259
+ authorities: Object.values(oValue),
260
+ };
261
+ }
262
+ const response = await this.execute({ command: Command.SetAuthority, config });
263
+ return response.ack;
231
264
  }
232
265
 
233
266
  /**
234
267
  * Commits the written frames to the database. Commit is synchronous, meaning that it
235
- * will not return until all frames have been commited to the database.
268
+ * will not return until all frames have been committed to the database.
236
269
  *
237
270
  * @returns false if the commit failed due to an error. In this case, the caller
238
271
  * should acknowledge the error by calling the error method or closing the writer.