@synnaxlabs/client 0.41.0 → 0.42.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 +6 -6
- package/dist/access/payload.d.ts +7 -1
- package/dist/access/payload.d.ts.map +1 -1
- package/dist/access/policy/payload.d.ts +182 -142
- package/dist/access/policy/payload.d.ts.map +1 -1
- package/dist/access/policy/retriever.d.ts +25 -22
- package/dist/access/policy/retriever.d.ts.map +1 -1
- package/dist/auth/auth.d.ts +1 -7
- package/dist/auth/auth.d.ts.map +1 -1
- package/dist/channel/client.d.ts +2 -7
- package/dist/channel/client.d.ts.map +1 -1
- package/dist/channel/payload.d.ts +13 -74
- package/dist/channel/payload.d.ts.map +1 -1
- package/dist/channel/retriever.d.ts +5 -31
- package/dist/channel/retriever.d.ts.map +1 -1
- package/dist/channel/writer.d.ts +6 -18
- package/dist/channel/writer.d.ts.map +1 -1
- package/dist/client.cjs +36 -31
- package/dist/client.d.ts +8 -56
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +6486 -3979
- package/dist/connection/checker.d.ts +22 -39
- package/dist/connection/checker.d.ts.map +1 -1
- package/dist/control/client.d.ts.map +1 -1
- package/dist/control/state.d.ts +6 -26
- package/dist/control/state.d.ts.map +1 -1
- package/dist/errors.d.ts +31 -56
- package/dist/errors.d.ts.map +1 -1
- package/dist/framer/adapter.d.ts +4 -0
- package/dist/framer/adapter.d.ts.map +1 -1
- package/dist/framer/client.d.ts +2 -2
- package/dist/framer/client.d.ts.map +1 -1
- package/dist/framer/codec.d.ts +34 -0
- package/dist/framer/codec.d.ts.map +1 -0
- package/dist/framer/codec.spec.d.ts +2 -0
- package/dist/framer/codec.spec.d.ts.map +1 -0
- package/dist/framer/deleter.d.ts +12 -49
- package/dist/framer/deleter.d.ts.map +1 -1
- package/dist/framer/frame.d.ts +26 -88
- package/dist/framer/frame.d.ts.map +1 -1
- package/dist/framer/iterator.d.ts.map +1 -1
- package/dist/framer/streamer.d.ts +69 -11
- package/dist/framer/streamer.d.ts.map +1 -1
- package/dist/framer/writer.d.ts +60 -257
- package/dist/framer/writer.d.ts.map +1 -1
- package/dist/hardware/device/client.d.ts +7 -31
- package/dist/hardware/device/client.d.ts.map +1 -1
- package/dist/hardware/device/payload.d.ts +11 -93
- package/dist/hardware/device/payload.d.ts.map +1 -1
- package/dist/hardware/rack/payload.d.ts +15 -103
- package/dist/hardware/rack/payload.d.ts.map +1 -1
- package/dist/hardware/task/client.d.ts +4 -20
- package/dist/hardware/task/client.d.ts.map +1 -1
- package/dist/hardware/task/payload.d.ts +41 -116
- package/dist/hardware/task/payload.d.ts.map +1 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/label/payload.d.ts +1 -9
- package/dist/label/payload.d.ts.map +1 -1
- package/dist/label/writer.d.ts +27 -36
- package/dist/label/writer.d.ts.map +1 -1
- package/dist/ontology/client.d.ts +46 -36
- package/dist/ontology/client.d.ts.map +1 -1
- package/dist/ontology/group/payload.d.ts +1 -7
- package/dist/ontology/group/payload.d.ts.map +1 -1
- package/dist/ontology/payload.d.ts +239 -146
- package/dist/ontology/payload.d.ts.map +1 -1
- package/dist/ranger/client.d.ts +13 -58
- package/dist/ranger/client.d.ts.map +1 -1
- package/dist/ranger/kv.d.ts +7 -49
- package/dist/ranger/kv.d.ts.map +1 -1
- package/dist/ranger/payload.d.ts +21 -99
- package/dist/ranger/payload.d.ts.map +1 -1
- package/dist/ranger/writer.d.ts +35 -88
- package/dist/ranger/writer.d.ts.map +1 -1
- package/dist/testutil/indexedPair.d.ts +5 -0
- package/dist/testutil/indexedPair.d.ts.map +1 -0
- package/dist/testutil/telem.d.ts +3 -0
- package/dist/testutil/telem.d.ts.map +1 -0
- package/dist/transport.d.ts +2 -2
- package/dist/transport.d.ts.map +1 -1
- package/dist/user/payload.d.ts +3 -29
- package/dist/user/payload.d.ts.map +1 -1
- package/dist/user/retriever.d.ts +3 -9
- package/dist/user/retriever.d.ts.map +1 -1
- package/dist/util/decodeJSONString.d.ts.map +1 -1
- package/dist/util/zod.d.ts +1 -1
- package/dist/util/zod.d.ts.map +1 -1
- package/dist/workspace/lineplot/payload.d.ts +10 -26
- package/dist/workspace/lineplot/payload.d.ts.map +1 -1
- package/dist/workspace/log/payload.d.ts +10 -26
- package/dist/workspace/log/payload.d.ts.map +1 -1
- package/dist/workspace/payload.d.ts +14 -40
- package/dist/workspace/payload.d.ts.map +1 -1
- package/dist/workspace/schematic/payload.d.ts +13 -45
- package/dist/workspace/schematic/payload.d.ts.map +1 -1
- package/dist/workspace/table/payload.d.ts +13 -39
- package/dist/workspace/table/payload.d.ts.map +1 -1
- package/package.json +6 -6
- package/src/channel/channel.spec.ts +26 -27
- package/src/channel/client.ts +0 -9
- package/src/channel/payload.ts +22 -5
- package/src/channel/retriever.ts +12 -6
- package/src/client.ts +3 -3
- package/src/control/client.ts +5 -2
- package/src/control/state.ts +8 -3
- package/src/errors.spec.ts +5 -4
- package/src/errors.ts +21 -82
- package/src/framer/adapter.ts +22 -3
- package/src/framer/client.ts +38 -21
- package/src/framer/codec.spec.ts +303 -0
- package/src/framer/codec.ts +396 -0
- package/src/framer/deleter.spec.ts +51 -63
- package/src/framer/frame.ts +16 -5
- package/src/framer/iterator.spec.ts +45 -28
- package/src/framer/iterator.ts +6 -5
- package/src/framer/streamProxy.ts +1 -1
- package/src/framer/streamer.spec.ts +10 -18
- package/src/framer/streamer.ts +138 -22
- package/src/framer/writer.spec.ts +125 -150
- package/src/framer/writer.ts +74 -68
- package/src/hardware/device/payload.ts +3 -3
- package/src/hardware/task/payload.ts +9 -6
- package/src/hardware/task/task.spec.ts +1 -1
- package/src/index.ts +0 -2
- package/src/ontology/group/group.spec.ts +2 -2
- package/src/ontology/payload.ts +3 -3
- package/src/ranger/ranger.spec.ts +9 -7
- package/src/testutil/indexedPair.ts +40 -0
- package/src/testutil/telem.ts +13 -0
- package/src/transport.ts +1 -2
- package/src/util/decodeJSONString.ts +2 -2
- package/src/util/retrieve.spec.ts +1 -1
package/src/channel/payload.ts
CHANGED
|
@@ -7,7 +7,8 @@
|
|
|
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 {
|
|
10
|
+
import { type Optional } from "@synnaxlabs/x";
|
|
11
|
+
import { type CrudeDataType, DataType } from "@synnaxlabs/x/telem";
|
|
11
12
|
import { z } from "zod";
|
|
12
13
|
|
|
13
14
|
import { nullableArrayZ } from "@/util/zod";
|
|
@@ -20,12 +21,12 @@ export type Name = z.infer<typeof nameZ>;
|
|
|
20
21
|
export type Names = Name[];
|
|
21
22
|
export type KeyOrName = Key | Name;
|
|
22
23
|
export type KeysOrNames = Keys | Names;
|
|
23
|
-
export type
|
|
24
|
+
export type PrimitiveParams = Key | Name | Keys | Names;
|
|
25
|
+
export type Params = Key | Name | Keys | Names | Payload | Payload[];
|
|
24
26
|
|
|
25
27
|
export const channelZ = z.object({
|
|
26
28
|
name: nameZ,
|
|
27
29
|
key: keyZ,
|
|
28
|
-
rate: Rate.z,
|
|
29
30
|
dataType: DataType.z,
|
|
30
31
|
leaseholder: z.number(),
|
|
31
32
|
index: keyZ,
|
|
@@ -42,14 +43,30 @@ export const newZ = channelZ.extend({
|
|
|
42
43
|
key: keyZ.optional(),
|
|
43
44
|
leaseholder: z.number().optional(),
|
|
44
45
|
index: keyZ.optional(),
|
|
45
|
-
rate: Rate.z.optional().default(0),
|
|
46
46
|
isIndex: z.boolean().optional(),
|
|
47
47
|
internal: z.boolean().optional().default(false),
|
|
48
48
|
virtual: z.boolean().optional().default(false),
|
|
49
49
|
expression: z.string().optional().default(""),
|
|
50
50
|
requires: nullableArrayZ(keyZ).optional().default([]),
|
|
51
51
|
});
|
|
52
|
-
|
|
52
|
+
|
|
53
|
+
export interface New
|
|
54
|
+
extends Omit<
|
|
55
|
+
Optional<
|
|
56
|
+
Payload,
|
|
57
|
+
| "key"
|
|
58
|
+
| "leaseholder"
|
|
59
|
+
| "index"
|
|
60
|
+
| "isIndex"
|
|
61
|
+
| "internal"
|
|
62
|
+
| "virtual"
|
|
63
|
+
| "expression"
|
|
64
|
+
| "requires"
|
|
65
|
+
>,
|
|
66
|
+
"dataType"
|
|
67
|
+
> {
|
|
68
|
+
dataType: CrudeDataType;
|
|
69
|
+
}
|
|
53
70
|
|
|
54
71
|
export const ONTOLOGY_TYPE = "channel";
|
|
55
72
|
export type OntologyType = typeof ONTOLOGY_TYPE;
|
package/src/channel/retriever.ts
CHANGED
|
@@ -20,6 +20,8 @@ import {
|
|
|
20
20
|
type Keys,
|
|
21
21
|
type KeysOrNames,
|
|
22
22
|
keyZ,
|
|
23
|
+
type Name,
|
|
24
|
+
type Names,
|
|
23
25
|
type Params,
|
|
24
26
|
type Payload,
|
|
25
27
|
} from "@/channel/payload";
|
|
@@ -53,8 +55,15 @@ const resZ = z.object({ channels: nullableArrayZ(channelZ) });
|
|
|
53
55
|
|
|
54
56
|
export const analyzeParams = (
|
|
55
57
|
channels: Params,
|
|
56
|
-
): ParamAnalysisResult<KeyOrName, { number: "keys"; string: "names" }> =>
|
|
57
|
-
|
|
58
|
+
): ParamAnalysisResult<KeyOrName, { number: "keys"; string: "names" }> => {
|
|
59
|
+
if (Array.isArray(channels) && channels.length > 0 && typeof channels[0] === "object")
|
|
60
|
+
channels = (channels as Payload[]).map((c) => c.key);
|
|
61
|
+
else if (typeof channels === "object" && "key" in channels) channels = [channels.key];
|
|
62
|
+
return analyzeParameters(channels as Key | Name | Keys | Names, {
|
|
63
|
+
number: "keys",
|
|
64
|
+
string: "names",
|
|
65
|
+
});
|
|
66
|
+
};
|
|
58
67
|
|
|
59
68
|
export interface Retriever {
|
|
60
69
|
retrieve: (channels: Params, opts?: RetrieveOptions) => Promise<Payload[]>;
|
|
@@ -120,10 +129,7 @@ export class CacheRetriever implements Retriever {
|
|
|
120
129
|
}
|
|
121
130
|
|
|
122
131
|
async retrieve(channels: Params, options?: RetrieveOptions): Promise<Payload[]> {
|
|
123
|
-
const { normalized } =
|
|
124
|
-
string: "names",
|
|
125
|
-
number: "keys",
|
|
126
|
-
});
|
|
132
|
+
const { normalized } = analyzeParams(channels);
|
|
127
133
|
const results: Payload[] = [];
|
|
128
134
|
const toFetch: KeysOrNames = [];
|
|
129
135
|
normalized.forEach((keyOrName) => {
|
package/src/client.ts
CHANGED
|
@@ -31,10 +31,10 @@ import { user } from "@/user";
|
|
|
31
31
|
import { workspace } from "@/workspace";
|
|
32
32
|
|
|
33
33
|
export const synnaxPropsZ = z.object({
|
|
34
|
-
host: z.string({
|
|
34
|
+
host: z.string({ error: "Host is required" }).min(1, "Host is required"),
|
|
35
35
|
port: z
|
|
36
|
-
.number({
|
|
37
|
-
.or(z.string({
|
|
36
|
+
.number({ error: "Port is required" })
|
|
37
|
+
.or(z.string({ error: "Port is required" })),
|
|
38
38
|
username: z.string().min(1, "Username is required"),
|
|
39
39
|
password: z.string().min(1, "Password is required"),
|
|
40
40
|
connectivityPollFrequency: TimeSpan.z.default(TimeSpan.seconds(30)),
|
package/src/control/client.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// included in the file licenses/APL.txt.
|
|
9
9
|
|
|
10
10
|
import { StateTracker } from "@/control/state";
|
|
11
|
-
import {
|
|
11
|
+
import { framer } from "@/framer";
|
|
12
12
|
|
|
13
13
|
const CONTROL_STATE_KEY = "sy_node_1_control";
|
|
14
14
|
|
|
@@ -20,7 +20,10 @@ export class Client {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
async openStateTracker(): Promise<StateTracker> {
|
|
23
|
-
const stream = await
|
|
23
|
+
const stream = await framer.HardenedStreamer.open(
|
|
24
|
+
async () => await this.framer.openStreamer(CONTROL_STATE_KEY),
|
|
25
|
+
CONTROL_STATE_KEY,
|
|
26
|
+
);
|
|
24
27
|
return new StateTracker(stream);
|
|
25
28
|
}
|
|
26
29
|
}
|
package/src/control/state.ts
CHANGED
|
@@ -15,8 +15,9 @@ import { z } from "zod";
|
|
|
15
15
|
import { type channel } from "@/channel";
|
|
16
16
|
import { framer } from "@/framer";
|
|
17
17
|
|
|
18
|
-
export
|
|
19
|
-
export const
|
|
18
|
+
export type Authority = control.Authority;
|
|
19
|
+
export const ABSOLUTE_AUTHORITY = control.ABSOLUTE_AUTHORITY;
|
|
20
|
+
export const ZERO_AUTHORITY = control.ZERO_AUTHORITY;
|
|
20
21
|
export type Transfer = control.Transfer<channel.Key>;
|
|
21
22
|
export interface State extends control.State<channel.Key> {}
|
|
22
23
|
export interface Subject extends control.Subject {}
|
|
@@ -33,6 +34,10 @@ export const transferString = (t: Transfer): string => {
|
|
|
33
34
|
} (${t.to.authority.toString()})`;
|
|
34
35
|
};
|
|
35
36
|
|
|
37
|
+
const updateZ = z.object({
|
|
38
|
+
transfers: z.array(control.transferZ),
|
|
39
|
+
});
|
|
40
|
+
|
|
36
41
|
interface Update {
|
|
37
42
|
transfers: control.Transfer<channel.Key>[];
|
|
38
43
|
}
|
|
@@ -46,7 +51,7 @@ export class StateTracker
|
|
|
46
51
|
|
|
47
52
|
constructor(streamer: framer.Streamer) {
|
|
48
53
|
super(streamer, (frame) => {
|
|
49
|
-
const update: Update = this.codec.decode(frame.series[0].buffer);
|
|
54
|
+
const update: Update = this.codec.decode(frame.series[0].buffer, updateZ);
|
|
50
55
|
this.merge(update);
|
|
51
56
|
return [update.transfers, true];
|
|
52
57
|
});
|
package/src/errors.spec.ts
CHANGED
|
@@ -7,8 +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 { type
|
|
11
|
-
import { id } from "@synnaxlabs/x";
|
|
10
|
+
import { type errors, id } from "@synnaxlabs/x";
|
|
12
11
|
import { v4 as uuid } from "uuid";
|
|
13
12
|
import { describe, expect, test } from "vitest";
|
|
14
13
|
|
|
@@ -30,7 +29,7 @@ import { newClient } from "@/setupspecs";
|
|
|
30
29
|
|
|
31
30
|
describe("error", () => {
|
|
32
31
|
describe("type matching", () => {
|
|
33
|
-
const ERRORS: [string, Error,
|
|
32
|
+
const ERRORS: [string, Error, errors.Matchable][] = [
|
|
34
33
|
[ValidationError.TYPE, new ValidationError(), ValidationError],
|
|
35
34
|
[FieldError.TYPE, new FieldError("field", "message"), FieldError],
|
|
36
35
|
[AuthError.TYPE, new AuthError(), AuthError],
|
|
@@ -45,7 +44,9 @@ describe("error", () => {
|
|
|
45
44
|
[ContiguityError.TYPE, new ContiguityError("message"), ContiguityError],
|
|
46
45
|
];
|
|
47
46
|
ERRORS.forEach(([typeName, error, type]) =>
|
|
48
|
-
test(`matches ${typeName}`, () =>
|
|
47
|
+
test(`matches ${typeName}`, () => {
|
|
48
|
+
expect(type.matches(error)).toBeTruthy();
|
|
49
|
+
}),
|
|
49
50
|
);
|
|
50
51
|
});
|
|
51
52
|
});
|
package/src/errors.ts
CHANGED
|
@@ -7,35 +7,17 @@
|
|
|
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 {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
type Middleware,
|
|
15
|
-
registerError,
|
|
16
|
-
Unreachable,
|
|
17
|
-
} from "@synnaxlabs/freighter";
|
|
18
|
-
|
|
19
|
-
const _FREIGHTER_EXCEPTION_PREFIX = "sy.";
|
|
20
|
-
|
|
21
|
-
export interface Field {
|
|
22
|
-
field: string;
|
|
23
|
-
message: string;
|
|
24
|
-
}
|
|
10
|
+
import { type Middleware, Unreachable } from "@synnaxlabs/freighter";
|
|
11
|
+
import { errors } from "@synnaxlabs/x";
|
|
12
|
+
|
|
13
|
+
export class SynnaxError extends errors.createTyped("sy") {}
|
|
25
14
|
|
|
26
15
|
/**
|
|
27
16
|
* Raised when a validation error occurs.
|
|
28
17
|
*/
|
|
29
|
-
export class ValidationError extends
|
|
30
|
-
static readonly TYPE: string = `${_FREIGHTER_EXCEPTION_PREFIX}validation`;
|
|
31
|
-
type = ValidationError.TYPE;
|
|
32
|
-
static readonly matches = errorMatcher(ValidationError.TYPE);
|
|
33
|
-
}
|
|
18
|
+
export class ValidationError extends SynnaxError.sub("validation") {}
|
|
34
19
|
|
|
35
|
-
export class FieldError extends ValidationError {
|
|
36
|
-
static readonly TYPE = `${ValidationError.TYPE}.field`;
|
|
37
|
-
type = FieldError.TYPE;
|
|
38
|
-
static readonly matches = errorMatcher(FieldError.TYPE);
|
|
20
|
+
export class FieldError extends ValidationError.sub("field") {
|
|
39
21
|
readonly field: string;
|
|
40
22
|
readonly message: string;
|
|
41
23
|
|
|
@@ -49,35 +31,19 @@ export class FieldError extends ValidationError {
|
|
|
49
31
|
/**
|
|
50
32
|
* AuthError is raised when an authentication error occurs.
|
|
51
33
|
*/
|
|
52
|
-
export class AuthError extends
|
|
53
|
-
static readonly TYPE: string = `${_FREIGHTER_EXCEPTION_PREFIX}auth`;
|
|
54
|
-
type = AuthError.TYPE;
|
|
55
|
-
static readonly matches = errorMatcher(AuthError.TYPE);
|
|
56
|
-
}
|
|
34
|
+
export class AuthError extends SynnaxError.sub("auth") {}
|
|
57
35
|
|
|
58
36
|
/**
|
|
59
37
|
* InvalidTokenError is raised when an authentication token is invalid.
|
|
60
38
|
*/
|
|
61
|
-
export class InvalidTokenError extends AuthError {
|
|
62
|
-
static readonly TYPE = `${AuthError.TYPE}.invalid-token`;
|
|
63
|
-
type = InvalidTokenError.TYPE;
|
|
64
|
-
static readonly matches = errorMatcher(InvalidTokenError.TYPE);
|
|
65
|
-
}
|
|
39
|
+
export class InvalidTokenError extends AuthError.sub("invalid-token") {}
|
|
66
40
|
|
|
67
|
-
export class ExpiredTokenError extends AuthError {
|
|
68
|
-
static readonly TYPE = `${AuthError.TYPE}.expired-token`;
|
|
69
|
-
type = ExpiredTokenError.TYPE;
|
|
70
|
-
static readonly matches = errorMatcher(ExpiredTokenError.TYPE);
|
|
71
|
-
}
|
|
41
|
+
export class ExpiredTokenError extends AuthError.sub("expired-token") {}
|
|
72
42
|
|
|
73
43
|
/**
|
|
74
44
|
* UnexpectedError is raised when an unexpected error occurs.
|
|
75
45
|
*/
|
|
76
|
-
export class UnexpectedError extends
|
|
77
|
-
static readonly TYPE = `${_FREIGHTER_EXCEPTION_PREFIX}unexpected`;
|
|
78
|
-
type = UnexpectedError.TYPE;
|
|
79
|
-
static readonly matches = errorMatcher(UnexpectedError.TYPE);
|
|
80
|
-
|
|
46
|
+
export class UnexpectedError extends SynnaxError.sub("unexpected") {
|
|
81
47
|
constructor(message: string) {
|
|
82
48
|
super(`
|
|
83
49
|
Unexpected error encountered:
|
|
@@ -92,31 +58,16 @@ export class UnexpectedError extends BaseTypedError {
|
|
|
92
58
|
/**
|
|
93
59
|
* QueryError is raised when a query error occurs.
|
|
94
60
|
*/
|
|
95
|
-
export class QueryError extends
|
|
96
|
-
static readonly TYPE: string = `${_FREIGHTER_EXCEPTION_PREFIX}query`;
|
|
97
|
-
type = QueryError.TYPE;
|
|
98
|
-
static readonly matches = errorMatcher(QueryError.TYPE);
|
|
99
|
-
}
|
|
61
|
+
export class QueryError extends SynnaxError.sub("query") {}
|
|
100
62
|
|
|
101
|
-
export class NotFoundError extends QueryError {
|
|
102
|
-
static readonly TYPE = `${QueryError.TYPE}.not_found`;
|
|
103
|
-
type = NotFoundError.TYPE;
|
|
104
|
-
static readonly matches = errorMatcher(NotFoundError.TYPE);
|
|
105
|
-
}
|
|
63
|
+
export class NotFoundError extends QueryError.sub("not_found") {}
|
|
106
64
|
|
|
107
|
-
export class MultipleFoundError extends QueryError {
|
|
108
|
-
static readonly TYPE = `${QueryError.TYPE}.multiple_results`;
|
|
109
|
-
type = MultipleFoundError.TYPE;
|
|
110
|
-
static readonly matches = errorMatcher(MultipleFoundError.TYPE);
|
|
111
|
-
}
|
|
65
|
+
export class MultipleFoundError extends QueryError.sub("multiple_results") {}
|
|
112
66
|
|
|
113
67
|
/**
|
|
114
68
|
* RouteError is raised when a routing error occurs.
|
|
115
69
|
*/
|
|
116
|
-
export class RouteError extends
|
|
117
|
-
static readonly TYPE = `${_FREIGHTER_EXCEPTION_PREFIX}route`;
|
|
118
|
-
type = RouteError.TYPE;
|
|
119
|
-
static readonly matches = errorMatcher(RouteError.TYPE);
|
|
70
|
+
export class RouteError extends SynnaxError.sub("route") {
|
|
120
71
|
path: string;
|
|
121
72
|
|
|
122
73
|
constructor(message: string, path: string) {
|
|
@@ -125,29 +76,17 @@ export class RouteError extends BaseTypedError {
|
|
|
125
76
|
}
|
|
126
77
|
}
|
|
127
78
|
|
|
128
|
-
export class ControlError extends
|
|
129
|
-
static readonly TYPE: string = `${_FREIGHTER_EXCEPTION_PREFIX}control`;
|
|
130
|
-
type = ControlError.TYPE;
|
|
131
|
-
static readonly matches = errorMatcher(ControlError.TYPE);
|
|
132
|
-
}
|
|
79
|
+
export class ControlError extends SynnaxError.sub("control") {}
|
|
133
80
|
|
|
134
|
-
export class UnauthorizedError extends ControlError {
|
|
135
|
-
static readonly TYPE = `${ControlError.TYPE}.unauthorized`;
|
|
136
|
-
type = UnauthorizedError.TYPE;
|
|
137
|
-
static readonly matches = errorMatcher(UnauthorizedError.TYPE);
|
|
138
|
-
}
|
|
81
|
+
export class UnauthorizedError extends ControlError.sub("unauthorized") {}
|
|
139
82
|
|
|
140
83
|
/**
|
|
141
84
|
* Raised when time-series data is not contiguous.
|
|
142
85
|
*/
|
|
143
|
-
export class ContiguityError extends
|
|
144
|
-
static readonly TYPE = `${_FREIGHTER_EXCEPTION_PREFIX}contiguity`;
|
|
145
|
-
type = ContiguityError.TYPE;
|
|
146
|
-
static readonly matches = errorMatcher(ContiguityError.TYPE);
|
|
147
|
-
}
|
|
86
|
+
export class ContiguityError extends SynnaxError.sub("contiguity") {}
|
|
148
87
|
|
|
149
|
-
const decode = (payload:
|
|
150
|
-
if (!payload.type.startsWith(
|
|
88
|
+
const decode = (payload: errors.Payload): Error | null => {
|
|
89
|
+
if (!payload.type.startsWith(SynnaxError.TYPE)) return null;
|
|
151
90
|
if (payload.type.startsWith(ValidationError.TYPE)) {
|
|
152
91
|
if (payload.type === FieldError.TYPE) {
|
|
153
92
|
const values = payload.data.split(": ");
|
|
@@ -188,11 +127,11 @@ const decode = (payload: ErrorPayload): Error | null => {
|
|
|
188
127
|
return new UnexpectedError(payload.data);
|
|
189
128
|
};
|
|
190
129
|
|
|
191
|
-
const encode = ():
|
|
130
|
+
const encode = (): errors.Payload => {
|
|
192
131
|
throw new Error("Not implemented");
|
|
193
132
|
};
|
|
194
133
|
|
|
195
|
-
|
|
134
|
+
errors.register({ encode, decode });
|
|
196
135
|
|
|
197
136
|
export const validateFieldNotNull = (
|
|
198
137
|
key: string,
|
package/src/framer/adapter.ts
CHANGED
|
@@ -11,17 +11,20 @@ import { type CrudeSeries, Series } from "@synnaxlabs/x/telem";
|
|
|
11
11
|
|
|
12
12
|
import { channel } from "@/channel";
|
|
13
13
|
import { ValidationError } from "@/errors";
|
|
14
|
+
import { Codec } from "@/framer/codec";
|
|
14
15
|
import { type Crude, Frame } from "@/framer/frame";
|
|
15
16
|
|
|
16
17
|
export class ReadAdapter {
|
|
17
18
|
private adapter: Map<channel.Key, channel.Name> | null;
|
|
18
19
|
retriever: channel.Retriever;
|
|
19
20
|
keys: channel.Key[];
|
|
21
|
+
codec: Codec;
|
|
20
22
|
|
|
21
23
|
private constructor(retriever: channel.Retriever) {
|
|
22
24
|
this.retriever = retriever;
|
|
23
25
|
this.adapter = null;
|
|
24
26
|
this.keys = [];
|
|
27
|
+
this.codec = new Codec();
|
|
25
28
|
}
|
|
26
29
|
|
|
27
30
|
static async open(
|
|
@@ -35,12 +38,16 @@ export class ReadAdapter {
|
|
|
35
38
|
|
|
36
39
|
async update(channels: channel.Params): Promise<void> {
|
|
37
40
|
const { variant, normalized } = channel.analyzeParams(channels);
|
|
41
|
+
const fetched = await this.retriever.retrieve(normalized);
|
|
42
|
+
this.codec.update(
|
|
43
|
+
fetched.map((c) => c.key),
|
|
44
|
+
fetched.map((c) => c.dataType),
|
|
45
|
+
);
|
|
38
46
|
if (variant === "keys") {
|
|
39
47
|
this.adapter = null;
|
|
40
48
|
this.keys = normalized as channel.Key[];
|
|
41
49
|
return;
|
|
42
50
|
}
|
|
43
|
-
const fetched = await this.retriever.retrieve(normalized);
|
|
44
51
|
const a = new Map<channel.Key, channel.Name>();
|
|
45
52
|
this.adapter = a;
|
|
46
53
|
normalized.forEach((name) => {
|
|
@@ -69,11 +76,13 @@ export class WriteAdapter {
|
|
|
69
76
|
private adapter: Map<channel.Name, channel.Key> | null;
|
|
70
77
|
retriever: channel.Retriever;
|
|
71
78
|
keys: channel.Key[];
|
|
79
|
+
codec: Codec;
|
|
72
80
|
|
|
73
81
|
private constructor(retriever: channel.Retriever) {
|
|
74
82
|
this.retriever = retriever;
|
|
75
83
|
this.adapter = null;
|
|
76
84
|
this.keys = [];
|
|
85
|
+
this.codec = new Codec();
|
|
77
86
|
}
|
|
78
87
|
|
|
79
88
|
static async open(
|
|
@@ -99,11 +108,17 @@ export class WriteAdapter {
|
|
|
99
108
|
results.map((c) => [c.name, c.key]),
|
|
100
109
|
);
|
|
101
110
|
this.keys = results.map((c) => c.key);
|
|
111
|
+
this.codec.update(
|
|
112
|
+
this.keys,
|
|
113
|
+
results.map((c) => c.dataType),
|
|
114
|
+
);
|
|
102
115
|
}
|
|
103
116
|
|
|
104
|
-
private async fetchChannel(
|
|
117
|
+
private async fetchChannel(
|
|
118
|
+
ch: channel.Key | channel.Name | channel.Payload,
|
|
119
|
+
): Promise<channel.Payload> {
|
|
105
120
|
const res = await this.retriever.retrieve(ch);
|
|
106
|
-
if (res.length === 0) throw new Error(`Channel ${ch} not found`);
|
|
121
|
+
if (res.length === 0) throw new Error(`Channel ${JSON.stringify(ch)} not found`);
|
|
107
122
|
return res[0];
|
|
108
123
|
}
|
|
109
124
|
|
|
@@ -113,6 +128,10 @@ export class WriteAdapter {
|
|
|
113
128
|
return res.key;
|
|
114
129
|
}
|
|
115
130
|
|
|
131
|
+
encode(frame: Frame): Uint8Array {
|
|
132
|
+
return this.codec.encode(frame.toPayload());
|
|
133
|
+
}
|
|
134
|
+
|
|
116
135
|
async adapt(
|
|
117
136
|
columnsOrData: channel.Params | Record<channel.KeyOrName, CrudeSeries> | Crude,
|
|
118
137
|
series?: CrudeSeries | CrudeSeries[],
|
package/src/framer/client.ts
CHANGED
|
@@ -7,7 +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 { type
|
|
10
|
+
import { type UnaryClient, type WebSocketClient } from "@synnaxlabs/freighter";
|
|
11
11
|
import {
|
|
12
12
|
type CrudeSeries,
|
|
13
13
|
type CrudeTimeRange,
|
|
@@ -21,19 +21,35 @@ import { channel } from "@/channel";
|
|
|
21
21
|
import { Deleter } from "@/framer/deleter";
|
|
22
22
|
import { Frame, ONTOLOGY_TYPE } from "@/framer/frame";
|
|
23
23
|
import { Iterator, type IteratorConfig } from "@/framer/iterator";
|
|
24
|
-
import { Streamer, type StreamerConfig } from "@/framer/streamer";
|
|
24
|
+
import { openStreamer, type Streamer, type StreamerConfig } from "@/framer/streamer";
|
|
25
25
|
import { Writer, type WriterConfig, WriterMode } from "@/framer/writer";
|
|
26
26
|
import { ontology } from "@/ontology";
|
|
27
27
|
|
|
28
28
|
export const ontologyID = (key: channel.Key): ontology.ID =>
|
|
29
29
|
new ontology.ID({ type: ONTOLOGY_TYPE, key: key.toString() });
|
|
30
30
|
|
|
31
|
+
const normalizeConfig = <T extends { channels: channel.Params }>(
|
|
32
|
+
config: T | channel.Params,
|
|
33
|
+
): T => {
|
|
34
|
+
if (
|
|
35
|
+
Array.isArray(config) ||
|
|
36
|
+
typeof config !== "object" ||
|
|
37
|
+
(typeof config === "object" && "key" in config)
|
|
38
|
+
)
|
|
39
|
+
return { channels: config } as T;
|
|
40
|
+
return config;
|
|
41
|
+
};
|
|
42
|
+
|
|
31
43
|
export class Client {
|
|
32
|
-
private readonly streamClient:
|
|
44
|
+
private readonly streamClient: WebSocketClient;
|
|
33
45
|
private readonly retriever: channel.Retriever;
|
|
34
46
|
private readonly deleter: Deleter;
|
|
35
47
|
|
|
36
|
-
constructor(
|
|
48
|
+
constructor(
|
|
49
|
+
stream: WebSocketClient,
|
|
50
|
+
unary: UnaryClient,
|
|
51
|
+
retriever: channel.Retriever,
|
|
52
|
+
) {
|
|
37
53
|
this.streamClient = stream;
|
|
38
54
|
this.retriever = retriever;
|
|
39
55
|
this.deleter = new Deleter(unary);
|
|
@@ -63,9 +79,11 @@ export class Client {
|
|
|
63
79
|
* @returns a new {@link Writer}.
|
|
64
80
|
*/
|
|
65
81
|
async openWriter(config: WriterConfig | channel.Params): Promise<Writer> {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
82
|
+
return await Writer._open(
|
|
83
|
+
this.retriever,
|
|
84
|
+
this.streamClient,
|
|
85
|
+
normalizeConfig<WriterConfig>(config),
|
|
86
|
+
);
|
|
69
87
|
}
|
|
70
88
|
|
|
71
89
|
/***
|
|
@@ -93,9 +111,11 @@ export class Client {
|
|
|
93
111
|
async openStreamer(config: StreamerConfig | channel.Params): Promise<Streamer>;
|
|
94
112
|
|
|
95
113
|
async openStreamer(config: StreamerConfig | channel.Params): Promise<Streamer> {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
114
|
+
return await openStreamer(
|
|
115
|
+
this.retriever,
|
|
116
|
+
this.streamClient,
|
|
117
|
+
normalizeConfig<StreamerConfig>(config),
|
|
118
|
+
);
|
|
99
119
|
}
|
|
100
120
|
|
|
101
121
|
async write(
|
|
@@ -135,13 +155,13 @@ export class Client {
|
|
|
135
155
|
start,
|
|
136
156
|
channels: Object.keys(data_),
|
|
137
157
|
mode: WriterMode.Persist,
|
|
158
|
+
errOnUnauthorized: true,
|
|
159
|
+
enableAutoCommit: true,
|
|
160
|
+
autoIndexPersistInterval: TimeSpan.MAX,
|
|
138
161
|
});
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
} finally {
|
|
143
|
-
await w.close();
|
|
144
|
-
}
|
|
162
|
+
await w.write(data_);
|
|
163
|
+
await w.commit();
|
|
164
|
+
await w.close();
|
|
145
165
|
return;
|
|
146
166
|
}
|
|
147
167
|
const w = await this.openWriter({
|
|
@@ -152,11 +172,8 @@ export class Client {
|
|
|
152
172
|
enableAutoCommit: true,
|
|
153
173
|
autoIndexPersistInterval: TimeSpan.MAX,
|
|
154
174
|
});
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
} finally {
|
|
158
|
-
await w.close();
|
|
159
|
-
}
|
|
175
|
+
await w.write(channels as channel.Params, data);
|
|
176
|
+
await w.close();
|
|
160
177
|
}
|
|
161
178
|
|
|
162
179
|
async read(tr: CrudeTimeRange, channel: channel.KeyOrName): Promise<MultiSeries>;
|