@synnaxlabs/client 0.20.0 → 0.22.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/.vscode/settings.json +3 -0
- package/README.md +13 -0
- package/dist/auth/auth.d.ts +7 -6
- package/dist/auth/auth.d.ts.map +1 -1
- package/dist/channel/client.d.ts +14 -11
- package/dist/channel/client.d.ts.map +1 -1
- package/dist/channel/creator.d.ts +10 -0
- package/dist/channel/creator.d.ts.map +1 -0
- package/dist/channel/payload.d.ts +6 -2
- package/dist/channel/payload.d.ts.map +1 -1
- package/dist/channel/retriever.d.ts +65 -35
- package/dist/channel/retriever.d.ts.map +1 -1
- package/dist/channel/writer.d.ts +4 -3
- package/dist/client.cjs +19 -22
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.ts +12 -10
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +6781 -6675
- package/dist/client.js.map +1 -1
- package/dist/connection/checker.d.ts +4 -3
- package/dist/connection/checker.d.ts.map +1 -1
- package/dist/control/authority.d.ts +2 -1
- package/dist/control/state.d.ts +6 -4
- package/dist/control/state.d.ts.map +1 -1
- package/dist/errors.d.ts +24 -20
- package/dist/errors.d.ts.map +1 -1
- package/dist/framer/adapter.d.ts +5 -4
- package/dist/framer/adapter.d.ts.map +1 -1
- package/dist/framer/client.d.ts +12 -12
- package/dist/framer/client.d.ts.map +1 -1
- package/dist/framer/frame.d.ts +13 -12
- package/dist/framer/frame.d.ts.map +1 -1
- package/dist/framer/iterator.d.ts +5 -4
- package/dist/framer/iterator.d.ts.map +1 -1
- package/dist/framer/streamProxy.d.ts +3 -2
- package/dist/framer/streamProxy.d.ts.map +1 -1
- package/dist/framer/streamer.d.ts +13 -4
- package/dist/framer/streamer.d.ts.map +1 -1
- package/dist/framer/writer.d.ts +67 -33
- package/dist/framer/writer.d.ts.map +1 -1
- package/dist/hardware/client.d.ts +4 -3
- package/dist/hardware/device/client.d.ts +107 -14
- package/dist/hardware/device/client.d.ts.map +1 -1
- package/dist/hardware/device/external.d.ts +0 -2
- package/dist/hardware/device/external.d.ts.map +1 -1
- package/dist/hardware/device/index.d.ts +1 -1
- package/dist/hardware/device/index.d.ts.map +1 -1
- package/dist/hardware/rack/client.d.ts +43 -20
- package/dist/hardware/rack/client.d.ts.map +1 -1
- package/dist/hardware/rack/external.d.ts +0 -2
- package/dist/hardware/rack/external.d.ts.map +1 -1
- package/dist/hardware/task/client.d.ts +197 -14
- package/dist/hardware/task/client.d.ts.map +1 -1
- package/dist/hardware/task/index.d.ts +1 -1
- package/dist/hardware/task/index.d.ts.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.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 +2 -1
- package/dist/label/retriever.d.ts +3 -2
- package/dist/label/writer.d.ts +4 -3
- package/dist/ontology/client.d.ts +82 -14
- package/dist/ontology/client.d.ts.map +1 -1
- package/dist/ontology/external.d.ts +0 -1
- package/dist/ontology/external.d.ts.map +1 -1
- package/dist/ontology/group/client.d.ts +3 -2
- package/dist/ontology/group/client.d.ts.map +1 -1
- package/dist/ontology/group/group.d.ts +1 -0
- package/dist/ontology/group/payload.d.ts +2 -1
- package/dist/ontology/group/writer.d.ts +4 -3
- package/dist/ontology/payload.d.ts +71 -60
- package/dist/ontology/payload.d.ts.map +1 -1
- package/dist/ontology/writer.d.ts +3 -2
- package/dist/ranger/active.d.ts +3 -2
- package/dist/ranger/alias.d.ts +7 -6
- package/dist/ranger/alias.d.ts.map +1 -1
- package/dist/ranger/client.d.ts +162 -11
- package/dist/ranger/client.d.ts.map +1 -1
- package/dist/ranger/external.d.ts +0 -1
- package/dist/ranger/external.d.ts.map +1 -1
- package/dist/ranger/kv.d.ts +5 -3
- package/dist/ranger/kv.d.ts.map +1 -1
- package/dist/ranger/payload.d.ts +57 -50
- package/dist/ranger/payload.d.ts.map +1 -1
- package/dist/ranger/range.d.ts +12 -10
- package/dist/ranger/range.d.ts.map +1 -1
- package/dist/ranger/writer.d.ts +3 -2
- package/dist/setupspecs.d.ts +2 -1
- package/dist/signals/observable.d.ts +8 -15
- package/dist/signals/observable.d.ts.map +1 -1
- package/dist/transport.d.ts +3 -2
- package/dist/transport.d.ts.map +1 -1
- package/dist/user/payload.d.ts +2 -1
- package/dist/util/retrieve.d.ts +24 -0
- package/dist/util/retrieve.d.ts.map +1 -0
- package/dist/util/retrieve.spec.d.ts +2 -0
- package/dist/util/retrieve.spec.d.ts.map +1 -0
- package/dist/util/telem.d.ts +2 -1
- package/dist/util/telem.d.ts.map +1 -1
- package/dist/util/zod.d.ts +4 -0
- package/dist/util/zod.d.ts.map +1 -0
- package/dist/workspace/client.d.ts +9 -6
- package/dist/workspace/client.d.ts.map +1 -1
- package/dist/workspace/lineplot/client.d.ts +6 -5
- package/dist/workspace/lineplot/client.d.ts.map +1 -1
- package/dist/workspace/lineplot/payload.d.ts +3 -2
- package/dist/workspace/lineplot/payload.d.ts.map +1 -1
- package/dist/workspace/lineplot/retriever.d.ts +3 -2
- package/dist/workspace/lineplot/retriever.d.ts.map +1 -1
- package/dist/workspace/lineplot/writer.d.ts +7 -6
- package/dist/workspace/lineplot/writer.d.ts.map +1 -1
- package/dist/workspace/payload.d.ts +3 -2
- package/dist/workspace/payload.d.ts.map +1 -1
- package/dist/workspace/retriever.d.ts +3 -2
- package/dist/workspace/schematic/client.d.ts +18 -0
- package/dist/workspace/schematic/client.d.ts.map +1 -0
- package/dist/workspace/schematic/external.d.ts.map +1 -0
- package/dist/workspace/schematic/index.d.ts +2 -0
- package/dist/workspace/schematic/index.d.ts.map +1 -0
- package/dist/workspace/{pid → schematic}/payload.d.ts +6 -5
- package/dist/workspace/schematic/payload.d.ts.map +1 -0
- package/dist/workspace/schematic/retriever.d.ts +10 -0
- package/dist/workspace/schematic/retriever.d.ts.map +1 -0
- package/dist/workspace/schematic/schematic.spec.d.ts +2 -0
- package/dist/workspace/schematic/schematic.spec.d.ts.map +1 -0
- package/dist/workspace/{pid → schematic}/writer.d.ts +11 -10
- package/dist/workspace/schematic/writer.d.ts.map +1 -0
- package/dist/workspace/writer.d.ts +5 -4
- package/dist/workspace/writer.d.ts.map +1 -1
- package/examples/node/package-lock.json +29 -12
- package/examples/node/package.json +2 -2
- package/examples/node/streamWrite.js +8 -11
- package/package.json +10 -9
- package/src/auth/auth.spec.ts +55 -15
- package/src/auth/auth.ts +41 -42
- package/src/channel/batchRetriever.spec.ts +37 -40
- package/src/channel/channel.spec.ts +4 -4
- package/src/channel/client.ts +42 -49
- package/src/channel/creator.ts +37 -0
- package/src/channel/payload.ts +2 -1
- package/src/channel/retriever.ts +55 -71
- package/src/client.ts +23 -20
- package/src/connection/checker.ts +1 -1
- package/src/connection/connection.spec.ts +1 -6
- package/src/control/state.ts +3 -1
- package/src/errors.ts +71 -67
- package/src/framer/adapter.spec.ts +33 -1
- package/src/framer/adapter.ts +10 -6
- package/src/framer/client.ts +13 -12
- package/src/framer/frame.spec.ts +1 -1
- package/src/framer/frame.ts +9 -6
- package/src/framer/iterator.spec.ts +1 -1
- package/src/framer/iterator.ts +1 -1
- package/src/framer/streamProxy.ts +12 -13
- package/src/framer/streamer.spec.ts +1 -1
- package/src/framer/streamer.ts +25 -1
- package/src/framer/writer.spec.ts +49 -2
- package/src/framer/writer.ts +27 -2
- package/src/hardware/device/client.ts +155 -28
- package/src/hardware/device/device.spec.ts +2 -2
- package/src/hardware/device/external.ts +0 -2
- package/src/hardware/device/index.ts +2 -2
- package/src/hardware/rack/client.ts +139 -56
- package/src/hardware/rack/external.ts +0 -2
- package/src/hardware/rack/rack.spec.ts +20 -1
- package/src/hardware/task/client.ts +324 -31
- package/src/hardware/task/index.ts +1 -1
- package/src/hardware/task/task.spec.ts +41 -0
- package/src/index.ts +3 -4
- package/src/label/client.ts +3 -2
- package/src/label/retriever.ts +1 -1
- package/src/label/writer.ts +1 -1
- package/src/ontology/client.ts +195 -41
- package/src/ontology/external.ts +0 -1
- package/src/ontology/group/client.ts +1 -2
- package/src/ontology/group/payload.ts +1 -1
- package/src/ontology/ontology.spec.ts +16 -0
- package/src/ontology/payload.ts +22 -13
- package/src/ranger/active.ts +5 -5
- package/src/ranger/alias.ts +2 -2
- package/src/ranger/client.ts +68 -17
- package/src/ranger/external.ts +0 -1
- package/src/ranger/kv.ts +6 -1
- package/src/ranger/payload.ts +6 -4
- package/src/ranger/range.ts +4 -1
- package/src/ranger/ranger.spec.ts +24 -2
- package/src/signals/observable.ts +24 -63
- package/src/transport.ts +2 -1
- package/src/util/retrieve.spec.ts +56 -0
- package/src/util/retrieve.ts +103 -0
- package/src/util/telem.ts +1 -1
- package/src/util/zod.ts +4 -0
- package/src/workspace/client.ts +6 -4
- package/src/workspace/lineplot/client.ts +3 -3
- package/src/workspace/lineplot/linePlot.spec.ts +11 -11
- package/src/workspace/lineplot/payload.ts +1 -1
- package/src/workspace/lineplot/retriever.ts +5 -13
- package/src/workspace/lineplot/writer.ts +8 -7
- package/src/workspace/payload.ts +6 -3
- package/src/workspace/retriever.ts +1 -1
- package/src/workspace/{pid → schematic}/client.ts +10 -10
- package/src/workspace/{pid → schematic}/external.ts +2 -2
- package/src/workspace/{pid → schematic}/index.ts +1 -1
- package/src/workspace/{pid → schematic}/payload.ts +4 -4
- package/src/workspace/{pid → schematic}/retriever.ts +10 -10
- package/src/workspace/{pid/pid.spec.ts → schematic/schematic.spec.ts} +35 -35
- package/src/workspace/{pid → schematic}/writer.ts +26 -25
- package/src/workspace/workspace.spec.ts +7 -7
- package/src/workspace/writer.ts +8 -2
- package/dist/hardware/device/payload.d.ts +0 -30
- package/dist/hardware/device/payload.d.ts.map +0 -1
- package/dist/hardware/device/retriever.d.ts +0 -10
- package/dist/hardware/device/retriever.d.ts.map +0 -1
- package/dist/hardware/device/writer.d.ts +0 -9
- package/dist/hardware/device/writer.d.ts.map +0 -1
- package/dist/hardware/rack/payload.d.ts +0 -26
- package/dist/hardware/rack/payload.d.ts.map +0 -1
- package/dist/hardware/rack/retriever.d.ts +0 -10
- package/dist/hardware/rack/retriever.d.ts.map +0 -1
- package/dist/hardware/rack/writer.d.ts +0 -9
- package/dist/hardware/rack/writer.d.ts.map +0 -1
- package/dist/hardware/task/external.d.ts +0 -4
- package/dist/hardware/task/external.d.ts.map +0 -1
- package/dist/hardware/task/payload.d.ts +0 -42
- package/dist/hardware/task/payload.d.ts.map +0 -1
- package/dist/hardware/task/retriever.d.ts +0 -29
- package/dist/hardware/task/retriever.d.ts.map +0 -1
- package/dist/hardware/task/writer.d.ts +0 -9
- package/dist/hardware/task/writer.d.ts.map +0 -1
- package/dist/ontology/retriever.d.ts +0 -13
- package/dist/ontology/retriever.d.ts.map +0 -1
- package/dist/ontology/signals.d.ts +0 -30
- package/dist/ontology/signals.d.ts.map +0 -1
- package/dist/ranger/retriever.d.ts +0 -11
- package/dist/ranger/retriever.d.ts.map +0 -1
- package/dist/workspace/pid/client.d.ts +0 -17
- package/dist/workspace/pid/client.d.ts.map +0 -1
- package/dist/workspace/pid/external.d.ts.map +0 -1
- package/dist/workspace/pid/index.d.ts +0 -2
- package/dist/workspace/pid/index.d.ts.map +0 -1
- package/dist/workspace/pid/payload.d.ts.map +0 -1
- package/dist/workspace/pid/pid.spec.d.ts +0 -2
- package/dist/workspace/pid/pid.spec.d.ts.map +0 -1
- package/dist/workspace/pid/retriever.d.ts +0 -9
- package/dist/workspace/pid/retriever.d.ts.map +0 -1
- package/dist/workspace/pid/writer.d.ts.map +0 -1
- package/src/hardware/device/payload.ts +0 -27
- package/src/hardware/device/retriever.ts +0 -60
- package/src/hardware/device/writer.ts +0 -59
- package/src/hardware/rack/payload.ts +0 -26
- package/src/hardware/rack/retriever.ts +0 -68
- package/src/hardware/rack/writer.ts +0 -59
- package/src/hardware/task/external.ts +0 -12
- package/src/hardware/task/payload.ts +0 -40
- package/src/hardware/task/retriever.ts +0 -70
- package/src/hardware/task/writer.ts +0 -65
- package/src/ontology/retriever.ts +0 -91
- package/src/ontology/signals.ts +0 -139
- package/src/ranger/retriever.ts +0 -50
- /package/dist/workspace/{pid → schematic}/external.d.ts +0 -0
package/src/ontology/client.ts
CHANGED
|
@@ -7,83 +7,108 @@
|
|
|
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 UnaryClient } from "@synnaxlabs/freighter";
|
|
11
|
-
import { type AsyncTermSearcher } from "@synnaxlabs/x";
|
|
10
|
+
import { sendRequired, type UnaryClient } from "@synnaxlabs/freighter";
|
|
11
|
+
import { type AsyncTermSearcher } from "@synnaxlabs/x/search";
|
|
12
12
|
|
|
13
|
-
import {
|
|
13
|
+
import { QueryError } from "@/errors";
|
|
14
|
+
import { framer } from "@/framer";
|
|
14
15
|
import { group } from "@/ontology/group";
|
|
15
|
-
import {
|
|
16
|
-
|
|
16
|
+
import {
|
|
17
|
+
ID,
|
|
18
|
+
IDPayload,
|
|
19
|
+
RelationshipChange,
|
|
20
|
+
ResourceChange,
|
|
21
|
+
idZ,
|
|
22
|
+
parseRelationship,
|
|
23
|
+
resourceSchemaZ,
|
|
24
|
+
type Resource,
|
|
25
|
+
} from "@/ontology/payload";
|
|
17
26
|
import { Writer } from "@/ontology/writer";
|
|
27
|
+
import { z } from "zod";
|
|
28
|
+
import { observe, toArray } from "@synnaxlabs/x";
|
|
29
|
+
import { Frame } from "@/framer/frame";
|
|
18
30
|
|
|
19
|
-
|
|
31
|
+
const RETRIEVE_ENDPOINT = "/ontology/retrieve";
|
|
32
|
+
|
|
33
|
+
const retrieveReqZ = z.object({
|
|
34
|
+
ids: idZ.array().optional(),
|
|
35
|
+
children: z.boolean().optional(),
|
|
36
|
+
parents: z.boolean().optional(),
|
|
37
|
+
includeSchema: z.boolean().optional(),
|
|
38
|
+
excludeFieldData: z.boolean().optional(),
|
|
39
|
+
term: z.string().optional(),
|
|
40
|
+
limit: z.number().optional(),
|
|
41
|
+
offset: z.number().optional(),
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
type RetrieveRequest = z.infer<typeof retrieveReqZ>;
|
|
45
|
+
|
|
46
|
+
export type RetrieveOptions = Pick<
|
|
47
|
+
RetrieveRequest,
|
|
48
|
+
"includeSchema" | "excludeFieldData"
|
|
49
|
+
>;
|
|
20
50
|
|
|
21
|
-
|
|
51
|
+
const retrieveResZ = z.object({
|
|
52
|
+
resources: resourceSchemaZ.array(),
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const parseIDs = (ids: ID | ID[] | string | string[]): IDPayload[] =>
|
|
56
|
+
toArray(ids).map((id) => new ID(id).payload);
|
|
22
57
|
|
|
23
58
|
/** The core client class for executing queries against a Synnax cluster ontology */
|
|
24
59
|
export class Client implements AsyncTermSearcher<string, string, Resource> {
|
|
60
|
+
readonly type: string = "ontology";
|
|
25
61
|
groups: group.Client;
|
|
26
|
-
|
|
62
|
+
private readonly client: UnaryClient;
|
|
27
63
|
private readonly writer: Writer;
|
|
28
|
-
private readonly framer:
|
|
64
|
+
private readonly framer: framer.Client;
|
|
29
65
|
|
|
30
|
-
constructor(unary: UnaryClient, framer:
|
|
31
|
-
this.
|
|
66
|
+
constructor(unary: UnaryClient, framer: framer.Client) {
|
|
67
|
+
this.client = unary;
|
|
32
68
|
this.writer = new Writer(unary);
|
|
33
69
|
this.groups = new group.Client(unary);
|
|
34
70
|
this.framer = framer;
|
|
35
71
|
}
|
|
36
72
|
|
|
37
|
-
async search(term: string): Promise<Resource[]> {
|
|
38
|
-
return await this.
|
|
73
|
+
async search(term: string, options?: RetrieveOptions): Promise<Resource[]> {
|
|
74
|
+
return await this.execRetrieve({ term, ...options });
|
|
39
75
|
}
|
|
40
76
|
|
|
41
|
-
async retrieve(
|
|
42
|
-
id: ID | string,
|
|
43
|
-
includeSchema?: boolean,
|
|
44
|
-
includeFieldData?: boolean,
|
|
45
|
-
): Promise<Resource>;
|
|
77
|
+
async retrieve(id: ID | string, options?: RetrieveOptions): Promise<Resource>;
|
|
46
78
|
|
|
47
|
-
async retrieve(
|
|
48
|
-
ids: ID[] | string[],
|
|
49
|
-
includeSchema?: boolean,
|
|
50
|
-
includeFieldData?: boolean,
|
|
51
|
-
): Promise<Resource[]>;
|
|
79
|
+
async retrieve(ids: ID[] | string[], options?: RetrieveOptions): Promise<Resource[]>;
|
|
52
80
|
|
|
53
81
|
async retrieve(
|
|
54
82
|
ids: ID | ID[] | string | string[],
|
|
55
|
-
|
|
56
|
-
includeFieldData?: boolean,
|
|
83
|
+
options?: RetrieveOptions,
|
|
57
84
|
): Promise<Resource | Resource[]> {
|
|
58
|
-
const resources = await this.
|
|
59
|
-
ids,
|
|
60
|
-
includeSchema,
|
|
61
|
-
includeFieldData,
|
|
62
|
-
);
|
|
85
|
+
const resources = await this.execRetrieve({ ids: parseIDs(ids), ...options });
|
|
63
86
|
if (Array.isArray(ids)) return resources;
|
|
64
87
|
if (resources.length === 0)
|
|
65
88
|
throw new QueryError(`No resource found with ID ${ids.toString()}`);
|
|
66
89
|
return resources[0];
|
|
67
90
|
}
|
|
68
91
|
|
|
69
|
-
async page(
|
|
70
|
-
|
|
92
|
+
async page(
|
|
93
|
+
offset: number,
|
|
94
|
+
limit: number,
|
|
95
|
+
options?: RetrieveOptions,
|
|
96
|
+
): Promise<Resource[]> {
|
|
97
|
+
return await this.execRetrieve({ offset, limit, ...options });
|
|
71
98
|
}
|
|
72
99
|
|
|
73
100
|
async retrieveChildren(
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
includeFieldData?: boolean,
|
|
101
|
+
ids: ID | ID[],
|
|
102
|
+
options?: RetrieveOptions,
|
|
77
103
|
): Promise<Resource[]> {
|
|
78
|
-
return await this.
|
|
104
|
+
return await this.execRetrieve({ ids: parseIDs(ids), children: true, ...options });
|
|
79
105
|
}
|
|
80
106
|
|
|
81
107
|
async retrieveParents(
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
includeFieldData?: boolean,
|
|
108
|
+
ids: ID | ID[],
|
|
109
|
+
options?: RetrieveOptions,
|
|
85
110
|
): Promise<Resource[]> {
|
|
86
|
-
return await this.
|
|
111
|
+
return await this.execRetrieve({ ids: parseIDs(ids), parents: true, ...options });
|
|
87
112
|
}
|
|
88
113
|
|
|
89
114
|
async addChildren(id: ID, ...children: ID[]): Promise<void> {
|
|
@@ -99,6 +124,135 @@ export class Client implements AsyncTermSearcher<string, string, Resource> {
|
|
|
99
124
|
}
|
|
100
125
|
|
|
101
126
|
async openChangeTracker(): Promise<ChangeTracker> {
|
|
102
|
-
return await ChangeTracker.open(this.framer, this
|
|
127
|
+
return await ChangeTracker.open(this.framer, this);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
newSearcherWithOptions(
|
|
131
|
+
options: RetrieveOptions,
|
|
132
|
+
): AsyncTermSearcher<string, string, Resource> {
|
|
133
|
+
return {
|
|
134
|
+
type: this.type,
|
|
135
|
+
search: (term: string) => this.search(term, options),
|
|
136
|
+
retrieve: (ids: string[]) => this.retrieve(ids, options),
|
|
137
|
+
page: (offset: number, limit: number) => this.page(offset, limit, options),
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
private async execRetrieve(request: RetrieveRequest): Promise<Resource[]> {
|
|
142
|
+
const { resources } = await sendRequired(
|
|
143
|
+
this.client,
|
|
144
|
+
RETRIEVE_ENDPOINT,
|
|
145
|
+
request,
|
|
146
|
+
retrieveReqZ,
|
|
147
|
+
retrieveResZ,
|
|
148
|
+
);
|
|
149
|
+
return resources;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const RESOURCE_SET_NAME = "sy_ontology_resource_set";
|
|
154
|
+
const RESOURCE_DELETE_NAME = "sy_ontology_resource_delete";
|
|
155
|
+
const RELATIONSHIP_SET_NAME = "sy_ontology_relationship_set";
|
|
156
|
+
const RELATIONSHIP_DELETE_NAME = "sy_ontology_relationship_delete";
|
|
157
|
+
|
|
158
|
+
export class ChangeTracker {
|
|
159
|
+
private readonly resourceObs: observe.Observer<ResourceChange[]>;
|
|
160
|
+
private readonly relationshipObs: observe.Observer<RelationshipChange[]>;
|
|
161
|
+
|
|
162
|
+
readonly relationships: observe.Observable<RelationshipChange[]>;
|
|
163
|
+
readonly resources: observe.Observable<ResourceChange[]>;
|
|
164
|
+
|
|
165
|
+
private readonly streamer: framer.Streamer;
|
|
166
|
+
private readonly client: Client;
|
|
167
|
+
private readonly closePromise: Promise<void>;
|
|
168
|
+
|
|
169
|
+
constructor(streamer: framer.Streamer, client: Client) {
|
|
170
|
+
this.relationshipObs = new observe.Observer<RelationshipChange[]>();
|
|
171
|
+
this.relationships = this.relationshipObs;
|
|
172
|
+
this.resourceObs = new observe.Observer<ResourceChange[]>();
|
|
173
|
+
this.resources = this.resourceObs;
|
|
174
|
+
this.client = client;
|
|
175
|
+
this.streamer = streamer;
|
|
176
|
+
this.closePromise = this.start();
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async close(): Promise<void> {
|
|
180
|
+
this.streamer.close();
|
|
181
|
+
await this.closePromise;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
private async start(): Promise<void> {
|
|
185
|
+
for await (const frame of this.streamer) {
|
|
186
|
+
await this.update(frame);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
private async update(frame: Frame): Promise<void> {
|
|
191
|
+
const resSets = await this.parseResourceSets(frame);
|
|
192
|
+
const resDeletes = this.parseResourceDeletes(frame);
|
|
193
|
+
const allResources = resSets.concat(resDeletes);
|
|
194
|
+
if (allResources.length > 0) this.resourceObs.notify(resSets.concat(resDeletes));
|
|
195
|
+
const relSets = this.parseRelationshipSets(frame);
|
|
196
|
+
const relDeletes = this.parseRelationshipDeletes(frame);
|
|
197
|
+
const allRelationships = relSets.concat(relDeletes);
|
|
198
|
+
if (allRelationships.length > 0)
|
|
199
|
+
this.relationshipObs.notify(relSets.concat(relDeletes));
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
private parseRelationshipSets(frame: Frame): RelationshipChange[] {
|
|
203
|
+
const relationships = frame.get(RELATIONSHIP_SET_NAME);
|
|
204
|
+
if (relationships.length === 0) return [];
|
|
205
|
+
return Array.from(relationships.as("string")).map((rel) => ({
|
|
206
|
+
variant: "set",
|
|
207
|
+
key: parseRelationship(rel),
|
|
208
|
+
value: undefined,
|
|
209
|
+
}));
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
private parseRelationshipDeletes(frame: Frame): RelationshipChange[] {
|
|
213
|
+
const relationships = frame.get(RELATIONSHIP_DELETE_NAME);
|
|
214
|
+
if (relationships.length === 0) return [];
|
|
215
|
+
return Array.from(relationships.as("string")).map((rel) => ({
|
|
216
|
+
variant: "delete",
|
|
217
|
+
key: parseRelationship(rel),
|
|
218
|
+
}));
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
private async parseResourceSets(frame: Frame): Promise<ResourceChange[]> {
|
|
222
|
+
const sets = frame.get(RESOURCE_SET_NAME);
|
|
223
|
+
if (sets.length === 0) return [];
|
|
224
|
+
// We should only ever get one series of sets
|
|
225
|
+
const ids = Array.from(sets.as("string")).map((id: string) => new ID(id));
|
|
226
|
+
try {
|
|
227
|
+
const resources = await this.client.retrieve(ids);
|
|
228
|
+
return resources.map((resource) => ({
|
|
229
|
+
variant: "set",
|
|
230
|
+
key: resource.id,
|
|
231
|
+
value: resource,
|
|
232
|
+
}));
|
|
233
|
+
} catch (e) {
|
|
234
|
+
if (e instanceof QueryError) return [];
|
|
235
|
+
throw e;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
private parseResourceDeletes(frame: Frame): ResourceChange[] {
|
|
240
|
+
const deletes = frame.get(RESOURCE_DELETE_NAME);
|
|
241
|
+
if (deletes.length === 0) return [];
|
|
242
|
+
// We should only ever get one series of deletes
|
|
243
|
+
return Array.from(deletes.as("string")).map((str) => ({
|
|
244
|
+
variant: "delete",
|
|
245
|
+
key: new ID(str),
|
|
246
|
+
}));
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
static async open(client: framer.Client, retriever: Client): Promise<ChangeTracker> {
|
|
250
|
+
const streamer = await client.openStreamer([
|
|
251
|
+
RESOURCE_SET_NAME,
|
|
252
|
+
RESOURCE_DELETE_NAME,
|
|
253
|
+
RELATIONSHIP_SET_NAME,
|
|
254
|
+
RELATIONSHIP_DELETE_NAME,
|
|
255
|
+
]);
|
|
256
|
+
return new ChangeTracker(streamer, retriever);
|
|
103
257
|
}
|
|
104
258
|
}
|
package/src/ontology/external.ts
CHANGED
|
@@ -9,11 +9,10 @@
|
|
|
9
9
|
|
|
10
10
|
import { type UnaryClient } from "@synnaxlabs/freighter";
|
|
11
11
|
|
|
12
|
-
import { type ID } from "@/ontology/payload";
|
|
13
|
-
|
|
14
12
|
import { Group } from "@/ontology/group/group";
|
|
15
13
|
import { type Payload } from "@/ontology/group/payload";
|
|
16
14
|
import { Writer } from "@/ontology/group/writer";
|
|
15
|
+
import { type ID } from "@/ontology/payload";
|
|
17
16
|
|
|
18
17
|
export class Client {
|
|
19
18
|
private readonly creator: Writer;
|
|
@@ -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 { toArray } from "@synnaxlabs/x";
|
|
10
|
+
import { toArray } from "@synnaxlabs/x/toArray";
|
|
11
11
|
import { z } from "zod";
|
|
12
12
|
|
|
13
13
|
export const keyZ = z.string().uuid();
|
|
@@ -42,6 +42,22 @@ describe("Ontology", () => {
|
|
|
42
42
|
expect(parents.length).toEqual(1);
|
|
43
43
|
expect(parents[0].name).toEqual(name);
|
|
44
44
|
});
|
|
45
|
+
});
|
|
46
|
+
describe("page", () => {
|
|
47
|
+
it("should return a page of resources", async () => {
|
|
48
|
+
for (let i = 0; i < 10; i++)
|
|
49
|
+
await client.ontology.groups.create(ontology.Root, randomName());
|
|
50
|
+
const page = await client.ontology.page(0, 5);
|
|
51
|
+
expect(page.length).toEqual(5);
|
|
52
|
+
const page2 = await client.ontology.page(5, 5);
|
|
53
|
+
expect(page2.length).toEqual(5);
|
|
54
|
+
const page1Keys = page.map((r) => r.key);
|
|
55
|
+
const page2Keys = page2.map((r) => r.key);
|
|
56
|
+
const intersection = page1Keys.filter((key) => page2Keys.includes(key));
|
|
57
|
+
expect(intersection.length).toEqual(0);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
describe("write", () => {
|
|
45
61
|
test("add children", async () => {
|
|
46
62
|
const name = randomName();
|
|
47
63
|
const g = await client.ontology.groups.create(ontology.Root, name);
|
package/src/ontology/payload.ts
CHANGED
|
@@ -7,8 +7,16 @@
|
|
|
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 { change } from "@synnaxlabs/x";
|
|
10
11
|
import { z } from "zod";
|
|
11
12
|
|
|
13
|
+
export type ResourceChange = change.Change<ID, Resource>;
|
|
14
|
+
export type ResourceSet = change.Set<ID, Resource>;
|
|
15
|
+
export type ResourceDelete = change.Delete<ID, Resource>;
|
|
16
|
+
export type RelationshipChange = change.Change<Relationship, undefined>;
|
|
17
|
+
export type RelationshipSet = change.Set<Relationship, undefined>;
|
|
18
|
+
export type RelationshipDelete = change.Delete<Relationship, undefined>;
|
|
19
|
+
|
|
12
20
|
const resourceTypeZ = z.union([
|
|
13
21
|
z.literal("label"),
|
|
14
22
|
z.literal("builtin"),
|
|
@@ -20,24 +28,22 @@ const resourceTypeZ = z.union([
|
|
|
20
28
|
z.literal("range-alias"),
|
|
21
29
|
z.literal("user"),
|
|
22
30
|
z.literal("workspace"),
|
|
23
|
-
z.literal("
|
|
31
|
+
z.literal("schematic"),
|
|
24
32
|
z.literal("lineplot"),
|
|
25
|
-
z.literal("rack")
|
|
33
|
+
z.literal("rack"),
|
|
34
|
+
z.literal("device"),
|
|
35
|
+
z.literal("task"),
|
|
26
36
|
]);
|
|
27
37
|
|
|
28
38
|
export type ResourceType = z.infer<typeof resourceTypeZ>;
|
|
29
39
|
|
|
30
|
-
export const idZ = z.object({
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
});
|
|
40
|
+
export const idZ = z.object({ type: resourceTypeZ, key: z.string() });
|
|
41
|
+
|
|
42
|
+
export type IDPayload = z.infer<typeof idZ>;
|
|
34
43
|
|
|
35
44
|
export const stringIDZ = z.string().transform((v) => {
|
|
36
45
|
const [type, key] = v.split(":");
|
|
37
|
-
return {
|
|
38
|
-
type: type as ResourceType,
|
|
39
|
-
key,
|
|
40
|
-
};
|
|
46
|
+
return { type: type as ResourceType, key };
|
|
41
47
|
});
|
|
42
48
|
|
|
43
49
|
export const crudeIDZ = z.union([stringIDZ, idZ]);
|
|
@@ -93,8 +99,8 @@ export const resourceSchemaZ = z
|
|
|
93
99
|
.object({
|
|
94
100
|
id: ID.z,
|
|
95
101
|
name: z.string(),
|
|
96
|
-
schema: schemaZ.optional(),
|
|
97
|
-
data: z.record(z.unknown()).optional(),
|
|
102
|
+
schema: schemaZ.optional().nullable(),
|
|
103
|
+
data: z.record(z.unknown()).optional().nullable(),
|
|
98
104
|
})
|
|
99
105
|
.transform((resource) => {
|
|
100
106
|
return {
|
|
@@ -103,7 +109,10 @@ export const resourceSchemaZ = z
|
|
|
103
109
|
};
|
|
104
110
|
});
|
|
105
111
|
|
|
106
|
-
export type Resource =
|
|
112
|
+
export type Resource<T extends {} = {}> = Omit<
|
|
113
|
+
z.output<typeof resourceSchemaZ>,
|
|
114
|
+
"data"
|
|
115
|
+
> & { data?: T | null };
|
|
107
116
|
|
|
108
117
|
export const relationshipSchemaZ = z.object({
|
|
109
118
|
from: ID.z,
|
package/src/ranger/active.ts
CHANGED
|
@@ -43,9 +43,9 @@ export class Active {
|
|
|
43
43
|
async setActive(range: Key): Promise<void> {
|
|
44
44
|
await sendRequired<typeof setActiveReqZ, typeof setActiveResZ>(
|
|
45
45
|
this.client,
|
|
46
|
-
SET_ENDPOINT,
|
|
47
|
-
{ range },
|
|
48
|
-
setActiveReqZ,
|
|
46
|
+
SET_ENDPOINT,
|
|
47
|
+
{ range },
|
|
48
|
+
setActiveReqZ,
|
|
49
49
|
setActiveResZ,
|
|
50
50
|
);
|
|
51
51
|
}
|
|
@@ -65,8 +65,8 @@ export class Active {
|
|
|
65
65
|
async clearActive(range: Key): Promise<void> {
|
|
66
66
|
await sendRequired<typeof clearActiveReqZ, typeof clearActiveResZ>(
|
|
67
67
|
this.client,
|
|
68
|
-
CLEAR_ENDPOINT,
|
|
69
|
-
{ range },
|
|
68
|
+
CLEAR_ENDPOINT,
|
|
69
|
+
{ range },
|
|
70
70
|
clearActiveReqZ,
|
|
71
71
|
clearActiveResZ,
|
|
72
72
|
);
|
package/src/ranger/alias.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// included in the file licenses/APL.txt.
|
|
9
9
|
|
|
10
10
|
import { sendRequired, type UnaryClient } from "@synnaxlabs/freighter";
|
|
11
|
-
import { type change } from "@synnaxlabs/x";
|
|
11
|
+
import { type change } from "@synnaxlabs/x/change";
|
|
12
12
|
import { z } from "zod";
|
|
13
13
|
|
|
14
14
|
import { type channel } from "@/channel";
|
|
@@ -133,7 +133,7 @@ export class Aliaser {
|
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
async openChangeTracker(): Promise<signals.Observable<string, Alias>> {
|
|
136
|
-
return await signals.
|
|
136
|
+
return await signals.openObservable<string, Alias>(
|
|
137
137
|
this.frameClient,
|
|
138
138
|
ALIAS_SET_NAME,
|
|
139
139
|
ALIAS_DELETE_NAME,
|
package/src/ranger/client.ts
CHANGED
|
@@ -7,11 +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 UnaryClient } from "@synnaxlabs/freighter";
|
|
11
|
-
import { type AsyncTermSearcher
|
|
10
|
+
import { sendRequired, type UnaryClient } from "@synnaxlabs/freighter";
|
|
11
|
+
import { type AsyncTermSearcher } from "@synnaxlabs/x/search";
|
|
12
|
+
import { toArray } from "@synnaxlabs/x/toArray";
|
|
12
13
|
|
|
13
14
|
import { type Retriever as ChannelRetriever } from "@/channel/retriever";
|
|
14
|
-
import { QueryError } from "@/errors";
|
|
15
|
+
import { MultipleFoundError, NotFoundError, QueryError } from "@/errors";
|
|
15
16
|
import { type framer } from "@/framer";
|
|
16
17
|
import { type label } from "@/label";
|
|
17
18
|
import { Active } from "@/ranger/active";
|
|
@@ -26,14 +27,34 @@ import {
|
|
|
26
27
|
type Params,
|
|
27
28
|
type Payload,
|
|
28
29
|
analyzeParams,
|
|
30
|
+
payloadZ,
|
|
31
|
+
keyZ,
|
|
29
32
|
} from "@/ranger/payload";
|
|
30
33
|
import { Range } from "@/ranger/range";
|
|
31
|
-
import { type Retriever } from "@/ranger/retriever";
|
|
32
34
|
import { type Writer } from "@/ranger/writer";
|
|
35
|
+
import { signals } from "@/signals";
|
|
36
|
+
import { z } from "zod";
|
|
37
|
+
import { CrudeTimeRange, TimeRange } from "@synnaxlabs/x";
|
|
38
|
+
import { nullableArrayZ } from "@/util/zod";
|
|
39
|
+
|
|
40
|
+
const retrieveReqZ = z.object({
|
|
41
|
+
keys: keyZ.array().optional(),
|
|
42
|
+
names: z.array(z.string()).optional(),
|
|
43
|
+
term: z.string().optional(),
|
|
44
|
+
overlapsWith: TimeRange.z.optional(),
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
export type RetrieveRequest = z.infer<typeof retrieveReqZ>;
|
|
48
|
+
|
|
49
|
+
const RETRIEVE_ENDPOINT = "/range/retrieve";
|
|
50
|
+
|
|
51
|
+
const retrieveResZ = z.object({
|
|
52
|
+
ranges: nullableArrayZ(payloadZ),
|
|
53
|
+
});
|
|
33
54
|
|
|
34
55
|
export class Client implements AsyncTermSearcher<string, Key, Range> {
|
|
56
|
+
readonly type: string = "range";
|
|
35
57
|
private readonly frameClient: framer.Client;
|
|
36
|
-
private readonly retriever: Retriever;
|
|
37
58
|
private readonly writer: Writer;
|
|
38
59
|
private readonly unaryClient: UnaryClient;
|
|
39
60
|
private readonly channels: ChannelRetriever;
|
|
@@ -42,14 +63,12 @@ export class Client implements AsyncTermSearcher<string, Key, Range> {
|
|
|
42
63
|
|
|
43
64
|
constructor(
|
|
44
65
|
frameClient: framer.Client,
|
|
45
|
-
retriever: Retriever,
|
|
46
66
|
writer: Writer,
|
|
47
67
|
unary: UnaryClient,
|
|
48
68
|
channels: ChannelRetriever,
|
|
49
69
|
labelClient: label.Client,
|
|
50
70
|
) {
|
|
51
71
|
this.frameClient = frameClient;
|
|
52
|
-
this.retriever = retriever;
|
|
53
72
|
this.writer = writer;
|
|
54
73
|
this.unaryClient = unary;
|
|
55
74
|
this.channels = channels;
|
|
@@ -76,25 +95,42 @@ export class Client implements AsyncTermSearcher<string, Key, Range> {
|
|
|
76
95
|
}
|
|
77
96
|
|
|
78
97
|
async search(term: string): Promise<Range[]> {
|
|
79
|
-
return this.sugar(await this.
|
|
98
|
+
return this.sugar(await this.execRetrieve({ term }));
|
|
80
99
|
}
|
|
81
100
|
|
|
82
101
|
async page(offset: number, limit: number): Promise<Range[]> {
|
|
83
102
|
return [];
|
|
84
103
|
}
|
|
85
104
|
|
|
105
|
+
async retrieve(range: CrudeTimeRange): Promise<Range[]>;
|
|
106
|
+
|
|
86
107
|
async retrieve(range: Key | Name): Promise<Range>;
|
|
87
108
|
|
|
88
|
-
async retrieve(
|
|
109
|
+
async retrieve(range: Keys | Names): Promise<Range[]>;
|
|
110
|
+
|
|
111
|
+
async retrieve(params: Params | CrudeTimeRange): Promise<Range | Range[]> {
|
|
112
|
+
if (typeof params === "object" && "start" in params)
|
|
113
|
+
return await this.execRetrieve({ overlapsWith: new TimeRange(params) });
|
|
114
|
+
const { single, actual, variant, normalized } = analyzeParams(params);
|
|
115
|
+
const ranges = await this.execRetrieve({ [variant]: normalized });
|
|
116
|
+
if (!single) return ranges;
|
|
117
|
+
if (ranges.length === 0)
|
|
118
|
+
throw new NotFoundError(`range matching ${actual} not found`);
|
|
119
|
+
if (ranges.length > 1)
|
|
120
|
+
throw new MultipleFoundError(`multiple ranges matching ${actual} found`);
|
|
121
|
+
return ranges[0];
|
|
122
|
+
}
|
|
89
123
|
|
|
90
|
-
async
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
124
|
+
private async execRetrieve(req: RetrieveRequest): Promise<Range[]> {
|
|
125
|
+
return this.sugar(
|
|
126
|
+
await sendRequired<typeof retrieveReqZ, typeof retrieveResZ>(
|
|
127
|
+
this.unaryClient,
|
|
128
|
+
RETRIEVE_ENDPOINT,
|
|
129
|
+
req,
|
|
130
|
+
retrieveReqZ,
|
|
131
|
+
retrieveResZ,
|
|
132
|
+
).then((res) => res.ranges),
|
|
133
|
+
);
|
|
98
134
|
}
|
|
99
135
|
|
|
100
136
|
async setActive(range: Key): Promise<void> {
|
|
@@ -117,6 +153,7 @@ export class Client implements AsyncTermSearcher<string, Key, Range> {
|
|
|
117
153
|
payload.name,
|
|
118
154
|
payload.timeRange,
|
|
119
155
|
payload.key,
|
|
156
|
+
payload.color,
|
|
120
157
|
this.frameClient,
|
|
121
158
|
new KV(payload.key, this.unaryClient),
|
|
122
159
|
new Aliaser(payload.key, this.frameClient, this.unaryClient),
|
|
@@ -125,4 +162,18 @@ export class Client implements AsyncTermSearcher<string, Key, Range> {
|
|
|
125
162
|
);
|
|
126
163
|
});
|
|
127
164
|
}
|
|
165
|
+
|
|
166
|
+
async openTracker(): Promise<signals.Observable<string, Range>> {
|
|
167
|
+
return await signals.openObservable<string, Range>(
|
|
168
|
+
this.frameClient,
|
|
169
|
+
"sy_range_set",
|
|
170
|
+
"sy_range_delete",
|
|
171
|
+
(variant, data) => {
|
|
172
|
+
if (variant === "delete")
|
|
173
|
+
return data.toStrings().map((k) => ({ variant, key: k, value: undefined }));
|
|
174
|
+
const sugared = this.sugar(data.parseJSON(payloadZ));
|
|
175
|
+
return sugared.map((r) => ({ variant, key: r.key, value: r }));
|
|
176
|
+
},
|
|
177
|
+
);
|
|
178
|
+
}
|
|
128
179
|
}
|
package/src/ranger/external.ts
CHANGED
package/src/ranger/kv.ts
CHANGED
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
// included in the file licenses/APL.txt.
|
|
9
9
|
|
|
10
10
|
import { type UnaryClient, sendRequired } from "@synnaxlabs/freighter";
|
|
11
|
-
import { isObject
|
|
11
|
+
import { isObject } from "@synnaxlabs/x/identity";
|
|
12
|
+
import { toArray } from "@synnaxlabs/x/toArray";
|
|
12
13
|
import { z } from "zod";
|
|
13
14
|
|
|
14
15
|
import { type Key, keyZ } from "@/ranger/payload";
|
|
@@ -65,6 +66,10 @@ export class KV {
|
|
|
65
66
|
return Array.isArray(keys) ? res.pairs : res.pairs[keys];
|
|
66
67
|
}
|
|
67
68
|
|
|
69
|
+
async list(): Promise<Record<string, string>> {
|
|
70
|
+
return this.get([]);
|
|
71
|
+
}
|
|
72
|
+
|
|
68
73
|
async set(key: string, value: string): Promise<void>;
|
|
69
74
|
|
|
70
75
|
async set(kv: Record<string, string>): Promise<void>;
|
package/src/ranger/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 { TimeRange
|
|
10
|
+
import { TimeRange } from "@synnaxlabs/x/telem";
|
|
11
|
+
import { toArray } from "@synnaxlabs/x/toArray";
|
|
11
12
|
import { z } from "zod";
|
|
12
13
|
|
|
13
14
|
export const keyZ = z.string().uuid();
|
|
@@ -21,6 +22,7 @@ export const payloadZ = z.object({
|
|
|
21
22
|
key: keyZ,
|
|
22
23
|
name: z.string().min(1),
|
|
23
24
|
timeRange: TimeRange.z,
|
|
25
|
+
color: z.string().optional(),
|
|
24
26
|
});
|
|
25
27
|
export type Payload = z.infer<typeof payloadZ>;
|
|
26
28
|
|
|
@@ -29,7 +31,7 @@ export const newPayloadZ = payloadZ.extend({
|
|
|
29
31
|
});
|
|
30
32
|
export type NewPayload = z.infer<typeof newPayloadZ>;
|
|
31
33
|
|
|
32
|
-
export type
|
|
34
|
+
export type ParamAnalysisResult =
|
|
33
35
|
| {
|
|
34
36
|
single: true;
|
|
35
37
|
variant: "keys";
|
|
@@ -55,7 +57,7 @@ export type ParamAnalsysisResult =
|
|
|
55
57
|
actual: Names;
|
|
56
58
|
};
|
|
57
59
|
|
|
58
|
-
export const analyzeParams = (params: Params):
|
|
60
|
+
export const analyzeParams = (params: Params): ParamAnalysisResult => {
|
|
59
61
|
const normal = toArray(params) as Keys | Names;
|
|
60
62
|
if (normal.length === 0) {
|
|
61
63
|
throw new Error("Range params must not be empty");
|
|
@@ -66,5 +68,5 @@ export const analyzeParams = (params: Params): ParamAnalsysisResult => {
|
|
|
66
68
|
variant: isKey ? "keys" : "names",
|
|
67
69
|
normalized: normal,
|
|
68
70
|
actual: params,
|
|
69
|
-
} as const as
|
|
71
|
+
} as const as ParamAnalysisResult;
|
|
70
72
|
};
|