@synnaxlabs/client 0.26.1 → 0.27.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.
- package/.turbo/turbo-build.log +7 -7
- package/README.md +36 -10
- package/api/client.api.md +3077 -0
- package/api-extractor.json +7 -0
- package/dist/access/client.d.ts +0 -1
- package/dist/access/payload.d.ts +0 -1
- package/dist/auth/auth.d.ts +0 -1
- package/dist/channel/client.d.ts +6 -2
- package/dist/channel/client.d.ts.map +1 -1
- package/dist/channel/creator.d.ts +0 -1
- package/dist/channel/payload.d.ts +4 -1
- package/dist/channel/payload.d.ts.map +1 -1
- package/dist/channel/retriever.d.ts +0 -1
- package/dist/channel/writer.d.ts +0 -1
- package/dist/client.cjs +17 -17
- package/dist/client.d.ts +6 -7
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +2006 -1745
- package/dist/connection/checker.d.ts +0 -1
- package/dist/control/client.d.ts +0 -1
- package/dist/control/client.d.ts.map +1 -1
- package/dist/control/state.d.ts +0 -1
- package/dist/errors.d.ts +0 -1
- package/dist/framer/adapter.d.ts +0 -1
- package/dist/framer/client.d.ts +0 -1
- package/dist/framer/deleter.d.ts +0 -1
- package/dist/framer/frame.d.ts +11 -12
- package/dist/framer/iterator.d.ts +0 -1
- package/dist/framer/streamProxy.d.ts +0 -1
- package/dist/framer/streamer.d.ts +0 -1
- package/dist/framer/writer.d.ts +0 -1
- package/dist/framer/writer.d.ts.map +1 -1
- package/dist/hardware/client.d.ts +0 -1
- package/dist/hardware/device/client.d.ts +0 -1
- package/dist/hardware/device/payload.d.ts +0 -1
- package/dist/hardware/device/payload.d.ts.map +1 -1
- package/dist/hardware/rack/client.d.ts +0 -1
- package/dist/hardware/rack/payload.d.ts +0 -1
- package/dist/hardware/rack/payload.d.ts.map +1 -1
- package/dist/hardware/task/client.d.ts +0 -1
- package/dist/hardware/task/payload.d.ts +0 -1
- package/dist/hardware/task/payload.d.ts.map +1 -1
- package/dist/label/client.d.ts +8 -6
- package/dist/label/client.d.ts.map +1 -1
- package/dist/label/payload.d.ts +0 -1
- package/dist/label/retriever.d.ts +0 -1
- package/dist/label/retriever.d.ts.map +1 -1
- package/dist/label/writer.d.ts +32 -2
- package/dist/label/writer.d.ts.map +1 -1
- package/dist/ontology/client.d.ts +124 -11
- package/dist/ontology/client.d.ts.map +1 -1
- package/dist/ontology/group/client.d.ts +0 -1
- package/dist/ontology/group/group.d.ts +0 -1
- package/dist/ontology/group/payload.d.ts +0 -1
- package/dist/ontology/group/writer.d.ts +0 -1
- package/dist/ontology/payload.d.ts +5 -1
- package/dist/ontology/payload.d.ts.map +1 -1
- package/dist/ontology/writer.d.ts +4 -5
- package/dist/ontology/writer.d.ts.map +1 -1
- package/dist/ranger/alias.d.ts +0 -1
- package/dist/ranger/client.d.ts +55 -14
- package/dist/ranger/client.d.ts.map +1 -1
- package/dist/ranger/external.d.ts +1 -1
- package/dist/ranger/external.d.ts.map +1 -1
- package/dist/ranger/kv.d.ts +42 -5
- package/dist/ranger/kv.d.ts.map +1 -1
- package/dist/ranger/payload.d.ts +5 -2
- package/dist/ranger/payload.d.ts.map +1 -1
- package/dist/ranger/writer.d.ts +107 -2
- package/dist/ranger/writer.d.ts.map +1 -1
- package/dist/setupspecs.d.ts +0 -1
- package/dist/signals/observable.d.ts +0 -1
- package/dist/transport.d.ts +0 -1
- package/dist/user/client.d.ts +0 -1
- package/dist/user/payload.d.ts +0 -1
- package/dist/util/retrieve.d.ts +0 -1
- package/dist/util/telem.d.ts +0 -1
- package/dist/util/zod.d.ts +0 -1
- package/dist/workspace/client.d.ts +0 -1
- package/dist/workspace/lineplot/client.d.ts +0 -1
- package/dist/workspace/lineplot/payload.d.ts +0 -1
- package/dist/workspace/lineplot/retriever.d.ts +0 -1
- package/dist/workspace/lineplot/writer.d.ts +0 -1
- package/dist/workspace/payload.d.ts +0 -1
- package/dist/workspace/retriever.d.ts +0 -1
- package/dist/workspace/schematic/client.d.ts +0 -1
- package/dist/workspace/schematic/payload.d.ts +0 -1
- package/dist/workspace/schematic/retriever.d.ts +0 -1
- package/dist/workspace/schematic/writer.d.ts +0 -1
- package/dist/workspace/writer.d.ts +0 -1
- package/package.json +14 -12
- package/src/access/access.spec.ts +11 -11
- package/src/channel/batchRetriever.spec.ts +2 -0
- package/src/channel/channel.spec.ts +51 -31
- package/src/channel/client.ts +7 -0
- package/src/channel/payload.ts +1 -0
- package/src/client.ts +4 -3
- package/src/control/client.ts +9 -0
- package/src/errors.spec.ts +9 -0
- package/src/framer/frame.spec.ts +2 -2
- package/src/framer/frame.ts +22 -22
- package/src/framer/writer.ts +2 -1
- package/src/hardware/device/payload.ts +9 -0
- package/src/hardware/rack/payload.ts +9 -0
- package/src/hardware/task/payload.ts +9 -0
- package/src/label/client.ts +49 -19
- package/src/label/label.spec.ts +9 -0
- package/src/label/retriever.ts +2 -1
- package/src/label/writer.ts +11 -3
- package/src/ontology/client.ts +214 -13
- package/src/ontology/payload.ts +4 -0
- package/src/ontology/writer.ts +26 -12
- package/src/ranger/client.ts +204 -28
- package/src/ranger/external.ts +1 -1
- package/src/ranger/kv.ts +50 -11
- package/src/ranger/payload.ts +9 -5
- package/src/ranger/ranger.spec.ts +114 -49
- package/src/ranger/writer.ts +7 -2
- package/vite.config.ts +1 -1
- package/dist/ranger/active.d.ts +0 -11
- package/dist/ranger/active.d.ts.map +0 -1
- package/dist/ranger/range.d.ts +0 -32
- package/dist/ranger/range.d.ts.map +0 -1
- package/src/ranger/active.ts +0 -74
- package/src/ranger/range.ts +0 -98
package/src/ranger/client.ts
CHANGED
|
@@ -8,17 +8,22 @@
|
|
|
8
8
|
// included in the file licenses/APL.txt.
|
|
9
9
|
|
|
10
10
|
import { sendRequired, type UnaryClient } from "@synnaxlabs/freighter";
|
|
11
|
-
import { CrudeTimeRange, TimeRange } from "@synnaxlabs/x";
|
|
11
|
+
import { CrudeTimeRange, observe, TimeRange } from "@synnaxlabs/x";
|
|
12
12
|
import { type AsyncTermSearcher } from "@synnaxlabs/x/search";
|
|
13
|
+
import { type Series } from "@synnaxlabs/x/telem";
|
|
13
14
|
import { toArray } from "@synnaxlabs/x/toArray";
|
|
14
15
|
import { z } from "zod";
|
|
15
16
|
|
|
17
|
+
import { Key as ChannelKey } from "@/channel/payload";
|
|
16
18
|
import { type Retriever as ChannelRetriever } from "@/channel/retriever";
|
|
17
19
|
import { MultipleFoundError, NotFoundError } from "@/errors";
|
|
20
|
+
import { QueryError } from "@/errors";
|
|
18
21
|
import { type framer } from "@/framer";
|
|
19
22
|
import { type label } from "@/label";
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
23
|
+
import { type Label } from "@/label/payload";
|
|
24
|
+
import { ontology } from "@/ontology";
|
|
25
|
+
import { Resource } from "@/ontology/payload";
|
|
26
|
+
import { type Alias, Aliaser } from "@/ranger/alias";
|
|
22
27
|
import { KV } from "@/ranger/kv";
|
|
23
28
|
import {
|
|
24
29
|
analyzeParams,
|
|
@@ -32,16 +37,169 @@ import {
|
|
|
32
37
|
type Payload,
|
|
33
38
|
payloadZ,
|
|
34
39
|
} from "@/ranger/payload";
|
|
35
|
-
import {
|
|
36
|
-
import { type Writer } from "@/ranger/writer";
|
|
40
|
+
import { CreateOptions, type Writer } from "@/ranger/writer";
|
|
37
41
|
import { signals } from "@/signals";
|
|
38
42
|
import { nullableArrayZ } from "@/util/zod";
|
|
39
43
|
|
|
44
|
+
const ontologyID = (key: string): ontology.ID =>
|
|
45
|
+
new ontology.ID({ type: "range", key });
|
|
46
|
+
|
|
47
|
+
export class Range {
|
|
48
|
+
key: string;
|
|
49
|
+
name: string;
|
|
50
|
+
readonly kv: KV;
|
|
51
|
+
readonly timeRange: TimeRange;
|
|
52
|
+
readonly color: string | undefined;
|
|
53
|
+
readonly channels: ChannelRetriever;
|
|
54
|
+
private readonly aliaser: Aliaser;
|
|
55
|
+
private readonly frameClient: framer.Client;
|
|
56
|
+
private readonly labelClient: label.Client;
|
|
57
|
+
private readonly ontologyClient: ontology.Client;
|
|
58
|
+
private readonly rangeClient: Client;
|
|
59
|
+
|
|
60
|
+
constructor(
|
|
61
|
+
name: string,
|
|
62
|
+
timeRange: TimeRange = TimeRange.ZERO,
|
|
63
|
+
key: string,
|
|
64
|
+
color: string | undefined,
|
|
65
|
+
_frameClient: framer.Client,
|
|
66
|
+
_kv: KV,
|
|
67
|
+
_aliaser: Aliaser,
|
|
68
|
+
_channels: ChannelRetriever,
|
|
69
|
+
_labelClient: label.Client,
|
|
70
|
+
_ontologyClient: ontology.Client,
|
|
71
|
+
_rangeClient: Client,
|
|
72
|
+
) {
|
|
73
|
+
this.key = key;
|
|
74
|
+
this.name = name;
|
|
75
|
+
this.timeRange = timeRange;
|
|
76
|
+
this.frameClient = _frameClient;
|
|
77
|
+
this.color = color;
|
|
78
|
+
this.kv = _kv;
|
|
79
|
+
this.aliaser = _aliaser;
|
|
80
|
+
this.channels = _channels;
|
|
81
|
+
this.labelClient = _labelClient;
|
|
82
|
+
this.ontologyClient = _ontologyClient;
|
|
83
|
+
this.rangeClient = _rangeClient;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
get ontologyID(): ontology.ID {
|
|
87
|
+
return new ontology.ID({ key: this.key, type: "range" });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
get payload(): Payload {
|
|
91
|
+
return {
|
|
92
|
+
key: this.key,
|
|
93
|
+
name: this.name,
|
|
94
|
+
timeRange: this.timeRange,
|
|
95
|
+
color: this.color,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async setAlias(channel: ChannelKey | Name, alias: string): Promise<void> {
|
|
100
|
+
const ch = await this.channels.retrieve(channel);
|
|
101
|
+
if (ch.length === 0) {
|
|
102
|
+
throw new QueryError(`Channel ${channel} does not exist`);
|
|
103
|
+
}
|
|
104
|
+
await this.aliaser.set({ [ch[0].key]: alias });
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async deleteAlias(...channels: ChannelKey[]): Promise<void> {
|
|
108
|
+
await this.aliaser.delete(channels);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async listAliases(): Promise<Record<ChannelKey, string>> {
|
|
112
|
+
return await this.aliaser.list();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async resolveAlias(alias: string): Promise<ChannelKey> {
|
|
116
|
+
return await this.aliaser.resolve(alias);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async openAliasTracker(): Promise<signals.Observable<string, Alias>> {
|
|
120
|
+
return await this.aliaser.openChangeTracker();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async retrieveParent(): Promise<Range | null> {
|
|
124
|
+
return this.rangeClient.retrieveParent(this.key);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async retrieveChildren(): Promise<Range[]> {
|
|
128
|
+
const res = (
|
|
129
|
+
await this.ontologyClient.retrieveChildren(this.ontologyID, {
|
|
130
|
+
excludeFieldData: true,
|
|
131
|
+
})
|
|
132
|
+
).map((r) => r.id.key);
|
|
133
|
+
return await this.rangeClient.retrieve(res);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async read(channel: Key | Name): Promise<Series>;
|
|
137
|
+
|
|
138
|
+
async read(channels: Params): Promise<framer.Frame>;
|
|
139
|
+
|
|
140
|
+
async read(channels: Params): Promise<Series | framer.Frame> {
|
|
141
|
+
return await this.frameClient.read(this.timeRange, channels);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async labels(): Promise<Label[]> {
|
|
145
|
+
return await this.labelClient.retrieveFor(ontologyID(this.key));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async addLabel(...labels: label.Key[]): Promise<void> {
|
|
149
|
+
await this.labelClient.label(ontologyID(this.key), labels);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async removeLabel(...labels: label.Key[]): Promise<void> {
|
|
153
|
+
await this.labelClient.removeLabels(ontologyID(this.key), labels);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async openChildRangeTracker(): Promise<observe.ObservableAsyncCloseable<Range[]>> {
|
|
157
|
+
const wrapper = new observe.Observer<Range[]>();
|
|
158
|
+
const initial: ontology.Resource[] = (await this.retrieveChildren()).map((r) => {
|
|
159
|
+
const id = new ontology.ID({ key: r.key, type: "range" });
|
|
160
|
+
return { id, key: id.toString(), name: r.name, data: r.payload };
|
|
161
|
+
});
|
|
162
|
+
const base = await this.ontologyClient.openDependentTracker(
|
|
163
|
+
this.ontologyID,
|
|
164
|
+
initial,
|
|
165
|
+
);
|
|
166
|
+
base.onChange((resources: Resource[]) =>
|
|
167
|
+
wrapper.notify(this.rangeClient.resourcesToRanges(resources)),
|
|
168
|
+
);
|
|
169
|
+
wrapper.setCloser(async () => await base.close());
|
|
170
|
+
return wrapper;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
async openParentRangeTracker(): Promise<observe.ObservableAsyncCloseable<Range> | null> {
|
|
174
|
+
const wrapper = new observe.Observer<Range>();
|
|
175
|
+
const p = await this.retrieveParent();
|
|
176
|
+
if (p == null) return null;
|
|
177
|
+
const id = new ontology.ID({ key: p.key, type: "range" });
|
|
178
|
+
const resourceP = { id, key: id.toString(), name: p.name, data: p.payload };
|
|
179
|
+
const base = await this.ontologyClient.openDependentTracker(
|
|
180
|
+
this.ontologyID,
|
|
181
|
+
[resourceP],
|
|
182
|
+
"parent",
|
|
183
|
+
"to",
|
|
184
|
+
);
|
|
185
|
+
base.onChange((resources: Resource[]) => {
|
|
186
|
+
const ranges = this.rangeClient.resourcesToRanges(resources);
|
|
187
|
+
if (ranges.length === 0) return;
|
|
188
|
+
const p = ranges[0];
|
|
189
|
+
wrapper.notify(p);
|
|
190
|
+
});
|
|
191
|
+
wrapper.setCloser(async () => await base.close());
|
|
192
|
+
return wrapper;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
40
196
|
const retrieveReqZ = z.object({
|
|
41
197
|
keys: keyZ.array().optional(),
|
|
42
198
|
names: z.array(z.string()).optional(),
|
|
43
199
|
term: z.string().optional(),
|
|
44
200
|
overlapsWith: TimeRange.z.optional(),
|
|
201
|
+
limit: z.number().int().optional(),
|
|
202
|
+
offset: z.number().int().optional(),
|
|
45
203
|
});
|
|
46
204
|
|
|
47
205
|
export type RetrieveRequest = z.infer<typeof retrieveReqZ>;
|
|
@@ -58,8 +216,8 @@ export class Client implements AsyncTermSearcher<string, Key, Range> {
|
|
|
58
216
|
private readonly writer: Writer;
|
|
59
217
|
private readonly unaryClient: UnaryClient;
|
|
60
218
|
private readonly channels: ChannelRetriever;
|
|
61
|
-
private readonly active: Active;
|
|
62
219
|
private readonly labelClient: label.Client;
|
|
220
|
+
private readonly ontologyClient: ontology.Client;
|
|
63
221
|
|
|
64
222
|
constructor(
|
|
65
223
|
frameClient: framer.Client,
|
|
@@ -67,22 +225,26 @@ export class Client implements AsyncTermSearcher<string, Key, Range> {
|
|
|
67
225
|
unary: UnaryClient,
|
|
68
226
|
channels: ChannelRetriever,
|
|
69
227
|
labelClient: label.Client,
|
|
228
|
+
ontologyClient: ontology.Client,
|
|
70
229
|
) {
|
|
71
230
|
this.frameClient = frameClient;
|
|
72
231
|
this.writer = writer;
|
|
73
232
|
this.unaryClient = unary;
|
|
74
233
|
this.channels = channels;
|
|
75
|
-
this.active = new Active(unary);
|
|
76
234
|
this.labelClient = labelClient;
|
|
235
|
+
this.ontologyClient = ontologyClient;
|
|
77
236
|
}
|
|
78
237
|
|
|
79
|
-
async create(range: NewPayload): Promise<Range>;
|
|
238
|
+
async create(range: NewPayload, options?: CreateOptions): Promise<Range>;
|
|
80
239
|
|
|
81
|
-
async create(ranges: NewPayload[]): Promise<Range[]>;
|
|
240
|
+
async create(ranges: NewPayload[], options?: CreateOptions): Promise<Range[]>;
|
|
82
241
|
|
|
83
|
-
async create(
|
|
242
|
+
async create(
|
|
243
|
+
ranges: NewPayload | NewPayload[],
|
|
244
|
+
options?: CreateOptions,
|
|
245
|
+
): Promise<Range | Range[]> {
|
|
84
246
|
const single = !Array.isArray(ranges);
|
|
85
|
-
const res = this.sugar(await this.writer.create(toArray(ranges)));
|
|
247
|
+
const res = this.sugar(await this.writer.create(toArray(ranges), options));
|
|
86
248
|
return single ? res[0] : res;
|
|
87
249
|
}
|
|
88
250
|
|
|
@@ -98,8 +260,8 @@ export class Client implements AsyncTermSearcher<string, Key, Range> {
|
|
|
98
260
|
return this.sugar(await this.execRetrieve({ term }));
|
|
99
261
|
}
|
|
100
262
|
|
|
101
|
-
async page(): Promise<Range[]> {
|
|
102
|
-
return
|
|
263
|
+
async page(offset: number, limit: number): Promise<Range[]> {
|
|
264
|
+
return this.sugar(await this.execRetrieve({ offset, limit }));
|
|
103
265
|
}
|
|
104
266
|
|
|
105
267
|
async retrieve(range: CrudeTimeRange): Promise<Range[]>;
|
|
@@ -111,7 +273,8 @@ export class Client implements AsyncTermSearcher<string, Key, Range> {
|
|
|
111
273
|
async retrieve(params: Params | CrudeTimeRange): Promise<Range | Range[]> {
|
|
112
274
|
if (typeof params === "object" && "start" in params)
|
|
113
275
|
return await this.execRetrieve({ overlapsWith: new TimeRange(params) });
|
|
114
|
-
const { single, actual, variant, normalized } = analyzeParams(params);
|
|
276
|
+
const { single, actual, variant, normalized, empty } = analyzeParams(params);
|
|
277
|
+
if (empty) return [];
|
|
115
278
|
const ranges = await this.execRetrieve({ [variant]: normalized });
|
|
116
279
|
if (!single) return ranges;
|
|
117
280
|
if (ranges.length === 0)
|
|
@@ -121,6 +284,10 @@ export class Client implements AsyncTermSearcher<string, Key, Range> {
|
|
|
121
284
|
return ranges[0];
|
|
122
285
|
}
|
|
123
286
|
|
|
287
|
+
getKV(range: Key): KV {
|
|
288
|
+
return new KV(range, this.unaryClient, this.frameClient);
|
|
289
|
+
}
|
|
290
|
+
|
|
124
291
|
private async execRetrieve(req: RetrieveRequest): Promise<Range[]> {
|
|
125
292
|
const { ranges } = await sendRequired<typeof retrieveReqZ, typeof retrieveResZ>(
|
|
126
293
|
this.unaryClient,
|
|
@@ -132,21 +299,18 @@ export class Client implements AsyncTermSearcher<string, Key, Range> {
|
|
|
132
299
|
return this.sugar(ranges);
|
|
133
300
|
}
|
|
134
301
|
|
|
135
|
-
async
|
|
136
|
-
await this.
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
async clearActive(range: Key): Promise<void> {
|
|
146
|
-
await this.active.clearActive(range);
|
|
302
|
+
async retrieveParent(range: Key): Promise<Range | null> {
|
|
303
|
+
const res = await this.ontologyClient.retrieveParents({
|
|
304
|
+
key: range,
|
|
305
|
+
type: "range",
|
|
306
|
+
});
|
|
307
|
+
if (res.length === 0) return null;
|
|
308
|
+
const first = res[0];
|
|
309
|
+
if (first.id.type !== "range") return null;
|
|
310
|
+
return await this.retrieve(first.id.key);
|
|
147
311
|
}
|
|
148
312
|
|
|
149
|
-
|
|
313
|
+
sugar(payloads: Payload[]): Range[] {
|
|
150
314
|
return payloads.map((payload) => {
|
|
151
315
|
return new Range(
|
|
152
316
|
payload.name,
|
|
@@ -154,10 +318,12 @@ export class Client implements AsyncTermSearcher<string, Key, Range> {
|
|
|
154
318
|
payload.key,
|
|
155
319
|
payload.color,
|
|
156
320
|
this.frameClient,
|
|
157
|
-
new KV(payload.key, this.unaryClient),
|
|
321
|
+
new KV(payload.key, this.unaryClient, this.frameClient),
|
|
158
322
|
new Aliaser(payload.key, this.frameClient, this.unaryClient),
|
|
159
323
|
this.channels,
|
|
160
324
|
this.labelClient,
|
|
325
|
+
this.ontologyClient,
|
|
326
|
+
this,
|
|
161
327
|
);
|
|
162
328
|
});
|
|
163
329
|
}
|
|
@@ -175,4 +341,14 @@ export class Client implements AsyncTermSearcher<string, Key, Range> {
|
|
|
175
341
|
},
|
|
176
342
|
);
|
|
177
343
|
}
|
|
344
|
+
|
|
345
|
+
resourcesToRanges(resources: Resource[]): Range[] {
|
|
346
|
+
return this.sugar(
|
|
347
|
+
resources.map((r) => ({
|
|
348
|
+
key: r.id.key,
|
|
349
|
+
name: r.data?.name as string,
|
|
350
|
+
timeRange: new TimeRange(r.data?.timeRange as CrudeTimeRange),
|
|
351
|
+
})),
|
|
352
|
+
);
|
|
353
|
+
}
|
|
178
354
|
}
|
package/src/ranger/external.ts
CHANGED
package/src/ranger/kv.ts
CHANGED
|
@@ -7,27 +7,36 @@
|
|
|
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 { sendRequired,type UnaryClient } from "@synnaxlabs/freighter";
|
|
10
|
+
import { sendRequired, type UnaryClient } from "@synnaxlabs/freighter";
|
|
11
11
|
import { isObject } from "@synnaxlabs/x/identity";
|
|
12
12
|
import { toArray } from "@synnaxlabs/x/toArray";
|
|
13
13
|
import { z } from "zod";
|
|
14
14
|
|
|
15
|
+
import { framer } from "@/framer";
|
|
15
16
|
import { type Key, keyZ } from "@/ranger/payload";
|
|
17
|
+
import { signals } from "@/signals";
|
|
18
|
+
import { nullableArrayZ } from "@/util/zod";
|
|
16
19
|
|
|
17
20
|
const getReqZ = z.object({
|
|
18
21
|
range: keyZ,
|
|
19
22
|
keys: z.string().array(),
|
|
20
23
|
});
|
|
21
24
|
|
|
25
|
+
const kvPairZ = z.object({
|
|
26
|
+
range: keyZ,
|
|
27
|
+
key: z.string(),
|
|
28
|
+
value: z.string(),
|
|
29
|
+
});
|
|
30
|
+
|
|
22
31
|
const getResZ = z.object({
|
|
23
|
-
pairs:
|
|
32
|
+
pairs: nullableArrayZ(kvPairZ),
|
|
24
33
|
});
|
|
25
34
|
|
|
26
35
|
export type GetRequest = z.infer<typeof getReqZ>;
|
|
27
36
|
|
|
28
37
|
const setReqZ = z.object({
|
|
29
38
|
range: keyZ,
|
|
30
|
-
pairs:
|
|
39
|
+
pairs: kvPairZ.array(),
|
|
31
40
|
});
|
|
32
41
|
|
|
33
42
|
export type SetRequest = z.infer<typeof setReqZ>;
|
|
@@ -39,16 +48,20 @@ const deleteReqZ = z.object({
|
|
|
39
48
|
|
|
40
49
|
export type DeleteRequest = z.infer<typeof deleteReqZ>;
|
|
41
50
|
|
|
51
|
+
export type KVPair = z.infer<typeof kvPairZ>;
|
|
52
|
+
|
|
42
53
|
export class KV {
|
|
43
54
|
private static readonly GET_ENDPOINT = "/range/kv/get";
|
|
44
55
|
private static readonly SET_ENDPOINT = "/range/kv/set";
|
|
45
56
|
private static readonly DELETE_ENDPOINT = "/range/kv/delete";
|
|
46
57
|
private readonly rangeKey: Key;
|
|
47
58
|
private readonly client: UnaryClient;
|
|
59
|
+
private readonly frameClient: framer.Client;
|
|
48
60
|
|
|
49
|
-
constructor(rng: Key, client: UnaryClient) {
|
|
61
|
+
constructor(rng: Key, client: UnaryClient, frameClient: framer.Client) {
|
|
50
62
|
this.rangeKey = rng;
|
|
51
63
|
this.client = client;
|
|
64
|
+
this.frameClient = frameClient;
|
|
52
65
|
}
|
|
53
66
|
|
|
54
67
|
async get(key: string): Promise<string>;
|
|
@@ -56,14 +69,15 @@ export class KV {
|
|
|
56
69
|
async get(keys: string[]): Promise<Record<string, string>>;
|
|
57
70
|
|
|
58
71
|
async get(keys: string | string[]): Promise<string | Record<string, string>> {
|
|
59
|
-
const
|
|
72
|
+
const res = await sendRequired(
|
|
73
|
+
this.client,
|
|
60
74
|
KV.GET_ENDPOINT,
|
|
61
75
|
{ range: this.rangeKey, keys: toArray(keys) },
|
|
62
76
|
getReqZ,
|
|
63
77
|
getResZ,
|
|
64
78
|
);
|
|
65
|
-
if (
|
|
66
|
-
return
|
|
79
|
+
if (typeof keys === "string") return res.pairs[0].value;
|
|
80
|
+
return Object.fromEntries(res.pairs.map((pair) => [pair.key, pair.value]));
|
|
67
81
|
}
|
|
68
82
|
|
|
69
83
|
async list(): Promise<Record<string, string>> {
|
|
@@ -75,13 +89,18 @@ export class KV {
|
|
|
75
89
|
async set(kv: Record<string, string>): Promise<void>;
|
|
76
90
|
|
|
77
91
|
async set(key: string | Record<string, string>, value: string = ""): Promise<void> {
|
|
92
|
+
let pairs: KVPair[];
|
|
93
|
+
if (isObject(key))
|
|
94
|
+
pairs = Object.entries(key).map(([k, v]) => ({
|
|
95
|
+
range: this.rangeKey,
|
|
96
|
+
key: k,
|
|
97
|
+
value: v,
|
|
98
|
+
}));
|
|
99
|
+
else pairs = [{ range: this.rangeKey, key: key, value: value }];
|
|
78
100
|
await sendRequired(
|
|
79
101
|
this.client,
|
|
80
102
|
KV.SET_ENDPOINT,
|
|
81
|
-
{
|
|
82
|
-
range: this.rangeKey,
|
|
83
|
-
pairs: isObject(key) ? key : { [key]: value },
|
|
84
|
-
},
|
|
103
|
+
{ range: this.rangeKey, pairs },
|
|
85
104
|
setReqZ,
|
|
86
105
|
z.unknown(),
|
|
87
106
|
);
|
|
@@ -96,4 +115,24 @@ export class KV {
|
|
|
96
115
|
z.unknown(),
|
|
97
116
|
);
|
|
98
117
|
}
|
|
118
|
+
|
|
119
|
+
async openTracker(): Promise<signals.Observable<string, KVPair>> {
|
|
120
|
+
return await signals.openObservable<string, KVPair>(
|
|
121
|
+
this.frameClient,
|
|
122
|
+
"sy_range_kv_set",
|
|
123
|
+
"sy_range_kv_delete",
|
|
124
|
+
(variant, data) => {
|
|
125
|
+
if (variant === "delete")
|
|
126
|
+
return data.toStrings().map((combinedKey) => {
|
|
127
|
+
const [range, key] = combinedKey.split("<--->", 2);
|
|
128
|
+
return { variant, key: combinedKey, value: { range, key, value: "" } };
|
|
129
|
+
});
|
|
130
|
+
return data.parseJSON(kvPairZ).map((pair) => ({
|
|
131
|
+
variant,
|
|
132
|
+
key: `${pair.range}${pair.key}`,
|
|
133
|
+
value: pair,
|
|
134
|
+
}));
|
|
135
|
+
},
|
|
136
|
+
);
|
|
137
|
+
}
|
|
99
138
|
}
|
package/src/ranger/payload.ts
CHANGED
|
@@ -31,7 +31,7 @@ export type Payload = z.infer<typeof payloadZ>;
|
|
|
31
31
|
export const newPayloadZ = payloadZ.extend({
|
|
32
32
|
key: z.string().uuid().optional(),
|
|
33
33
|
});
|
|
34
|
-
export type NewPayload = z.
|
|
34
|
+
export type NewPayload = z.input<typeof newPayloadZ>;
|
|
35
35
|
|
|
36
36
|
export type ParamAnalysisResult =
|
|
37
37
|
| {
|
|
@@ -39,37 +39,41 @@ export type ParamAnalysisResult =
|
|
|
39
39
|
variant: "keys";
|
|
40
40
|
normalized: Keys;
|
|
41
41
|
actual: Key;
|
|
42
|
+
empty: never;
|
|
42
43
|
}
|
|
43
44
|
| {
|
|
44
45
|
single: true;
|
|
45
46
|
variant: "names";
|
|
46
47
|
normalized: Names;
|
|
47
48
|
actual: Name;
|
|
49
|
+
empty: never;
|
|
48
50
|
}
|
|
49
51
|
| {
|
|
50
52
|
single: false;
|
|
51
53
|
variant: "keys";
|
|
52
54
|
normalized: Keys;
|
|
53
55
|
actual: Keys;
|
|
56
|
+
empty: boolean;
|
|
54
57
|
}
|
|
55
58
|
| {
|
|
56
59
|
single: false;
|
|
57
60
|
variant: "names";
|
|
58
61
|
normalized: Names;
|
|
59
62
|
actual: Names;
|
|
63
|
+
empty: boolean;
|
|
60
64
|
};
|
|
61
65
|
|
|
62
66
|
export const analyzeParams = (params: Params): ParamAnalysisResult => {
|
|
63
67
|
const normal = toArray(params) as Keys | Names;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const isKey = keyZ.safeParse(normal[0]).success;
|
|
68
|
+
const empty = normal.length === 0;
|
|
69
|
+
let isKey = false;
|
|
70
|
+
if (!empty) isKey = keyZ.safeParse(normal[0]).success;
|
|
68
71
|
return {
|
|
69
72
|
single: !Array.isArray(params),
|
|
70
73
|
variant: isKey ? "keys" : "names",
|
|
71
74
|
normalized: normal,
|
|
72
75
|
actual: params,
|
|
76
|
+
empty,
|
|
73
77
|
} as const as ParamAnalysisResult;
|
|
74
78
|
};
|
|
75
79
|
|