@synnaxlabs/client 0.43.0 → 0.44.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +7 -7
- package/dist/access/payload.d.ts +1 -1
- package/dist/access/payload.d.ts.map +1 -1
- package/dist/access/policy/client.d.ts +263 -6
- package/dist/access/policy/client.d.ts.map +1 -1
- package/dist/access/policy/external.d.ts +0 -1
- package/dist/access/policy/external.d.ts.map +1 -1
- package/dist/access/policy/payload.d.ts +105 -93
- package/dist/access/policy/payload.d.ts.map +1 -1
- package/dist/auth/auth.d.ts +1 -1
- package/dist/auth/auth.d.ts.map +1 -1
- package/dist/channel/client.d.ts +12 -13
- package/dist/channel/client.d.ts.map +1 -1
- package/dist/channel/payload.d.ts +77 -19
- package/dist/channel/payload.d.ts.map +1 -1
- package/dist/channel/retriever.d.ts +9 -16
- package/dist/channel/retriever.d.ts.map +1 -1
- package/dist/channel/writer.d.ts +1 -1
- package/dist/channel/writer.d.ts.map +1 -1
- package/dist/client.cjs +27 -135
- package/dist/client.d.ts +3 -3
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +8619 -28938
- package/dist/connection/checker.d.ts +1 -1
- package/dist/connection/checker.d.ts.map +1 -1
- package/dist/control/client.d.ts +1 -0
- package/dist/control/client.d.ts.map +1 -1
- package/dist/control/state.d.ts +6 -6
- package/dist/control/state.d.ts.map +1 -1
- package/dist/errors.d.ts +18 -5
- package/dist/errors.d.ts.map +1 -1
- package/dist/framer/adapter.d.ts +3 -3
- package/dist/framer/adapter.d.ts.map +1 -1
- package/dist/framer/client.d.ts +4 -13
- package/dist/framer/client.d.ts.map +1 -1
- package/dist/framer/codec.d.ts +1 -1
- package/dist/framer/codec.d.ts.map +1 -1
- package/dist/framer/deleter.d.ts +5 -5
- package/dist/framer/deleter.d.ts.map +1 -1
- package/dist/framer/frame.d.ts +5 -7
- package/dist/framer/frame.d.ts.map +1 -1
- package/dist/framer/streamProxy.d.ts +1 -1
- package/dist/framer/streamProxy.d.ts.map +1 -1
- package/dist/framer/streamer.d.ts +139 -20
- package/dist/framer/streamer.d.ts.map +1 -1
- package/dist/framer/writer.d.ts +222 -33
- package/dist/framer/writer.d.ts.map +1 -1
- package/dist/hardware/device/client.d.ts +49 -28
- package/dist/hardware/device/client.d.ts.map +1 -1
- package/dist/hardware/device/payload.d.ts +126 -46
- package/dist/hardware/device/payload.d.ts.map +1 -1
- package/dist/hardware/rack/client.d.ts +78 -22
- package/dist/hardware/rack/client.d.ts.map +1 -1
- package/dist/hardware/rack/payload.d.ts +99 -56
- package/dist/hardware/rack/payload.d.ts.map +1 -1
- package/dist/hardware/task/client.d.ts +100 -41
- package/dist/hardware/task/client.d.ts.map +1 -1
- package/dist/hardware/task/payload.d.ts +83 -61
- package/dist/hardware/task/payload.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/label/client.d.ts +138 -20
- package/dist/label/client.d.ts.map +1 -1
- package/dist/label/external.d.ts +0 -2
- package/dist/label/external.d.ts.map +1 -1
- package/dist/label/payload.d.ts +4 -5
- package/dist/label/payload.d.ts.map +1 -1
- package/dist/ontology/client.d.ts +45 -135
- package/dist/ontology/client.d.ts.map +1 -1
- package/dist/ontology/group/group.d.ts +3 -3
- package/dist/ontology/group/group.d.ts.map +1 -1
- package/dist/ontology/group/payload.d.ts +3 -27
- package/dist/ontology/group/payload.d.ts.map +1 -1
- package/dist/ontology/payload.d.ts +113 -243
- package/dist/ontology/payload.d.ts.map +1 -1
- package/dist/ontology/writer.d.ts +4 -4
- package/dist/ontology/writer.d.ts.map +1 -1
- package/dist/ranger/alias.d.ts +11 -5
- package/dist/ranger/alias.d.ts.map +1 -1
- package/dist/ranger/client.d.ts +87 -30
- 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 +10 -12
- package/dist/ranger/kv.d.ts.map +1 -1
- package/dist/ranger/payload.d.ts +23 -44
- package/dist/ranger/payload.d.ts.map +1 -1
- package/dist/ranger/writer.d.ts +22 -19
- package/dist/ranger/writer.d.ts.map +1 -1
- package/dist/testutil/client.d.ts +4 -0
- package/dist/testutil/client.d.ts.map +1 -0
- package/dist/user/client.d.ts +59 -6
- package/dist/user/client.d.ts.map +1 -1
- package/dist/user/payload.d.ts +4 -6
- package/dist/user/payload.d.ts.map +1 -1
- package/dist/user/retriever.d.ts +2 -2
- package/dist/user/retriever.d.ts.map +1 -1
- package/dist/util/decodeJSONString.d.ts +2 -2
- package/dist/util/decodeJSONString.d.ts.map +1 -1
- package/dist/util/parseWithoutKeyConversion.d.ts +2 -2
- package/dist/util/parseWithoutKeyConversion.d.ts.map +1 -1
- package/dist/util/retrieve.d.ts +1 -1
- package/dist/util/retrieve.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/client.d.ts +17 -6
- package/dist/workspace/client.d.ts.map +1 -1
- package/dist/workspace/lineplot/client.d.ts +2 -2
- package/dist/workspace/lineplot/client.d.ts.map +1 -1
- package/dist/workspace/lineplot/payload.d.ts +8 -9
- package/dist/workspace/lineplot/payload.d.ts.map +1 -1
- package/dist/workspace/log/client.d.ts +2 -2
- package/dist/workspace/log/client.d.ts.map +1 -1
- package/dist/workspace/log/payload.d.ts +8 -9
- package/dist/workspace/log/payload.d.ts.map +1 -1
- package/dist/workspace/payload.d.ts +10 -11
- package/dist/workspace/payload.d.ts.map +1 -1
- package/dist/workspace/schematic/client.d.ts +2 -2
- package/dist/workspace/schematic/client.d.ts.map +1 -1
- package/dist/workspace/schematic/payload.d.ts +10 -11
- package/dist/workspace/schematic/payload.d.ts.map +1 -1
- package/dist/workspace/table/client.d.ts +2 -2
- package/dist/workspace/table/client.d.ts.map +1 -1
- package/dist/workspace/table/payload.d.ts +10 -11
- package/dist/workspace/table/payload.d.ts.map +1 -1
- package/examples/node/package-lock.json +47 -39
- package/examples/node/package.json +2 -1
- package/examples/node/streamWrite.js +5 -11
- package/package.json +14 -13
- package/src/access/payload.ts +1 -1
- package/src/access/policy/client.ts +87 -32
- package/src/access/policy/external.ts +0 -1
- package/src/access/policy/payload.ts +4 -4
- package/src/access/policy/policy.spec.ts +86 -83
- package/src/auth/auth.spec.ts +29 -18
- package/src/auth/auth.ts +1 -1
- package/src/channel/batchRetriever.spec.ts +4 -9
- package/src/channel/channel.spec.ts +24 -6
- package/src/channel/client.ts +31 -46
- package/src/channel/payload.ts +13 -14
- package/src/channel/retriever.ts +26 -41
- package/src/channel/writer.ts +3 -3
- package/src/client.ts +4 -4
- package/src/connection/checker.ts +1 -1
- package/src/connection/connection.spec.ts +31 -23
- package/src/control/client.ts +2 -2
- package/src/control/state.spec.ts +3 -3
- package/src/control/state.ts +1 -1
- package/src/errors.spec.ts +9 -5
- package/src/errors.ts +28 -15
- package/src/framer/adapter.spec.ts +118 -9
- package/src/framer/adapter.ts +24 -11
- package/src/framer/client.spec.ts +125 -2
- package/src/framer/client.ts +41 -47
- package/src/framer/codec.ts +1 -1
- package/src/framer/deleter.spec.ts +2 -2
- package/src/framer/deleter.ts +1 -1
- package/src/framer/frame.ts +1 -4
- package/src/framer/iterator.spec.ts +8 -8
- package/src/framer/iterator.ts +1 -1
- package/src/framer/streamProxy.ts +1 -1
- package/src/framer/streamer.spec.ts +185 -36
- package/src/framer/streamer.ts +28 -36
- package/src/framer/writer.spec.ts +6 -6
- package/src/framer/writer.ts +97 -111
- package/src/hardware/device/client.ts +45 -131
- package/src/hardware/device/device.spec.ts +163 -52
- package/src/hardware/device/payload.ts +10 -21
- package/src/hardware/rack/client.ts +87 -105
- package/src/hardware/rack/payload.ts +4 -13
- package/src/hardware/rack/rack.spec.ts +28 -35
- package/src/hardware/task/client.ts +335 -291
- package/src/hardware/task/payload.ts +86 -62
- package/src/hardware/task/task.spec.ts +208 -32
- package/src/index.ts +2 -1
- package/src/label/client.ts +100 -95
- package/src/label/external.ts +0 -2
- package/src/label/label.spec.ts +8 -6
- package/src/label/payload.ts +3 -4
- package/src/ontology/client.ts +41 -324
- package/src/ontology/group/group.spec.ts +2 -2
- package/src/ontology/group/group.ts +4 -5
- package/src/ontology/group/payload.ts +2 -25
- package/src/ontology/group/writer.ts +1 -1
- package/src/ontology/ontology.spec.ts +355 -41
- package/src/ontology/payload.ts +74 -112
- package/src/ontology/writer.ts +8 -17
- package/src/ranger/alias.ts +19 -37
- package/src/ranger/client.ts +118 -150
- package/src/ranger/external.ts +9 -1
- package/src/ranger/kv.ts +6 -27
- package/src/ranger/payload.ts +21 -37
- package/src/ranger/ranger.spec.ts +37 -56
- package/src/ranger/writer.ts +1 -1
- package/src/{signals/index.ts → testutil/client.ts} +11 -1
- package/src/user/client.ts +122 -47
- package/src/user/payload.ts +2 -5
- package/src/user/retriever.ts +1 -1
- package/src/user/user.spec.ts +31 -31
- package/src/user/writer.ts +1 -1
- package/src/util/decodeJSONString.ts +3 -3
- package/src/util/parseWithoutKeyConversion.ts +2 -2
- package/src/util/retrieve.ts +1 -1
- package/src/util/zod.ts +1 -1
- package/src/workspace/client.ts +20 -36
- package/src/workspace/lineplot/client.ts +5 -7
- package/src/workspace/lineplot/lineplot.spec.ts +2 -2
- package/src/workspace/lineplot/payload.ts +4 -7
- package/src/workspace/log/client.ts +5 -7
- package/src/workspace/log/log.spec.ts +2 -2
- package/src/workspace/log/payload.ts +4 -7
- package/src/workspace/payload.ts +4 -7
- package/src/workspace/schematic/client.ts +5 -7
- package/src/workspace/schematic/payload.ts +4 -7
- package/src/workspace/schematic/schematic.spec.ts +2 -2
- package/src/workspace/table/client.ts +5 -7
- package/src/workspace/table/payload.ts +4 -7
- package/src/workspace/table/table.spec.ts +2 -2
- package/src/workspace/workspace.spec.ts +2 -2
- package/dist/access/policy/ontology.d.ts +0 -5
- package/dist/access/policy/ontology.d.ts.map +0 -1
- package/dist/access/policy/retriever.d.ts +0 -40
- package/dist/access/policy/retriever.d.ts.map +0 -1
- package/dist/access/policy/writer.d.ts +0 -9
- package/dist/access/policy/writer.d.ts.map +0 -1
- package/dist/label/retriever.d.ts +0 -14
- package/dist/label/retriever.d.ts.map +0 -1
- package/dist/label/writer.d.ts +0 -54
- package/dist/label/writer.d.ts.map +0 -1
- package/dist/setupspecs.d.ts +0 -5
- package/dist/setupspecs.d.ts.map +0 -1
- package/dist/signals/external.d.ts +0 -2
- package/dist/signals/external.d.ts.map +0 -1
- package/dist/signals/index.d.ts +0 -2
- package/dist/signals/index.d.ts.map +0 -1
- package/dist/signals/observable.d.ts +0 -12
- package/dist/signals/observable.d.ts.map +0 -1
- package/src/access/policy/ontology.ts +0 -17
- package/src/access/policy/retriever.ts +0 -44
- package/src/access/policy/writer.ts +0 -65
- package/src/label/retriever.ts +0 -63
- package/src/label/writer.ts +0 -95
- package/src/setupspecs.ts +0 -27
- package/src/signals/external.ts +0 -10
- package/src/signals/observable.ts +0 -42
package/src/ontology/client.ts
CHANGED
|
@@ -8,23 +8,18 @@
|
|
|
8
8
|
// included in the file licenses/APL.txt.
|
|
9
9
|
|
|
10
10
|
import { sendRequired, type UnaryClient } from "@synnaxlabs/freighter";
|
|
11
|
-
import { array,
|
|
12
|
-
import {
|
|
13
|
-
import { z } from "zod/v4";
|
|
11
|
+
import { array, strings } from "@synnaxlabs/x";
|
|
12
|
+
import { z } from "zod";
|
|
14
13
|
|
|
15
14
|
import { QueryError } from "@/errors";
|
|
16
15
|
import { type framer } from "@/framer";
|
|
17
16
|
import { group } from "@/ontology/group";
|
|
18
17
|
import {
|
|
19
|
-
type
|
|
20
|
-
|
|
21
|
-
type IDPayload,
|
|
18
|
+
type ID,
|
|
19
|
+
idToString,
|
|
22
20
|
idZ,
|
|
23
|
-
|
|
24
|
-
type RelationshipChange,
|
|
25
|
-
type RelationshipDirection,
|
|
21
|
+
parseIDs,
|
|
26
22
|
type Resource,
|
|
27
|
-
type ResourceChange,
|
|
28
23
|
resourceTypeZ,
|
|
29
24
|
resourceZ,
|
|
30
25
|
} from "@/ontology/payload";
|
|
@@ -36,25 +31,24 @@ const retrieveReqZ = z.object({
|
|
|
36
31
|
ids: idZ.array().optional(),
|
|
37
32
|
children: z.boolean().optional(),
|
|
38
33
|
parents: z.boolean().optional(),
|
|
39
|
-
includeSchema: z.boolean().optional(),
|
|
40
34
|
excludeFieldData: z.boolean().optional(),
|
|
41
|
-
|
|
35
|
+
searchTerm: z.string().optional(),
|
|
42
36
|
limit: z.number().optional(),
|
|
43
37
|
offset: z.number().optional(),
|
|
44
38
|
types: resourceTypeZ.array().optional(),
|
|
45
39
|
});
|
|
46
|
-
interface RetrieveRequest extends z.infer<typeof retrieveReqZ> {}
|
|
40
|
+
export interface RetrieveRequest extends z.infer<typeof retrieveReqZ> {}
|
|
47
41
|
|
|
48
42
|
export interface RetrieveOptions
|
|
49
|
-
extends Pick<
|
|
43
|
+
extends Pick<
|
|
44
|
+
RetrieveRequest,
|
|
45
|
+
"excludeFieldData" | "types" | "children" | "parents"
|
|
46
|
+
> {}
|
|
50
47
|
|
|
51
48
|
const retrieveResZ = z.object({ resources: resourceZ.array() });
|
|
52
49
|
|
|
53
|
-
export const parseIDs = (ids: CrudeID | CrudeID[] | string | string[]): IDPayload[] =>
|
|
54
|
-
array.toArray(ids).map((id) => new ID(id).payload);
|
|
55
|
-
|
|
56
50
|
/** The core client class for executing queries against a Synnax cluster ontology */
|
|
57
|
-
export class Client
|
|
51
|
+
export class Client {
|
|
58
52
|
readonly type: string = "ontology";
|
|
59
53
|
groups: group.Client;
|
|
60
54
|
private readonly client: UnaryClient;
|
|
@@ -68,96 +62,65 @@ export class Client implements AsyncTermSearcher<string, string, Resource> {
|
|
|
68
62
|
this.framer = framer;
|
|
69
63
|
}
|
|
70
64
|
|
|
71
|
-
/**
|
|
72
|
-
* Executes a fuzzy search on the ontology for resources with names/fields similar to the
|
|
73
|
-
* given term.
|
|
74
|
-
*
|
|
75
|
-
* @param term The search term.
|
|
76
|
-
* @param options Additional options for the search.
|
|
77
|
-
* @param options.includeSchema Whether to include the schema of the resources in the
|
|
78
|
-
* results.
|
|
79
|
-
* @param options.excludeFieldData Whether to exclude the field data of the resources in
|
|
80
|
-
* the results.
|
|
81
|
-
* @returns A list of resources that match the search term.
|
|
82
|
-
*/
|
|
83
|
-
async search(term: string, options?: RetrieveOptions): Promise<Resource[]> {
|
|
84
|
-
return await this.execRetrieve({ term, ...options });
|
|
85
|
-
}
|
|
86
|
-
|
|
87
65
|
/**
|
|
88
66
|
* Retrieves the resource in the ontology with the given ID.
|
|
89
67
|
* @param id - The ID of the resource to retrieve.
|
|
90
68
|
* @param options - Additional options for the retrieval.
|
|
91
|
-
* @param options.includeSchema - Whether to include the schema of the resource in the
|
|
92
|
-
* results.
|
|
93
69
|
* @param options.excludeFieldData - Whether to exclude the field data of the resource
|
|
94
70
|
* in the results.
|
|
95
71
|
* @returns The resource with the given ID.
|
|
96
72
|
* @throws {QueryError} If no resource is found with the given ID.
|
|
97
73
|
*/
|
|
98
|
-
async retrieve(id:
|
|
74
|
+
async retrieve(id: ID | string, options?: RetrieveOptions): Promise<Resource>;
|
|
99
75
|
|
|
100
76
|
/**
|
|
101
77
|
* Retrieves the resources in the ontology with the given IDs.
|
|
102
78
|
*
|
|
103
79
|
* @param ids - The IDs of the resources to retrieve.
|
|
104
80
|
* @param options - Additional options for the retrieval.
|
|
105
|
-
* @param options.includeSchema - Whether to include the schema of the resources in
|
|
106
|
-
* the results.
|
|
107
81
|
* @param options.excludeFieldData - Whether to exclude the field data of the
|
|
108
82
|
* resources in the results.
|
|
109
83
|
* @returns The resources with the given IDs.
|
|
110
84
|
* @throws {QueryError} If no resource is found with any of the given IDs.
|
|
111
85
|
*/
|
|
112
|
-
async retrieve(ids:
|
|
86
|
+
async retrieve(ids: ID[] | string[], options?: RetrieveOptions): Promise<Resource[]>;
|
|
87
|
+
|
|
88
|
+
async retrieve(params: RetrieveRequest): Promise<Resource[]>;
|
|
113
89
|
|
|
114
90
|
async retrieve(
|
|
115
|
-
ids:
|
|
91
|
+
ids: ID | ID[] | string | string[] | RetrieveRequest,
|
|
116
92
|
options?: RetrieveOptions,
|
|
117
93
|
): Promise<Resource | Resource[]> {
|
|
118
|
-
|
|
94
|
+
if (!Array.isArray(ids) && typeof ids === "object" && !("key" in ids))
|
|
95
|
+
return this.execRetrieve(ids);
|
|
96
|
+
const parsedIDs = parseIDs(ids);
|
|
97
|
+
const resources = await this.execRetrieve({ ids: parsedIDs, ...options });
|
|
119
98
|
if (Array.isArray(ids)) return resources;
|
|
120
99
|
if (resources.length === 0)
|
|
121
100
|
throw new QueryError(
|
|
122
101
|
`No resource found with ID ${strings.naturalLanguageJoin(
|
|
123
|
-
|
|
102
|
+
parsedIDs.map((id) => idToString(id)),
|
|
124
103
|
)}`,
|
|
125
104
|
);
|
|
126
105
|
return resources[0];
|
|
127
106
|
}
|
|
128
107
|
|
|
129
|
-
/**
|
|
130
|
-
* Retrieves resources from the ontology in a paginated manner.
|
|
131
|
-
*
|
|
132
|
-
* @param offset - The offset of the page (i.e. how many resources to skip before
|
|
133
|
-
* returning results).
|
|
134
|
-
* @param limit - The maximum number of resources to return.
|
|
135
|
-
* @param options - Additional options for the retrieval.
|
|
136
|
-
* @returns A list of resources in the ontology.
|
|
137
|
-
*/
|
|
138
|
-
async page(
|
|
139
|
-
offset: number,
|
|
140
|
-
limit: number,
|
|
141
|
-
options?: RetrieveOptions,
|
|
142
|
-
): Promise<Resource[]> {
|
|
143
|
-
return await this.execRetrieve({ offset, limit, ...options });
|
|
144
|
-
}
|
|
145
|
-
|
|
146
108
|
/**
|
|
147
109
|
* Retrieves the children of the resources with the given IDs.
|
|
148
110
|
* @param ids - The IDs of the resources whose children to retrieve.
|
|
149
111
|
* @param options - Additional options for the retrieval.
|
|
150
|
-
* @param options.includeSchema - Whether to include the schema of the children in the
|
|
151
|
-
* results.
|
|
152
|
-
* @param options.excludeFieldData - Whether to exclude the field data of the children in
|
|
153
112
|
* the results.
|
|
154
113
|
* @returns The children of the resources with the given IDs.
|
|
155
114
|
*/
|
|
156
115
|
async retrieveChildren(
|
|
157
|
-
ids:
|
|
116
|
+
ids: ID | ID[],
|
|
158
117
|
options?: RetrieveOptions,
|
|
159
118
|
): Promise<Resource[]> {
|
|
160
|
-
return await this.execRetrieve({
|
|
119
|
+
return await this.execRetrieve({
|
|
120
|
+
ids: array.toArray(ids),
|
|
121
|
+
children: true,
|
|
122
|
+
...options,
|
|
123
|
+
});
|
|
161
124
|
}
|
|
162
125
|
|
|
163
126
|
/**
|
|
@@ -165,17 +128,19 @@ export class Client implements AsyncTermSearcher<string, string, Resource> {
|
|
|
165
128
|
*
|
|
166
129
|
* @param ids - the IDs of the resources whose parents to retrieve
|
|
167
130
|
* @param options - additional options for the retrieval
|
|
168
|
-
* @param options.includeSchema - whether to include the schema of the parents in the
|
|
169
|
-
* results
|
|
170
131
|
* @param options.excludeFieldData - whether to exclude the field data of the parents
|
|
171
132
|
* in the results
|
|
172
133
|
* @returns the parents of the resources with the given IDs
|
|
173
134
|
*/
|
|
174
135
|
async retrieveParents(
|
|
175
|
-
ids:
|
|
136
|
+
ids: ID | ID[],
|
|
176
137
|
options?: RetrieveOptions,
|
|
177
138
|
): Promise<Resource[]> {
|
|
178
|
-
return await this.execRetrieve({
|
|
139
|
+
return await this.execRetrieve({
|
|
140
|
+
ids: array.toArray(ids),
|
|
141
|
+
parents: true,
|
|
142
|
+
...options,
|
|
143
|
+
});
|
|
179
144
|
}
|
|
180
145
|
|
|
181
146
|
/**
|
|
@@ -183,7 +148,7 @@ export class Client implements AsyncTermSearcher<string, string, Resource> {
|
|
|
183
148
|
* @param id - The ID of the resource to add children to.
|
|
184
149
|
* @param children - The IDs of the children to add.
|
|
185
150
|
*/
|
|
186
|
-
async addChildren(id:
|
|
151
|
+
async addChildren(id: ID, ...children: ID[]): Promise<void> {
|
|
187
152
|
return await this.writer.addChildren(id, ...children);
|
|
188
153
|
}
|
|
189
154
|
|
|
@@ -192,7 +157,7 @@ export class Client implements AsyncTermSearcher<string, string, Resource> {
|
|
|
192
157
|
* @param id - The ID of the resource to remove children from.
|
|
193
158
|
* @param children - The IDs of the children to remove.
|
|
194
159
|
*/
|
|
195
|
-
async removeChildren(id:
|
|
160
|
+
async removeChildren(id: ID, ...children: ID[]): Promise<void> {
|
|
196
161
|
return await this.writer.removeChildren(id, ...children);
|
|
197
162
|
}
|
|
198
163
|
|
|
@@ -202,41 +167,10 @@ export class Client implements AsyncTermSearcher<string, string, Resource> {
|
|
|
202
167
|
* @param to - The ID of the resource to move children to.
|
|
203
168
|
* @param children - The IDs of the children to move.
|
|
204
169
|
*/
|
|
205
|
-
async moveChildren(
|
|
206
|
-
from: CrudeID,
|
|
207
|
-
to: CrudeID,
|
|
208
|
-
...children: CrudeID[]
|
|
209
|
-
): Promise<void> {
|
|
170
|
+
async moveChildren(from: ID, to: ID, ...children: ID[]): Promise<void> {
|
|
210
171
|
return await this.writer.moveChildren(from, to, ...children);
|
|
211
172
|
}
|
|
212
173
|
|
|
213
|
-
/**
|
|
214
|
-
* Opens an observable that can be used to subscribe to changes in both the ontology's
|
|
215
|
-
* resources and relationships.
|
|
216
|
-
* @link ChangeTracker for more information.
|
|
217
|
-
* @returns An observable that emits changes to the ontology's resources and relationships.
|
|
218
|
-
*/
|
|
219
|
-
async openChangeTracker(): Promise<ChangeTracker> {
|
|
220
|
-
return await ChangeTracker.open(this.framer, this);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
async openDependentTracker(
|
|
224
|
-
props: DependentTrackerProps,
|
|
225
|
-
): Promise<observe.ObservableAsyncCloseable<Resource[]>> {
|
|
226
|
-
return await DependentTracker.open(props, this.framer, this);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
newSearcherWithOptions(
|
|
230
|
-
options: RetrieveOptions,
|
|
231
|
-
): AsyncTermSearcher<string, string, Resource> {
|
|
232
|
-
return {
|
|
233
|
-
type: this.type,
|
|
234
|
-
search: (term: string) => this.search(term, options),
|
|
235
|
-
retrieve: (ids: string[]) => this.retrieve(ids, options),
|
|
236
|
-
page: (offset: number, limit: number) => this.page(offset, limit, options),
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
|
-
|
|
240
174
|
private async execRetrieve(request: RetrieveRequest): Promise<Resource[]> {
|
|
241
175
|
const { resources } = await sendRequired(
|
|
242
176
|
this.client,
|
|
@@ -249,224 +183,7 @@ export class Client implements AsyncTermSearcher<string, string, Resource> {
|
|
|
249
183
|
}
|
|
250
184
|
}
|
|
251
185
|
|
|
252
|
-
const RESOURCE_SET_CHANNEL_NAME = "sy_ontology_resource_set";
|
|
253
|
-
const RESOURCE_DELETE_CHANNEL_NAME = "sy_ontology_resource_delete";
|
|
254
|
-
const RELATIONSHIP_SET_CHANNEL_NAME = "sy_ontology_relationship_set";
|
|
255
|
-
const RELATIONSHIP_DELETE_CHANNEL_NAME = "sy_ontology_relationship_delete";
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* A class that tracks changes to the ontology's resources and relationships.
|
|
259
|
-
*/
|
|
260
|
-
export class ChangeTracker {
|
|
261
|
-
/**
|
|
262
|
-
* An observable that emits changes to the ontology's relationships.
|
|
263
|
-
*/
|
|
264
|
-
readonly relationships: observe.Observable<RelationshipChange[]>;
|
|
265
|
-
/**
|
|
266
|
-
* An observable that emits changes to the ontology's resources.
|
|
267
|
-
*/
|
|
268
|
-
readonly resources: observe.Observable<ResourceChange[]>;
|
|
269
|
-
|
|
270
|
-
private readonly resourceObs: observe.Observer<ResourceChange[]>;
|
|
271
|
-
private readonly relationshipObs: observe.Observer<RelationshipChange[]>;
|
|
272
|
-
private readonly streamer: framer.Streamer;
|
|
273
|
-
private readonly client: Client;
|
|
274
|
-
private readonly closePromise: Promise<void>;
|
|
275
|
-
|
|
276
|
-
constructor(streamer: framer.Streamer, client: Client) {
|
|
277
|
-
this.relationshipObs = new observe.Observer<RelationshipChange[]>();
|
|
278
|
-
this.relationships = this.relationshipObs;
|
|
279
|
-
this.resourceObs = new observe.Observer<ResourceChange[]>();
|
|
280
|
-
this.resources = this.resourceObs;
|
|
281
|
-
this.client = client;
|
|
282
|
-
this.streamer = streamer;
|
|
283
|
-
this.closePromise = this.start();
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
async close(): Promise<void> {
|
|
287
|
-
this.streamer.close();
|
|
288
|
-
await this.closePromise;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
private async start(): Promise<void> {
|
|
292
|
-
for await (const frame of this.streamer) await this.update(frame);
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
private async update(frame: framer.Frame): Promise<void> {
|
|
296
|
-
const resSets = await this.parseResourceSets(frame);
|
|
297
|
-
const resDeletes = this.parseResourceDeletes(frame);
|
|
298
|
-
const allResources = resSets.concat(resDeletes);
|
|
299
|
-
if (allResources.length > 0) this.resourceObs.notify(resSets.concat(resDeletes));
|
|
300
|
-
const relSets = this.parseRelationshipSets(frame);
|
|
301
|
-
const relDeletes = this.parseRelationshipDeletes(frame);
|
|
302
|
-
const allRelationships = relSets.concat(relDeletes);
|
|
303
|
-
if (allRelationships.length > 0)
|
|
304
|
-
this.relationshipObs.notify(relSets.concat(relDeletes));
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
private parseRelationshipSets(frame: framer.Frame): RelationshipChange[] {
|
|
308
|
-
const relationships = frame.get(RELATIONSHIP_SET_CHANNEL_NAME);
|
|
309
|
-
if (relationships.length === 0) return [];
|
|
310
|
-
return Array.from(relationships.as("string")).map((rel) => ({
|
|
311
|
-
variant: "set",
|
|
312
|
-
key: parseRelationship(rel),
|
|
313
|
-
value: undefined,
|
|
314
|
-
}));
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
private parseRelationshipDeletes(frame: framer.Frame): RelationshipChange[] {
|
|
318
|
-
const relationships = frame.get(RELATIONSHIP_DELETE_CHANNEL_NAME);
|
|
319
|
-
if (relationships.length === 0) return [];
|
|
320
|
-
return Array.from(relationships.as("string")).map((rel) => ({
|
|
321
|
-
variant: "delete",
|
|
322
|
-
key: parseRelationship(rel),
|
|
323
|
-
}));
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
private async parseResourceSets(frame: framer.Frame): Promise<ResourceChange[]> {
|
|
327
|
-
const sets = frame.get(RESOURCE_SET_CHANNEL_NAME);
|
|
328
|
-
if (sets.length === 0) return [];
|
|
329
|
-
// We should only ever get one series of sets
|
|
330
|
-
const ids = Array.from(sets.as("string")).map((id: string) => new ID(id));
|
|
331
|
-
try {
|
|
332
|
-
const resources = await this.client.retrieve(ids);
|
|
333
|
-
return resources.map((resource) => ({
|
|
334
|
-
variant: "set",
|
|
335
|
-
key: resource.id,
|
|
336
|
-
value: resource,
|
|
337
|
-
}));
|
|
338
|
-
} catch (e) {
|
|
339
|
-
if (e instanceof QueryError) return [];
|
|
340
|
-
throw e;
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
private parseResourceDeletes(frame: framer.Frame): ResourceChange[] {
|
|
345
|
-
const deletes = frame.get(RESOURCE_DELETE_CHANNEL_NAME);
|
|
346
|
-
if (deletes.length === 0) return [];
|
|
347
|
-
// We should only ever get one series of deletes
|
|
348
|
-
return Array.from(deletes.as("string")).map((str) => ({
|
|
349
|
-
variant: "delete",
|
|
350
|
-
key: new ID(str),
|
|
351
|
-
}));
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
static async open(client: framer.Client, retriever: Client): Promise<ChangeTracker> {
|
|
355
|
-
const streamer = await client.openStreamer([
|
|
356
|
-
RESOURCE_SET_CHANNEL_NAME,
|
|
357
|
-
RESOURCE_DELETE_CHANNEL_NAME,
|
|
358
|
-
RELATIONSHIP_SET_CHANNEL_NAME,
|
|
359
|
-
RELATIONSHIP_DELETE_CHANNEL_NAME,
|
|
360
|
-
]);
|
|
361
|
-
return new ChangeTracker(streamer, retriever);
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
const oppositeDirection = (dir: RelationshipDirection): RelationshipDirection =>
|
|
366
|
-
dir === "from" ? "to" : "from";
|
|
367
|
-
|
|
368
|
-
interface DependentTrackerProps {
|
|
369
|
-
target: ID;
|
|
370
|
-
dependents: Resource[];
|
|
371
|
-
relationshipType?: string;
|
|
372
|
-
relationshipDirection?: RelationshipDirection;
|
|
373
|
-
resourceType?: string;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
/**
|
|
377
|
-
* A class that tracks a resource (called the 'target' resource) and related resources
|
|
378
|
-
* (called 'dependents') of a particular type (called the 'type') in a Synnax cluster
|
|
379
|
-
* ontology.
|
|
380
|
-
*/
|
|
381
|
-
export class DependentTracker
|
|
382
|
-
extends observe.Observer<Resource[]>
|
|
383
|
-
implements observe.ObservableAsyncCloseable<Resource[]>
|
|
384
|
-
{
|
|
385
|
-
private readonly internal: ChangeTracker;
|
|
386
|
-
private readonly target: ID;
|
|
387
|
-
private readonly relDir: RelationshipDirection;
|
|
388
|
-
private readonly resourceType?: string;
|
|
389
|
-
private dependents: Resource[];
|
|
390
|
-
private readonly client: Client;
|
|
391
|
-
private readonly relType: string;
|
|
392
|
-
|
|
393
|
-
private constructor(
|
|
394
|
-
{
|
|
395
|
-
target,
|
|
396
|
-
dependents,
|
|
397
|
-
relationshipType = "parent",
|
|
398
|
-
relationshipDirection = "from",
|
|
399
|
-
resourceType,
|
|
400
|
-
}: DependentTrackerProps,
|
|
401
|
-
internal: ChangeTracker,
|
|
402
|
-
client: Client,
|
|
403
|
-
) {
|
|
404
|
-
super();
|
|
405
|
-
this.resourceType = resourceType;
|
|
406
|
-
this.internal = internal;
|
|
407
|
-
this.target = target;
|
|
408
|
-
this.dependents = dependents;
|
|
409
|
-
if (this.resourceType != null)
|
|
410
|
-
this.dependents = this.dependents.filter((r) => r.id.type === this.resourceType);
|
|
411
|
-
this.client = client;
|
|
412
|
-
this.relType = relationshipType;
|
|
413
|
-
this.relDir = relationshipDirection;
|
|
414
|
-
this.internal.resources.onChange(this.handleResourceChange);
|
|
415
|
-
this.internal.relationships.onChange(this.handleRelationshipChange);
|
|
416
|
-
}
|
|
417
|
-
static async open(
|
|
418
|
-
props: DependentTrackerProps,
|
|
419
|
-
framer: framer.Client,
|
|
420
|
-
client: Client,
|
|
421
|
-
): Promise<DependentTracker> {
|
|
422
|
-
const internal = await ChangeTracker.open(framer, client);
|
|
423
|
-
return new DependentTracker(props, internal, client);
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
private handleResourceChange = (changes: ResourceChange[]): void => {
|
|
427
|
-
this.dependents = this.dependents.map((child) => {
|
|
428
|
-
const change = changes.find((c) => c.key.toString() == child.id.toString());
|
|
429
|
-
if (change == null || change.variant === "delete") return child;
|
|
430
|
-
return change.value;
|
|
431
|
-
});
|
|
432
|
-
this.notify(this.dependents);
|
|
433
|
-
};
|
|
434
|
-
|
|
435
|
-
private handleRelationshipChange = (changes: RelationshipChange[]): void => {
|
|
436
|
-
const deletes = changes.filter(
|
|
437
|
-
(c) =>
|
|
438
|
-
c.variant === "delete" &&
|
|
439
|
-
c.key[this.relDir].toString() === this.target.toString() &&
|
|
440
|
-
(this.resourceType == null ||
|
|
441
|
-
c.key[oppositeDirection(this.relDir)].type === this.resourceType),
|
|
442
|
-
);
|
|
443
|
-
this.dependents = this.dependents.filter(
|
|
444
|
-
(child) =>
|
|
445
|
-
!deletes.some(
|
|
446
|
-
(del) =>
|
|
447
|
-
del.key.to.toString() === child.id.toString() &&
|
|
448
|
-
del.key.type === this.relType,
|
|
449
|
-
),
|
|
450
|
-
);
|
|
451
|
-
const sets = changes.filter(
|
|
452
|
-
(c) =>
|
|
453
|
-
c.variant === "set" &&
|
|
454
|
-
c.key.type === this.relType &&
|
|
455
|
-
c.key[this.relDir].toString() === this.target.toString() &&
|
|
456
|
-
(this.resourceType == null ||
|
|
457
|
-
c.key[oppositeDirection(this.relDir)].type === this.resourceType),
|
|
458
|
-
);
|
|
459
|
-
if (sets.length === 0) return this.notify(this.dependents);
|
|
460
|
-
this.client
|
|
461
|
-
.retrieve(sets.map((s) => s.key.to))
|
|
462
|
-
.then((resources) => {
|
|
463
|
-
this.dependents = this.dependents.concat(resources);
|
|
464
|
-
this.notify(this.dependents);
|
|
465
|
-
})
|
|
466
|
-
.catch(console.error);
|
|
467
|
-
};
|
|
468
|
-
|
|
469
|
-
async close(): Promise<void> {
|
|
470
|
-
await this.internal.close();
|
|
471
|
-
}
|
|
472
|
-
}
|
|
186
|
+
export const RESOURCE_SET_CHANNEL_NAME = "sy_ontology_resource_set";
|
|
187
|
+
export const RESOURCE_DELETE_CHANNEL_NAME = "sy_ontology_resource_delete";
|
|
188
|
+
export const RELATIONSHIP_SET_CHANNEL_NAME = "sy_ontology_relationship_set";
|
|
189
|
+
export const RELATIONSHIP_DELETE_CHANNEL_NAME = "sy_ontology_relationship_delete";
|
|
@@ -11,9 +11,9 @@ import { describe, expect, it } from "vitest";
|
|
|
11
11
|
|
|
12
12
|
import { NotFoundError } from "@/errors";
|
|
13
13
|
import { ontology } from "@/ontology";
|
|
14
|
-
import {
|
|
14
|
+
import { newTestClient } from "@/testutil/client";
|
|
15
15
|
|
|
16
|
-
const client =
|
|
16
|
+
const client = newTestClient();
|
|
17
17
|
|
|
18
18
|
describe("Group", () => {
|
|
19
19
|
describe("create", () => {
|
|
@@ -7,8 +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 { type
|
|
11
|
-
import {
|
|
10
|
+
import { type ontology } from "@/ontology";
|
|
11
|
+
import { type Key, type Name } from "@/ontology/group/payload";
|
|
12
12
|
|
|
13
13
|
export class Group {
|
|
14
14
|
key: Key;
|
|
@@ -19,10 +19,9 @@ export class Group {
|
|
|
19
19
|
this.name = name;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
get ontologyID():
|
|
22
|
+
get ontologyID(): ontology.ID {
|
|
23
23
|
return ontologyID(this.key);
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
export const ontologyID = (key: Key):
|
|
28
|
-
new OntologyID({ type: ONTOLOGY_TYPE, key });
|
|
27
|
+
export const ontologyID = (key: Key): ontology.ID => ({ type: "group", key });
|
|
@@ -7,37 +7,14 @@
|
|
|
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
|
-
import { z } from "zod/v4";
|
|
10
|
+
import { z } from "zod";
|
|
12
11
|
|
|
13
|
-
export const keyZ = z.
|
|
12
|
+
export const keyZ = z.uuid();
|
|
14
13
|
export type Key = z.infer<typeof keyZ>;
|
|
15
14
|
export const nameZ = z.string();
|
|
16
15
|
export type Name = z.infer<typeof nameZ>;
|
|
17
16
|
export type Keys = Key[];
|
|
18
17
|
export type Names = Name[];
|
|
19
18
|
export type Params = Key | Name | Keys | Names;
|
|
20
|
-
|
|
21
19
|
export const groupZ = z.object({ key: keyZ, name: nameZ });
|
|
22
20
|
export interface Payload extends z.infer<typeof groupZ> {}
|
|
23
|
-
|
|
24
|
-
export type ParamAnalysisResult =
|
|
25
|
-
| { single: true; variant: "keys"; normalized: Keys; actual: Key }
|
|
26
|
-
| { single: true; variant: "names"; normalized: Names; actual: Name }
|
|
27
|
-
| { single: false; variant: "keys"; normalized: Keys; actual: Keys }
|
|
28
|
-
| { single: false; variant: "names"; normalized: Names; actual: Names };
|
|
29
|
-
|
|
30
|
-
export const analyzeParams = (groups: Params): ParamAnalysisResult => {
|
|
31
|
-
const normal = array.toArray(groups) as Keys | Names;
|
|
32
|
-
if (normal.length === 0) throw new Error("No groups specified");
|
|
33
|
-
const isKey = keyZ.safeParse(normal[0]).success;
|
|
34
|
-
return {
|
|
35
|
-
single: !Array.isArray(groups),
|
|
36
|
-
variant: isKey ? "keys" : "names",
|
|
37
|
-
normalized: normal,
|
|
38
|
-
actual: groups,
|
|
39
|
-
} as ParamAnalysisResult;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export const ONTOLOGY_TYPE = "group";
|
|
43
|
-
export type OntologyType = typeof ONTOLOGY_TYPE;
|