@synnaxlabs/client 0.50.0 → 0.53.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 (264) hide show
  1. package/.turbo/turbo-build.log +7 -7
  2. package/dist/client.cjs +58 -34
  3. package/dist/client.js +5368 -4546
  4. package/dist/eslint.config.d.ts +2 -2
  5. package/dist/eslint.config.d.ts.map +1 -1
  6. package/dist/src/access/policy/client.d.ts +90 -90
  7. package/dist/src/access/policy/payload.d.ts +17 -17
  8. package/dist/src/access/role/payload.d.ts +2 -2
  9. package/dist/src/arc/payload.d.ts +2 -2
  10. package/dist/src/channel/client.d.ts +4 -5
  11. package/dist/src/channel/client.d.ts.map +1 -1
  12. package/dist/src/channel/payload.d.ts +9 -11
  13. package/dist/src/channel/payload.d.ts.map +1 -1
  14. package/dist/src/channel/retriever.d.ts.map +1 -1
  15. package/dist/src/client.d.ts +10 -0
  16. package/dist/src/client.d.ts.map +1 -1
  17. package/dist/src/device/client.d.ts +14 -7
  18. package/dist/src/device/client.d.ts.map +1 -1
  19. package/dist/src/device/payload.d.ts +65 -32
  20. package/dist/src/device/payload.d.ts.map +1 -1
  21. package/dist/src/device/payload.spec.d.ts +2 -0
  22. package/dist/src/device/payload.spec.d.ts.map +1 -0
  23. package/dist/src/framer/adapter.d.ts.map +1 -1
  24. package/dist/src/framer/client.d.ts +2 -2
  25. package/dist/src/framer/frame.d.ts +5 -5
  26. package/dist/src/framer/frame.d.ts.map +1 -1
  27. package/dist/src/framer/streamer.d.ts +6 -6
  28. package/dist/src/framer/writer.d.ts +9 -9
  29. package/dist/src/group/access.spec.d.ts.map +1 -0
  30. package/dist/src/{ontology/group → group}/client.d.ts +3 -3
  31. package/dist/src/group/client.d.ts.map +1 -0
  32. package/dist/src/group/external.d.ts.map +1 -0
  33. package/dist/src/group/group.spec.d.ts.map +1 -0
  34. package/dist/src/group/index.d.ts.map +1 -0
  35. package/dist/src/{ontology/group → group}/payload.d.ts +1 -1
  36. package/dist/src/group/payload.d.ts.map +1 -0
  37. package/dist/src/index.d.ts +5 -5
  38. package/dist/src/index.d.ts.map +1 -1
  39. package/dist/src/label/client.d.ts +27 -13
  40. package/dist/src/label/client.d.ts.map +1 -1
  41. package/dist/src/label/payload.d.ts +15 -1
  42. package/dist/src/label/payload.d.ts.map +1 -1
  43. package/dist/src/lineplot/access.spec.d.ts.map +1 -0
  44. package/dist/src/{workspace/lineplot → lineplot}/client.d.ts +6 -6
  45. package/dist/src/lineplot/client.d.ts.map +1 -0
  46. package/dist/src/lineplot/external.d.ts.map +1 -0
  47. package/dist/src/lineplot/index.d.ts.map +1 -0
  48. package/dist/src/lineplot/lineplot.spec.d.ts.map +1 -0
  49. package/dist/src/lineplot/payload.d.ts.map +1 -0
  50. package/dist/src/log/access.spec.d.ts.map +1 -0
  51. package/dist/src/{workspace/log → log}/client.d.ts +6 -6
  52. package/dist/src/log/client.d.ts.map +1 -0
  53. package/dist/src/log/external.d.ts.map +1 -0
  54. package/dist/src/log/index.d.ts.map +1 -0
  55. package/dist/src/log/log.spec.d.ts.map +1 -0
  56. package/dist/src/log/payload.d.ts.map +1 -0
  57. package/dist/src/ontology/client.d.ts +6 -10
  58. package/dist/src/ontology/client.d.ts.map +1 -1
  59. package/dist/src/ontology/payload.d.ts +22 -22
  60. package/dist/src/ontology/writer.d.ts +15 -15
  61. package/dist/src/rack/client.d.ts +3 -3
  62. package/dist/src/rack/client.d.ts.map +1 -1
  63. package/dist/src/rack/payload.d.ts +44 -16
  64. package/dist/src/rack/payload.d.ts.map +1 -1
  65. package/dist/src/ranger/alias/client.d.ts +17 -0
  66. package/dist/src/ranger/alias/client.d.ts.map +1 -0
  67. package/dist/src/ranger/alias/external.d.ts +2 -0
  68. package/dist/src/ranger/alias/external.d.ts.map +1 -0
  69. package/dist/src/ranger/alias/index.d.ts +2 -0
  70. package/dist/src/ranger/alias/index.d.ts.map +1 -0
  71. package/dist/src/ranger/{alias.d.ts → alias/payload.d.ts} +14 -20
  72. package/dist/src/ranger/alias/payload.d.ts.map +1 -0
  73. package/dist/src/ranger/client.d.ts +10 -10
  74. package/dist/src/ranger/client.d.ts.map +1 -1
  75. package/dist/src/ranger/external.d.ts +20 -0
  76. package/dist/src/ranger/external.d.ts.map +1 -1
  77. package/dist/src/ranger/kv/client.d.ts +14 -0
  78. package/dist/src/ranger/kv/client.d.ts.map +1 -0
  79. package/dist/src/ranger/kv/external.d.ts +2 -0
  80. package/dist/src/ranger/kv/external.d.ts.map +1 -0
  81. package/dist/src/ranger/kv/index.d.ts +2 -0
  82. package/dist/src/ranger/kv/index.d.ts.map +1 -0
  83. package/dist/src/ranger/kv/payload.d.ts +26 -0
  84. package/dist/src/ranger/kv/payload.d.ts.map +1 -0
  85. package/dist/src/ranger/payload.d.ts +45 -3
  86. package/dist/src/ranger/payload.d.ts.map +1 -1
  87. package/dist/src/ranger/writer.d.ts +18 -4
  88. package/dist/src/ranger/writer.d.ts.map +1 -1
  89. package/dist/src/schematic/access.spec.d.ts.map +1 -0
  90. package/dist/src/{workspace/schematic → schematic}/client.d.ts +6 -6
  91. package/dist/src/schematic/client.d.ts.map +1 -0
  92. package/dist/src/schematic/external.d.ts.map +1 -0
  93. package/dist/src/schematic/index.d.ts.map +1 -0
  94. package/dist/src/schematic/payload.d.ts.map +1 -0
  95. package/dist/src/schematic/schematic.spec.d.ts.map +1 -0
  96. package/dist/src/schematic/symbol/access.spec.d.ts.map +1 -0
  97. package/dist/src/{workspace/schematic → schematic}/symbol/client.d.ts +2 -2
  98. package/dist/src/schematic/symbol/client.d.ts.map +1 -0
  99. package/dist/src/schematic/symbol/client.spec.d.ts.map +1 -0
  100. package/dist/src/schematic/symbol/external.d.ts.map +1 -0
  101. package/dist/src/schematic/symbol/index.d.ts.map +1 -0
  102. package/dist/src/schematic/symbol/payload.d.ts.map +1 -0
  103. package/dist/src/status/payload.d.ts +43 -7
  104. package/dist/src/status/payload.d.ts.map +1 -1
  105. package/dist/src/table/access.spec.d.ts.map +1 -0
  106. package/dist/src/{workspace/table → table}/client.d.ts +6 -6
  107. package/dist/src/table/client.d.ts.map +1 -0
  108. package/dist/src/table/external.d.ts.map +1 -0
  109. package/dist/src/table/index.d.ts.map +1 -0
  110. package/dist/src/table/payload.d.ts.map +1 -0
  111. package/dist/src/table/table.spec.d.ts.map +1 -0
  112. package/dist/src/task/client.d.ts +19 -21
  113. package/dist/src/task/client.d.ts.map +1 -1
  114. package/dist/src/task/payload.d.ts +32 -27
  115. package/dist/src/task/payload.d.ts.map +1 -1
  116. package/dist/src/user/client.d.ts +2 -2
  117. package/dist/src/view/client.d.ts +2 -2
  118. package/dist/src/workspace/client.d.ts +2 -10
  119. package/dist/src/workspace/client.d.ts.map +1 -1
  120. package/eslint.config.ts +2 -3
  121. package/package.json +10 -9
  122. package/src/arc/lsp.spec.ts +155 -283
  123. package/src/channel/client.ts +3 -5
  124. package/src/channel/payload.spec.ts +0 -57
  125. package/src/channel/payload.ts +7 -14
  126. package/src/channel/retriever.ts +2 -3
  127. package/src/client.ts +16 -1
  128. package/src/device/client.ts +89 -43
  129. package/src/device/payload.spec.ts +118 -0
  130. package/src/device/payload.ts +55 -30
  131. package/src/errors.spec.ts +1 -1
  132. package/src/framer/adapter.ts +5 -7
  133. package/src/framer/frame.ts +8 -8
  134. package/src/{ontology/group → group}/access.spec.ts +7 -7
  135. package/src/{ontology/group → group}/client.ts +1 -1
  136. package/src/group/external.ts +11 -0
  137. package/src/{ontology/group → group}/group.spec.ts +9 -9
  138. package/src/{workspace/log → group}/index.ts +1 -1
  139. package/src/index.ts +5 -5
  140. package/src/label/access.spec.ts +1 -1
  141. package/src/label/client.ts +1 -1
  142. package/src/label/label.spec.ts +4 -4
  143. package/src/{workspace/lineplot → lineplot}/access.spec.ts +14 -14
  144. package/src/{workspace/lineplot → lineplot}/client.ts +13 -13
  145. package/src/lineplot/external.ts +11 -0
  146. package/src/{ontology/group → lineplot}/index.ts +1 -1
  147. package/src/{workspace/lineplot → lineplot}/lineplot.spec.ts +12 -12
  148. package/src/{workspace/log → log}/access.spec.ts +16 -18
  149. package/src/{workspace/log → log}/client.ts +13 -13
  150. package/src/{workspace/schematic/index.ts → log/external.ts} +2 -1
  151. package/src/{workspace/table → log}/index.ts +1 -1
  152. package/src/{workspace/log → log}/log.spec.ts +10 -10
  153. package/src/ontology/client.ts +1 -7
  154. package/src/ontology/ontology.spec.ts +12 -12
  155. package/src/rack/client.ts +10 -21
  156. package/src/ranger/{alias.ts → alias/client.ts} +6 -37
  157. package/src/{workspace/lineplot → ranger/alias}/external.ts +10 -2
  158. package/src/{workspace/lineplot → ranger/alias}/index.ts +1 -1
  159. package/src/ranger/alias/payload.ts +50 -0
  160. package/src/ranger/client.ts +26 -19
  161. package/src/ranger/external.ts +22 -0
  162. package/src/ranger/{kv.ts → kv/client.ts} +5 -19
  163. package/src/{workspace/schematic → ranger/kv}/external.ts +7 -3
  164. package/src/ranger/kv/index.ts +10 -0
  165. package/src/ranger/kv/payload.ts +32 -0
  166. package/src/ranger/payload.ts +2 -2
  167. package/src/ranger/ranger.spec.ts +1 -1
  168. package/src/{workspace/schematic → schematic}/access.spec.ts +14 -14
  169. package/src/{workspace/schematic → schematic}/client.ts +14 -14
  170. package/src/{workspace/log → schematic}/external.ts +3 -2
  171. package/src/schematic/index.ts +10 -0
  172. package/src/{workspace/schematic → schematic}/schematic.spec.ts +17 -17
  173. package/src/{workspace/schematic → schematic}/symbol/access.spec.ts +19 -19
  174. package/src/{workspace/schematic → schematic}/symbol/client.spec.ts +16 -16
  175. package/src/{workspace/schematic → schematic}/symbol/client.ts +8 -8
  176. package/src/{ontology/group → schematic/symbol}/external.ts +2 -2
  177. package/src/schematic/symbol/index.ts +10 -0
  178. package/src/status/payload.ts +1 -1
  179. package/src/status/status.spec.ts +2 -2
  180. package/src/{workspace/table → table}/access.spec.ts +14 -14
  181. package/src/{workspace/table → table}/client.ts +15 -12
  182. package/src/table/external.ts +11 -0
  183. package/src/table/index.ts +10 -0
  184. package/src/{workspace/table → table}/table.spec.ts +12 -12
  185. package/src/task/client.ts +56 -148
  186. package/src/task/payload.ts +34 -58
  187. package/src/workspace/client.ts +0 -12
  188. package/dist/src/ontology/group/access.spec.d.ts.map +0 -1
  189. package/dist/src/ontology/group/client.d.ts.map +0 -1
  190. package/dist/src/ontology/group/external.d.ts.map +0 -1
  191. package/dist/src/ontology/group/group.spec.d.ts.map +0 -1
  192. package/dist/src/ontology/group/index.d.ts.map +0 -1
  193. package/dist/src/ontology/group/payload.d.ts.map +0 -1
  194. package/dist/src/ranger/alias.d.ts.map +0 -1
  195. package/dist/src/ranger/kv.d.ts +0 -48
  196. package/dist/src/ranger/kv.d.ts.map +0 -1
  197. package/dist/src/workspace/lineplot/access.spec.d.ts.map +0 -1
  198. package/dist/src/workspace/lineplot/client.d.ts.map +0 -1
  199. package/dist/src/workspace/lineplot/external.d.ts.map +0 -1
  200. package/dist/src/workspace/lineplot/index.d.ts.map +0 -1
  201. package/dist/src/workspace/lineplot/lineplot.spec.d.ts.map +0 -1
  202. package/dist/src/workspace/lineplot/payload.d.ts.map +0 -1
  203. package/dist/src/workspace/log/access.spec.d.ts.map +0 -1
  204. package/dist/src/workspace/log/client.d.ts.map +0 -1
  205. package/dist/src/workspace/log/external.d.ts.map +0 -1
  206. package/dist/src/workspace/log/index.d.ts.map +0 -1
  207. package/dist/src/workspace/log/log.spec.d.ts.map +0 -1
  208. package/dist/src/workspace/log/payload.d.ts.map +0 -1
  209. package/dist/src/workspace/schematic/access.spec.d.ts.map +0 -1
  210. package/dist/src/workspace/schematic/client.d.ts.map +0 -1
  211. package/dist/src/workspace/schematic/external.d.ts.map +0 -1
  212. package/dist/src/workspace/schematic/index.d.ts.map +0 -1
  213. package/dist/src/workspace/schematic/payload.d.ts.map +0 -1
  214. package/dist/src/workspace/schematic/schematic.spec.d.ts.map +0 -1
  215. package/dist/src/workspace/schematic/symbol/access.spec.d.ts.map +0 -1
  216. package/dist/src/workspace/schematic/symbol/client.d.ts.map +0 -1
  217. package/dist/src/workspace/schematic/symbol/client.spec.d.ts.map +0 -1
  218. package/dist/src/workspace/schematic/symbol/external.d.ts.map +0 -1
  219. package/dist/src/workspace/schematic/symbol/index.d.ts.map +0 -1
  220. package/dist/src/workspace/schematic/symbol/payload.d.ts.map +0 -1
  221. package/dist/src/workspace/table/access.spec.d.ts.map +0 -1
  222. package/dist/src/workspace/table/client.d.ts.map +0 -1
  223. package/dist/src/workspace/table/external.d.ts.map +0 -1
  224. package/dist/src/workspace/table/index.d.ts.map +0 -1
  225. package/dist/src/workspace/table/payload.d.ts.map +0 -1
  226. package/dist/src/workspace/table/table.spec.d.ts.map +0 -1
  227. package/src/workspace/schematic/symbol/external.ts +0 -11
  228. package/src/workspace/schematic/symbol/index.ts +0 -10
  229. package/src/workspace/table/external.ts +0 -11
  230. /package/dist/src/{ontology/group → group}/access.spec.d.ts +0 -0
  231. /package/dist/src/{ontology/group → group}/external.d.ts +0 -0
  232. /package/dist/src/{ontology/group → group}/group.spec.d.ts +0 -0
  233. /package/dist/src/{ontology/group → group}/index.d.ts +0 -0
  234. /package/dist/src/{workspace/lineplot → lineplot}/access.spec.d.ts +0 -0
  235. /package/dist/src/{workspace/lineplot → lineplot}/external.d.ts +0 -0
  236. /package/dist/src/{workspace/lineplot → lineplot}/index.d.ts +0 -0
  237. /package/dist/src/{workspace/lineplot → lineplot}/lineplot.spec.d.ts +0 -0
  238. /package/dist/src/{workspace/lineplot → lineplot}/payload.d.ts +0 -0
  239. /package/dist/src/{workspace/log → log}/access.spec.d.ts +0 -0
  240. /package/dist/src/{workspace/log → log}/external.d.ts +0 -0
  241. /package/dist/src/{workspace/log → log}/index.d.ts +0 -0
  242. /package/dist/src/{workspace/log → log}/log.spec.d.ts +0 -0
  243. /package/dist/src/{workspace/log → log}/payload.d.ts +0 -0
  244. /package/dist/src/{workspace/schematic → schematic}/access.spec.d.ts +0 -0
  245. /package/dist/src/{workspace/schematic → schematic}/external.d.ts +0 -0
  246. /package/dist/src/{workspace/schematic → schematic}/index.d.ts +0 -0
  247. /package/dist/src/{workspace/schematic → schematic}/payload.d.ts +0 -0
  248. /package/dist/src/{workspace/schematic → schematic}/schematic.spec.d.ts +0 -0
  249. /package/dist/src/{workspace/schematic → schematic}/symbol/access.spec.d.ts +0 -0
  250. /package/dist/src/{workspace/schematic → schematic}/symbol/client.spec.d.ts +0 -0
  251. /package/dist/src/{workspace/schematic → schematic}/symbol/external.d.ts +0 -0
  252. /package/dist/src/{workspace/schematic → schematic}/symbol/index.d.ts +0 -0
  253. /package/dist/src/{workspace/schematic → schematic}/symbol/payload.d.ts +0 -0
  254. /package/dist/src/{workspace/table → table}/access.spec.d.ts +0 -0
  255. /package/dist/src/{workspace/table → table}/external.d.ts +0 -0
  256. /package/dist/src/{workspace/table → table}/index.d.ts +0 -0
  257. /package/dist/src/{workspace/table → table}/payload.d.ts +0 -0
  258. /package/dist/src/{workspace/table → table}/table.spec.d.ts +0 -0
  259. /package/src/{ontology/group → group}/payload.ts +0 -0
  260. /package/src/{workspace/lineplot → lineplot}/payload.ts +0 -0
  261. /package/src/{workspace/log → log}/payload.ts +0 -0
  262. /package/src/{workspace/schematic → schematic}/payload.ts +0 -0
  263. /package/src/{workspace/schematic → schematic}/symbol/payload.ts +0 -0
  264. /package/src/{workspace/table → table}/payload.ts +0 -0
@@ -24,7 +24,6 @@ import {
24
24
  type Key,
25
25
  type KeyOrName,
26
26
  keyZ,
27
- type Name,
28
27
  type New,
29
28
  ontologyID,
30
29
  type Operation,
@@ -45,8 +44,8 @@ import {
45
44
  import { type Writer } from "@/channel/writer";
46
45
  import { ValidationError } from "@/errors";
47
46
  import { type framer } from "@/framer";
47
+ import { group } from "@/group";
48
48
  import { type ontology } from "@/ontology";
49
- import { group } from "@/ontology/group";
50
49
  import { checkForMultipleOrNoResults } from "@/util/retrieve";
51
50
 
52
51
  interface CreateOptions {
@@ -73,10 +72,9 @@ export class Channel {
73
72
  */
74
73
  readonly key: Key;
75
74
  /**
76
- * A human-readable name for the channel. This name is not guaranteed to be
77
- * unique.
75
+ * A human-readable name for the channel. This name is not guaranteed to be unique.
78
76
  */
79
- readonly name: Name;
77
+ readonly name: string;
80
78
  /**
81
79
  * The data type of the channel.
82
80
  */
@@ -43,48 +43,6 @@ describe("nameZ", () => {
43
43
  expect(result.success).toBe(false);
44
44
  expect(result.error?.issues[0].message).toContain("Name must not be empty");
45
45
  });
46
-
47
- it("should reject name starting with digit", () => {
48
- const result = nameZ.safeParse("1sensor");
49
- expect(result.success).toBe(false);
50
- // Regex validation covers both "cannot start with digit" and "invalid characters"
51
- expect(result.error?.issues[0].message).toContain(
52
- "can only contain letters, digits, and underscores",
53
- );
54
- });
55
-
56
- it("should reject name with spaces", () => {
57
- const result = nameZ.safeParse("my channel");
58
- expect(result.success).toBe(false);
59
- expect(result.error?.issues[0].message).toContain(
60
- "can only contain letters, digits, and underscores",
61
- );
62
- });
63
-
64
- it("should reject name with special characters", () => {
65
- const result = nameZ.safeParse("sensor!");
66
- expect(result.success).toBe(false);
67
- });
68
-
69
- it("should reject name with hyphens", () => {
70
- const result = nameZ.safeParse("sensor-temp");
71
- expect(result.success).toBe(false);
72
- });
73
-
74
- it("should reject name with dots", () => {
75
- const result = nameZ.safeParse("sensor.temp");
76
- expect(result.success).toBe(false);
77
- });
78
-
79
- it("should reject name with parentheses", () => {
80
- const result = nameZ.safeParse("sensor(1)");
81
- expect(result.success).toBe(false);
82
- });
83
-
84
- it("should reject name with brackets", () => {
85
- const result = nameZ.safeParse("sensor[0]");
86
- expect(result.success).toBe(false);
87
- });
88
46
  });
89
47
  });
90
48
 
@@ -106,21 +64,6 @@ describe("newZ", () => {
106
64
  expect(result.success).toBe(false);
107
65
  });
108
66
 
109
- it("should reject name starting with digit", () => {
110
- const result = newZ.safeParse({ ...validNewChannel, name: "1sensor" });
111
- expect(result.success).toBe(false);
112
- });
113
-
114
- it("should reject name with spaces", () => {
115
- const result = newZ.safeParse({ ...validNewChannel, name: "my channel" });
116
- expect(result.success).toBe(false);
117
- });
118
-
119
- it("should reject name with special characters", () => {
120
- const result = newZ.safeParse({ ...validNewChannel, name: "sensor-temp" });
121
- expect(result.success).toBe(false);
122
- });
123
-
124
67
  it("should accept name with underscores", () => {
125
68
  const result = newZ.safeParse({
126
69
  ...validNewChannel,
@@ -30,19 +30,10 @@ export const keyZ = z.uint32().or(
30
30
  );
31
31
  export type Key = z.infer<typeof keyZ>;
32
32
  export type Keys = Key[];
33
- const VALID_NAME_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
34
- export const nameZ = z
35
- .string()
36
- .min(1, "Name must not be empty")
37
- .regex(
38
- VALID_NAME_PATTERN,
39
- "Name can only contain letters, digits, and underscores, and cannot start with a digit",
40
- );
41
- export type Name = z.infer<typeof nameZ>;
42
- export type Names = Name[];
43
- export type KeyOrName = Key | Name;
44
- export type KeysOrNames = Keys | Names;
45
- export type PrimitiveParams = Key | Name | Keys | Names;
33
+ export const nameZ = z.string().min(1, "Name must not be empty");
34
+ export type KeyOrName = Key | string;
35
+ export type KeysOrNames = Keys | string[];
36
+ export type PrimitiveParams = KeyOrName | KeysOrNames;
46
37
 
47
38
  export const OPERATION_TYPES = ["min", "max", "avg", "none"] as const;
48
39
  export const operationType = z.enum(OPERATION_TYPES);
@@ -105,13 +96,15 @@ export const paramsZ = z.union([
105
96
  zod.toArray(nameZ),
106
97
  zod.toArray(payloadZ).transform((p) => p.map((c) => c.key)),
107
98
  ]);
108
- export type Params = Key | Name | Keys | Names | Payload | Payload[];
99
+ export type Params = PrimitiveParams | Payload | Payload[];
109
100
 
110
101
  export const ontologyID = ontology.createIDFactory<Key>("channel");
111
102
  export const TYPE_ONTOLOGY_ID = ontologyID(0);
112
103
 
113
104
  const CHAR_REGEX = /[a-zA-Z0-9_]/;
114
105
 
106
+ const VALID_NAME_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
107
+
115
108
  export const escapeInvalidName = (name: string, changeEmptyToUnderscore = false) => {
116
109
  if (name === "") return changeEmptyToUnderscore ? "_" : "";
117
110
  if (name.match(VALID_NAME_PATTERN)) return name;
@@ -18,11 +18,10 @@ import {
18
18
  type Keys,
19
19
  type KeysOrNames,
20
20
  keyZ,
21
- type Name,
22
- type Names,
23
21
  type Params,
24
22
  type Payload,
25
23
  payloadZ,
24
+ type PrimitiveParams,
26
25
  } from "@/channel/payload";
27
26
  import { QueryError } from "@/errors";
28
27
  import { keyZ as rangeKeyZ } from "@/ranger/payload";
@@ -62,7 +61,7 @@ export const analyzeParams = (
62
61
  if (Array.isArray(channels) && channels.length > 0 && typeof channels[0] === "object")
63
62
  channels = (channels as Payload[]).map((c) => c.key);
64
63
  else if (typeof channels === "object" && "key" in channels) channels = [channels.key];
65
- return analyzeParameters(channels as Key | Name | Keys | Names, {
64
+ return analyzeParameters(channels as PrimitiveParams, {
66
65
  number: "keys",
67
66
  string: "names",
68
67
  });
package/src/client.ts CHANGED
@@ -19,11 +19,16 @@ import { control } from "@/control";
19
19
  import { device } from "@/device";
20
20
  import { errorsMiddleware } from "@/errors";
21
21
  import { framer } from "@/framer";
22
+ import { group } from "@/group";
22
23
  import { label } from "@/label";
24
+ import { lineplot } from "@/lineplot";
25
+ import { log } from "@/log";
23
26
  import { ontology } from "@/ontology";
24
27
  import { rack } from "@/rack";
25
28
  import { ranger } from "@/ranger";
29
+ import { schematic } from "@/schematic";
26
30
  import { status } from "@/status";
31
+ import { table } from "@/table";
27
32
  import { task } from "@/task";
28
33
  import { Transport } from "@/transport";
29
34
  import { user } from "@/user";
@@ -73,6 +78,11 @@ export default class Synnax extends framer.Client {
73
78
  readonly control: control.Client;
74
79
  readonly arcs: arc.Client;
75
80
  readonly views: view.Client;
81
+ readonly schematics: schematic.Client;
82
+ readonly lineplots: lineplot.Client;
83
+ readonly logs: log.Client;
84
+ readonly tables: table.Client;
85
+ readonly groups: group.Client;
76
86
  static readonly connectivity = connection.Checker;
77
87
  private readonly transport: Transport;
78
88
 
@@ -131,7 +141,7 @@ export default class Synnax extends framer.Client {
131
141
  parsedParams.name,
132
142
  );
133
143
  this.control = new control.Client(this);
134
- this.ontology = new ontology.Client(transport.unary, this);
144
+ this.ontology = new ontology.Client(this.transport.unary);
135
145
  const rangeWriter = new ranger.Writer(this.transport.unary);
136
146
  this.labels = new label.Client(this.transport.unary);
137
147
  this.statuses = new status.Client(this.transport.unary);
@@ -156,6 +166,11 @@ export default class Synnax extends framer.Client {
156
166
  this.devices = new device.Client(this.transport.unary);
157
167
  this.arcs = new arc.Client(this.transport.unary, this.transport.stream);
158
168
  this.views = new view.Client(this.transport.unary);
169
+ this.schematics = new schematic.Client(this.transport.unary);
170
+ this.lineplots = new lineplot.Client(this.transport.unary);
171
+ this.logs = new log.Client(this.transport.unary);
172
+ this.tables = new table.Client(this.transport.unary);
173
+ this.groups = new group.Client(this.transport.unary);
159
174
  }
160
175
 
161
176
  get key(): string {
@@ -8,10 +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, type record } from "@synnaxlabs/x";
11
+ import { array, type record, zod } from "@synnaxlabs/x";
12
12
  import { z } from "zod";
13
13
 
14
- import { type Device, deviceZ, type Key, keyZ, type New, newZ } from "@/device/payload";
14
+ import {
15
+ type Device,
16
+ type DeviceSchemas,
17
+ deviceZ,
18
+ type Key,
19
+ keyZ,
20
+ type New,
21
+ newZ,
22
+ } from "@/device/payload";
15
23
  import { ontology } from "@/ontology";
16
24
  import { keyZ as rackKeyZ } from "@/rack/payload";
17
25
  import { checkForMultipleOrNoResults } from "@/util/retrieve";
@@ -19,8 +27,21 @@ import { checkForMultipleOrNoResults } from "@/util/retrieve";
19
27
  export const SET_CHANNEL_NAME = "sy_device_set";
20
28
  export const DELETE_CHANNEL_NAME = "sy_device_delete";
21
29
 
22
- const createReqZ = z.object({ devices: newZ.array() });
23
- const createResZ = z.object({ devices: deviceZ.array() });
30
+ const createReqZ = <
31
+ Properties extends z.ZodType<record.Unknown> = typeof record.unknownZ,
32
+ Make extends z.ZodType<string> = z.ZodString,
33
+ Model extends z.ZodType<string> = z.ZodString,
34
+ >(
35
+ schemas?: DeviceSchemas<Properties, Make, Model>,
36
+ ) => z.object({ devices: zod.toArray(newZ(schemas)) });
37
+
38
+ const createResZ = <
39
+ Properties extends z.ZodType<record.Unknown> = typeof record.unknownZ,
40
+ Make extends z.ZodType<string> = z.ZodString,
41
+ Model extends z.ZodType<string> = z.ZodString,
42
+ >(
43
+ schemas?: DeviceSchemas<Properties, Make, Model>,
44
+ ) => z.object({ devices: deviceZ(schemas).array() });
24
45
 
25
46
  const deleteReqZ = z.object({ keys: keyZ.array() });
26
47
  const deleteResZ = z.object({});
@@ -37,7 +58,14 @@ const retrieveRequestZ = z.object({
37
58
  offset: z.int().optional(),
38
59
  includeStatus: z.boolean().optional(),
39
60
  });
40
- const retrieveResZ = z.object({ devices: array.nullableZ(deviceZ) });
61
+
62
+ const retrieveResZ = <
63
+ Properties extends z.ZodType<record.Unknown> = typeof record.unknownZ,
64
+ Make extends z.ZodType<string> = z.ZodString,
65
+ Model extends z.ZodType<string> = z.ZodString,
66
+ >(
67
+ schemas?: DeviceSchemas<Properties, Make, Model>,
68
+ ) => z.object({ devices: array.nullableZ(deviceZ(schemas)) });
41
69
 
42
70
  const singleRetrieveArgsZ = z
43
71
  .object({
@@ -56,6 +84,12 @@ const retrieveArgsZ = z.union([singleRetrieveArgsZ, retrieveRequestZ]);
56
84
 
57
85
  export type RetrieveArgs = z.input<typeof retrieveArgsZ>;
58
86
 
87
+ type RetrieveSchemas<
88
+ Properties extends z.ZodType<record.Unknown>,
89
+ Make extends z.ZodType<string>,
90
+ Model extends z.ZodType<string>,
91
+ > = { schemas: DeviceSchemas<Properties, Make, Model> };
92
+
59
93
  export class Client {
60
94
  private readonly client: UnaryClient;
61
95
 
@@ -64,64 +98,76 @@ export class Client {
64
98
  }
65
99
 
66
100
  async retrieve<
67
- Properties extends record.Unknown = record.Unknown,
68
- Make extends string = string,
69
- Model extends string = string,
70
- >(args: RetrieveSingleParams): Promise<Device<Properties, Make, Model>>;
101
+ Properties extends z.ZodType<record.Unknown>,
102
+ Make extends z.ZodType<string>,
103
+ Model extends z.ZodType<string>,
104
+ >(
105
+ args: RetrieveSingleParams & RetrieveSchemas<Properties, Make, Model>,
106
+ ): Promise<Device<Properties, Make, Model>>;
71
107
 
72
- async retrieve<
73
- Properties extends record.Unknown = record.Unknown,
74
- Make extends string = string,
75
- Model extends string = string,
76
- >(args: RetrieveMultipleParams): Promise<Array<Device<Properties, Make, Model>>>;
108
+ async retrieve(args: RetrieveSingleParams): Promise<Device>;
77
109
 
78
110
  async retrieve<
79
- Properties extends record.Unknown = record.Unknown,
80
- Make extends string = string,
81
- Model extends string = string,
111
+ Properties extends z.ZodType<record.Unknown>,
112
+ Make extends z.ZodType<string>,
113
+ Model extends z.ZodType<string>,
82
114
  >(
83
- args: RetrieveArgs,
84
- ): Promise<Device<Properties, Make, Model> | Array<Device<Properties, Make, Model>>> {
85
- const isSingle = typeof args === "object" && "key" in args;
115
+ args: RetrieveMultipleParams & RetrieveSchemas<Properties, Make, Model>,
116
+ ): Promise<Array<Device<Properties, Make, Model>>>;
117
+
118
+ async retrieve(args: RetrieveMultipleParams): Promise<Array<Device>>;
119
+
120
+ async retrieve(
121
+ args: RetrieveArgs & { schemas?: DeviceSchemas },
122
+ ): Promise<Device | Array<Device>> {
123
+ const { schemas, ...rest } = args as RetrieveArgs & { schemas?: DeviceSchemas };
124
+ const isSingle = typeof rest === "object" && "key" in rest;
86
125
  const res = await sendRequired(
87
126
  this.client,
88
127
  "/device/retrieve",
89
- args,
128
+ rest,
90
129
  retrieveArgsZ,
91
- retrieveResZ,
130
+ retrieveResZ(schemas),
92
131
  );
93
- checkForMultipleOrNoResults("Device", args, res.devices, isSingle);
94
- const devices = res.devices as Device<Properties, Make, Model>[];
95
- return isSingle ? devices[0] : devices;
132
+ checkForMultipleOrNoResults("Device", rest, res.devices, isSingle);
133
+ return isSingle ? res.devices[0] : res.devices;
96
134
  }
97
135
 
98
136
  async create<
99
- Properties extends record.Unknown = record.Unknown,
100
- Make extends string = string,
101
- Model extends string = string,
102
- >(device: New<Properties, Make>): Promise<Device<Properties, Make, Model>>;
103
- async create<
104
- Properties extends record.Unknown = record.Unknown,
105
- Make extends string = string,
106
- Model extends string = string,
107
- >(devices: New<Properties, Make>[]): Promise<Device<Properties, Make, Model>[]>;
137
+ Properties extends z.ZodType<record.Unknown>,
138
+ Make extends z.ZodType<string>,
139
+ Model extends z.ZodType<string>,
140
+ >(
141
+ device: New<Properties, Make, Model>,
142
+ schemas: DeviceSchemas<Properties, Make, Model>,
143
+ ): Promise<Device<Properties, Make, Model>>;
144
+
145
+ async create(device: New): Promise<Device>;
146
+
108
147
  async create<
109
- Properties extends record.Unknown = record.Unknown,
110
- Make extends string = string,
111
- Model extends string = string,
148
+ Properties extends z.ZodType<record.Unknown>,
149
+ Make extends z.ZodType<string>,
150
+ Model extends z.ZodType<string>,
112
151
  >(
113
- devices: New<Properties, Make> | New<Properties, Make>[],
114
- ): Promise<Device<Properties, Make, Model> | Device<Properties, Make, Model>[]> {
152
+ devices: New<Properties, Make, Model>[],
153
+ schemas: DeviceSchemas<Properties, Make, Model>,
154
+ ): Promise<Device<Properties, Make, Model>[]>;
155
+
156
+ async create(devices: New[]): Promise<Device[]>;
157
+
158
+ async create(
159
+ devices: New | New[],
160
+ schemas?: DeviceSchemas,
161
+ ): Promise<Device | Device[]> {
115
162
  const isSingle = !Array.isArray(devices);
116
163
  const res = await sendRequired(
117
164
  this.client,
118
165
  "/device/create",
119
166
  { devices: array.toArray(devices) },
120
- createReqZ,
121
- createResZ,
167
+ createReqZ(schemas),
168
+ createResZ(schemas),
122
169
  );
123
- const created = res.devices as Device<Properties, Make, Model>[];
124
- return isSingle ? created[0] : created;
170
+ return isSingle ? res.devices[0] : res.devices;
125
171
  }
126
172
 
127
173
  async delete(keys: Key | Key[]): Promise<void> {
@@ -0,0 +1,118 @@
1
+ // Copyright 2026 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
+ import { describe, expect, it } from "vitest";
11
+ import { z } from "zod";
12
+
13
+ import { deviceZ, newZ } from "@/device/payload";
14
+
15
+ const VALID_DEVICE = {
16
+ key: "dev-1",
17
+ rack: 1,
18
+ name: "Test Device",
19
+ make: "ni",
20
+ model: "pxi-6281",
21
+ location: "Lab1",
22
+ properties: { rate: 10 },
23
+ status: null,
24
+ };
25
+
26
+ describe("deviceZ", () => {
27
+ describe("default schemas", () => {
28
+ it("should accept a valid device", () => {
29
+ const result = deviceZ().safeParse(VALID_DEVICE);
30
+ expect(result.success).toBe(true);
31
+ });
32
+
33
+ it("should reject a device with an empty name", () => {
34
+ const result = deviceZ().safeParse({ ...VALID_DEVICE, name: "" });
35
+ expect(result.success).toBe(false);
36
+ });
37
+
38
+ it("should reject a device with an empty make", () => {
39
+ const result = deviceZ().safeParse({ ...VALID_DEVICE, make: "" });
40
+ expect(result.success).toBe(false);
41
+ });
42
+
43
+ it("should reject a device with an empty model", () => {
44
+ const result = deviceZ().safeParse({ ...VALID_DEVICE, model: "" });
45
+ expect(result.success).toBe(false);
46
+ });
47
+
48
+ it("should accept properties as an object", () => {
49
+ const result = deviceZ().parse(VALID_DEVICE);
50
+ expect(result.properties).toEqual({ rate: 10 });
51
+ });
52
+ });
53
+
54
+ describe("custom make schema", () => {
55
+ const makeZ = z.enum(["ni", "labjack"]);
56
+
57
+ it("should accept a valid make value", () => {
58
+ const result = deviceZ({ make: makeZ }).safeParse(VALID_DEVICE);
59
+ expect(result.success).toBe(true);
60
+ });
61
+
62
+ it("should reject an invalid make value", () => {
63
+ const result = deviceZ({ make: makeZ }).safeParse({
64
+ ...VALID_DEVICE,
65
+ make: "unknown",
66
+ });
67
+ expect(result.success).toBe(false);
68
+ });
69
+ });
70
+
71
+ describe("custom model schema", () => {
72
+ const modelZ = z.literal("pxi-6281");
73
+
74
+ it("should accept a matching model", () => {
75
+ const result = deviceZ({ model: modelZ }).safeParse(VALID_DEVICE);
76
+ expect(result.success).toBe(true);
77
+ });
78
+
79
+ it("should reject a non-matching model", () => {
80
+ const result = deviceZ({ model: modelZ }).safeParse({
81
+ ...VALID_DEVICE,
82
+ model: "t7",
83
+ });
84
+ expect(result.success).toBe(false);
85
+ });
86
+ });
87
+
88
+ describe("custom properties schema", () => {
89
+ const propertiesZ = z.object({ rate: z.number(), channel: z.string() });
90
+
91
+ it("should validate properties against the custom schema", () => {
92
+ const result = deviceZ({ properties: propertiesZ }).safeParse({
93
+ ...VALID_DEVICE,
94
+ properties: { rate: 10, channel: "ai0" },
95
+ });
96
+ expect(result.success).toBe(true);
97
+ });
98
+
99
+ it("should reject properties that don't match the custom schema", () => {
100
+ expect(() => deviceZ({ properties: propertiesZ }).parse(VALID_DEVICE)).toThrow();
101
+ });
102
+ });
103
+ });
104
+
105
+ describe("newZ", () => {
106
+ it("should encode properties to a JSON string", () => {
107
+ const result = newZ().parse(VALID_DEVICE);
108
+ expect(result.properties).toEqual(VALID_DEVICE.properties);
109
+ });
110
+
111
+ it("should still validate make and model with custom schemas", () => {
112
+ const makeZ = z.literal("ni");
113
+ const result = newZ({ make: makeZ }).safeParse(VALID_DEVICE);
114
+ expect(result.success).toBe(true);
115
+ const bad = newZ({ make: makeZ }).safeParse({ ...VALID_DEVICE, make: "opc" });
116
+ expect(bad.success).toBe(false);
117
+ });
118
+ });
@@ -7,11 +7,10 @@
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 { binary, record, status, zod } from "@synnaxlabs/x";
10
+ import { record, status, zod } from "@synnaxlabs/x";
11
11
  import { z } from "zod";
12
12
 
13
13
  import { keyZ as rackKeyZ } from "@/rack/payload";
14
- import { decodeJSONString } from "@/util/decodeJSONString";
15
14
 
16
15
  export const keyZ = z.string();
17
16
  export type Key = z.infer<typeof keyZ>;
@@ -21,38 +20,64 @@ export const statusZ = status.statusZ(statusDetailsZ);
21
20
 
22
21
  export interface Status extends z.infer<typeof statusZ> {}
23
22
 
24
- export const deviceZ = z.object({
25
- key: keyZ,
26
- rack: rackKeyZ.min(1, "Must select a location to connect from"),
27
- name: z.string().min(1, "Name is required"),
28
- make: z.string().min(1, "Make is required"),
29
- model: z.string().min(1, "Model is required"),
30
- location: z.string().min(1, "Location is required"),
31
- configured: z.boolean().optional(),
32
- properties: record.unknownZ.or(z.string().transform(decodeJSONString)),
33
- status: zod.nullToUndefined(statusZ),
34
- });
23
+ export interface DeviceSchemas<
24
+ Properties extends z.ZodType<record.Unknown> = typeof record.unknownZ,
25
+ Make extends z.ZodType<string> = z.ZodString,
26
+ Model extends z.ZodType<string> = z.ZodString,
27
+ > {
28
+ properties?: Properties;
29
+ make?: Make;
30
+ model?: Model;
31
+ }
32
+
33
+ export const deviceZ = <
34
+ Properties extends z.ZodType<record.Unknown> = typeof record.unknownZ,
35
+ Make extends z.ZodType<string> = z.ZodString,
36
+ Model extends z.ZodType<string> = z.ZodString,
37
+ >({ properties, make, model }: DeviceSchemas<Properties, Make, Model> = {}) =>
38
+ z.object({
39
+ key: keyZ,
40
+ rack: rackKeyZ.min(1, "Must select a location to connect from"),
41
+ name: z.string().min(1, "Name is required"),
42
+ make: make ?? z.string().min(1, "Make is required"),
43
+ model: model ?? z.string().min(1, "Model is required"),
44
+ location: z.string().min(1, "Location is required"),
45
+ configured: z.boolean().optional(),
46
+ properties: properties ?? record.nullishToEmpty(),
47
+ status: zod.nullToUndefined(statusZ),
48
+ });
35
49
 
36
50
  export interface Device<
37
- Properties extends record.Unknown = record.Unknown,
38
- Make extends string = string,
39
- Model extends string = string,
40
- > extends Omit<z.infer<typeof deviceZ>, "properties" | "status"> {
41
- properties: Properties;
42
- make: Make;
43
- model: Model;
51
+ Properties extends z.ZodType<record.Unknown> = typeof record.unknownZ,
52
+ Make extends z.ZodType<string> = z.ZodString,
53
+ Model extends z.ZodType<string> = z.ZodString,
54
+ > extends Omit<
55
+ z.infer<ReturnType<typeof deviceZ>>,
56
+ "properties" | "make" | "model" | "status"
57
+ > {
58
+ properties: z.infer<Properties>;
59
+ make: z.infer<Make>;
60
+ model: z.infer<Model>;
44
61
  status?: Status;
45
62
  }
46
63
 
47
- export const newZ = deviceZ.extend({
48
- properties: z.unknown().transform((c) => binary.JSON_CODEC.encodeString(c)),
49
- });
64
+ export const newZ = <
65
+ Properties extends z.ZodType<record.Unknown> = typeof record.unknownZ,
66
+ Make extends z.ZodType<string> = z.ZodString,
67
+ Model extends z.ZodType<string> = z.ZodString,
68
+ >(
69
+ schemas: DeviceSchemas<Properties, Make, Model> = {},
70
+ ) =>
71
+ deviceZ(schemas).extend({
72
+ properties: schemas?.properties ?? record.nullishToEmpty(),
73
+ });
74
+
50
75
  export interface New<
51
- Properties extends record.Unknown = record.Unknown,
52
- Make extends string = string,
53
- Model extends string = string,
54
- > extends Omit<z.input<typeof newZ>, "properties"> {
55
- properties: Properties;
56
- make: Make;
57
- model: Model;
76
+ Properties extends z.ZodType<record.Unknown> = typeof record.unknownZ,
77
+ Make extends z.ZodType<string> = z.ZodString,
78
+ Model extends z.ZodType<string> = z.ZodString,
79
+ > extends Omit<z.input<ReturnType<typeof newZ>>, "properties"> {
80
+ properties: z.infer<Properties>;
81
+ make: z.infer<Make>;
82
+ model: z.infer<Model>;
58
83
  }
@@ -64,7 +64,7 @@ test("client", async () => {
64
64
  expect(NotFoundError.matches(e)).toBe(true);
65
65
  }
66
66
  try {
67
- await client.workspaces.schematics.retrieve({ key: uuid.create() });
67
+ await client.schematics.retrieve({ key: uuid.create() });
68
68
  } catch (e) {
69
69
  expect(NotFoundError.matches(e)).toBe(true);
70
70
  }