@synnaxlabs/client 0.43.1 → 0.44.2

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.
Files changed (245) hide show
  1. package/.turbo/turbo-build.log +7 -7
  2. package/dist/access/payload.d.ts +1 -1
  3. package/dist/access/payload.d.ts.map +1 -1
  4. package/dist/access/policy/client.d.ts +263 -6
  5. package/dist/access/policy/client.d.ts.map +1 -1
  6. package/dist/access/policy/external.d.ts +0 -1
  7. package/dist/access/policy/external.d.ts.map +1 -1
  8. package/dist/access/policy/payload.d.ts +105 -93
  9. package/dist/access/policy/payload.d.ts.map +1 -1
  10. package/dist/auth/auth.d.ts +1 -1
  11. package/dist/auth/auth.d.ts.map +1 -1
  12. package/dist/channel/client.d.ts +23 -17
  13. package/dist/channel/client.d.ts.map +1 -1
  14. package/dist/channel/payload.d.ts +151 -21
  15. package/dist/channel/payload.d.ts.map +1 -1
  16. package/dist/channel/retriever.d.ts +9 -16
  17. package/dist/channel/retriever.d.ts.map +1 -1
  18. package/dist/channel/writer.d.ts +1 -1
  19. package/dist/channel/writer.d.ts.map +1 -1
  20. package/dist/client.cjs +27 -135
  21. package/dist/client.d.ts +3 -3
  22. package/dist/client.d.ts.map +1 -1
  23. package/dist/client.js +8657 -28963
  24. package/dist/connection/checker.d.ts +1 -1
  25. package/dist/connection/checker.d.ts.map +1 -1
  26. package/dist/control/client.d.ts +1 -0
  27. package/dist/control/client.d.ts.map +1 -1
  28. package/dist/control/state.d.ts +6 -6
  29. package/dist/control/state.d.ts.map +1 -1
  30. package/dist/errors.d.ts +18 -5
  31. package/dist/errors.d.ts.map +1 -1
  32. package/dist/framer/adapter.d.ts +3 -3
  33. package/dist/framer/adapter.d.ts.map +1 -1
  34. package/dist/framer/client.d.ts +4 -13
  35. package/dist/framer/client.d.ts.map +1 -1
  36. package/dist/framer/codec.d.ts +1 -1
  37. package/dist/framer/codec.d.ts.map +1 -1
  38. package/dist/framer/deleter.d.ts +5 -5
  39. package/dist/framer/deleter.d.ts.map +1 -1
  40. package/dist/framer/frame.d.ts +5 -7
  41. package/dist/framer/frame.d.ts.map +1 -1
  42. package/dist/framer/streamProxy.d.ts +1 -1
  43. package/dist/framer/streamProxy.d.ts.map +1 -1
  44. package/dist/framer/streamer.d.ts +235 -20
  45. package/dist/framer/streamer.d.ts.map +1 -1
  46. package/dist/framer/writer.d.ts +302 -33
  47. package/dist/framer/writer.d.ts.map +1 -1
  48. package/dist/hardware/device/client.d.ts +49 -28
  49. package/dist/hardware/device/client.d.ts.map +1 -1
  50. package/dist/hardware/device/payload.d.ts +126 -46
  51. package/dist/hardware/device/payload.d.ts.map +1 -1
  52. package/dist/hardware/rack/client.d.ts +78 -22
  53. package/dist/hardware/rack/client.d.ts.map +1 -1
  54. package/dist/hardware/rack/payload.d.ts +99 -56
  55. package/dist/hardware/rack/payload.d.ts.map +1 -1
  56. package/dist/hardware/task/client.d.ts +100 -41
  57. package/dist/hardware/task/client.d.ts.map +1 -1
  58. package/dist/hardware/task/payload.d.ts +83 -61
  59. package/dist/hardware/task/payload.d.ts.map +1 -1
  60. package/dist/index.d.ts +2 -2
  61. package/dist/index.d.ts.map +1 -1
  62. package/dist/label/client.d.ts +138 -20
  63. package/dist/label/client.d.ts.map +1 -1
  64. package/dist/label/external.d.ts +0 -2
  65. package/dist/label/external.d.ts.map +1 -1
  66. package/dist/label/payload.d.ts +4 -5
  67. package/dist/label/payload.d.ts.map +1 -1
  68. package/dist/ontology/client.d.ts +45 -135
  69. package/dist/ontology/client.d.ts.map +1 -1
  70. package/dist/ontology/group/group.d.ts +3 -3
  71. package/dist/ontology/group/group.d.ts.map +1 -1
  72. package/dist/ontology/group/payload.d.ts +3 -27
  73. package/dist/ontology/group/payload.d.ts.map +1 -1
  74. package/dist/ontology/payload.d.ts +114 -243
  75. package/dist/ontology/payload.d.ts.map +1 -1
  76. package/dist/ontology/writer.d.ts +4 -4
  77. package/dist/ontology/writer.d.ts.map +1 -1
  78. package/dist/ranger/alias.d.ts +15 -5
  79. package/dist/ranger/alias.d.ts.map +1 -1
  80. package/dist/ranger/client.d.ts +91 -30
  81. package/dist/ranger/client.d.ts.map +1 -1
  82. package/dist/ranger/external.d.ts +1 -1
  83. package/dist/ranger/external.d.ts.map +1 -1
  84. package/dist/ranger/kv.d.ts +11 -12
  85. package/dist/ranger/kv.d.ts.map +1 -1
  86. package/dist/ranger/payload.d.ts +19 -44
  87. package/dist/ranger/payload.d.ts.map +1 -1
  88. package/dist/ranger/writer.d.ts +22 -19
  89. package/dist/ranger/writer.d.ts.map +1 -1
  90. package/dist/testutil/client.d.ts +4 -0
  91. package/dist/testutil/client.d.ts.map +1 -0
  92. package/dist/user/client.d.ts +59 -6
  93. package/dist/user/client.d.ts.map +1 -1
  94. package/dist/user/payload.d.ts +4 -6
  95. package/dist/user/payload.d.ts.map +1 -1
  96. package/dist/user/retriever.d.ts +2 -2
  97. package/dist/user/retriever.d.ts.map +1 -1
  98. package/dist/util/decodeJSONString.d.ts +2 -2
  99. package/dist/util/decodeJSONString.d.ts.map +1 -1
  100. package/dist/util/parseWithoutKeyConversion.d.ts +2 -2
  101. package/dist/util/parseWithoutKeyConversion.d.ts.map +1 -1
  102. package/dist/util/retrieve.d.ts +1 -1
  103. package/dist/util/retrieve.d.ts.map +1 -1
  104. package/dist/util/zod.d.ts +1 -1
  105. package/dist/util/zod.d.ts.map +1 -1
  106. package/dist/workspace/client.d.ts +17 -6
  107. package/dist/workspace/client.d.ts.map +1 -1
  108. package/dist/workspace/lineplot/client.d.ts +2 -2
  109. package/dist/workspace/lineplot/client.d.ts.map +1 -1
  110. package/dist/workspace/lineplot/payload.d.ts +8 -9
  111. package/dist/workspace/lineplot/payload.d.ts.map +1 -1
  112. package/dist/workspace/log/client.d.ts +2 -2
  113. package/dist/workspace/log/client.d.ts.map +1 -1
  114. package/dist/workspace/log/payload.d.ts +8 -9
  115. package/dist/workspace/log/payload.d.ts.map +1 -1
  116. package/dist/workspace/payload.d.ts +10 -11
  117. package/dist/workspace/payload.d.ts.map +1 -1
  118. package/dist/workspace/schematic/client.d.ts +2 -2
  119. package/dist/workspace/schematic/client.d.ts.map +1 -1
  120. package/dist/workspace/schematic/payload.d.ts +10 -11
  121. package/dist/workspace/schematic/payload.d.ts.map +1 -1
  122. package/dist/workspace/table/client.d.ts +2 -2
  123. package/dist/workspace/table/client.d.ts.map +1 -1
  124. package/dist/workspace/table/payload.d.ts +10 -11
  125. package/dist/workspace/table/payload.d.ts.map +1 -1
  126. package/examples/node/package-lock.json +47 -39
  127. package/examples/node/package.json +2 -1
  128. package/examples/node/streamWrite.js +5 -11
  129. package/package.json +14 -13
  130. package/src/access/payload.ts +1 -1
  131. package/src/access/policy/client.ts +87 -32
  132. package/src/access/policy/external.ts +0 -1
  133. package/src/access/policy/payload.ts +4 -4
  134. package/src/access/policy/policy.spec.ts +86 -83
  135. package/src/auth/auth.spec.ts +29 -18
  136. package/src/auth/auth.ts +1 -1
  137. package/src/channel/batchRetriever.spec.ts +4 -9
  138. package/src/channel/channel.spec.ts +24 -6
  139. package/src/channel/client.ts +52 -51
  140. package/src/channel/payload.ts +15 -16
  141. package/src/channel/retriever.ts +26 -41
  142. package/src/channel/writer.ts +7 -4
  143. package/src/client.ts +4 -4
  144. package/src/connection/checker.ts +1 -1
  145. package/src/connection/connection.spec.ts +31 -23
  146. package/src/control/client.ts +2 -2
  147. package/src/control/state.spec.ts +3 -3
  148. package/src/control/state.ts +1 -1
  149. package/src/errors.spec.ts +9 -5
  150. package/src/errors.ts +28 -15
  151. package/src/framer/adapter.spec.ts +118 -9
  152. package/src/framer/adapter.ts +24 -11
  153. package/src/framer/client.spec.ts +125 -2
  154. package/src/framer/client.ts +41 -47
  155. package/src/framer/codec.ts +1 -1
  156. package/src/framer/deleter.spec.ts +2 -2
  157. package/src/framer/deleter.ts +1 -1
  158. package/src/framer/frame.ts +1 -4
  159. package/src/framer/iterator.spec.ts +8 -8
  160. package/src/framer/iterator.ts +1 -1
  161. package/src/framer/streamProxy.ts +1 -1
  162. package/src/framer/streamer.spec.ts +185 -36
  163. package/src/framer/streamer.ts +28 -36
  164. package/src/framer/writer.spec.ts +7 -6
  165. package/src/framer/writer.ts +97 -111
  166. package/src/hardware/device/client.ts +45 -131
  167. package/src/hardware/device/device.spec.ts +163 -52
  168. package/src/hardware/device/payload.ts +10 -21
  169. package/src/hardware/rack/client.ts +87 -105
  170. package/src/hardware/rack/payload.ts +4 -13
  171. package/src/hardware/rack/rack.spec.ts +28 -35
  172. package/src/hardware/task/client.ts +335 -291
  173. package/src/hardware/task/payload.ts +86 -62
  174. package/src/hardware/task/task.spec.ts +208 -32
  175. package/src/index.ts +2 -1
  176. package/src/label/client.ts +100 -95
  177. package/src/label/external.ts +0 -2
  178. package/src/label/label.spec.ts +8 -6
  179. package/src/label/payload.ts +3 -4
  180. package/src/ontology/client.ts +41 -324
  181. package/src/ontology/group/group.spec.ts +2 -2
  182. package/src/ontology/group/group.ts +4 -5
  183. package/src/ontology/group/payload.ts +2 -25
  184. package/src/ontology/group/writer.ts +1 -1
  185. package/src/ontology/ontology.spec.ts +355 -41
  186. package/src/ontology/payload.ts +77 -112
  187. package/src/ontology/writer.ts +8 -17
  188. package/src/ranger/alias.ts +45 -37
  189. package/src/ranger/client.ts +144 -149
  190. package/src/ranger/external.ts +1 -1
  191. package/src/ranger/kv.ts +9 -27
  192. package/src/ranger/payload.ts +23 -37
  193. package/src/ranger/ranger.spec.ts +37 -56
  194. package/src/ranger/writer.ts +1 -1
  195. package/src/{signals/index.ts → testutil/client.ts} +11 -1
  196. package/src/user/client.ts +122 -47
  197. package/src/user/payload.ts +2 -5
  198. package/src/user/retriever.ts +1 -1
  199. package/src/user/user.spec.ts +31 -31
  200. package/src/user/writer.ts +1 -1
  201. package/src/util/decodeJSONString.ts +3 -3
  202. package/src/util/parseWithoutKeyConversion.ts +2 -2
  203. package/src/util/retrieve.ts +1 -1
  204. package/src/util/zod.ts +1 -1
  205. package/src/workspace/client.ts +20 -36
  206. package/src/workspace/lineplot/client.ts +5 -7
  207. package/src/workspace/lineplot/lineplot.spec.ts +2 -2
  208. package/src/workspace/lineplot/payload.ts +4 -7
  209. package/src/workspace/log/client.ts +5 -7
  210. package/src/workspace/log/log.spec.ts +2 -2
  211. package/src/workspace/log/payload.ts +4 -7
  212. package/src/workspace/payload.ts +4 -7
  213. package/src/workspace/schematic/client.ts +5 -7
  214. package/src/workspace/schematic/payload.ts +4 -7
  215. package/src/workspace/schematic/schematic.spec.ts +2 -2
  216. package/src/workspace/table/client.ts +5 -7
  217. package/src/workspace/table/payload.ts +4 -7
  218. package/src/workspace/table/table.spec.ts +2 -2
  219. package/src/workspace/workspace.spec.ts +2 -2
  220. package/dist/access/policy/ontology.d.ts +0 -5
  221. package/dist/access/policy/ontology.d.ts.map +0 -1
  222. package/dist/access/policy/retriever.d.ts +0 -40
  223. package/dist/access/policy/retriever.d.ts.map +0 -1
  224. package/dist/access/policy/writer.d.ts +0 -9
  225. package/dist/access/policy/writer.d.ts.map +0 -1
  226. package/dist/label/retriever.d.ts +0 -14
  227. package/dist/label/retriever.d.ts.map +0 -1
  228. package/dist/label/writer.d.ts +0 -54
  229. package/dist/label/writer.d.ts.map +0 -1
  230. package/dist/setupspecs.d.ts +0 -5
  231. package/dist/setupspecs.d.ts.map +0 -1
  232. package/dist/signals/external.d.ts +0 -2
  233. package/dist/signals/external.d.ts.map +0 -1
  234. package/dist/signals/index.d.ts +0 -2
  235. package/dist/signals/index.d.ts.map +0 -1
  236. package/dist/signals/observable.d.ts +0 -12
  237. package/dist/signals/observable.d.ts.map +0 -1
  238. package/src/access/policy/ontology.ts +0 -17
  239. package/src/access/policy/retriever.ts +0 -44
  240. package/src/access/policy/writer.ts +0 -65
  241. package/src/label/retriever.ts +0 -63
  242. package/src/label/writer.ts +0 -95
  243. package/src/setupspecs.ts +0 -27
  244. package/src/signals/external.ts +0 -10
  245. package/src/signals/observable.ts +0 -42
@@ -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, observe, strings } from "@synnaxlabs/x";
12
- import { type AsyncTermSearcher } from "@synnaxlabs/x/search";
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 CrudeID,
20
- ID,
21
- type IDPayload,
18
+ type ID,
19
+ idToString,
22
20
  idZ,
23
- parseRelationship,
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
- term: z.string().optional(),
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<RetrieveRequest, "includeSchema" | "excludeFieldData" | "types"> {}
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 implements AsyncTermSearcher<string, string, Resource> {
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: CrudeID, options?: RetrieveOptions): Promise<Resource>;
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: CrudeID[], options?: RetrieveOptions): Promise<Resource[]>;
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: CrudeID | CrudeID[],
91
+ ids: ID | ID[] | string | string[] | RetrieveRequest,
116
92
  options?: RetrieveOptions,
117
93
  ): Promise<Resource | Resource[]> {
118
- const resources = await this.execRetrieve({ ids: parseIDs(ids), ...options });
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
- array.toArray(ids).map((id) => new ID(id).toString()),
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: CrudeID | CrudeID[],
116
+ ids: ID | ID[],
158
117
  options?: RetrieveOptions,
159
118
  ): Promise<Resource[]> {
160
- return await this.execRetrieve({ ids: parseIDs(ids), children: true, ...options });
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: CrudeID | CrudeID[],
136
+ ids: ID | ID[],
176
137
  options?: RetrieveOptions,
177
138
  ): Promise<Resource[]> {
178
- return await this.execRetrieve({ ids: parseIDs(ids), parents: true, ...options });
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: CrudeID, ...children: CrudeID[]): Promise<void> {
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: CrudeID, ...children: CrudeID[]): Promise<void> {
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 { newClient } from "@/setupspecs";
14
+ import { createTestClient } from "@/testutil/client";
15
15
 
16
- const client = newClient();
16
+ const client = createTestClient();
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 Key, type Name, ONTOLOGY_TYPE } from "@/ontology/group/payload";
11
- import { ID as OntologyID } from "@/ontology/payload";
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(): OntologyID {
22
+ get ontologyID(): ontology.ID {
23
23
  return ontologyID(this.key);
24
24
  }
25
25
  }
26
26
 
27
- export const ontologyID = (key: Key): OntologyID =>
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 { array } from "@synnaxlabs/x/array";
11
- import { z } from "zod/v4";
10
+ import { z } from "zod";
12
11
 
13
- export const keyZ = z.string().uuid();
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;
@@ -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 { z } from "zod/v4";
11
+ import { z } from "zod";
12
12
 
13
13
  import {
14
14
  groupZ,