@synnaxlabs/client 0.38.1 → 0.40.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.
Files changed (257) hide show
  1. package/.turbo/turbo-build.log +7 -7
  2. package/dist/access/payload.d.ts +6 -6
  3. package/dist/access/payload.d.ts.map +1 -1
  4. package/dist/access/policy/client.d.ts +5 -3
  5. package/dist/access/policy/client.d.ts.map +1 -1
  6. package/dist/access/policy/external.d.ts +1 -0
  7. package/dist/access/policy/external.d.ts.map +1 -1
  8. package/dist/access/policy/ontology.d.ts +5 -0
  9. package/dist/access/policy/ontology.d.ts.map +1 -0
  10. package/dist/access/policy/payload.d.ts +86 -89
  11. package/dist/access/policy/payload.d.ts.map +1 -1
  12. package/dist/access/policy/retriever.d.ts +7 -6
  13. package/dist/access/policy/retriever.d.ts.map +1 -1
  14. package/dist/access/policy/writer.d.ts +2 -2
  15. package/dist/access/policy/writer.d.ts.map +1 -1
  16. package/dist/auth/auth.d.ts +2 -1
  17. package/dist/auth/auth.d.ts.map +1 -1
  18. package/dist/channel/client.d.ts +6 -5
  19. package/dist/channel/client.d.ts.map +1 -1
  20. package/dist/channel/payload.d.ts +13 -11
  21. package/dist/channel/payload.d.ts.map +1 -1
  22. package/dist/channel/retriever.d.ts +9 -6
  23. package/dist/channel/retriever.d.ts.map +1 -1
  24. package/dist/channel/writer.d.ts +6 -4
  25. package/dist/channel/writer.d.ts.map +1 -1
  26. package/dist/client.cjs +30 -30
  27. package/dist/client.d.ts +4 -2
  28. package/dist/client.d.ts.map +1 -1
  29. package/dist/client.js +3387 -3433
  30. package/dist/connection/checker.d.ts +5 -4
  31. package/dist/connection/checker.d.ts.map +1 -1
  32. package/dist/control/state.d.ts +10 -8
  33. package/dist/control/state.d.ts.map +1 -1
  34. package/dist/errors.d.ts +5 -0
  35. package/dist/errors.d.ts.map +1 -1
  36. package/dist/framer/adapter.d.ts +14 -15
  37. package/dist/framer/adapter.d.ts.map +1 -1
  38. package/dist/framer/client.d.ts +13 -15
  39. package/dist/framer/client.d.ts.map +1 -1
  40. package/dist/framer/deleter.d.ts +3 -2
  41. package/dist/framer/deleter.d.ts.map +1 -1
  42. package/dist/framer/frame.d.ts +31 -27
  43. package/dist/framer/frame.d.ts.map +1 -1
  44. package/dist/framer/iterator.d.ts +4 -5
  45. package/dist/framer/iterator.d.ts.map +1 -1
  46. package/dist/framer/streamer.d.ts +5 -6
  47. package/dist/framer/streamer.d.ts.map +1 -1
  48. package/dist/framer/writer.d.ts +42 -39
  49. package/dist/framer/writer.d.ts.map +1 -1
  50. package/dist/hardware/device/client.d.ts +20 -12
  51. package/dist/hardware/device/client.d.ts.map +1 -1
  52. package/dist/hardware/device/payload.d.ts +19 -16
  53. package/dist/hardware/device/payload.d.ts.map +1 -1
  54. package/dist/hardware/rack/client.d.ts +15 -15
  55. package/dist/hardware/rack/client.d.ts.map +1 -1
  56. package/dist/hardware/rack/payload.d.ts +9 -8
  57. package/dist/hardware/rack/payload.d.ts.map +1 -1
  58. package/dist/hardware/task/client.d.ts +38 -29
  59. package/dist/hardware/task/client.d.ts.map +1 -1
  60. package/dist/hardware/task/payload.d.ts +58 -53
  61. package/dist/hardware/task/payload.d.ts.map +1 -1
  62. package/dist/label/client.d.ts +4 -3
  63. package/dist/label/client.d.ts.map +1 -1
  64. package/dist/label/payload.d.ts +4 -4
  65. package/dist/label/payload.d.ts.map +1 -1
  66. package/dist/label/retriever.d.ts.map +1 -1
  67. package/dist/label/writer.d.ts +13 -10
  68. package/dist/label/writer.d.ts.map +1 -1
  69. package/dist/ontology/client.d.ts +12 -10
  70. package/dist/ontology/client.d.ts.map +1 -1
  71. package/dist/ontology/group/client.d.ts +5 -4
  72. package/dist/ontology/group/client.d.ts.map +1 -1
  73. package/dist/ontology/group/group.d.ts +7 -5
  74. package/dist/ontology/group/group.d.ts.map +1 -1
  75. package/dist/ontology/group/payload.d.ts +6 -5
  76. package/dist/ontology/group/payload.d.ts.map +1 -1
  77. package/dist/ontology/group/writer.d.ts +8 -8
  78. package/dist/ontology/group/writer.d.ts.map +1 -1
  79. package/dist/ontology/payload.d.ts +72 -62
  80. package/dist/ontology/payload.d.ts.map +1 -1
  81. package/dist/ontology/writer.d.ts.map +1 -1
  82. package/dist/ranger/alias.d.ts +9 -10
  83. package/dist/ranger/alias.d.ts.map +1 -1
  84. package/dist/ranger/client.d.ts +18 -18
  85. package/dist/ranger/client.d.ts.map +1 -1
  86. package/dist/ranger/external.d.ts +1 -1
  87. package/dist/ranger/external.d.ts.map +1 -1
  88. package/dist/ranger/kv.d.ts +18 -14
  89. package/dist/ranger/kv.d.ts.map +1 -1
  90. package/dist/ranger/payload.d.ts +13 -13
  91. package/dist/ranger/payload.d.ts.map +1 -1
  92. package/dist/ranger/writer.d.ts +14 -14
  93. package/dist/ranger/writer.d.ts.map +1 -1
  94. package/dist/setupspecs.d.ts.map +1 -1
  95. package/dist/signals/observable.d.ts +3 -1
  96. package/dist/signals/observable.d.ts.map +1 -1
  97. package/dist/user/client.d.ts +5 -3
  98. package/dist/user/client.d.ts.map +1 -1
  99. package/dist/user/payload.d.ts +7 -6
  100. package/dist/user/payload.d.ts.map +1 -1
  101. package/dist/user/retriever.d.ts +2 -1
  102. package/dist/user/retriever.d.ts.map +1 -1
  103. package/dist/user/writer.d.ts +2 -2
  104. package/dist/user/writer.d.ts.map +1 -1
  105. package/dist/util/decodeJSONString.d.ts +3 -0
  106. package/dist/util/decodeJSONString.d.ts.map +1 -0
  107. package/dist/util/parseWithoutKeyConversion.d.ts +3 -0
  108. package/dist/util/parseWithoutKeyConversion.d.ts.map +1 -0
  109. package/dist/util/retrieve.d.ts +1 -1
  110. package/dist/util/retrieve.d.ts.map +1 -1
  111. package/dist/util/telem.d.ts.map +1 -1
  112. package/dist/util/zod.d.ts.map +1 -1
  113. package/dist/workspace/client.d.ts +6 -60
  114. package/dist/workspace/client.d.ts.map +1 -1
  115. package/dist/workspace/external.d.ts +3 -0
  116. package/dist/workspace/external.d.ts.map +1 -0
  117. package/dist/workspace/index.d.ts +1 -1
  118. package/dist/workspace/index.d.ts.map +1 -1
  119. package/dist/workspace/lineplot/client.d.ts +5 -44
  120. package/dist/workspace/lineplot/client.d.ts.map +1 -1
  121. package/dist/workspace/lineplot/external.d.ts +3 -0
  122. package/dist/workspace/lineplot/external.d.ts.map +1 -0
  123. package/dist/workspace/lineplot/index.d.ts +1 -1
  124. package/dist/workspace/lineplot/index.d.ts.map +1 -1
  125. package/dist/workspace/lineplot/payload.d.ts +45 -0
  126. package/dist/workspace/lineplot/payload.d.ts.map +1 -0
  127. package/dist/workspace/log/client.d.ts +5 -44
  128. package/dist/workspace/log/client.d.ts.map +1 -1
  129. package/dist/workspace/log/external.d.ts +3 -0
  130. package/dist/workspace/log/external.d.ts.map +1 -0
  131. package/dist/workspace/log/index.d.ts +1 -1
  132. package/dist/workspace/log/index.d.ts.map +1 -1
  133. package/dist/workspace/log/payload.d.ts +45 -0
  134. package/dist/workspace/log/payload.d.ts.map +1 -0
  135. package/dist/workspace/payload.d.ts +60 -0
  136. package/dist/workspace/payload.d.ts.map +1 -0
  137. package/dist/workspace/schematic/client.d.ts +5 -68
  138. package/dist/workspace/schematic/client.d.ts.map +1 -1
  139. package/dist/workspace/schematic/external.d.ts +3 -0
  140. package/dist/workspace/schematic/external.d.ts.map +1 -0
  141. package/dist/workspace/schematic/index.d.ts +1 -1
  142. package/dist/workspace/schematic/index.d.ts.map +1 -1
  143. package/dist/workspace/schematic/payload.d.ts +71 -0
  144. package/dist/workspace/schematic/payload.d.ts.map +1 -0
  145. package/dist/workspace/table/client.d.ts +5 -57
  146. package/dist/workspace/table/client.d.ts.map +1 -1
  147. package/dist/workspace/table/external.d.ts +3 -0
  148. package/dist/workspace/table/external.d.ts.map +1 -0
  149. package/dist/workspace/table/index.d.ts +1 -1
  150. package/dist/workspace/table/index.d.ts.map +1 -1
  151. package/dist/workspace/table/payload.d.ts +60 -0
  152. package/dist/workspace/table/payload.d.ts.map +1 -0
  153. package/examples/node/basicReadWrite.js +26 -26
  154. package/examples/node/liveStream.js +15 -15
  155. package/examples/node/seriesAndFrames.js +38 -38
  156. package/examples/node/streamWrite.js +47 -45
  157. package/package.json +15 -13
  158. package/src/access/payload.ts +12 -12
  159. package/src/access/policy/client.ts +13 -12
  160. package/src/access/policy/external.ts +1 -0
  161. package/src/access/policy/ontology.ts +17 -0
  162. package/src/access/policy/payload.ts +7 -19
  163. package/src/access/policy/policy.spec.ts +16 -16
  164. package/src/access/policy/retriever.ts +2 -1
  165. package/src/access/policy/writer.ts +4 -4
  166. package/src/auth/auth.spec.ts +27 -23
  167. package/src/auth/auth.ts +7 -11
  168. package/src/channel/batchRetriever.spec.ts +25 -22
  169. package/src/channel/client.ts +19 -21
  170. package/src/channel/payload.ts +16 -20
  171. package/src/channel/retriever.ts +20 -21
  172. package/src/channel/writer.ts +11 -13
  173. package/src/client.ts +6 -16
  174. package/src/connection/checker.ts +9 -11
  175. package/src/connection/connection.spec.ts +17 -5
  176. package/src/control/state.ts +8 -9
  177. package/src/errors.spec.ts +1 -1
  178. package/src/errors.ts +8 -0
  179. package/src/framer/adapter.spec.ts +28 -23
  180. package/src/framer/adapter.ts +37 -41
  181. package/src/framer/client.spec.ts +5 -11
  182. package/src/framer/client.ts +34 -38
  183. package/src/framer/deleter.ts +5 -6
  184. package/src/framer/frame.ts +62 -50
  185. package/src/framer/iterator.ts +11 -16
  186. package/src/framer/streamer.spec.ts +2 -10
  187. package/src/framer/streamer.ts +15 -19
  188. package/src/framer/writer.spec.ts +48 -7
  189. package/src/framer/writer.ts +39 -31
  190. package/src/hardware/device/client.ts +67 -39
  191. package/src/hardware/device/device.spec.ts +91 -33
  192. package/src/hardware/device/payload.ts +29 -28
  193. package/src/hardware/rack/client.ts +52 -65
  194. package/src/hardware/rack/payload.ts +9 -18
  195. package/src/hardware/rack/rack.spec.ts +12 -0
  196. package/src/hardware/task/client.ts +160 -131
  197. package/src/hardware/task/payload.ts +49 -68
  198. package/src/hardware/task/task.spec.ts +98 -81
  199. package/src/label/client.ts +12 -15
  200. package/src/label/payload.ts +3 -9
  201. package/src/label/retriever.ts +3 -7
  202. package/src/label/writer.ts +8 -15
  203. package/src/ontology/client.ts +17 -22
  204. package/src/ontology/group/client.ts +5 -5
  205. package/src/ontology/group/group.spec.ts +4 -4
  206. package/src/ontology/group/group.ts +10 -7
  207. package/src/ontology/group/payload.ts +11 -35
  208. package/src/ontology/group/writer.ts +22 -26
  209. package/src/ontology/ontology.spec.ts +15 -15
  210. package/src/ontology/payload.ts +67 -43
  211. package/src/ontology/writer.ts +16 -23
  212. package/src/ranger/alias.ts +25 -42
  213. package/src/ranger/client.ts +29 -38
  214. package/src/ranger/external.ts +1 -1
  215. package/src/ranger/kv.ts +9 -32
  216. package/src/ranger/payload.ts +14 -36
  217. package/src/ranger/ranger.spec.ts +1 -2
  218. package/src/ranger/writer.ts +8 -26
  219. package/src/signals/observable.ts +3 -4
  220. package/src/user/client.ts +8 -4
  221. package/src/user/payload.ts +5 -9
  222. package/src/user/retriever.ts +1 -1
  223. package/src/user/user.spec.ts +17 -15
  224. package/src/user/writer.ts +3 -10
  225. package/src/util/decodeJSONString.ts +13 -0
  226. package/src/util/parseWithoutKeyConversion.ts +19 -0
  227. package/src/util/retrieve.spec.ts +3 -13
  228. package/src/util/retrieve.ts +2 -12
  229. package/src/util/telem.ts +1 -1
  230. package/src/vite-env.d.ts +1 -0
  231. package/src/workspace/client.ts +30 -57
  232. package/src/workspace/external.ts +11 -0
  233. package/src/workspace/index.ts +1 -1
  234. package/src/workspace/lineplot/client.ts +22 -36
  235. package/src/workspace/lineplot/external.ts +11 -0
  236. package/src/workspace/lineplot/index.ts +1 -1
  237. package/src/workspace/lineplot/linePlot.spec.ts +1 -2
  238. package/src/workspace/lineplot/payload.ts +32 -0
  239. package/src/workspace/log/client.ts +25 -39
  240. package/src/workspace/log/external.ts +11 -0
  241. package/src/workspace/log/index.ts +1 -1
  242. package/src/workspace/log/log.spec.ts +5 -18
  243. package/src/workspace/log/payload.ts +32 -0
  244. package/src/workspace/payload.ts +36 -0
  245. package/src/workspace/schematic/client.ts +30 -56
  246. package/src/workspace/schematic/external.ts +11 -0
  247. package/src/workspace/schematic/index.ts +1 -1
  248. package/src/workspace/schematic/payload.ts +37 -0
  249. package/src/workspace/schematic/schematic.spec.ts +15 -6
  250. package/src/workspace/table/client.ts +27 -50
  251. package/src/workspace/table/external.ts +11 -0
  252. package/src/workspace/table/index.ts +1 -1
  253. package/src/workspace/table/payload.ts +36 -0
  254. package/src/workspace/workspace.spec.ts +1 -2
  255. package/dist/channel/creator.d.ts +0 -9
  256. package/dist/channel/creator.d.ts.map +0 -1
  257. package/src/channel/creator.ts +0 -37
@@ -16,58 +16,65 @@ import { toArray } from "@synnaxlabs/x/toArray";
16
16
  import { z } from "zod";
17
17
 
18
18
  import { framer } from "@/framer";
19
- import { type Frame } from "@/framer/frame";
20
- import { rack } from "@/hardware/rack";
19
+ import { keyZ as rackKeyZ } from "@/hardware/rack/payload";
21
20
  import {
22
21
  type Command,
23
22
  type CommandObservable,
24
23
  commandZ,
25
- type NewTask,
26
- newTaskZ,
27
- ontologyID as payloadOntologyID,
24
+ type Key,
25
+ keyZ,
26
+ type New,
27
+ newZ,
28
+ ONTOLOGY_TYPE,
28
29
  type Payload,
29
30
  type State,
30
31
  type StateObservable,
31
32
  stateZ,
32
- type TaskKey,
33
- taskKeyZ,
34
33
  taskZ,
35
34
  } from "@/hardware/task/payload";
36
- import { type ontology } from "@/ontology";
35
+ import { ontology } from "@/ontology";
37
36
  import { type ranger } from "@/ranger";
38
37
  import { signals } from "@/signals";
39
38
  import { analyzeParams, checkForMultipleOrNoResults } from "@/util/retrieve";
40
39
  import { nullableArrayZ } from "@/util/zod";
41
40
 
42
- const TASK_STATE_CHANNEL = "sy_task_state";
43
- const TASK_CMD_CHANNEL = "sy_task_cmd";
41
+ const STATE_CHANNEL_NAME = "sy_task_state";
42
+ const COMMAND_CHANNEL_NAME = "sy_task_cmd";
43
+ const SET_CHANNEL_NAME = "sy_task_set";
44
+ const DELETE_CHANNEL_NAME = "sy_task_delete";
44
45
 
45
- const TASK_NOT_CREATED = new Error("Task not created");
46
+ const NOT_CREATED_ERROR = new Error("Task not created");
47
+
48
+ const retrieveSnapshottedTo = async (taskKey: Key, ontologyClient: ontology.Client) => {
49
+ const task = await ontologyClient.retrieveParents(taskKey);
50
+ if (task.length === 0) return null;
51
+ return task[0];
52
+ };
46
53
 
47
54
  export class Task<
48
- C extends UnknownRecord = UnknownRecord,
49
- D extends {} = UnknownRecord,
50
- T extends string = string,
55
+ Config extends UnknownRecord = UnknownRecord,
56
+ Details extends {} = UnknownRecord,
57
+ Type extends string = string,
51
58
  > {
52
- readonly key: TaskKey;
59
+ readonly key: Key;
53
60
  name: string;
54
61
  readonly internal: boolean;
55
- readonly type: T;
56
- config: C;
62
+ readonly type: Type;
63
+ config: Config;
57
64
  readonly snapshot: boolean;
58
- state?: State<D>;
65
+ state?: State<Details>;
59
66
  private readonly frameClient: framer.Client | null;
60
67
  private readonly ontologyClient: ontology.Client | null;
61
68
  private readonly rangeClient: ranger.Client | null;
62
69
 
63
70
  constructor(
64
- key: TaskKey,
71
+ key: Key,
65
72
  name: string,
66
- type: T,
67
- config: C,
73
+ type: Type,
74
+ config: Config,
68
75
  internal: boolean = false,
69
76
  snapshot: boolean = false,
70
- state?: State<D> | null,
77
+ state?: State<Details> | null,
71
78
  frameClient: framer.Client | null = null,
72
79
  ontologyClient: ontology.Client | null = null,
73
80
  rangeClient: ranger.Client | null = null,
@@ -84,7 +91,7 @@ export class Task<
84
91
  this.rangeClient = rangeClient;
85
92
  }
86
93
 
87
- get payload(): Payload<C, D> {
94
+ get payload(): Payload<Config, Details, Type> {
88
95
  return {
89
96
  key: this.key,
90
97
  name: this.name,
@@ -96,132 +103,127 @@ export class Task<
96
103
  }
97
104
 
98
105
  get ontologyID(): ontology.ID {
99
- return payloadOntologyID(this.key);
106
+ return ontologyID(this.key);
100
107
  }
101
108
 
102
- async executeCommand(type: string, args?: UnknownRecord): Promise<string> {
103
- if (this.frameClient == null) throw TASK_NOT_CREATED;
104
- const writer = await this.frameClient.openWriter(TASK_CMD_CHANNEL);
105
- const key = id.id();
106
- await writer.write(TASK_CMD_CHANNEL, [{ task: this.key, type, key, args }]);
109
+ async executeCommand<Args>(type: string, args?: Args): Promise<string> {
110
+ if (this.frameClient == null) throw NOT_CREATED_ERROR;
111
+ const writer = await this.frameClient.openWriter(COMMAND_CHANNEL_NAME);
112
+ const key = id.create();
113
+ await writer.write(COMMAND_CHANNEL_NAME, [{ task: this.key, type, key, args }]);
107
114
  await writer.close();
108
115
  return key;
109
116
  }
110
117
 
111
- async executeCommandSync<D extends UnknownRecord = UnknownRecord>(
118
+ async executeCommandSync<Details extends {} = UnknownRecord>(
112
119
  type: string,
113
120
  args: UnknownRecord,
114
121
  timeout: CrudeTimeSpan,
115
- ): Promise<State<D>> {
116
- if (this.frameClient == null) throw TASK_NOT_CREATED;
117
- const streamer = await this.frameClient.openStreamer(TASK_STATE_CHANNEL);
122
+ ): Promise<State<Details>> {
123
+ if (this.frameClient == null) throw NOT_CREATED_ERROR;
124
+ const streamer = await this.frameClient.openStreamer(STATE_CHANNEL_NAME);
118
125
  const cmdKey = await this.executeCommand(type, args);
119
- let res: State<D>;
126
+ let res: State<Details>;
120
127
  const to = new Promise((resolve) =>
121
128
  setTimeout(() => resolve(false), new TimeSpan(timeout).milliseconds),
122
129
  );
123
130
  while (true) {
124
- const frame = (await Promise.any([streamer.read(), to])) as Frame | false;
131
+ const frame = (await Promise.any([streamer.read(), to])) as framer.Frame | false;
125
132
  if (frame === false) throw new Error("Command timed out");
126
133
  const parsed = stateZ.safeParse(frame.at(-1).sy_task_state);
127
134
  if (parsed.success) {
128
- res = parsed.data as State<D>;
135
+ res = parsed.data as State<Details>;
129
136
  if (res.key === cmdKey) break;
130
- } else console.error(parsed.error);
137
+ } else throw parsed.error;
131
138
  }
132
139
  streamer.close();
133
140
  return res;
134
141
  }
135
142
 
136
- async openStateObserver<D extends UnknownRecord = UnknownRecord>(): Promise<
137
- StateObservable<D>
143
+ async openStateObserver<Details extends {} = UnknownRecord>(): Promise<
144
+ StateObservable<Details>
138
145
  > {
139
- if (this.frameClient == null) throw TASK_NOT_CREATED;
140
- return new framer.ObservableStreamer<State<D>>(
141
- await this.frameClient.openStreamer(TASK_STATE_CHANNEL),
146
+ if (this.frameClient == null) throw NOT_CREATED_ERROR;
147
+ return new framer.ObservableStreamer<State<Details>>(
148
+ await this.frameClient.openStreamer(STATE_CHANNEL_NAME),
142
149
  (frame) => {
143
- const s = frame.get(TASK_STATE_CHANNEL);
150
+ const s = frame.get(STATE_CHANNEL_NAME);
144
151
  if (s.length === 0) return [null, false];
145
152
  const parse = stateZ.safeParse(s.at(-1));
146
153
  if (!parse.success) {
147
154
  console.error(parse.error);
148
155
  return [null, false];
149
156
  }
150
- const state = parse.data as State<D>;
157
+ const state = parse.data;
151
158
  if (state.task !== this.key) return [null, false];
152
- return [state, true];
159
+ return [state as State<Details>, true];
153
160
  },
154
161
  );
155
162
  }
156
163
 
157
- async openCommandObserver<A extends UnknownRecord = UnknownRecord>(): Promise<
158
- CommandObservable<A>
164
+ async openCommandObserver<Args extends {} = UnknownRecord>(): Promise<
165
+ CommandObservable<Args>
159
166
  > {
160
- if (this.frameClient == null) throw TASK_NOT_CREATED;
161
- return new framer.ObservableStreamer<Command<A>>(
162
- await this.frameClient.openStreamer(TASK_CMD_CHANNEL),
167
+ if (this.frameClient == null) throw NOT_CREATED_ERROR;
168
+ return new framer.ObservableStreamer<Command<Args>>(
169
+ await this.frameClient.openStreamer(COMMAND_CHANNEL_NAME),
163
170
  (frame) => {
164
- const s = frame.get(TASK_CMD_CHANNEL);
171
+ const s = frame.get(COMMAND_CHANNEL_NAME);
165
172
  if (s.length === 0) return [null, false];
166
173
  const parse = commandZ.safeParse(s.at(-1));
167
174
  if (!parse.success) {
168
175
  console.error(parse.error);
169
176
  return [null, false];
170
177
  }
171
- const cmd = parse.data as Command<A>;
178
+ const cmd = parse.data;
172
179
  if (cmd.task !== this.key) return [null, false];
173
- return [cmd, true];
180
+ return [cmd as Command<Args>, true];
174
181
  },
175
182
  );
176
183
  }
177
184
 
178
185
  async snapshottedTo(): Promise<ontology.Resource | null> {
179
- if (this.ontologyClient == null || this.rangeClient == null) throw TASK_NOT_CREATED;
186
+ if (this.ontologyClient == null || this.rangeClient == null)
187
+ throw NOT_CREATED_ERROR;
180
188
  if (!this.snapshot) return null;
181
- const parents = await this.ontologyClient.retrieveParents(this.ontologyID);
182
- if (parents.length == 0) return null;
183
- return parents[0];
189
+ return await retrieveSnapshottedTo(this.key, this.ontologyClient);
184
190
  }
185
191
  }
186
192
 
187
193
  const retrieveReqZ = z.object({
188
- rack: rack.rackKeyZ.optional(),
189
- keys: z.string().array().optional(),
194
+ rack: rackKeyZ.optional(),
195
+ keys: keyZ.array().optional(),
190
196
  names: z.string().array().optional(),
197
+ types: z.string().array().optional(),
198
+ includeState: z.boolean().optional(),
191
199
  offset: z.number().optional(),
192
200
  limit: z.number().optional(),
193
- includeState: z.boolean().optional(),
194
201
  });
195
202
 
196
- const retrieveResZ = z.object({
197
- tasks: nullableArrayZ(taskZ),
198
- });
203
+ const retrieveResZ = z.object({ tasks: nullableArrayZ(taskZ) });
199
204
 
200
- export type RetrieveRequest = z.infer<typeof retrieveReqZ>;
205
+ export interface RetrieveRequest extends z.infer<typeof retrieveReqZ> {}
201
206
 
202
- export type RetrieveOptions = Pick<
203
- RetrieveRequest,
204
- "rack" | "offset" | "limit" | "includeState"
205
- >;
207
+ export interface RetrieveOptions
208
+ extends Pick<
209
+ RetrieveRequest,
210
+ "rack" | "offset" | "limit" | "includeState" | "types"
211
+ > {}
206
212
 
207
213
  const RETRIEVE_ENDPOINT = "/hardware/task/retrieve";
208
214
  const CREATE_ENDPOINT = "/hardware/task/create";
209
215
  const DELETE_ENDPOINT = "/hardware/task/delete";
210
216
  const COPY_ENDPOINT = "/hardware/task/copy";
211
217
 
212
- const createReqZ = z.object({ tasks: newTaskZ.array() });
218
+ const createReqZ = z.object({ tasks: newZ.array() });
213
219
  const createResZ = z.object({ tasks: taskZ.array() });
214
- const deleteReqZ = z.object({ keys: taskKeyZ.array() });
220
+ const deleteReqZ = z.object({ keys: keyZ.array() });
215
221
  const deleteResZ = z.object({});
216
- const copyReqZ = z.object({
217
- key: taskKeyZ,
218
- name: z.string(),
219
- snapshot: z.boolean(),
220
- });
222
+ const copyReqZ = z.object({ key: keyZ, name: z.string(), snapshot: z.boolean() });
221
223
  const copyResZ = z.object({ task: taskZ });
222
224
 
223
- export class Client implements AsyncTermSearcher<string, TaskKey, Payload> {
224
- readonly type: string = "task";
225
+ export class Client implements AsyncTermSearcher<string, Key, Payload> {
226
+ readonly type: string = ONTOLOGY_TYPE;
225
227
  private readonly client: UnaryClient;
226
228
  private readonly frameClient: framer.Client;
227
229
  private readonly ontologyClient: ontology.Client;
@@ -240,24 +242,24 @@ export class Client implements AsyncTermSearcher<string, TaskKey, Payload> {
240
242
  }
241
243
 
242
244
  async create<
243
- C extends UnknownRecord = UnknownRecord,
244
- D extends {} = UnknownRecord,
245
- T extends string = string,
246
- >(task: NewTask<C, T>): Promise<Task<C, D, T>>;
245
+ Config extends UnknownRecord = UnknownRecord,
246
+ Details extends {} = UnknownRecord,
247
+ Type extends string = string,
248
+ >(task: New<Config, Type>): Promise<Task<Config, Details, Type>>;
247
249
 
248
250
  async create<
249
- C extends UnknownRecord = UnknownRecord,
250
- D extends {} = UnknownRecord,
251
- T extends string = string,
252
- >(tasks: NewTask<C, T>[]): Promise<Task<C, D, T>[]>;
251
+ Config extends UnknownRecord = UnknownRecord,
252
+ Details extends {} = UnknownRecord,
253
+ Type extends string = string,
254
+ >(tasks: New<Config, Type>[]): Promise<Task<Config, Details, Type>[]>;
253
255
 
254
256
  async create<
255
- C extends UnknownRecord = UnknownRecord,
256
- D extends {} = UnknownRecord,
257
- T extends string = string,
257
+ Config extends UnknownRecord = UnknownRecord,
258
+ Details extends {} = UnknownRecord,
259
+ Type extends string = string,
258
260
  >(
259
- task: NewTask<C, T> | Array<NewTask<C, T>>,
260
- ): Promise<Task<C, D, T> | Array<Task<C, D, T>>> {
261
+ task: New<Config, Type> | Array<New<Config, Type>>,
262
+ ): Promise<Task<Config, Details, Type> | Array<Task<Config, Details, Type>>> {
261
263
  const isSingle = !Array.isArray(task);
262
264
  const res = await sendRequired<typeof createReqZ, typeof createResZ>(
263
265
  this.client,
@@ -266,7 +268,7 @@ export class Client implements AsyncTermSearcher<string, TaskKey, Payload> {
266
268
  createReqZ,
267
269
  createResZ,
268
270
  );
269
- const sugared = this.sugar(res.tasks) as Array<Task<C, D, T>>;
271
+ const sugared = this.sugar(res.tasks) as Array<Task<Config, Details, Type>>;
270
272
  return isSingle ? sugared[0] : sugared;
271
273
  }
272
274
 
@@ -293,31 +295,31 @@ export class Client implements AsyncTermSearcher<string, TaskKey, Payload> {
293
295
  }
294
296
 
295
297
  async retrieve<
296
- C extends UnknownRecord = UnknownRecord,
297
- D extends {} = UnknownRecord,
298
- T extends string = string,
299
- >(rack: number, options?: RetrieveOptions): Promise<Task<C, D, T>[]>;
298
+ Config extends UnknownRecord = UnknownRecord,
299
+ Details extends {} = UnknownRecord,
300
+ Type extends string = string,
301
+ >(rack: number, options?: RetrieveOptions): Promise<Task<Config, Details, Type>[]>;
300
302
 
301
303
  async retrieve<
302
- C extends UnknownRecord = UnknownRecord,
303
- D extends {} = UnknownRecord,
304
- T extends string = string,
305
- >(keys: string[], options?: RetrieveOptions): Promise<Task<C, D, T>[]>;
304
+ Config extends UnknownRecord = UnknownRecord,
305
+ Details extends {} = UnknownRecord,
306
+ Type extends string = string,
307
+ >(keys: string[], options?: RetrieveOptions): Promise<Task<Config, Details, Type>[]>;
306
308
 
307
309
  async retrieve<
308
- C extends UnknownRecord = UnknownRecord,
309
- D extends {} = UnknownRecord,
310
- T extends string = string,
311
- >(key: string, options?: RetrieveOptions): Promise<Task<C, D, T>>;
310
+ Config extends UnknownRecord = UnknownRecord,
311
+ Details extends {} = UnknownRecord,
312
+ Type extends string = string,
313
+ >(key: string, options?: RetrieveOptions): Promise<Task<Config, Details, Type>>;
312
314
 
313
315
  async retrieve<
314
- C extends UnknownRecord = UnknownRecord,
315
- D extends {} = UnknownRecord,
316
- T extends string = string,
316
+ Config extends UnknownRecord = UnknownRecord,
317
+ Details extends {} = UnknownRecord,
318
+ Type extends string = string,
317
319
  >(
318
320
  rack: number | string | string[],
319
321
  options?: RetrieveOptions,
320
- ): Promise<Task<C, D, T> | Task<C, D, T>[]> {
322
+ ): Promise<Task<Config, Details, Type> | Task<Config, Details, Type>[]> {
321
323
  const { single, normalized, variant } = analyzeParams(
322
324
  rack,
323
325
  { number: "rack", string: "keys" },
@@ -327,7 +329,7 @@ export class Client implements AsyncTermSearcher<string, TaskKey, Payload> {
327
329
  if (variant === "rack") req.rack = rack as number;
328
330
  else req.keys = normalized as string[];
329
331
  const tasks = await this.execRetrieve(req);
330
- const sugared = this.sugar(tasks) as Array<Task<C, D, T>>;
332
+ const sugared = this.sugar(tasks) as Array<Task<Config, Details, Type>>;
331
333
  return single && variant !== "rack" ? sugared[0] : sugared;
332
334
  }
333
335
 
@@ -343,13 +345,27 @@ export class Client implements AsyncTermSearcher<string, TaskKey, Payload> {
343
345
  }
344
346
 
345
347
  async retrieveByName<
346
- C extends UnknownRecord = UnknownRecord,
347
- D extends {} = UnknownRecord,
348
- T extends string = string,
349
- >(name: string, rack?: number): Promise<Task<C, D, T>> {
348
+ Config extends UnknownRecord = UnknownRecord,
349
+ Details extends {} = UnknownRecord,
350
+ Type extends string = string,
351
+ >(name: string, rack?: number): Promise<Task<Config, Details, Type>> {
350
352
  const tasks = await this.execRetrieve({ names: [name], rack });
351
353
  checkForMultipleOrNoResults("Task", name, tasks, true);
352
- return this.sugar(tasks)[0] as Task<C, D, T>;
354
+ return this.sugar(tasks)[0] as Task<Config, Details, Type>;
355
+ }
356
+
357
+ async retrieveByType<
358
+ Config extends UnknownRecord = UnknownRecord,
359
+ Details extends {} = UnknownRecord,
360
+ Type extends string = string,
361
+ >(type: Type, rack?: number): Promise<Task<Config, Details, Type>[]> {
362
+ const tasks = await this.execRetrieve({ types: [type], rack });
363
+ return this.sugar(tasks) as Task<Config, Details, Type>[];
364
+ }
365
+
366
+ async retrieveSnapshottedTo(taskKey: Key): Promise<ontology.Resource | null> {
367
+ if (this.ontologyClient == null) throw NOT_CREATED_ERROR;
368
+ return await retrieveSnapshottedTo(taskKey, this.ontologyClient);
353
369
  }
354
370
 
355
371
  private async execRetrieve(req: RetrieveRequest): Promise<Payload[]> {
@@ -363,8 +379,21 @@ export class Client implements AsyncTermSearcher<string, TaskKey, Payload> {
363
379
  return res.tasks;
364
380
  }
365
381
 
366
- private sugar(payloads: Payload[]): Task[] {
367
- return payloads.map(
382
+ sugar<
383
+ Config extends UnknownRecord = UnknownRecord,
384
+ Details extends {} = UnknownRecord,
385
+ Type extends string = string,
386
+ >(payload: Payload<Config, Details, Type>): Task<Config, Details, Type>;
387
+
388
+ sugar<
389
+ Config extends UnknownRecord = UnknownRecord,
390
+ Details extends {} = UnknownRecord,
391
+ Type extends string = string,
392
+ >(payloads: Payload<Config, Details, Type>[]): Task<Config, Details, Type>[];
393
+
394
+ sugar(payloads: Payload | Payload[]): Task | Task[] {
395
+ const isSingle = !Array.isArray(payloads);
396
+ const res = toArray(payloads).map(
368
397
  ({ key, name, type, config, state, internal, snapshot }) =>
369
398
  new Task(
370
399
  key,
@@ -379,13 +408,14 @@ export class Client implements AsyncTermSearcher<string, TaskKey, Payload> {
379
408
  this.rangeClient,
380
409
  ),
381
410
  );
411
+ return isSingle ? res[0] : res;
382
412
  }
383
413
 
384
414
  async openTracker(): Promise<signals.Observable<string, string>> {
385
415
  return await signals.openObservable<string, string>(
386
416
  this.frameClient,
387
- "sy_task_set",
388
- "sy_task_delete",
417
+ SET_CHANNEL_NAME,
418
+ DELETE_CHANNEL_NAME,
389
419
  (variant, data) =>
390
420
  Array.from(data).map((k) => ({
391
421
  variant,
@@ -395,39 +425,38 @@ export class Client implements AsyncTermSearcher<string, TaskKey, Payload> {
395
425
  );
396
426
  }
397
427
 
398
- async openStateObserver<D extends UnknownRecord = UnknownRecord>(): Promise<
399
- StateObservable<D>
400
- > {
401
- return new framer.ObservableStreamer<State<D>>(
402
- await this.frameClient.openStreamer(TASK_STATE_CHANNEL),
428
+ async openStateObserver(): Promise<StateObservable> {
429
+ return new framer.ObservableStreamer<State>(
430
+ await this.frameClient.openStreamer(STATE_CHANNEL_NAME),
403
431
  (frame) => {
404
- const s = frame.get(TASK_STATE_CHANNEL);
432
+ const s = frame.get(STATE_CHANNEL_NAME);
405
433
  if (s.length === 0) return [null, false];
406
434
  const parse = stateZ.safeParse(s.at(-1));
407
435
  if (!parse.success) {
408
436
  console.error(parse.error);
409
437
  return [null, false];
410
438
  }
411
- return [parse.data as State<D>, true];
439
+ return [parse.data, true];
412
440
  },
413
441
  );
414
442
  }
415
443
 
416
- async openCommandObserver<A extends UnknownRecord = UnknownRecord>(): Promise<
417
- CommandObservable<A>
418
- > {
419
- return new framer.ObservableStreamer<Command<A>>(
420
- await this.frameClient.openStreamer(TASK_CMD_CHANNEL),
444
+ async openCommandObserver(): Promise<CommandObservable> {
445
+ return new framer.ObservableStreamer<Command>(
446
+ await this.frameClient.openStreamer(COMMAND_CHANNEL_NAME),
421
447
  (frame) => {
422
- const s = frame.get(TASK_CMD_CHANNEL);
448
+ const s = frame.get(COMMAND_CHANNEL_NAME);
423
449
  if (s.length === 0) return [null, false];
424
450
  const parse = commandZ.safeParse(s.at(-1));
425
451
  if (!parse.success) {
426
452
  console.error(parse.error);
427
453
  return [null, false];
428
454
  }
429
- return [parse.data as Command<A>, true];
455
+ return [parse.data, true];
430
456
  },
431
457
  );
432
458
  }
433
459
  }
460
+
461
+ export const ontologyID = (key: Key): ontology.ID =>
462
+ new ontology.ID({ type: ONTOLOGY_TYPE, key });
@@ -10,108 +10,89 @@
10
10
  import { binary, type observe, type UnknownRecord } from "@synnaxlabs/x";
11
11
  import { z } from "zod";
12
12
 
13
- import { ontology } from "@/ontology";
13
+ import { type Key as RackKey } from "@/hardware/rack/payload";
14
+ import { decodeJSONString } from "@/util/decodeJSONString";
15
+ import { parseWithoutKeyConversion } from "@/util/parseWithoutKeyConversion";
14
16
 
15
- export const taskKeyZ = z.union([
17
+ export const keyZ = z.union([
16
18
  z.string(),
17
19
  z.bigint().transform((k) => k.toString()),
18
20
  z.number().transform((k) => k.toString()),
19
21
  ]);
22
+ export type Key = z.infer<typeof keyZ>;
20
23
 
21
- export type TaskKey = z.infer<typeof taskKeyZ>;
24
+ export const statusZ = z.enum(["info", "success", "error", "warning"]);
25
+ export type Status = z.infer<typeof statusZ>;
22
26
 
23
27
  export const stateZ = z.object({
24
- task: taskKeyZ,
25
- variant: z.string(),
28
+ task: keyZ,
29
+ variant: statusZ,
26
30
  key: z.string().optional(),
27
31
  details: z
28
32
  .record(z.unknown())
29
- .or(
30
- z.string().transform((c) => {
31
- if (c === "") return {};
32
- return JSON.parse(c);
33
- }),
34
- )
33
+ .or(z.string().transform(parseWithoutKeyConversion))
35
34
  .or(z.array(z.unknown()))
36
- .or(z.null()),
35
+ .or(z.null()) as z.ZodType<UnknownRecord | undefined>,
37
36
  });
38
-
39
- export type State<D extends {} = UnknownRecord> = Omit<
40
- z.infer<typeof stateZ>,
41
- "details"
42
- > & {
43
- details?: D;
44
- };
37
+ export interface State<Details extends {} = UnknownRecord>
38
+ extends Omit<z.infer<typeof stateZ>, "details"> {
39
+ details?: Details;
40
+ }
45
41
 
46
42
  export const taskZ = z.object({
47
- key: taskKeyZ,
43
+ key: keyZ,
48
44
  name: z.string(),
49
45
  type: z.string(),
50
46
  internal: z.boolean().optional(),
51
- config: z.record(z.unknown()).or(
52
- z.string().transform((c) => {
53
- if (c === "") return {};
54
- return binary.JSON_CODEC.decodeString(c);
55
- }),
56
- ) as z.ZodType<UnknownRecord>,
47
+ config: z.record(z.unknown()).or(z.string().transform(decodeJSONString)),
57
48
  state: stateZ.optional().nullable(),
58
49
  snapshot: z.boolean().optional(),
59
50
  });
60
-
61
- export const newTaskZ = taskZ.omit({ key: true }).extend({
62
- key: taskKeyZ.transform((k) => k.toString()).optional(),
51
+ export interface Payload<
52
+ Config extends UnknownRecord = UnknownRecord,
53
+ Details extends {} = UnknownRecord,
54
+ Type extends string = string,
55
+ > extends Omit<z.output<typeof taskZ>, "config" | "type" | "state"> {
56
+ type: Type;
57
+ config: Config;
58
+ state?: State<Details> | null;
59
+ }
60
+
61
+ export const newZ = taskZ.omit({ key: true }).extend({
62
+ key: keyZ.transform((k) => k.toString()).optional(),
63
63
  config: z.unknown().transform((c) => binary.JSON_CODEC.encodeString(c)),
64
64
  });
65
-
66
- export type NewTask<
67
- C extends UnknownRecord = UnknownRecord,
68
- T extends string = string,
69
- > = Omit<z.input<typeof newTaskZ>, "config" | "state"> & {
70
- type: T;
71
- config: C;
72
- };
73
-
74
- export type Payload<
75
- C extends UnknownRecord = UnknownRecord,
76
- D extends {} = UnknownRecord,
77
- T extends string = string,
78
- > = Omit<z.output<typeof taskZ>, "config" | "type" | "state"> & {
79
- type: T;
80
- config: C;
81
- state?: State<D> | null;
82
- };
65
+ export interface New<
66
+ Config extends UnknownRecord = UnknownRecord,
67
+ Type extends string = string,
68
+ > extends Omit<z.input<typeof newZ>, "config" | "state"> {
69
+ type: Type;
70
+ config: Config;
71
+ }
83
72
 
84
73
  export const commandZ = z.object({
85
- task: taskKeyZ,
74
+ task: keyZ,
86
75
  type: z.string(),
87
76
  key: z.string(),
88
77
  args: z
89
78
  .record(z.unknown())
90
- .or(
91
- z.string().transform((c) => {
92
- if (c === "") return {};
93
- return JSON.parse(c);
94
- }),
95
- )
79
+ .or(z.string().transform(parseWithoutKeyConversion))
96
80
  .or(z.array(z.unknown()))
97
81
  .or(z.null())
98
82
  .optional() as z.ZodOptional<z.ZodType<UnknownRecord>>,
99
83
  });
84
+ export interface Command<Args extends {} = UnknownRecord>
85
+ extends Omit<z.infer<typeof commandZ>, "args"> {
86
+ args?: Args;
87
+ }
100
88
 
101
- export type Command<A extends {} = UnknownRecord> = Omit<
102
- z.infer<typeof commandZ>,
103
- "args"
104
- > & {
105
- args?: A;
106
- };
107
-
108
- export type StateObservable<D extends UnknownRecord = UnknownRecord> =
109
- observe.ObservableAsyncCloseable<State<D>>;
89
+ export interface StateObservable<Details extends {} = UnknownRecord>
90
+ extends observe.ObservableAsyncCloseable<State<Details>> {}
110
91
 
111
- export type CommandObservable<A extends UnknownRecord = UnknownRecord> =
112
- observe.ObservableAsyncCloseable<Command<A>>;
92
+ export interface CommandObservable<Args extends {} = UnknownRecord>
93
+ extends observe.ObservableAsyncCloseable<Command<Args>> {}
113
94
 
114
- export const ONTOLOGY_TYPE: ontology.ResourceType = "task";
95
+ export const ONTOLOGY_TYPE = "task";
96
+ export type OntologyType = typeof ONTOLOGY_TYPE;
115
97
 
116
- export const ontologyID = (key: TaskKey): ontology.ID =>
117
- new ontology.ID({ type: ONTOLOGY_TYPE, key: key.toString() });
98
+ export const getRackKey = (key: Key): RackKey => Number(BigInt(key) >> 32n);