@synnaxlabs/client 0.47.0 → 0.49.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 (311) hide show
  1. package/.turbo/turbo-build.log +7 -7
  2. package/dist/client.cjs +35 -35
  3. package/dist/client.js +6264 -5984
  4. package/dist/eslint.config.d.ts +3 -2
  5. package/dist/eslint.config.d.ts.map +1 -1
  6. package/dist/src/access/client.d.ts +3 -1
  7. package/dist/src/access/client.d.ts.map +1 -1
  8. package/dist/src/access/enforce.d.ts +35 -0
  9. package/dist/src/access/enforce.d.ts.map +1 -0
  10. package/dist/src/access/enforce.spec.d.ts +2 -0
  11. package/dist/src/access/enforce.spec.d.ts.map +1 -0
  12. package/dist/src/access/external.d.ts +3 -0
  13. package/dist/src/access/external.d.ts.map +1 -1
  14. package/dist/src/access/payload.d.ts +0 -6
  15. package/dist/src/access/payload.d.ts.map +1 -1
  16. package/dist/src/access/policy/access.spec.d.ts +2 -0
  17. package/dist/src/access/policy/access.spec.d.ts.map +1 -0
  18. package/dist/src/access/policy/client.d.ts +485 -31
  19. package/dist/src/access/policy/client.d.ts.map +1 -1
  20. package/dist/src/access/policy/payload.d.ts +36 -113
  21. package/dist/src/access/policy/payload.d.ts.map +1 -1
  22. package/dist/src/access/role/client.d.ts +135 -0
  23. package/dist/src/access/role/client.d.ts.map +1 -0
  24. package/dist/src/access/role/external.d.ts.map +1 -0
  25. package/dist/src/access/role/index.d.ts +2 -0
  26. package/dist/src/access/role/index.d.ts.map +1 -0
  27. package/dist/src/access/role/payload.d.ts +27 -0
  28. package/dist/src/access/role/payload.d.ts.map +1 -0
  29. package/dist/src/access/role/role.spec.d.ts +2 -0
  30. package/dist/src/access/role/role.spec.d.ts.map +1 -0
  31. package/dist/src/arc/access.spec.d.ts +2 -0
  32. package/dist/src/arc/access.spec.d.ts.map +1 -0
  33. package/dist/src/arc/client.d.ts +5 -14
  34. package/dist/src/arc/client.d.ts.map +1 -1
  35. package/dist/src/arc/payload.d.ts +11 -2
  36. package/dist/src/arc/payload.d.ts.map +1 -1
  37. package/dist/src/auth/auth.d.ts +5 -3
  38. package/dist/src/auth/auth.d.ts.map +1 -1
  39. package/dist/src/channel/access.spec.d.ts +2 -0
  40. package/dist/src/channel/access.spec.d.ts.map +1 -0
  41. package/dist/src/channel/client.d.ts +0 -1
  42. package/dist/src/channel/client.d.ts.map +1 -1
  43. package/dist/src/channel/payload.d.ts +19 -8
  44. package/dist/src/channel/payload.d.ts.map +1 -1
  45. package/dist/src/channel/payload.spec.d.ts +2 -0
  46. package/dist/src/channel/payload.spec.d.ts.map +1 -0
  47. package/dist/src/channel/retriever.d.ts +4 -6
  48. package/dist/src/channel/retriever.d.ts.map +1 -1
  49. package/dist/src/channel/writer.d.ts.map +1 -1
  50. package/dist/src/client.d.ts +18 -10
  51. package/dist/src/client.d.ts.map +1 -1
  52. package/dist/src/connection/checker.d.ts +2 -3
  53. package/dist/src/connection/checker.d.ts.map +1 -1
  54. package/dist/src/connection.spec.d.ts +2 -0
  55. package/dist/src/connection.spec.d.ts.map +1 -0
  56. package/dist/src/device/access.spec.d.ts +2 -0
  57. package/dist/src/device/access.spec.d.ts.map +1 -0
  58. package/dist/src/{hardware/device → device}/client.d.ts +14 -7
  59. package/dist/src/device/client.d.ts.map +1 -0
  60. package/dist/src/device/device.spec.d.ts.map +1 -0
  61. package/dist/src/device/external.d.ts.map +1 -0
  62. package/dist/src/device/index.d.ts.map +1 -0
  63. package/dist/src/{hardware/device → device}/payload.d.ts +1 -1
  64. package/dist/src/device/payload.d.ts.map +1 -0
  65. package/dist/src/errors.d.ts +3 -0
  66. package/dist/src/errors.d.ts.map +1 -1
  67. package/dist/src/framer/adapter.d.ts +2 -2
  68. package/dist/src/framer/adapter.d.ts.map +1 -1
  69. package/dist/src/framer/client.d.ts +8 -1
  70. package/dist/src/framer/client.d.ts.map +1 -1
  71. package/dist/src/framer/frame.d.ts +11 -5
  72. package/dist/src/framer/frame.d.ts.map +1 -1
  73. package/dist/src/framer/iterator.d.ts +3 -3
  74. package/dist/src/framer/streamer.d.ts +24 -21
  75. package/dist/src/framer/streamer.d.ts.map +1 -1
  76. package/dist/src/framer/writer.d.ts +13 -13
  77. package/dist/src/index.d.ts +6 -7
  78. package/dist/src/index.d.ts.map +1 -1
  79. package/dist/src/label/access.spec.d.ts +2 -0
  80. package/dist/src/label/access.spec.d.ts.map +1 -0
  81. package/dist/src/label/client.d.ts +20 -11
  82. package/dist/src/label/client.d.ts.map +1 -1
  83. package/dist/src/ontology/client.d.ts +6 -6
  84. package/dist/src/ontology/client.d.ts.map +1 -1
  85. package/dist/src/ontology/group/access.spec.d.ts +2 -0
  86. package/dist/src/ontology/group/access.spec.d.ts.map +1 -0
  87. package/dist/src/ontology/group/client.d.ts +2 -2
  88. package/dist/src/ontology/group/client.d.ts.map +1 -1
  89. package/dist/src/ontology/group/payload.d.ts +1 -2
  90. package/dist/src/ontology/group/payload.d.ts.map +1 -1
  91. package/dist/src/ontology/payload.d.ts +23 -17
  92. package/dist/src/ontology/payload.d.ts.map +1 -1
  93. package/dist/src/ontology/writer.d.ts +10 -10
  94. package/dist/src/ontology/writer.d.ts.map +1 -1
  95. package/dist/src/rack/access.spec.d.ts +2 -0
  96. package/dist/src/rack/access.spec.d.ts.map +1 -0
  97. package/dist/src/{hardware/rack → rack}/client.d.ts +15 -8
  98. package/dist/src/rack/client.d.ts.map +1 -0
  99. package/dist/src/rack/external.d.ts.map +1 -0
  100. package/dist/src/rack/index.d.ts.map +1 -0
  101. package/dist/src/{hardware/rack → rack}/payload.d.ts +1 -1
  102. package/dist/src/rack/payload.d.ts.map +1 -0
  103. package/dist/src/rack/rack.spec.d.ts.map +1 -0
  104. package/dist/src/ranger/access.spec.d.ts +2 -0
  105. package/dist/src/ranger/access.spec.d.ts.map +1 -0
  106. package/dist/src/ranger/alias.d.ts +1 -8
  107. package/dist/src/ranger/alias.d.ts.map +1 -1
  108. package/dist/src/ranger/client.d.ts +12 -5
  109. package/dist/src/ranger/client.d.ts.map +1 -1
  110. package/dist/src/ranger/kv.d.ts +0 -3
  111. package/dist/src/ranger/kv.d.ts.map +1 -1
  112. package/dist/src/ranger/writer.d.ts +2 -2
  113. package/dist/src/ranger/writer.d.ts.map +1 -1
  114. package/dist/src/status/access.spec.d.ts +2 -0
  115. package/dist/src/status/access.spec.d.ts.map +1 -0
  116. package/dist/src/status/client.d.ts +4 -4
  117. package/dist/src/status/client.d.ts.map +1 -1
  118. package/dist/src/status/payload.d.ts +9 -2
  119. package/dist/src/status/payload.d.ts.map +1 -1
  120. package/dist/src/task/access.spec.d.ts +2 -0
  121. package/dist/src/task/access.spec.d.ts.map +1 -0
  122. package/dist/src/{hardware/task → task}/client.d.ts +26 -15
  123. package/dist/src/task/client.d.ts.map +1 -0
  124. package/dist/src/task/external.d.ts +3 -0
  125. package/dist/src/task/external.d.ts.map +1 -0
  126. package/dist/src/task/index.d.ts.map +1 -0
  127. package/dist/src/{hardware/task → task}/payload.d.ts +45 -6
  128. package/dist/src/task/payload.d.ts.map +1 -0
  129. package/dist/src/task/task.spec.d.ts.map +1 -0
  130. package/dist/src/testutil/access.d.ts +4 -0
  131. package/dist/src/testutil/access.d.ts.map +1 -0
  132. package/dist/src/testutil/client.d.ts +3 -3
  133. package/dist/src/testutil/client.d.ts.map +1 -1
  134. package/dist/src/transport.d.ts.map +1 -1
  135. package/dist/src/user/access.spec.d.ts +2 -0
  136. package/dist/src/user/access.spec.d.ts.map +1 -0
  137. package/dist/src/user/client.d.ts +10 -1
  138. package/dist/src/user/client.d.ts.map +1 -1
  139. package/dist/src/user/external.d.ts +1 -1
  140. package/dist/src/user/external.d.ts.map +1 -1
  141. package/dist/src/user/payload.d.ts.map +1 -1
  142. package/dist/src/workspace/access.spec.d.ts +2 -0
  143. package/dist/src/workspace/access.spec.d.ts.map +1 -0
  144. package/dist/src/workspace/client.d.ts +10 -5
  145. package/dist/src/workspace/client.d.ts.map +1 -1
  146. package/dist/src/workspace/lineplot/access.spec.d.ts +2 -0
  147. package/dist/src/workspace/lineplot/access.spec.d.ts.map +1 -0
  148. package/dist/src/workspace/lineplot/client.d.ts +8 -1
  149. package/dist/src/workspace/lineplot/client.d.ts.map +1 -1
  150. package/dist/src/workspace/log/access.spec.d.ts +2 -0
  151. package/dist/src/workspace/log/access.spec.d.ts.map +1 -0
  152. package/dist/src/workspace/log/client.d.ts +8 -1
  153. package/dist/src/workspace/log/client.d.ts.map +1 -1
  154. package/dist/src/workspace/schematic/access.spec.d.ts +2 -0
  155. package/dist/src/workspace/schematic/access.spec.d.ts.map +1 -0
  156. package/dist/src/workspace/schematic/client.d.ts +8 -1
  157. package/dist/src/workspace/schematic/client.d.ts.map +1 -1
  158. package/dist/src/workspace/schematic/symbol/access.spec.d.ts +2 -0
  159. package/dist/src/workspace/schematic/symbol/access.spec.d.ts.map +1 -0
  160. package/dist/src/workspace/schematic/symbol/client.d.ts +1 -5
  161. package/dist/src/workspace/schematic/symbol/client.d.ts.map +1 -1
  162. package/dist/src/workspace/schematic/symbol/payload.d.ts +2 -2
  163. package/dist/src/workspace/table/access.spec.d.ts +2 -0
  164. package/dist/src/workspace/table/access.spec.d.ts.map +1 -0
  165. package/dist/src/workspace/table/client.d.ts +8 -1
  166. package/dist/src/workspace/table/client.d.ts.map +1 -1
  167. package/eslint.config.ts +3 -1
  168. package/package.json +8 -8
  169. package/src/access/client.ts +5 -2
  170. package/src/access/enforce.spec.ts +189 -0
  171. package/src/access/enforce.ts +84 -0
  172. package/src/access/external.ts +3 -0
  173. package/src/access/payload.ts +1 -13
  174. package/src/access/policy/access.spec.ts +147 -0
  175. package/src/access/policy/client.ts +21 -25
  176. package/src/access/policy/payload.ts +9 -5
  177. package/src/access/role/client.ts +135 -0
  178. package/src/access/role/external.ts +11 -0
  179. package/src/{hardware → access/role}/index.ts +1 -1
  180. package/src/access/role/payload.ts +32 -0
  181. package/src/access/role/role.spec.ts +95 -0
  182. package/src/arc/access.spec.ts +143 -0
  183. package/src/arc/client.ts +7 -31
  184. package/src/arc/payload.ts +4 -0
  185. package/src/auth/auth.spec.ts +13 -13
  186. package/src/auth/auth.ts +33 -11
  187. package/src/channel/access.spec.ts +116 -0
  188. package/src/channel/channel.spec.ts +63 -73
  189. package/src/channel/client.ts +2 -8
  190. package/src/channel/payload.spec.ts +171 -0
  191. package/src/channel/payload.ts +37 -8
  192. package/src/channel/retriever.ts +10 -11
  193. package/src/channel/writer.ts +3 -7
  194. package/src/client.ts +38 -28
  195. package/src/connection/checker.ts +10 -10
  196. package/src/connection/connection.spec.ts +13 -13
  197. package/src/connection.spec.ts +145 -0
  198. package/src/device/access.spec.ts +159 -0
  199. package/src/{hardware/device → device}/client.ts +12 -21
  200. package/src/{hardware/device → device}/device.spec.ts +70 -34
  201. package/src/device/external.ts +11 -0
  202. package/src/{hardware/rack → device}/index.ts +1 -1
  203. package/src/{hardware/device → device}/payload.ts +3 -3
  204. package/src/errors.ts +2 -0
  205. package/src/framer/adapter.spec.ts +351 -13
  206. package/src/framer/adapter.ts +23 -13
  207. package/src/framer/client.spec.ts +14 -20
  208. package/src/framer/client.ts +3 -5
  209. package/src/framer/deleter.spec.ts +1 -1
  210. package/src/framer/frame.spec.ts +427 -0
  211. package/src/framer/frame.ts +30 -3
  212. package/src/framer/iterator.ts +4 -4
  213. package/src/framer/streamer.spec.ts +155 -10
  214. package/src/framer/streamer.ts +35 -12
  215. package/src/framer/writer.spec.ts +5 -5
  216. package/src/index.ts +13 -7
  217. package/src/label/access.spec.ts +109 -0
  218. package/src/label/client.ts +10 -14
  219. package/src/ontology/client.ts +4 -6
  220. package/src/ontology/group/access.spec.ts +77 -0
  221. package/src/ontology/group/client.ts +3 -7
  222. package/src/ontology/group/group.spec.ts +18 -0
  223. package/src/ontology/group/payload.ts +2 -2
  224. package/src/ontology/ontology.spec.ts +2 -0
  225. package/src/ontology/payload.ts +18 -2
  226. package/src/ontology/writer.ts +3 -7
  227. package/src/rack/access.spec.ts +102 -0
  228. package/src/{hardware/rack → rack}/client.ts +14 -19
  229. package/src/{hardware/device/index.ts → rack/external.ts} +2 -1
  230. package/src/{hardware/external.ts → rack/index.ts} +1 -1
  231. package/src/{hardware/rack → rack}/payload.ts +2 -2
  232. package/src/{hardware/rack → rack}/rack.spec.ts +43 -17
  233. package/src/ranger/access.spec.ts +115 -0
  234. package/src/ranger/alias.ts +6 -14
  235. package/src/ranger/client.ts +13 -14
  236. package/src/ranger/kv.ts +7 -9
  237. package/src/ranger/ranger.spec.ts +4 -4
  238. package/src/ranger/writer.ts +3 -7
  239. package/src/status/access.spec.ts +129 -0
  240. package/src/status/client.ts +5 -9
  241. package/src/status/payload.ts +3 -2
  242. package/src/task/access.spec.ts +131 -0
  243. package/src/{hardware/task → task}/client.ts +50 -25
  244. package/src/task/external.ts +11 -0
  245. package/src/{hardware/task → task}/index.ts +1 -1
  246. package/src/{hardware/task → task}/payload.ts +22 -3
  247. package/src/{hardware/task → task}/task.spec.ts +197 -34
  248. package/src/testutil/access.ts +34 -0
  249. package/src/testutil/channels.ts +3 -3
  250. package/src/testutil/client.ts +4 -4
  251. package/src/transport.ts +1 -3
  252. package/src/user/access.spec.ts +107 -0
  253. package/src/user/client.ts +10 -12
  254. package/src/user/external.ts +12 -1
  255. package/src/user/payload.ts +3 -5
  256. package/src/workspace/access.spec.ts +108 -0
  257. package/src/workspace/client.ts +11 -27
  258. package/src/workspace/lineplot/access.spec.ts +134 -0
  259. package/src/workspace/lineplot/client.ts +8 -13
  260. package/src/workspace/log/access.spec.ts +134 -0
  261. package/src/workspace/log/client.ts +8 -13
  262. package/src/workspace/schematic/access.spec.ts +134 -0
  263. package/src/workspace/schematic/client.ts +9 -18
  264. package/src/workspace/schematic/symbol/access.spec.ts +172 -0
  265. package/src/workspace/schematic/symbol/client.ts +6 -17
  266. package/src/workspace/schematic/symbol/payload.ts +1 -1
  267. package/src/workspace/table/access.spec.ts +134 -0
  268. package/src/workspace/table/client.ts +8 -13
  269. package/dist/src/access/policy/policy.spec.d.ts +0 -2
  270. package/dist/src/access/policy/policy.spec.d.ts.map +0 -1
  271. package/dist/src/hardware/client.d.ts +0 -10
  272. package/dist/src/hardware/client.d.ts.map +0 -1
  273. package/dist/src/hardware/device/client.d.ts.map +0 -1
  274. package/dist/src/hardware/device/device.spec.d.ts.map +0 -1
  275. package/dist/src/hardware/device/external.d.ts.map +0 -1
  276. package/dist/src/hardware/device/index.d.ts.map +0 -1
  277. package/dist/src/hardware/device/payload.d.ts.map +0 -1
  278. package/dist/src/hardware/external.d.ts +0 -2
  279. package/dist/src/hardware/external.d.ts.map +0 -1
  280. package/dist/src/hardware/index.d.ts +0 -2
  281. package/dist/src/hardware/index.d.ts.map +0 -1
  282. package/dist/src/hardware/rack/client.d.ts.map +0 -1
  283. package/dist/src/hardware/rack/external.d.ts.map +0 -1
  284. package/dist/src/hardware/rack/index.d.ts.map +0 -1
  285. package/dist/src/hardware/rack/payload.d.ts.map +0 -1
  286. package/dist/src/hardware/rack/rack.spec.d.ts.map +0 -1
  287. package/dist/src/hardware/task/client.d.ts.map +0 -1
  288. package/dist/src/hardware/task/external.d.ts.map +0 -1
  289. package/dist/src/hardware/task/index.d.ts.map +0 -1
  290. package/dist/src/hardware/task/payload.d.ts.map +0 -1
  291. package/dist/src/hardware/task/task.spec.d.ts.map +0 -1
  292. package/dist/src/user/retriever.d.ts +0 -16
  293. package/dist/src/user/retriever.d.ts.map +0 -1
  294. package/dist/src/user/writer.d.ts +0 -11
  295. package/dist/src/user/writer.d.ts.map +0 -1
  296. package/src/access/policy/policy.spec.ts +0 -329
  297. package/src/hardware/client.ts +0 -24
  298. package/src/hardware/device/external.ts +0 -11
  299. package/src/hardware/rack/external.ts +0 -11
  300. package/src/hardware/task/external.ts +0 -11
  301. package/src/user/retriever.ts +0 -41
  302. package/src/user/writer.ts +0 -84
  303. /package/dist/src/{hardware/device → access/role}/external.d.ts +0 -0
  304. /package/dist/src/{hardware/device → device}/device.spec.d.ts +0 -0
  305. /package/dist/src/{hardware/rack → device}/external.d.ts +0 -0
  306. /package/dist/src/{hardware/device → device}/index.d.ts +0 -0
  307. /package/dist/src/{hardware/task → rack}/external.d.ts +0 -0
  308. /package/dist/src/{hardware/rack → rack}/index.d.ts +0 -0
  309. /package/dist/src/{hardware/rack → rack}/rack.spec.d.ts +0 -0
  310. /package/dist/src/{hardware/task → task}/index.d.ts +0 -0
  311. /package/dist/src/{hardware/task → task}/task.spec.d.ts +0 -0
@@ -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 { array } from "@synnaxlabs/x";
10
+ import { array, zod } from "@synnaxlabs/x";
11
11
  import { z } from "zod";
12
12
 
13
13
  import { actionZ } from "@/access/payload";
@@ -18,16 +18,20 @@ export type Key = z.infer<typeof keyZ>;
18
18
 
19
19
  export const policyZ = z.object({
20
20
  key: keyZ,
21
- subjects: array.nullableZ(ontology.idZ),
21
+ name: z.string(),
22
22
  objects: array.nullableZ(ontology.idZ),
23
23
  actions: array.nullableZ(actionZ),
24
+ internal: z.boolean(),
24
25
  });
25
26
  export interface Policy extends z.infer<typeof policyZ> {}
26
27
 
27
28
  export const newZ = z.object({
28
29
  key: keyZ.optional(),
29
- subjects: ontology.idZ.array().or(ontology.idZ),
30
- objects: ontology.idZ.array().or(ontology.idZ),
31
- actions: actionZ.array().or(actionZ),
30
+ name: z.string(),
31
+ objects: zod.toArray(ontology.idZ),
32
+ actions: zod.toArray(actionZ),
32
33
  });
33
34
  export interface New extends z.input<typeof newZ> {}
35
+
36
+ export const ontologyID = ontology.createIDFactory<Key>("policy");
37
+ export const TYPE_ONTOLOGY_ID = ontologyID("");
@@ -0,0 +1,135 @@
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
+ import { sendRequired, type UnaryClient } from "@synnaxlabs/freighter";
11
+ import { array } from "@synnaxlabs/x";
12
+ import { z } from "zod";
13
+
14
+ import { keyZ, type New, newZ, type Role, roleZ } from "@/access/role/payload";
15
+ import { user } from "@/user";
16
+
17
+ const retrieveRequestZ = z.object({
18
+ keys: keyZ.array().optional(),
19
+ limit: z.number().optional(),
20
+ offset: z.number().optional(),
21
+ internal: z.boolean().optional(),
22
+ });
23
+
24
+ const keyRetrieveRequestZ = z
25
+ .object({ key: keyZ })
26
+ .transform(({ key }) => ({ keys: [key] }));
27
+
28
+ const singleCreateArgsZ = newZ.transform((r) => ({ roles: [r] }));
29
+ export type SingleCreateArgs = z.input<typeof singleCreateArgsZ>;
30
+
31
+ export const multipleCreateArgsZ = newZ.array().transform((roles) => ({ roles }));
32
+
33
+ export const createArgsZ = z.union([singleCreateArgsZ, multipleCreateArgsZ]);
34
+ export type CreateArgs = z.input<typeof createArgsZ>;
35
+
36
+ const createResZ = z.object({ roles: roleZ.array() });
37
+ const retrieveResZ = z.object({ roles: array.nullableZ(roleZ) });
38
+
39
+ export type RetrieveSingleParams = z.input<typeof keyRetrieveRequestZ>;
40
+ export type RetrieveMultipleParams = z.input<typeof retrieveRequestZ>;
41
+
42
+ export const retrieveArgsZ = z.union([keyRetrieveRequestZ, retrieveRequestZ]);
43
+ export type RetrieveArgs = z.input<typeof retrieveArgsZ>;
44
+
45
+ const deleteResZ = z.object({});
46
+
47
+ const deleteArgsZ = keyZ
48
+ .transform((key) => ({ keys: [key] }))
49
+ .or(keyZ.array().transform((keys) => ({ keys })));
50
+ export type DeleteArgs = z.input<typeof deleteArgsZ>;
51
+
52
+ const assignReqZ = z.object({
53
+ user: user.keyZ,
54
+ role: keyZ,
55
+ });
56
+ export type AssignArgs = z.input<typeof assignReqZ>;
57
+
58
+ const assignResZ = z.object({});
59
+
60
+ const unassignReqZ = z.object({
61
+ user: user.keyZ,
62
+ role: keyZ,
63
+ });
64
+ export type UnassignArgs = z.input<typeof unassignReqZ>;
65
+
66
+ const unassignResZ = z.object({});
67
+
68
+ export const SET_CHANNEL_NAME = "sy_role_set";
69
+ export const DELETE_CHANNEL_NAME = "sy_role_delete";
70
+
71
+ export class Client {
72
+ private readonly client: UnaryClient;
73
+
74
+ constructor(client: UnaryClient) {
75
+ this.client = client;
76
+ }
77
+
78
+ async create(role: New): Promise<Role>;
79
+ async create(roles: New[]): Promise<Role[]>;
80
+ async create(roles: New | New[]): Promise<Role | Role[]> {
81
+ const isMany = Array.isArray(roles);
82
+ const res = await sendRequired<typeof createArgsZ, typeof createResZ>(
83
+ this.client,
84
+ "/access/role/create",
85
+ roles,
86
+ createArgsZ,
87
+ createResZ,
88
+ );
89
+ return isMany ? res.roles : res.roles[0];
90
+ }
91
+
92
+ async retrieve(args: RetrieveSingleParams): Promise<Role>;
93
+ async retrieve(args: RetrieveMultipleParams): Promise<Role[]>;
94
+ async retrieve(args: RetrieveArgs): Promise<Role | Role[]> {
95
+ const isSingle = "key" in args;
96
+ const res = await sendRequired<typeof retrieveArgsZ, typeof retrieveResZ>(
97
+ this.client,
98
+ "/access/role/retrieve",
99
+ args,
100
+ retrieveArgsZ,
101
+ retrieveResZ,
102
+ );
103
+ return isSingle ? res.roles[0] : res.roles;
104
+ }
105
+
106
+ async delete(args: DeleteArgs): Promise<void> {
107
+ await sendRequired<typeof deleteArgsZ, typeof deleteResZ>(
108
+ this.client,
109
+ "/access/role/delete",
110
+ args,
111
+ deleteArgsZ,
112
+ deleteResZ,
113
+ );
114
+ }
115
+
116
+ async assign(args: AssignArgs): Promise<void> {
117
+ await sendRequired<typeof assignReqZ, typeof assignResZ>(
118
+ this.client,
119
+ "/access/role/assign",
120
+ args,
121
+ assignReqZ,
122
+ assignResZ,
123
+ );
124
+ }
125
+
126
+ async unassign(args: UnassignArgs): Promise<void> {
127
+ await sendRequired<typeof unassignReqZ, typeof unassignResZ>(
128
+ this.client,
129
+ "/access/role/unassign",
130
+ args,
131
+ unassignReqZ,
132
+ unassignResZ,
133
+ );
134
+ }
135
+ }
@@ -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 "@/access/role/client";
11
+ export * from "@/access/role/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 hardware from "@/hardware/external";
10
+ export * as role from "@/access/role/external";
@@ -0,0 +1,32 @@
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
+ import { z } from "zod";
11
+
12
+ import { ontology } from "@/ontology";
13
+
14
+ export const keyZ = z.uuid();
15
+
16
+ export type Key = z.infer<typeof keyZ>;
17
+
18
+ export const roleZ = z.object({
19
+ key: keyZ,
20
+ name: z.string(),
21
+ description: z.string().optional(),
22
+ internal: z.boolean().optional(),
23
+ });
24
+
25
+ export type Role = z.infer<typeof roleZ>;
26
+
27
+ export const newZ = roleZ.partial({ key: true });
28
+
29
+ export type New = z.infer<typeof newZ>;
30
+
31
+ export const ontologyID = ontology.createIDFactory<Key>("role");
32
+ export const TYPE_ONTOLOGY_ID = ontologyID("");
@@ -0,0 +1,95 @@
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
+ import { id } from "@synnaxlabs/x";
11
+ import { describe, expect, it } from "vitest";
12
+
13
+ import { NotFoundError } from "@/errors";
14
+ import { createTestClient } from "@/testutil/client";
15
+
16
+ const client = createTestClient();
17
+
18
+ describe("role", () => {
19
+ describe("create", () => {
20
+ it("should allow the caller to create a role", async () => {
21
+ const role = await client.access.roles.create({
22
+ name: "test",
23
+ description: "test",
24
+ });
25
+ expect(role.key).toBeDefined();
26
+ expect(role.name).toBe("test");
27
+ expect(role.description).toBe("test");
28
+ });
29
+ });
30
+
31
+ describe("retrieve", () => {
32
+ it("should allow the caller to retrieve a role", async () => {
33
+ const created = await client.access.roles.create({
34
+ name: "test",
35
+ description: "test",
36
+ });
37
+ const retrieved = await client.access.roles.retrieve({ key: created.key });
38
+ expect(retrieved.key).toBe(created.key);
39
+ expect(retrieved.name).toBe(created.name);
40
+ expect(retrieved.description).toBe(created.description);
41
+ });
42
+
43
+ it("should filter by internal flag when retrieving roles", async () => {
44
+ // Create a non-internal role
45
+ const created = await client.access.roles.create({
46
+ name: "test-non-internal",
47
+ description: "test",
48
+ });
49
+
50
+ // Retrieve only internal roles (built-in system roles)
51
+ const internalRoles = await client.access.roles.retrieve({ internal: true });
52
+ expect(internalRoles.length).toBeGreaterThan(0);
53
+ expect(internalRoles.every((r) => r.internal === true)).toBe(true);
54
+ expect(internalRoles.find((r) => r.key === created.key)).toBeUndefined();
55
+
56
+ // Retrieve only non-internal roles
57
+ const nonInternalRoles = await client.access.roles.retrieve({ internal: false });
58
+ expect(nonInternalRoles.every((r) => r.internal !== true)).toBe(true);
59
+ expect(nonInternalRoles.find((r) => r.key === created.key)).toBeDefined();
60
+ });
61
+ });
62
+
63
+ describe("delete", () => {
64
+ it("should allow the caller to delete a role", async () => {
65
+ const created = await client.access.roles.create({
66
+ name: "test",
67
+ description: "test",
68
+ });
69
+ await client.access.roles.delete(created.key);
70
+ await expect(client.access.roles.retrieve({ key: created.key })).rejects.toThrow(
71
+ NotFoundError,
72
+ );
73
+ });
74
+ });
75
+
76
+ describe("assign", () => {
77
+ it("should allow the caller to assign a role to a user", async () => {
78
+ const role = await client.access.roles.create({
79
+ name: "test",
80
+ description: "test",
81
+ });
82
+ const username = id.create();
83
+ const u = await client.users.create({
84
+ username,
85
+ password: "test",
86
+ firstName: "test",
87
+ lastName: "test",
88
+ });
89
+ await client.access.roles.assign({
90
+ user: u.key,
91
+ role: role.key,
92
+ });
93
+ });
94
+ });
95
+ });
@@ -0,0 +1,143 @@
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
+ import { describe, expect, it } from "vitest";
11
+
12
+ import { arc } from "@/arc";
13
+ import { AuthError, NotFoundError } from "@/errors";
14
+ import { createTestClientWithPolicy } from "@/testutil/access";
15
+ import { createTestClient } from "@/testutil/client";
16
+
17
+ const client = createTestClient();
18
+
19
+ describe("arc", () => {
20
+ describe("access control", () => {
21
+ it("should deny access when no retrieve policy exists", async () => {
22
+ const userClient = await createTestClientWithPolicy(client, {
23
+ name: "test",
24
+ objects: [],
25
+ actions: [],
26
+ });
27
+ const a: arc.New = {
28
+ name: "test",
29
+ graph: {
30
+ nodes: [],
31
+ edges: [],
32
+ },
33
+ text: { raw: "" },
34
+ deploy: false,
35
+ version: "1.0.0",
36
+ };
37
+ const randomArc = await client.arcs.create(a);
38
+ await expect(userClient.arcs.retrieve({ key: randomArc.key })).rejects.toThrow(
39
+ AuthError,
40
+ );
41
+ });
42
+
43
+ it("should allow the caller to retrieve arcs with the correct policy", async () => {
44
+ const userClient = await createTestClientWithPolicy(client, {
45
+ name: "test",
46
+ objects: [arc.ontologyID("")],
47
+ actions: ["retrieve"],
48
+ });
49
+ const randomArc = await client.arcs.create({
50
+ name: "test",
51
+ graph: {
52
+ nodes: [],
53
+ edges: [],
54
+ },
55
+ text: { raw: "" },
56
+ deploy: false,
57
+ version: "1.0.0",
58
+ });
59
+ const retrieved = await userClient.arcs.retrieve({ key: randomArc.key });
60
+ expect(retrieved.key).toBe(randomArc.key);
61
+ expect(retrieved.name).toBe(randomArc.name);
62
+ });
63
+
64
+ it("should allow the caller to create arcs with the correct policy", async () => {
65
+ const userClient = await createTestClientWithPolicy(client, {
66
+ name: "test",
67
+ objects: [arc.ontologyID("")],
68
+ actions: ["create"],
69
+ });
70
+ await userClient.arcs.create({
71
+ name: "test",
72
+ graph: {
73
+ nodes: [],
74
+ edges: [],
75
+ },
76
+ text: { raw: "" },
77
+ deploy: false,
78
+ version: "1.0.0",
79
+ });
80
+ });
81
+
82
+ it("should deny access when no create policy exists", async () => {
83
+ const userClient = await createTestClientWithPolicy(client, {
84
+ name: "test",
85
+ objects: [arc.ontologyID("")],
86
+ actions: [],
87
+ });
88
+ await expect(
89
+ userClient.arcs.create({
90
+ name: "test",
91
+ graph: {
92
+ nodes: [],
93
+ edges: [],
94
+ },
95
+ text: { raw: "" },
96
+ deploy: false,
97
+ version: "1.0.0",
98
+ }),
99
+ ).rejects.toThrow(AuthError);
100
+ });
101
+
102
+ it("should allow the caller to delete arcs with the correct policy", async () => {
103
+ const userClient = await createTestClientWithPolicy(client, {
104
+ name: "test",
105
+ objects: [arc.ontologyID("")],
106
+ actions: ["delete", "retrieve"],
107
+ });
108
+ const randomArc = await client.arcs.create({
109
+ name: "test",
110
+ graph: {
111
+ nodes: [],
112
+ edges: [],
113
+ },
114
+ text: { raw: "" },
115
+ deploy: false,
116
+ version: "1.0.0",
117
+ });
118
+ await userClient.arcs.delete(randomArc.key);
119
+ await expect(userClient.arcs.retrieve({ key: randomArc.key })).rejects.toThrow(
120
+ NotFoundError,
121
+ );
122
+ });
123
+
124
+ it("should deny access when no delete policy exists", async () => {
125
+ const userClient = await createTestClientWithPolicy(client, {
126
+ name: "test",
127
+ objects: [arc.ontologyID("")],
128
+ actions: [],
129
+ });
130
+ const randomArc = await client.arcs.create({
131
+ name: "test",
132
+ graph: {
133
+ nodes: [],
134
+ edges: [],
135
+ },
136
+ text: { raw: "" },
137
+ deploy: false,
138
+ version: "1.0.0",
139
+ });
140
+ await expect(userClient.arcs.delete(randomArc.key)).rejects.toThrow(AuthError);
141
+ });
142
+ });
143
+ });
package/src/arc/client.ts CHANGED
@@ -16,33 +16,18 @@ import {
16
16
  import { array } from "@synnaxlabs/x";
17
17
  import { z } from "zod/v4";
18
18
 
19
- import {
20
- type Arc,
21
- arcZ,
22
- type Key,
23
- keyZ,
24
- type New,
25
- newZ,
26
- ONTOLOGY_TYPE,
27
- type Params,
28
- } from "@/arc/payload";
29
- import { type ontology } from "@/ontology";
19
+ import { type Arc, arcZ, keyZ, type New, newZ, type Params } from "@/arc/payload";
30
20
  import { checkForMultipleOrNoResults } from "@/util/retrieve";
31
21
 
32
22
  export const SET_CHANNEL_NAME = "sy_arc_set";
33
23
  export const DELETE_CHANNEL_NAME = "sy_arc_delete";
34
24
 
35
- const RETRIEVE_ENDPOINT = "/arc/retrieve";
36
- const CREATE_ENDPOINT = "/arc/create";
37
- const DELETE_ENDPOINT = "/arc/delete";
38
- const LSP_ENDPOINT = "/arc/lsp";
39
-
40
25
  const retrieveReqZ = z.object({
41
26
  keys: keyZ.array().optional(),
42
27
  names: z.string().array().optional(),
43
28
  searchTerm: z.string().optional(),
44
- limit: z.number().optional(),
45
- offset: z.number().optional(),
29
+ limit: z.int().optional(),
30
+ offset: z.int().optional(),
46
31
  includeStatus: z.boolean().optional(),
47
32
  });
48
33
  const createReqZ = z.object({ arcs: newZ.array() });
@@ -94,7 +79,7 @@ export class Client {
94
79
  const isMany = Array.isArray(arcs);
95
80
  const res = await sendRequired(
96
81
  this.client,
97
- CREATE_ENDPOINT,
82
+ "/arc/create",
98
83
  { arcs: array.toArray(arcs) },
99
84
  createReqZ,
100
85
  createResZ,
@@ -108,7 +93,7 @@ export class Client {
108
93
  const isSingle = "key" in args || "name" in args;
109
94
  const res = await sendRequired(
110
95
  this.client,
111
- RETRIEVE_ENDPOINT,
96
+ "/arc/retrieve",
112
97
  args,
113
98
  retrieveArgsZ,
114
99
  retrieveResZ,
@@ -120,23 +105,14 @@ export class Client {
120
105
  async delete(keys: Params): Promise<void> {
121
106
  await sendRequired(
122
107
  this.client,
123
- DELETE_ENDPOINT,
108
+ "/arc/delete",
124
109
  { keys: array.toArray(keys) },
125
110
  deleteReqZ,
126
111
  emptyResZ,
127
112
  );
128
113
  }
129
114
 
130
- /**
131
- * Opens a new LSP stream to the server for Language Server Protocol communication.
132
- * This allows editor integrations to communicate with the Arc LSP server using
133
- * JSON-RPC messages over a WebSocket transport.
134
- *
135
- * @returns A bidirectional stream for sending and receiving JSON-RPC messages
136
- */
137
115
  async openLSP(): Promise<Stream<typeof lspMessageZ, typeof lspMessageZ>> {
138
- return await this.streamClient.stream(LSP_ENDPOINT, lspMessageZ, lspMessageZ);
116
+ return await this.streamClient.stream("/arc/lsp", lspMessageZ, lspMessageZ);
139
117
  }
140
118
  }
141
-
142
- export const ontologyID = (key: Key): ontology.ID => ({ type: ONTOLOGY_TYPE, key });
@@ -10,6 +10,7 @@
10
10
  import { record, xy } from "@synnaxlabs/x";
11
11
  import { z } from "zod/v4";
12
12
 
13
+ import { ontology } from "@/ontology";
13
14
  import { statusZ as baseStatusZ } from "@/status/payload";
14
15
  import { parseWithoutKeyConversion } from "@/util/parseWithoutKeyConversion";
15
16
 
@@ -72,3 +73,6 @@ export interface New extends z.input<typeof newZ> {}
72
73
 
73
74
  export const ONTOLOGY_TYPE = "arc";
74
75
  export type OntologyType = typeof ONTOLOGY_TYPE;
76
+
77
+ export const ontologyID = ontology.createIDFactory<Key>("arc");
78
+ export const TYPE_ONTOLOGY_ID = ontologyID("");
@@ -13,7 +13,7 @@ import { describe, expect, it, test } from "vitest";
13
13
 
14
14
  import { auth } from "@/auth";
15
15
  import { AuthError, ExpiredTokenError, InvalidTokenError } from "@/errors";
16
- import { TEST_CLIENT_PROPS } from "@/testutil/client";
16
+ import { TEST_CLIENT_PARAMS } from "@/testutil/client";
17
17
  import { Transport } from "@/transport";
18
18
 
19
19
  const DUMMY_CTX: Context = {
@@ -27,11 +27,11 @@ describe("auth", () => {
27
27
  test("valid credentials", async () => {
28
28
  const transport = new Transport(
29
29
  new URL({
30
- host: TEST_CLIENT_PROPS.host,
31
- port: Number(TEST_CLIENT_PROPS.port),
30
+ host: TEST_CLIENT_PARAMS.host,
31
+ port: Number(TEST_CLIENT_PARAMS.port),
32
32
  }),
33
33
  );
34
- const client = new auth.Client(transport.unary, TEST_CLIENT_PROPS);
34
+ const client = new auth.Client(transport.unary, TEST_CLIENT_PARAMS);
35
35
  const mw = client.middleware();
36
36
  const res = await mw(DUMMY_CTX, async () => [DUMMY_CTX, null]);
37
37
  expect(res).toEqual([DUMMY_CTX, null]);
@@ -40,12 +40,12 @@ describe("auth", () => {
40
40
  test("invalid credentials", async () => {
41
41
  const transport = new Transport(
42
42
  new URL({
43
- host: TEST_CLIENT_PROPS.host,
44
- port: Number(TEST_CLIENT_PROPS.port),
43
+ host: TEST_CLIENT_PARAMS.host,
44
+ port: Number(TEST_CLIENT_PARAMS.port),
45
45
  }),
46
46
  );
47
47
  const client = new auth.Client(transport.unary, {
48
- ...TEST_CLIENT_PROPS,
48
+ ...TEST_CLIENT_PARAMS,
49
49
  password: "wrong",
50
50
  });
51
51
  const mw = client.middleware();
@@ -59,11 +59,11 @@ describe("auth", () => {
59
59
  it(`should re-authenticate and retry the request for ${ErrorType.name}`, async () => {
60
60
  const transport = new Transport(
61
61
  new URL({
62
- host: TEST_CLIENT_PROPS.host,
63
- port: Number(TEST_CLIENT_PROPS.port),
62
+ host: TEST_CLIENT_PARAMS.host,
63
+ port: Number(TEST_CLIENT_PARAMS.port),
64
64
  }),
65
65
  );
66
- const client = new auth.Client(transport.unary, TEST_CLIENT_PROPS);
66
+ const client = new auth.Client(transport.unary, TEST_CLIENT_PARAMS);
67
67
  const mw = client.middleware();
68
68
  let isFirst = true;
69
69
  let tkOne: string | undefined;
@@ -86,11 +86,11 @@ describe("auth", () => {
86
86
  it("should fail after MAX_RETRIES", async () => {
87
87
  const transport = new Transport(
88
88
  new URL({
89
- host: TEST_CLIENT_PROPS.host,
90
- port: Number(TEST_CLIENT_PROPS.port),
89
+ host: TEST_CLIENT_PARAMS.host,
90
+ port: Number(TEST_CLIENT_PARAMS.port),
91
91
  }),
92
92
  );
93
- const client = new auth.Client(transport.unary, TEST_CLIENT_PROPS);
93
+ const client = new auth.Client(transport.unary, TEST_CLIENT_PARAMS);
94
94
  const mw = client.middleware();
95
95
  const [, err] = await mw(DUMMY_CTX, async () => [
96
96
  DUMMY_CTX,