@synnaxlabs/client 0.48.0 → 0.49.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 (300) hide show
  1. package/.turbo/turbo-build.log +6 -6
  2. package/dist/client.cjs +33 -31
  3. package/dist/client.js +6522 -6167
  4. package/dist/src/access/client.d.ts +3 -1
  5. package/dist/src/access/client.d.ts.map +1 -1
  6. package/dist/src/access/enforce.d.ts +35 -0
  7. package/dist/src/access/enforce.d.ts.map +1 -0
  8. package/dist/src/access/enforce.spec.d.ts +2 -0
  9. package/dist/src/access/enforce.spec.d.ts.map +1 -0
  10. package/dist/src/access/external.d.ts +3 -0
  11. package/dist/src/access/external.d.ts.map +1 -1
  12. package/dist/src/access/payload.d.ts +0 -6
  13. package/dist/src/access/payload.d.ts.map +1 -1
  14. package/dist/src/access/policy/access.spec.d.ts +2 -0
  15. package/dist/src/access/policy/access.spec.d.ts.map +1 -0
  16. package/dist/src/access/policy/client.d.ts +485 -31
  17. package/dist/src/access/policy/client.d.ts.map +1 -1
  18. package/dist/src/access/policy/payload.d.ts +36 -113
  19. package/dist/src/access/policy/payload.d.ts.map +1 -1
  20. package/dist/src/access/role/client.d.ts +135 -0
  21. package/dist/src/access/role/client.d.ts.map +1 -0
  22. package/dist/src/access/role/external.d.ts.map +1 -0
  23. package/dist/src/access/role/index.d.ts +2 -0
  24. package/dist/src/access/role/index.d.ts.map +1 -0
  25. package/dist/src/access/role/payload.d.ts +27 -0
  26. package/dist/src/access/role/payload.d.ts.map +1 -0
  27. package/dist/src/access/role/role.spec.d.ts +2 -0
  28. package/dist/src/access/role/role.spec.d.ts.map +1 -0
  29. package/dist/src/arc/access.spec.d.ts +2 -0
  30. package/dist/src/arc/access.spec.d.ts.map +1 -0
  31. package/dist/src/arc/client.d.ts +5 -14
  32. package/dist/src/arc/client.d.ts.map +1 -1
  33. package/dist/src/arc/payload.d.ts +11 -2
  34. package/dist/src/arc/payload.d.ts.map +1 -1
  35. package/dist/src/auth/auth.d.ts +5 -3
  36. package/dist/src/auth/auth.d.ts.map +1 -1
  37. package/dist/src/channel/access.spec.d.ts +2 -0
  38. package/dist/src/channel/access.spec.d.ts.map +1 -0
  39. package/dist/src/channel/client.d.ts +0 -1
  40. package/dist/src/channel/client.d.ts.map +1 -1
  41. package/dist/src/channel/payload.d.ts +18 -8
  42. package/dist/src/channel/payload.d.ts.map +1 -1
  43. package/dist/src/channel/payload.spec.d.ts +2 -0
  44. package/dist/src/channel/payload.spec.d.ts.map +1 -0
  45. package/dist/src/channel/retriever.d.ts +4 -6
  46. package/dist/src/channel/retriever.d.ts.map +1 -1
  47. package/dist/src/channel/writer.d.ts.map +1 -1
  48. package/dist/src/client.d.ts +9 -5
  49. package/dist/src/client.d.ts.map +1 -1
  50. package/dist/src/device/access.spec.d.ts +2 -0
  51. package/dist/src/device/access.spec.d.ts.map +1 -0
  52. package/dist/src/{hardware/device → device}/client.d.ts +14 -7
  53. package/dist/src/device/client.d.ts.map +1 -0
  54. package/dist/src/device/device.spec.d.ts.map +1 -0
  55. package/dist/src/device/external.d.ts.map +1 -0
  56. package/dist/src/device/index.d.ts.map +1 -0
  57. package/dist/src/{hardware/device → device}/payload.d.ts +1 -1
  58. package/dist/src/device/payload.d.ts.map +1 -0
  59. package/dist/src/errors.d.ts +3 -0
  60. package/dist/src/errors.d.ts.map +1 -1
  61. package/dist/src/framer/client.d.ts +11 -1
  62. package/dist/src/framer/client.d.ts.map +1 -1
  63. package/dist/src/framer/frame.d.ts +10 -5
  64. package/dist/src/framer/frame.d.ts.map +1 -1
  65. package/dist/src/framer/iterator.d.ts +3 -3
  66. package/dist/src/framer/reader.d.ts +16 -0
  67. package/dist/src/framer/reader.d.ts.map +1 -0
  68. package/dist/src/framer/reader.spec.d.ts +2 -0
  69. package/dist/src/framer/reader.spec.d.ts.map +1 -0
  70. package/dist/src/framer/streamer.d.ts +24 -21
  71. package/dist/src/framer/streamer.d.ts.map +1 -1
  72. package/dist/src/framer/writer.d.ts +13 -13
  73. package/dist/src/index.d.ts +4 -5
  74. package/dist/src/index.d.ts.map +1 -1
  75. package/dist/src/label/access.spec.d.ts +2 -0
  76. package/dist/src/label/access.spec.d.ts.map +1 -0
  77. package/dist/src/label/client.d.ts +20 -11
  78. package/dist/src/label/client.d.ts.map +1 -1
  79. package/dist/src/ontology/client.d.ts +6 -6
  80. package/dist/src/ontology/client.d.ts.map +1 -1
  81. package/dist/src/ontology/group/access.spec.d.ts +2 -0
  82. package/dist/src/ontology/group/access.spec.d.ts.map +1 -0
  83. package/dist/src/ontology/group/client.d.ts +2 -2
  84. package/dist/src/ontology/group/client.d.ts.map +1 -1
  85. package/dist/src/ontology/group/payload.d.ts +1 -2
  86. package/dist/src/ontology/group/payload.d.ts.map +1 -1
  87. package/dist/src/ontology/payload.d.ts +23 -17
  88. package/dist/src/ontology/payload.d.ts.map +1 -1
  89. package/dist/src/ontology/writer.d.ts +10 -10
  90. package/dist/src/ontology/writer.d.ts.map +1 -1
  91. package/dist/src/rack/access.spec.d.ts +2 -0
  92. package/dist/src/rack/access.spec.d.ts.map +1 -0
  93. package/dist/src/{hardware/rack → rack}/client.d.ts +15 -8
  94. package/dist/src/rack/client.d.ts.map +1 -0
  95. package/dist/src/rack/external.d.ts.map +1 -0
  96. package/dist/src/rack/index.d.ts.map +1 -0
  97. package/dist/src/{hardware/rack → rack}/payload.d.ts +1 -1
  98. package/dist/src/rack/payload.d.ts.map +1 -0
  99. package/dist/src/rack/rack.spec.d.ts.map +1 -0
  100. package/dist/src/ranger/access.spec.d.ts +2 -0
  101. package/dist/src/ranger/access.spec.d.ts.map +1 -0
  102. package/dist/src/ranger/alias.d.ts +1 -8
  103. package/dist/src/ranger/alias.d.ts.map +1 -1
  104. package/dist/src/ranger/client.d.ts +12 -5
  105. package/dist/src/ranger/client.d.ts.map +1 -1
  106. package/dist/src/ranger/kv.d.ts +0 -3
  107. package/dist/src/ranger/kv.d.ts.map +1 -1
  108. package/dist/src/ranger/writer.d.ts +2 -2
  109. package/dist/src/ranger/writer.d.ts.map +1 -1
  110. package/dist/src/status/access.spec.d.ts +2 -0
  111. package/dist/src/status/access.spec.d.ts.map +1 -0
  112. package/dist/src/status/client.d.ts +4 -4
  113. package/dist/src/status/client.d.ts.map +1 -1
  114. package/dist/src/status/payload.d.ts +9 -2
  115. package/dist/src/status/payload.d.ts.map +1 -1
  116. package/dist/src/task/access.spec.d.ts +2 -0
  117. package/dist/src/task/access.spec.d.ts.map +1 -0
  118. package/dist/src/{hardware/task → task}/client.d.ts +26 -15
  119. package/dist/src/task/client.d.ts.map +1 -0
  120. package/dist/src/task/external.d.ts +3 -0
  121. package/dist/src/task/external.d.ts.map +1 -0
  122. package/dist/src/task/index.d.ts.map +1 -0
  123. package/dist/src/{hardware/task → task}/payload.d.ts +45 -6
  124. package/dist/src/task/payload.d.ts.map +1 -0
  125. package/dist/src/task/task.spec.d.ts.map +1 -0
  126. package/dist/src/testutil/access.d.ts +4 -0
  127. package/dist/src/testutil/access.d.ts.map +1 -0
  128. package/dist/src/transport.d.ts.map +1 -1
  129. package/dist/src/user/access.spec.d.ts +2 -0
  130. package/dist/src/user/access.spec.d.ts.map +1 -0
  131. package/dist/src/user/client.d.ts +10 -1
  132. package/dist/src/user/client.d.ts.map +1 -1
  133. package/dist/src/user/external.d.ts +1 -1
  134. package/dist/src/user/external.d.ts.map +1 -1
  135. package/dist/src/user/payload.d.ts.map +1 -1
  136. package/dist/src/workspace/access.spec.d.ts +2 -0
  137. package/dist/src/workspace/access.spec.d.ts.map +1 -0
  138. package/dist/src/workspace/client.d.ts +10 -5
  139. package/dist/src/workspace/client.d.ts.map +1 -1
  140. package/dist/src/workspace/lineplot/access.spec.d.ts +2 -0
  141. package/dist/src/workspace/lineplot/access.spec.d.ts.map +1 -0
  142. package/dist/src/workspace/lineplot/client.d.ts +8 -1
  143. package/dist/src/workspace/lineplot/client.d.ts.map +1 -1
  144. package/dist/src/workspace/log/access.spec.d.ts +2 -0
  145. package/dist/src/workspace/log/access.spec.d.ts.map +1 -0
  146. package/dist/src/workspace/log/client.d.ts +8 -1
  147. package/dist/src/workspace/log/client.d.ts.map +1 -1
  148. package/dist/src/workspace/schematic/access.spec.d.ts +2 -0
  149. package/dist/src/workspace/schematic/access.spec.d.ts.map +1 -0
  150. package/dist/src/workspace/schematic/client.d.ts +8 -1
  151. package/dist/src/workspace/schematic/client.d.ts.map +1 -1
  152. package/dist/src/workspace/schematic/symbol/access.spec.d.ts +2 -0
  153. package/dist/src/workspace/schematic/symbol/access.spec.d.ts.map +1 -0
  154. package/dist/src/workspace/schematic/symbol/client.d.ts +1 -5
  155. package/dist/src/workspace/schematic/symbol/client.d.ts.map +1 -1
  156. package/dist/src/workspace/schematic/symbol/payload.d.ts +2 -2
  157. package/dist/src/workspace/table/access.spec.d.ts +2 -0
  158. package/dist/src/workspace/table/access.spec.d.ts.map +1 -0
  159. package/dist/src/workspace/table/client.d.ts +8 -1
  160. package/dist/src/workspace/table/client.d.ts.map +1 -1
  161. package/package.json +3 -3
  162. package/src/access/client.ts +5 -2
  163. package/src/access/enforce.spec.ts +189 -0
  164. package/src/access/enforce.ts +84 -0
  165. package/src/access/external.ts +3 -0
  166. package/src/access/payload.ts +1 -13
  167. package/src/access/policy/access.spec.ts +147 -0
  168. package/src/access/policy/client.ts +21 -25
  169. package/src/access/policy/payload.ts +9 -5
  170. package/src/access/role/client.ts +135 -0
  171. package/src/access/role/external.ts +11 -0
  172. package/src/{hardware → access/role}/index.ts +1 -1
  173. package/src/access/role/payload.ts +32 -0
  174. package/src/access/role/role.spec.ts +95 -0
  175. package/src/arc/access.spec.ts +143 -0
  176. package/src/arc/client.ts +7 -31
  177. package/src/arc/payload.ts +4 -0
  178. package/src/auth/auth.ts +33 -11
  179. package/src/channel/access.spec.ts +116 -0
  180. package/src/channel/channel.spec.ts +63 -73
  181. package/src/channel/client.ts +2 -8
  182. package/src/channel/payload.spec.ts +171 -0
  183. package/src/channel/payload.ts +35 -7
  184. package/src/channel/retriever.ts +10 -11
  185. package/src/channel/writer.ts +3 -7
  186. package/src/client.ts +14 -18
  187. package/src/device/access.spec.ts +159 -0
  188. package/src/{hardware/device → device}/client.ts +12 -21
  189. package/src/{hardware/device → device}/device.spec.ts +70 -34
  190. package/src/device/external.ts +11 -0
  191. package/src/{hardware/rack → device}/index.ts +1 -1
  192. package/src/{hardware/device → device}/payload.ts +3 -3
  193. package/src/errors.ts +2 -0
  194. package/src/framer/adapter.spec.ts +14 -14
  195. package/src/framer/client.spec.ts +14 -20
  196. package/src/framer/client.ts +15 -20
  197. package/src/framer/deleter.spec.ts +1 -1
  198. package/src/framer/frame.spec.ts +131 -0
  199. package/src/framer/frame.ts +10 -2
  200. package/src/framer/iterator.ts +3 -3
  201. package/src/framer/reader.spec.ts +736 -0
  202. package/src/framer/reader.ts +265 -0
  203. package/src/framer/streamer.spec.ts +100 -12
  204. package/src/framer/streamer.ts +29 -9
  205. package/src/framer/writer.spec.ts +5 -5
  206. package/src/index.ts +4 -5
  207. package/src/label/access.spec.ts +109 -0
  208. package/src/label/client.ts +10 -14
  209. package/src/ontology/client.ts +4 -6
  210. package/src/ontology/group/access.spec.ts +77 -0
  211. package/src/ontology/group/client.ts +3 -7
  212. package/src/ontology/group/group.spec.ts +18 -0
  213. package/src/ontology/group/payload.ts +2 -2
  214. package/src/ontology/ontology.spec.ts +2 -0
  215. package/src/ontology/payload.ts +18 -2
  216. package/src/ontology/writer.ts +3 -7
  217. package/src/rack/access.spec.ts +102 -0
  218. package/src/{hardware/rack → rack}/client.ts +14 -19
  219. package/src/{hardware/device/index.ts → rack/external.ts} +2 -1
  220. package/src/{hardware/external.ts → rack/index.ts} +1 -1
  221. package/src/{hardware/rack → rack}/payload.ts +2 -2
  222. package/src/{hardware/rack → rack}/rack.spec.ts +43 -17
  223. package/src/ranger/access.spec.ts +115 -0
  224. package/src/ranger/alias.ts +6 -14
  225. package/src/ranger/client.ts +13 -14
  226. package/src/ranger/kv.ts +7 -9
  227. package/src/ranger/ranger.spec.ts +4 -4
  228. package/src/ranger/writer.ts +3 -7
  229. package/src/status/access.spec.ts +129 -0
  230. package/src/status/client.ts +5 -9
  231. package/src/status/payload.ts +3 -2
  232. package/src/task/access.spec.ts +131 -0
  233. package/src/{hardware/task → task}/client.ts +50 -25
  234. package/src/task/external.ts +11 -0
  235. package/src/{hardware/task → task}/index.ts +1 -1
  236. package/src/{hardware/task → task}/payload.ts +22 -3
  237. package/src/{hardware/task → task}/task.spec.ts +197 -34
  238. package/src/testutil/access.ts +34 -0
  239. package/src/testutil/channels.ts +3 -3
  240. package/src/transport.ts +1 -3
  241. package/src/user/access.spec.ts +107 -0
  242. package/src/user/client.ts +10 -12
  243. package/src/user/external.ts +12 -1
  244. package/src/user/payload.ts +3 -5
  245. package/src/workspace/access.spec.ts +108 -0
  246. package/src/workspace/client.ts +11 -27
  247. package/src/workspace/lineplot/access.spec.ts +134 -0
  248. package/src/workspace/lineplot/client.ts +8 -13
  249. package/src/workspace/log/access.spec.ts +134 -0
  250. package/src/workspace/log/client.ts +8 -13
  251. package/src/workspace/schematic/access.spec.ts +134 -0
  252. package/src/workspace/schematic/client.ts +9 -18
  253. package/src/workspace/schematic/symbol/access.spec.ts +172 -0
  254. package/src/workspace/schematic/symbol/client.ts +6 -17
  255. package/src/workspace/schematic/symbol/payload.ts +1 -1
  256. package/src/workspace/table/access.spec.ts +134 -0
  257. package/src/workspace/table/client.ts +8 -13
  258. package/dist/src/access/policy/policy.spec.d.ts +0 -2
  259. package/dist/src/access/policy/policy.spec.d.ts.map +0 -1
  260. package/dist/src/hardware/client.d.ts +0 -10
  261. package/dist/src/hardware/client.d.ts.map +0 -1
  262. package/dist/src/hardware/device/client.d.ts.map +0 -1
  263. package/dist/src/hardware/device/device.spec.d.ts.map +0 -1
  264. package/dist/src/hardware/device/external.d.ts.map +0 -1
  265. package/dist/src/hardware/device/index.d.ts.map +0 -1
  266. package/dist/src/hardware/device/payload.d.ts.map +0 -1
  267. package/dist/src/hardware/external.d.ts +0 -2
  268. package/dist/src/hardware/external.d.ts.map +0 -1
  269. package/dist/src/hardware/index.d.ts +0 -2
  270. package/dist/src/hardware/index.d.ts.map +0 -1
  271. package/dist/src/hardware/rack/client.d.ts.map +0 -1
  272. package/dist/src/hardware/rack/external.d.ts.map +0 -1
  273. package/dist/src/hardware/rack/index.d.ts.map +0 -1
  274. package/dist/src/hardware/rack/payload.d.ts.map +0 -1
  275. package/dist/src/hardware/rack/rack.spec.d.ts.map +0 -1
  276. package/dist/src/hardware/task/client.d.ts.map +0 -1
  277. package/dist/src/hardware/task/external.d.ts.map +0 -1
  278. package/dist/src/hardware/task/index.d.ts.map +0 -1
  279. package/dist/src/hardware/task/payload.d.ts.map +0 -1
  280. package/dist/src/hardware/task/task.spec.d.ts.map +0 -1
  281. package/dist/src/user/retriever.d.ts +0 -16
  282. package/dist/src/user/retriever.d.ts.map +0 -1
  283. package/dist/src/user/writer.d.ts +0 -11
  284. package/dist/src/user/writer.d.ts.map +0 -1
  285. package/src/access/policy/policy.spec.ts +0 -329
  286. package/src/hardware/client.ts +0 -24
  287. package/src/hardware/device/external.ts +0 -11
  288. package/src/hardware/rack/external.ts +0 -11
  289. package/src/hardware/task/external.ts +0 -11
  290. package/src/user/retriever.ts +0 -41
  291. package/src/user/writer.ts +0 -84
  292. /package/dist/src/{hardware/device → access/role}/external.d.ts +0 -0
  293. /package/dist/src/{hardware/device → device}/device.spec.d.ts +0 -0
  294. /package/dist/src/{hardware/rack → device}/external.d.ts +0 -0
  295. /package/dist/src/{hardware/device → device}/index.d.ts +0 -0
  296. /package/dist/src/{hardware/task → rack}/external.d.ts +0 -0
  297. /package/dist/src/{hardware/rack → rack}/index.d.ts +0 -0
  298. /package/dist/src/{hardware/rack → rack}/rack.spec.d.ts +0 -0
  299. /package/dist/src/{hardware/task → task}/index.d.ts +0 -0
  300. /package/dist/src/{hardware/task → task}/task.spec.d.ts +0 -0
@@ -7,19 +7,20 @@
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 { id, unique } from "@synnaxlabs/x";
10
+ import { id, TimeStamp, unique } from "@synnaxlabs/x";
11
11
  import { beforeAll, describe, expect, it } from "vitest";
12
12
 
13
+ import { type device } from "@/device";
13
14
  import { createTestClient } from "@/testutil/client";
14
15
 
15
16
  const client = createTestClient();
16
17
 
17
18
  describe("Device", async () => {
18
- const testRack = await client.hardware.racks.create({ name: "test" });
19
+ const testRack = await client.racks.create({ name: "test" });
19
20
  describe("create", () => {
20
21
  it("should create a device on a rack", async () => {
21
22
  const key = id.create();
22
- const d = await client.hardware.devices.create({
23
+ const d = await client.devices.create({
23
24
  rack: testRack.key,
24
25
  location: "Dev1",
25
26
  key,
@@ -32,7 +33,40 @@ describe("Device", async () => {
32
33
  expect(d.name).toBe("test");
33
34
  expect(d.make).toBe("ni");
34
35
  });
36
+ it("should create a device with a custom status", async () => {
37
+ const key = id.create();
38
+ const customStatus: device.Status = {
39
+ key: "",
40
+ name: "",
41
+ variant: "success",
42
+ message: "Custom device status",
43
+ description: "Device is connected",
44
+ time: TimeStamp.now(),
45
+ details: { rack: 0, device: "" },
46
+ };
47
+ const d = await client.devices.create({
48
+ rack: testRack.key,
49
+ location: "Dev1",
50
+ key,
51
+ name: "device-with-status",
52
+ make: "ni",
53
+ model: "dog",
54
+ properties: { cat: "dog" },
55
+ status: customStatus,
56
+ });
57
+ expect(d.key).toEqual(key);
58
+ const retrieved = await client.devices.retrieve({
59
+ key: d.key,
60
+ includeStatus: true,
61
+ });
62
+ expect(retrieved.status).toBeDefined();
63
+ expect(retrieved.status?.variant).toBe("success");
64
+ expect(retrieved.status?.message).toBe("Custom device status");
65
+ expect(retrieved.status?.description).toBe("Device is connected");
66
+ expect(retrieved.status?.details?.device).toBe(d.key);
67
+ });
35
68
  });
69
+
36
70
  it("should properly encode and decode properties", async () => {
37
71
  const properties = {
38
72
  rate: 10,
@@ -40,7 +74,7 @@ describe("Device", async () => {
40
74
  inputChannels: { port1: 34214 },
41
75
  outputChannels: [{ port2: 232 }],
42
76
  };
43
- const d = await client.hardware.devices.create({
77
+ const d = await client.devices.create({
44
78
  key: id.create(),
45
79
  rack: testRack.key,
46
80
  location: "Dev1",
@@ -49,13 +83,14 @@ describe("Device", async () => {
49
83
  model: "dog",
50
84
  properties,
51
85
  });
52
- const retrieved = await client.hardware.devices.retrieve({ key: d.key });
86
+ const retrieved = await client.devices.retrieve({ key: d.key });
53
87
  expect(retrieved.key).toEqual(d.key);
54
88
  expect(retrieved.properties).toEqual(properties);
55
89
  });
90
+
56
91
  describe("retrieve", () => {
57
92
  it("should retrieve a device by its key", async () => {
58
- const d = await client.hardware.devices.create({
93
+ const d = await client.devices.create({
59
94
  key: id.create(),
60
95
  rack: testRack.key,
61
96
  location: "Dev1",
@@ -64,13 +99,14 @@ describe("Device", async () => {
64
99
  model: "dog",
65
100
  properties: { cat: "dog" },
66
101
  });
67
- const retrieved = await client.hardware.devices.retrieve({ key: d.key });
102
+ const retrieved = await client.devices.retrieve({ key: d.key });
68
103
  expect(retrieved.key).toBe(d.key);
69
104
  expect(retrieved.name).toBe("test");
70
105
  expect(retrieved.make).toBe("ni");
71
106
  });
107
+
72
108
  it("should retrieve multiple devices by their keys", async () => {
73
- const d1 = await client.hardware.devices.create({
109
+ const d1 = await client.devices.create({
74
110
  key: id.create(),
75
111
  rack: testRack.key,
76
112
  location: "Dev1",
@@ -79,7 +115,7 @@ describe("Device", async () => {
79
115
  model: "dog",
80
116
  properties: { cat: "dog" },
81
117
  });
82
- const d2 = await client.hardware.devices.create({
118
+ const d2 = await client.devices.create({
83
119
  key: id.create(),
84
120
  rack: testRack.key,
85
121
  location: "Dev2",
@@ -88,7 +124,7 @@ describe("Device", async () => {
88
124
  model: "dog",
89
125
  properties: { cat: "dog" },
90
126
  });
91
- const retrieved = await client.hardware.devices.retrieve({
127
+ const retrieved = await client.devices.retrieve({
92
128
  keys: [d1.key, d2.key],
93
129
  });
94
130
  expect(retrieved.length).toBe(2);
@@ -96,9 +132,9 @@ describe("Device", async () => {
96
132
  expect(retrieved[1].key).toBe(d2.key);
97
133
  });
98
134
 
99
- describe("state", () => {
100
- it("should not include state by default", async () => {
101
- const d = await client.hardware.devices.create({
135
+ describe("status", () => {
136
+ it("should not include status by default", async () => {
137
+ const d = await client.devices.create({
102
138
  key: id.create(),
103
139
  rack: testRack.key,
104
140
  location: "Dev1",
@@ -108,12 +144,12 @@ describe("Device", async () => {
108
144
  properties: { cat: "dog" },
109
145
  });
110
146
 
111
- const retrieved = await client.hardware.devices.retrieve({ key: d.key });
147
+ const retrieved = await client.devices.retrieve({ key: d.key });
112
148
  expect(retrieved.status).toBeUndefined();
113
149
  });
114
150
 
115
151
  it("should include status when includeStatus is true", async () => {
116
- const d = await client.hardware.devices.create({
152
+ const d = await client.devices.create({
117
153
  key: id.create(),
118
154
  rack: testRack.key,
119
155
  location: "Dev1",
@@ -125,7 +161,7 @@ describe("Device", async () => {
125
161
 
126
162
  await expect
127
163
  .poll(async () => {
128
- const { status } = await client.hardware.devices.retrieve({
164
+ const { status } = await client.devices.retrieve({
129
165
  key: d.key,
130
166
  includeStatus: true,
131
167
  });
@@ -134,8 +170,8 @@ describe("Device", async () => {
134
170
  .toBe(true);
135
171
  });
136
172
 
137
- it("should include state for multiple devices", async () => {
138
- const d1 = await client.hardware.devices.create({
173
+ it("should include status for multiple devices", async () => {
174
+ const d1 = await client.devices.create({
139
175
  key: id.create(),
140
176
  rack: testRack.key,
141
177
  location: "Dev1",
@@ -145,7 +181,7 @@ describe("Device", async () => {
145
181
  properties: { cat: "dog" },
146
182
  });
147
183
 
148
- const d2 = await client.hardware.devices.create({
184
+ const d2 = await client.devices.create({
149
185
  key: id.create(),
150
186
  rack: testRack.key,
151
187
  location: "Dev2",
@@ -157,7 +193,7 @@ describe("Device", async () => {
157
193
 
158
194
  await expect
159
195
  .poll(async () => {
160
- const retrievedDevices = await client.hardware.devices.retrieve({
196
+ const retrievedDevices = await client.devices.retrieve({
161
197
  keys: [d1.key, d2.key],
162
198
  includeStatus: true,
163
199
  });
@@ -169,7 +205,7 @@ describe("Device", async () => {
169
205
 
170
206
  it("should handle state with type-safe details", async () => {
171
207
  const key = id.create();
172
- await client.hardware.devices.create({
208
+ await client.devices.create({
173
209
  key,
174
210
  rack: testRack.key,
175
211
  location: "Dev1",
@@ -181,13 +217,13 @@ describe("Device", async () => {
181
217
 
182
218
  await expect
183
219
  .poll(async () => {
184
- const retrieved = await client.hardware.devices.retrieve({
220
+ const retrieved = await client.devices.retrieve({
185
221
  key,
186
222
  includeStatus: true,
187
223
  });
188
224
  return (
189
225
  retrieved.status !== undefined &&
190
- retrieved.status.variant === "info" &&
226
+ retrieved.status.variant === "warning" &&
191
227
  retrieved.status.details.device === key
192
228
  );
193
229
  })
@@ -215,7 +251,7 @@ describe("Device", async () => {
215
251
 
216
252
  for (const config of deviceConfigs) {
217
253
  const key = id.create();
218
- await client.hardware.devices.create({
254
+ await client.devices.create({
219
255
  key,
220
256
  rack: testRack.key,
221
257
  location: config.location,
@@ -229,7 +265,7 @@ describe("Device", async () => {
229
265
  });
230
266
 
231
267
  it("should retrieve devices by names", async () => {
232
- const result = await client.hardware.devices.retrieve({
268
+ const result = await client.devices.retrieve({
233
269
  names: ["sensor1", "actuator1"],
234
270
  });
235
271
  expect(result.length).toBeGreaterThanOrEqual(2);
@@ -240,7 +276,7 @@ describe("Device", async () => {
240
276
  });
241
277
 
242
278
  it("should retrieve devices by makes", async () => {
243
- const result = await client.hardware.devices.retrieve({
279
+ const result = await client.devices.retrieve({
244
280
  makes: ["ni"],
245
281
  });
246
282
  expect(result.length).toBeGreaterThanOrEqual(2);
@@ -248,7 +284,7 @@ describe("Device", async () => {
248
284
  });
249
285
 
250
286
  it("should retrieve devices by models", async () => {
251
- const result = await client.hardware.devices.retrieve({
287
+ const result = await client.devices.retrieve({
252
288
  models: ["pxi-6281", "t7"],
253
289
  });
254
290
  expect(result.length).toBeGreaterThanOrEqual(2);
@@ -259,7 +295,7 @@ describe("Device", async () => {
259
295
  });
260
296
 
261
297
  it("should retrieve devices by locations", async () => {
262
- const result = await client.hardware.devices.retrieve({
298
+ const result = await client.devices.retrieve({
263
299
  locations: ["Lab1"],
264
300
  });
265
301
  expect(result.length).toBeGreaterThanOrEqual(2);
@@ -267,7 +303,7 @@ describe("Device", async () => {
267
303
  });
268
304
 
269
305
  it("should retrieve devices by racks", async () => {
270
- const result = await client.hardware.devices.retrieve({
306
+ const result = await client.devices.retrieve({
271
307
  racks: [testRack.key],
272
308
  });
273
309
  expect(result.length).toBeGreaterThanOrEqual(5);
@@ -275,7 +311,7 @@ describe("Device", async () => {
275
311
  });
276
312
 
277
313
  it("should retrieve devices by search term", async () => {
278
- const result = await client.hardware.devices.retrieve({
314
+ const result = await client.devices.retrieve({
279
315
  searchTerm: "sensor1",
280
316
  });
281
317
  expect(result.length).toBeGreaterThanOrEqual(2);
@@ -283,14 +319,14 @@ describe("Device", async () => {
283
319
  });
284
320
 
285
321
  it("should support pagination with limit and offset", async () => {
286
- const firstPage = await client.hardware.devices.retrieve({
322
+ const firstPage = await client.devices.retrieve({
287
323
  racks: [testRack.key],
288
324
  limit: 2,
289
325
  offset: 0,
290
326
  });
291
327
  expect(firstPage).toHaveLength(2);
292
328
 
293
- const secondPage = await client.hardware.devices.retrieve({
329
+ const secondPage = await client.devices.retrieve({
294
330
  racks: [testRack.key],
295
331
  limit: 2,
296
332
  offset: 2,
@@ -303,7 +339,7 @@ describe("Device", async () => {
303
339
  });
304
340
 
305
341
  it("should support combined filters", async () => {
306
- const result = await client.hardware.devices.retrieve({
342
+ const result = await client.devices.retrieve({
307
343
  makes: ["ni"],
308
344
  locations: ["Lab1", "Lab2"],
309
345
  includeStatus: true,
@@ -315,7 +351,7 @@ describe("Device", async () => {
315
351
 
316
352
  await expect
317
353
  .poll(async () => {
318
- const devices = await client.hardware.devices.retrieve({
354
+ const devices = await client.devices.retrieve({
319
355
  makes: ["ni"],
320
356
  locations: ["Lab1", "Lab2"],
321
357
  includeStatus: true,
@@ -0,0 +1,11 @@
1
+ // Copyright 2025 Synnax Labs, Inc.
2
+ //
3
+ // Use of this software is governed by the Business Source License included in the file
4
+ // licenses/BSL.txt.
5
+ //
6
+ // As of the Change Date specified in that file, in accordance with the Business Source
7
+ // License, use of this software will be governed by the Apache License, Version 2.0,
8
+ // included in the file licenses/APL.txt.
9
+
10
+ export * from "@/device/client";
11
+ export * from "@/device/payload";
@@ -7,4 +7,4 @@
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
- export * as rack from "@/hardware/rack/external";
10
+ export * as device from "@/device/external";
@@ -10,14 +10,14 @@
10
10
  import { binary, record, status, zod } from "@synnaxlabs/x";
11
11
  import { z } from "zod";
12
12
 
13
- import { keyZ as rackKeyZ } from "@/hardware/rack/payload";
13
+ import { keyZ as rackKeyZ } from "@/rack/payload";
14
14
  import { decodeJSONString } from "@/util/decodeJSONString";
15
15
 
16
16
  export const keyZ = z.string();
17
17
  export type Key = z.infer<typeof keyZ>;
18
18
 
19
- export const statusDetailsSchema = z.object({ rack: rackKeyZ, device: keyZ });
20
- export const statusZ = status.statusZ(statusDetailsSchema);
19
+ export const statusDetailsZ = z.object({ rack: rackKeyZ, device: keyZ });
20
+ export const statusZ = status.statusZ(statusDetailsZ);
21
21
 
22
22
  export interface Status extends z.infer<typeof statusZ> {}
23
23
 
package/src/errors.ts CHANGED
@@ -51,6 +51,8 @@ export class InvalidTokenError extends AuthError.sub("invalid_token") {}
51
51
 
52
52
  export class ExpiredTokenError extends AuthError.sub("expired_token") {}
53
53
 
54
+ export class AccessDeniedError extends AuthError.sub("access_denied") {}
55
+
54
56
  /**
55
57
  * UnexpectedError is raised when an unexpected error occurs.
56
58
  */
@@ -7,7 +7,7 @@
7
7
  // License, use of this software will be governed by the Apache License, Version 2.0,
8
8
  // included in the file licenses/APL.txt.
9
9
 
10
- import { DataType, Series, TimeStamp } from "@synnaxlabs/x";
10
+ import { DataType, id, Series, TimeStamp } from "@synnaxlabs/x";
11
11
  import { beforeAll, describe, expect, it } from "vitest";
12
12
 
13
13
  import { type channel } from "@/channel";
@@ -24,12 +24,12 @@ describe("WriteFrameAdapter", () => {
24
24
 
25
25
  beforeAll(async () => {
26
26
  timeCh = await client.channels.create({
27
- name: `time-${Math.random()}-${TimeStamp.now().toString()}`,
27
+ name: id.create(),
28
28
  dataType: DataType.TIMESTAMP,
29
29
  isIndex: true,
30
30
  });
31
31
  dataCh = await client.channels.create({
32
- name: `data-${Math.random()}-${TimeStamp.now().toString()}`,
32
+ name: id.create(),
33
33
  dataType: DataType.FLOAT32,
34
34
  index: timeCh.key,
35
35
  });
@@ -118,7 +118,7 @@ describe("WriteFrameAdapter", () => {
118
118
 
119
119
  it("should correctly adapt a name and JSON value", async () => {
120
120
  const jsonChannel = await client.channels.create({
121
- name: `json-${Math.random()}-${TimeStamp.now().toString()}`,
121
+ name: id.create(),
122
122
  dataType: DataType.JSON,
123
123
  virtual: true,
124
124
  });
@@ -134,7 +134,7 @@ describe("WriteFrameAdapter", () => {
134
134
 
135
135
  it("should correctly adapt a name and a json typed series", async () => {
136
136
  const jsonChannel = await client.channels.create({
137
- name: `json-${Math.random()}-${TimeStamp.now().toString()}`,
137
+ name: id.create(),
138
138
  dataType: DataType.JSON,
139
139
  virtual: true,
140
140
  });
@@ -150,7 +150,7 @@ describe("WriteFrameAdapter", () => {
150
150
 
151
151
  it("should correctly adapt a numeric value to a BigInt keyed by key", async () => {
152
152
  const bigIntCh = await client.channels.create({
153
- name: `bigint-${Math.random()}-${TimeStamp.now().toString()}`,
153
+ name: id.create(),
154
154
  dataType: DataType.INT64,
155
155
  virtual: true,
156
156
  });
@@ -176,7 +176,7 @@ describe("WriteFrameAdapter", () => {
176
176
 
177
177
  it("should return true when adding a new channel", async () => {
178
178
  const newCh = await client.channels.create({
179
- name: `new-${Math.random()}-${TimeStamp.now().toString()}`,
179
+ name: id.create(),
180
180
  dataType: DataType.FLOAT32,
181
181
  index: timeCh.key,
182
182
  });
@@ -191,7 +191,7 @@ describe("WriteFrameAdapter", () => {
191
191
 
192
192
  it("should return true when replacing channels", async () => {
193
193
  const newCh = await client.channels.create({
194
- name: `replacement-${Math.random()}-${TimeStamp.now().toString()}`,
194
+ name: id.create(),
195
195
  dataType: DataType.FLOAT32,
196
196
  index: timeCh.key,
197
197
  });
@@ -221,17 +221,17 @@ describe("ReadFrameAdapter", () => {
221
221
 
222
222
  beforeAll(async () => {
223
223
  timeCh = await client.channels.create({
224
- name: `read-time-${Math.random()}-${TimeStamp.now().toString()}`,
224
+ name: id.create(),
225
225
  dataType: DataType.TIMESTAMP,
226
226
  isIndex: true,
227
227
  });
228
228
  dataCh = await client.channels.create({
229
- name: `read-data-${Math.random()}-${TimeStamp.now().toString()}`,
229
+ name: id.create(),
230
230
  dataType: DataType.FLOAT32,
231
231
  index: timeCh.key,
232
232
  });
233
233
  extraCh = await client.channels.create({
234
- name: `read-extra-${Math.random()}-${TimeStamp.now().toString()}`,
234
+ name: id.create(),
235
235
  dataType: DataType.FLOAT64,
236
236
  index: timeCh.key,
237
237
  });
@@ -471,7 +471,7 @@ describe("ReadFrameAdapter", () => {
471
471
  describe("data integrity", () => {
472
472
  it("should preserve series values across multiple data types", async () => {
473
473
  const int64Ch = await client.channels.create({
474
- name: `read-int64-${Math.random()}-${TimeStamp.now().toString()}`,
474
+ name: id.create(),
475
475
  dataType: DataType.INT64,
476
476
  index: timeCh.key,
477
477
  });
@@ -582,7 +582,7 @@ describe("ReadFrameAdapter", () => {
582
582
 
583
583
  it("should return true when adding a new channel", async () => {
584
584
  const newCh = await client.channels.create({
585
- name: `read-new-${Math.random()}-${TimeStamp.now().toString()}`,
585
+ name: id.create(),
586
586
  dataType: DataType.FLOAT32,
587
587
  index: timeCh.key,
588
588
  });
@@ -597,7 +597,7 @@ describe("ReadFrameAdapter", () => {
597
597
 
598
598
  it("should return true when replacing channels", async () => {
599
599
  const newCh = await client.channels.create({
600
- name: `read-replacement-${Math.random()}-${TimeStamp.now().toString()}`,
600
+ name: id.create(),
601
601
  dataType: DataType.FLOAT32,
602
602
  index: timeCh.key,
603
603
  });
@@ -7,7 +7,7 @@
7
7
  // License, use of this software will be governed by the Apache License, Version 2.0,
8
8
  // included in the file licenses/APL.txt.
9
9
 
10
- import { TimeSpan, TimeStamp } from "@synnaxlabs/x";
10
+ import { id, TimeSpan, TimeStamp } from "@synnaxlabs/x";
11
11
  import { describe, expect, it } from "vitest";
12
12
 
13
13
  import { createTestClient } from "@/testutil/client";
@@ -17,14 +17,13 @@ const client = createTestClient();
17
17
  describe("Client", () => {
18
18
  describe("read + write", () => {
19
19
  it("should correctly write and read a frame of data", async () => {
20
- const rand = `${TimeStamp.now().toString()}${Math.random()}`;
21
20
  const time = await client.channels.create({
22
- name: `time-${rand}`,
21
+ name: id.create(),
23
22
  dataType: "timestamp",
24
23
  isIndex: true,
25
24
  });
26
25
  const data = await client.channels.create({
27
- name: `data-${rand}`,
26
+ name: id.create(),
28
27
  dataType: "float32",
29
28
  index: time.key,
30
29
  });
@@ -38,14 +37,13 @@ describe("Client", () => {
38
37
  expect(Array.from(frame.get(data.key))).toEqual([1]);
39
38
  });
40
39
  it("should correctly write a single series of data", async () => {
41
- const rand = `${TimeStamp.now().toString()}${Math.random()}`;
42
40
  const time = await client.channels.create({
43
- name: `time-${rand}`,
41
+ name: id.create(),
44
42
  dataType: "timestamp",
45
43
  isIndex: true,
46
44
  });
47
45
  const data = await client.channels.create({
48
- name: `data-${rand}`,
46
+ name: id.create(),
49
47
  dataType: "float32",
50
48
  index: time.key,
51
49
  });
@@ -62,14 +60,13 @@ describe("Client", () => {
62
60
  });
63
61
  describe("readLatestN", () => {
64
62
  it("should correctly read the latest N samples from a single channel", async () => {
65
- const rand = `${TimeStamp.now().toString()}${Math.random()}`;
66
63
  const time = await client.channels.create({
67
- name: `time-${rand}`,
64
+ name: id.create(),
68
65
  dataType: "timestamp",
69
66
  isIndex: true,
70
67
  });
71
68
  const data = await client.channels.create({
72
- name: `data-${rand}`,
69
+ name: id.create(),
73
70
  dataType: "float32",
74
71
  index: time.key,
75
72
  });
@@ -94,19 +91,18 @@ describe("Client", () => {
94
91
  });
95
92
 
96
93
  it("should correctly read the latest N samples from multiple channels", async () => {
97
- const rand = `${TimeStamp.now().toString()}${Math.random()}`;
98
94
  const time = await client.channels.create({
99
- name: `time-${rand}`,
95
+ name: id.create(),
100
96
  dataType: "timestamp",
101
97
  isIndex: true,
102
98
  });
103
99
  const data1 = await client.channels.create({
104
- name: `data1-${rand}`,
100
+ name: id.create(),
105
101
  dataType: "float32",
106
102
  index: time.key,
107
103
  });
108
104
  const data2 = await client.channels.create({
109
- name: `data2-${rand}`,
105
+ name: id.create(),
110
106
  dataType: "float32",
111
107
  index: time.key,
112
108
  });
@@ -142,14 +138,13 @@ describe("Client", () => {
142
138
  });
143
139
 
144
140
  it("should return empty series when no data exists", async () => {
145
- const rand = `${TimeStamp.now().toString()}${Math.random()}`;
146
141
  const time = await client.channels.create({
147
- name: `time-${rand}`,
142
+ name: id.create(),
148
143
  dataType: "timestamp",
149
144
  isIndex: true,
150
145
  });
151
146
  const data = await client.channels.create({
152
- name: `data-${rand}`,
147
+ name: id.create(),
153
148
  dataType: "float32",
154
149
  index: time.key,
155
150
  });
@@ -159,14 +154,13 @@ describe("Client", () => {
159
154
  });
160
155
 
161
156
  it("should correctly handle N larger than available data", async () => {
162
- const rand = `${TimeStamp.now().toString()}${Math.random()}`;
163
157
  const time = await client.channels.create({
164
- name: `time-${rand}`,
158
+ name: id.create(),
165
159
  dataType: "timestamp",
166
160
  isIndex: true,
167
161
  });
168
162
  const data = await client.channels.create({
169
- name: `data-${rand}`,
163
+ name: id.create(),
170
164
  dataType: "float32",
171
165
  index: time.key,
172
166
  });
@@ -21,19 +21,19 @@ import { channel } from "@/channel";
21
21
  import { Deleter } from "@/framer/deleter";
22
22
  import { Frame } from "@/framer/frame";
23
23
  import { AUTO_SPAN, Iterator, type IteratorConfig } from "@/framer/iterator";
24
+ import { Reader, type ReadRequest } from "@/framer/reader";
24
25
  import { openStreamer, type Streamer, type StreamerConfig } from "@/framer/streamer";
25
26
  import { Writer, type WriterConfig, WriterMode } from "@/framer/writer";
26
- import { type ontology } from "@/ontology";
27
+ import { ontology } from "@/ontology";
27
28
 
28
- export const ontologyID = (key: channel.Key): ontology.ID => ({
29
- type: "framer",
30
- key: key.toString(),
31
- });
29
+ export const ontologyID = ontology.createIDFactory<string>("framer");
30
+ export const TYPE_ONTOLOGY_ID = ontologyID("");
32
31
 
33
32
  export class Client {
34
33
  private readonly streamClient: WebSocketClient;
35
34
  private readonly retriever: channel.Retriever;
36
35
  private readonly deleter: Deleter;
36
+ private readonly reader: Reader;
37
37
 
38
38
  constructor(
39
39
  stream: WebSocketClient,
@@ -43,6 +43,7 @@ export class Client {
43
43
  this.streamClient = stream;
44
44
  this.retriever = retriever;
45
45
  this.deleter = new Deleter(unary);
46
+ this.reader = new Reader(retriever, stream);
46
47
  }
47
48
 
48
49
  /**
@@ -142,15 +143,15 @@ export class Client {
142
143
  }
143
144
 
144
145
  async read(tr: CrudeTimeRange, channel: channel.KeyOrName): Promise<MultiSeries>;
145
-
146
146
  async read(tr: CrudeTimeRange, channels: channel.Params): Promise<Frame>;
147
-
147
+ async read(request: ReadRequest): Promise<ReadableStream<Uint8Array>>;
148
148
  async read(
149
- tr: CrudeTimeRange,
150
- channels: channel.Params,
151
- ): Promise<MultiSeries | Frame> {
152
- const { single } = channel.analyzeParams(channels);
153
- const fr = await this.readFrame(tr, channels);
149
+ tr: CrudeTimeRange | ReadRequest,
150
+ channels?: channel.Params,
151
+ ): Promise<MultiSeries | Frame | ReadableStream<Uint8Array>> {
152
+ if (!("start" in tr)) return this.reader.read(tr);
153
+ const { single } = channel.analyzeParams(channels!);
154
+ const fr = await this.readFrame(tr, channels!);
154
155
  if (single) return fr.get(channels as channel.KeyOrName);
155
156
  return fr;
156
157
  }
@@ -201,13 +202,7 @@ export class Client {
201
202
  const { normalized, variant } = channel.analyzeParams(channels);
202
203
  const bounds = new TimeRange(timeRange);
203
204
  if (variant === "keys")
204
- return await this.deleter.delete({
205
- keys: normalized as channel.Key[],
206
- bounds,
207
- });
208
- return await this.deleter.delete({
209
- names: normalized as string[],
210
- bounds,
211
- });
205
+ return await this.deleter.delete({ keys: normalized as channel.Key[], bounds });
206
+ return await this.deleter.delete({ names: normalized as string[], bounds });
212
207
  }
213
208
  }
@@ -58,7 +58,7 @@ describe("Deleter", () => {
58
58
  });
59
59
 
60
60
  await expect(
61
- client.delete(["billy bob", dataCh.name], TimeRange.MAX),
61
+ client.delete(["nonexistent_channel_name", dataCh.name], TimeRange.MAX),
62
62
  ).rejects.toThrow(NotFoundError);
63
63
 
64
64
  const res = await client.read(TimeRange.MAX, dataCh.key);