@synnaxlabs/client 0.56.2 → 0.57.1

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 (741) hide show
  1. package/dist/client-DDACDVZ-.js +14505 -0
  2. package/dist/client-DDACDVZ-.js.map +1 -0
  3. package/dist/client.js +1128 -14876
  4. package/dist/client.js.map +1 -0
  5. package/dist/src/access/client.d.ts +10 -1
  6. package/dist/src/access/client.d.ts.map +1 -1
  7. package/dist/src/access/enforce.d.ts.map +1 -1
  8. package/dist/src/access/external.d.ts +1 -0
  9. package/dist/src/access/external.d.ts.map +1 -1
  10. package/dist/src/access/granted.d.ts +39 -0
  11. package/dist/src/access/granted.d.ts.map +1 -0
  12. package/dist/src/access/policy/client.d.ts +136 -147
  13. package/dist/src/access/policy/client.d.ts.map +1 -1
  14. package/dist/src/access/policy/types.gen.d.ts +15 -68
  15. package/dist/src/access/policy/types.gen.d.ts.map +1 -1
  16. package/dist/src/access/role/client.d.ts +77 -58
  17. package/dist/src/access/role/client.d.ts.map +1 -1
  18. package/dist/src/access/role/types.gen.d.ts +8 -14
  19. package/dist/src/access/role/types.gen.d.ts.map +1 -1
  20. package/dist/src/actions/actions.d.ts +5 -6
  21. package/dist/src/actions/actions.d.ts.map +1 -1
  22. package/dist/src/actions/controller.d.ts +194 -0
  23. package/dist/src/actions/controller.d.ts.map +1 -0
  24. package/dist/src/actions/external.d.ts +1 -0
  25. package/dist/src/actions/external.d.ts.map +1 -1
  26. package/dist/src/arc/actions.d.ts +575 -0
  27. package/dist/src/arc/actions.d.ts.map +1 -0
  28. package/dist/src/arc/actions.gen.d.ts +1439 -0
  29. package/dist/src/arc/actions.gen.d.ts.map +1 -0
  30. package/dist/src/arc/client.d.ts +97 -13
  31. package/dist/src/arc/client.d.ts.map +1 -1
  32. package/dist/src/arc/compiler/types.gen.d.ts +3 -3
  33. package/dist/src/arc/compiler/types.gen.d.ts.map +1 -1
  34. package/dist/src/arc/external.d.ts +2 -0
  35. package/dist/src/arc/external.d.ts.map +1 -1
  36. package/dist/src/arc/graph/types.gen.d.ts +45 -597
  37. package/dist/src/arc/graph/types.gen.d.ts.map +1 -1
  38. package/dist/src/arc/ir/index.d.ts +1 -1
  39. package/dist/src/arc/ir/index.d.ts.map +1 -1
  40. package/dist/src/arc/ir/ir.d.ts +2 -0
  41. package/dist/src/arc/ir/ir.d.ts.map +1 -0
  42. package/dist/src/arc/ir/types.gen.d.ts +58 -2807
  43. package/dist/src/arc/ir/types.gen.d.ts.map +1 -1
  44. package/dist/src/arc/module/types.gen.d.ts +18 -1090
  45. package/dist/src/arc/module/types.gen.d.ts.map +1 -1
  46. package/dist/src/arc/program/types.gen.d.ts +18 -1090
  47. package/dist/src/arc/program/types.gen.d.ts.map +1 -1
  48. package/dist/src/arc/text/types.gen.d.ts +54 -1
  49. package/dist/src/arc/text/types.gen.d.ts.map +1 -1
  50. package/dist/src/arc/types/types.gen.d.ts +35 -153
  51. package/dist/src/arc/types/types.gen.d.ts.map +1 -1
  52. package/dist/src/arc/types.gen.d.ts +98 -2278
  53. package/dist/src/arc/types.gen.d.ts.map +1 -1
  54. package/dist/src/auth/auth.d.ts +14 -2
  55. package/dist/src/auth/auth.d.ts.map +1 -1
  56. package/dist/src/channel/client.d.ts +113 -75
  57. package/dist/src/channel/client.d.ts.map +1 -1
  58. package/dist/src/channel/external.d.ts +0 -1
  59. package/dist/src/channel/external.d.ts.map +1 -1
  60. package/dist/src/channel/payload.d.ts +65 -56
  61. package/dist/src/channel/payload.d.ts.map +1 -1
  62. package/dist/src/channel/types.gen.d.ts +26 -73
  63. package/dist/src/channel/types.gen.d.ts.map +1 -1
  64. package/dist/src/channel/writer.d.ts +1 -3
  65. package/dist/src/channel/writer.d.ts.map +1 -1
  66. package/dist/src/client.d.ts +55 -27
  67. package/dist/src/client.d.ts.map +1 -1
  68. package/dist/src/connection/client.d.ts +146 -0
  69. package/dist/src/connection/client.d.ts.map +1 -0
  70. package/dist/src/connection/external.d.ts +3 -0
  71. package/dist/src/connection/external.d.ts.map +1 -0
  72. package/dist/src/connection/index.d.ts +1 -1
  73. package/dist/src/connection/index.d.ts.map +1 -1
  74. package/dist/src/connection/status.d.ts +252 -0
  75. package/dist/src/connection/status.d.ts.map +1 -0
  76. package/dist/src/control/client.d.ts +31 -7
  77. package/dist/src/control/client.d.ts.map +1 -1
  78. package/dist/src/control/state.d.ts +47 -16
  79. package/dist/src/control/state.d.ts.map +1 -1
  80. package/dist/src/device/client.d.ts +59 -17
  81. package/dist/src/device/client.d.ts.map +1 -1
  82. package/dist/src/device/types.gen.d.ts +17 -67
  83. package/dist/src/device/types.gen.d.ts.map +1 -1
  84. package/dist/src/errors.d.ts +17 -20
  85. package/dist/src/errors.d.ts.map +1 -1
  86. package/dist/src/ethercat/external.d.ts +2 -0
  87. package/dist/src/ethercat/external.d.ts.map +1 -0
  88. package/dist/src/ethercat/index.d.ts +2 -0
  89. package/dist/src/ethercat/index.d.ts.map +1 -0
  90. package/dist/src/ethercat/types.gen.d.ts +243 -0
  91. package/dist/src/ethercat/types.gen.d.ts.map +1 -0
  92. package/dist/src/framer/adapter.d.ts +8 -5
  93. package/dist/src/framer/adapter.d.ts.map +1 -1
  94. package/dist/src/framer/benchutil.d.ts +19 -0
  95. package/dist/src/framer/benchutil.d.ts.map +1 -0
  96. package/dist/src/framer/cache/cache.d.ts +38 -0
  97. package/dist/src/framer/cache/cache.d.ts.map +1 -0
  98. package/dist/src/framer/cache/dynamic.d.ts +91 -0
  99. package/dist/src/framer/cache/dynamic.d.ts.map +1 -0
  100. package/dist/src/framer/cache/reader.d.ts +57 -0
  101. package/dist/src/framer/cache/reader.d.ts.map +1 -0
  102. package/dist/src/framer/cache/static.d.ts +66 -0
  103. package/dist/src/framer/cache/static.d.ts.map +1 -0
  104. package/dist/src/framer/cache/streamer.d.ts +86 -0
  105. package/dist/src/framer/cache/streamer.d.ts.map +1 -0
  106. package/dist/src/framer/cache/transform.d.ts +18 -0
  107. package/dist/src/framer/cache/transform.d.ts.map +1 -0
  108. package/dist/src/framer/cache/unary.d.ts +39 -0
  109. package/dist/src/framer/cache/unary.d.ts.map +1 -0
  110. package/dist/src/framer/client.d.ts +35 -14
  111. package/dist/src/framer/client.d.ts.map +1 -1
  112. package/dist/src/framer/codec.d.ts.map +1 -1
  113. package/dist/src/framer/deleter.d.ts +3 -2
  114. package/dist/src/framer/deleter.d.ts.map +1 -1
  115. package/dist/src/framer/external.d.ts +6 -0
  116. package/dist/src/framer/external.d.ts.map +1 -1
  117. package/dist/src/framer/feed.d.ts +40 -0
  118. package/dist/src/framer/feed.d.ts.map +1 -0
  119. package/dist/src/framer/frame.d.ts +16 -20
  120. package/dist/src/framer/frame.d.ts.map +1 -1
  121. package/dist/src/framer/hardened.d.ts +70 -0
  122. package/dist/src/framer/hardened.d.ts.map +1 -0
  123. package/dist/src/framer/iterator.d.ts +36 -43
  124. package/dist/src/framer/iterator.d.ts.map +1 -1
  125. package/dist/src/framer/reader.d.ts +3 -2
  126. package/dist/src/framer/reader.d.ts.map +1 -1
  127. package/dist/src/framer/streamer.d.ts +132 -205
  128. package/dist/src/framer/streamer.d.ts.map +1 -1
  129. package/dist/src/framer/writer.d.ts +130 -161
  130. package/dist/src/framer/writer.d.ts.map +1 -1
  131. package/dist/src/group/client.d.ts +66 -9
  132. package/dist/src/group/client.d.ts.map +1 -1
  133. package/dist/src/group/types.gen.d.ts +2 -2
  134. package/dist/src/http/external.d.ts +2 -0
  135. package/dist/src/http/external.d.ts.map +1 -0
  136. package/dist/src/http/index.d.ts +2 -0
  137. package/dist/src/http/index.d.ts.map +1 -0
  138. package/dist/src/http/types.gen.d.ts +451 -0
  139. package/dist/src/http/types.gen.d.ts.map +1 -0
  140. package/dist/src/imex/client.d.ts +88 -0
  141. package/dist/src/imex/client.d.ts.map +1 -0
  142. package/dist/src/imex/index.d.ts +2 -0
  143. package/dist/src/imex/index.d.ts.map +1 -0
  144. package/dist/src/index.d.ts +18 -5
  145. package/dist/src/index.d.ts.map +1 -1
  146. package/dist/src/label/client.d.ts +55 -36
  147. package/dist/src/label/client.d.ts.map +1 -1
  148. package/dist/src/label/external.d.ts +2 -0
  149. package/dist/src/label/external.d.ts.map +1 -1
  150. package/dist/src/label/payload.d.ts +4 -46
  151. package/dist/src/label/payload.d.ts.map +1 -1
  152. package/dist/src/label/store.d.ts +8 -0
  153. package/dist/src/label/store.d.ts.map +1 -0
  154. package/dist/src/label/types.gen.d.ts +45 -0
  155. package/dist/src/label/types.gen.d.ts.map +1 -0
  156. package/dist/src/labjack/external.d.ts +2 -0
  157. package/dist/src/labjack/external.d.ts.map +1 -0
  158. package/dist/src/labjack/index.d.ts +2 -0
  159. package/dist/src/labjack/index.d.ts.map +1 -0
  160. package/dist/src/labjack/types.gen.d.ts +442 -0
  161. package/dist/src/labjack/types.gen.d.ts.map +1 -0
  162. package/dist/src/lineplot/actions.d.ts +914 -0
  163. package/dist/src/lineplot/actions.d.ts.map +1 -0
  164. package/dist/src/lineplot/actions.gen.d.ts +4208 -0
  165. package/dist/src/lineplot/actions.gen.d.ts.map +1 -0
  166. package/dist/src/lineplot/client.d.ts +66 -16
  167. package/dist/src/lineplot/client.d.ts.map +1 -1
  168. package/dist/src/lineplot/external.d.ts +3 -0
  169. package/dist/src/lineplot/external.d.ts.map +1 -1
  170. package/dist/src/lineplot/line.d.ts +16 -0
  171. package/dist/src/lineplot/line.d.ts.map +1 -0
  172. package/dist/src/lineplot/types.gen.d.ts +837 -14
  173. package/dist/src/lineplot/types.gen.d.ts.map +1 -1
  174. package/dist/src/log/actions.d.ts +271 -0
  175. package/dist/src/log/actions.d.ts.map +1 -0
  176. package/dist/src/log/actions.gen.d.ts +1529 -0
  177. package/dist/src/log/actions.gen.d.ts.map +1 -0
  178. package/dist/src/log/client.d.ts +66 -16
  179. package/dist/src/log/client.d.ts.map +1 -1
  180. package/dist/src/log/external.d.ts +2 -0
  181. package/dist/src/log/external.d.ts.map +1 -1
  182. package/dist/src/log/types.gen.d.ts +139 -14
  183. package/dist/src/log/types.gen.d.ts.map +1 -1
  184. package/dist/src/modbus/external.d.ts +2 -0
  185. package/dist/src/modbus/external.d.ts.map +1 -0
  186. package/dist/src/modbus/index.d.ts +2 -0
  187. package/dist/src/modbus/index.d.ts.map +1 -0
  188. package/dist/src/modbus/types.gen.d.ts +280 -0
  189. package/dist/src/modbus/types.gen.d.ts.map +1 -0
  190. package/dist/src/ni/external.d.ts +2 -0
  191. package/dist/src/ni/external.d.ts.map +1 -0
  192. package/dist/src/ni/index.d.ts +2 -0
  193. package/dist/src/ni/index.d.ts.map +1 -0
  194. package/dist/src/ni/types.gen.d.ts +21029 -0
  195. package/dist/src/ni/types.gen.d.ts.map +1 -0
  196. package/dist/src/node/index.d.ts +2 -0
  197. package/dist/src/node/index.d.ts.map +1 -0
  198. package/dist/src/node/types.gen.d.ts +4 -0
  199. package/dist/src/node/types.gen.d.ts.map +1 -0
  200. package/dist/src/ontology/client.d.ts +314 -67
  201. package/dist/src/ontology/client.d.ts.map +1 -1
  202. package/dist/src/ontology/external.d.ts +1 -0
  203. package/dist/src/ontology/external.d.ts.map +1 -1
  204. package/dist/src/ontology/payload.d.ts +60 -18
  205. package/dist/src/ontology/payload.d.ts.map +1 -1
  206. package/dist/src/ontology/store.d.ts +32 -0
  207. package/dist/src/ontology/store.d.ts.map +1 -0
  208. package/dist/src/ontology/types.gen.d.ts +3 -2
  209. package/dist/src/ontology/types.gen.d.ts.map +1 -1
  210. package/dist/src/ontology/writer.d.ts +16 -10
  211. package/dist/src/ontology/writer.d.ts.map +1 -1
  212. package/dist/src/opcua/external.d.ts +2 -0
  213. package/dist/src/opcua/external.d.ts.map +1 -0
  214. package/dist/src/opcua/index.d.ts +2 -0
  215. package/dist/src/opcua/index.d.ts.map +1 -0
  216. package/dist/src/opcua/types.gen.d.ts +82 -0
  217. package/dist/src/opcua/types.gen.d.ts.map +1 -0
  218. package/dist/src/pagerduty/external.d.ts +2 -0
  219. package/dist/src/pagerduty/external.d.ts.map +1 -0
  220. package/dist/src/pagerduty/index.d.ts +2 -0
  221. package/dist/src/pagerduty/index.d.ts.map +1 -0
  222. package/dist/src/pagerduty/types.gen.d.ts +30 -0
  223. package/dist/src/pagerduty/types.gen.d.ts.map +1 -0
  224. package/dist/src/panel/actions.d.ts +273 -0
  225. package/dist/src/panel/actions.d.ts.map +1 -0
  226. package/dist/src/panel/actions.gen.d.ts +1255 -0
  227. package/dist/src/panel/actions.gen.d.ts.map +1 -0
  228. package/dist/src/panel/client.d.ts +148 -0
  229. package/dist/src/panel/client.d.ts.map +1 -0
  230. package/dist/src/panel/external.d.ts +6 -0
  231. package/dist/src/panel/external.d.ts.map +1 -0
  232. package/dist/src/panel/index.d.ts +2 -0
  233. package/dist/src/panel/index.d.ts.map +1 -0
  234. package/dist/src/panel/tree.d.ts +50 -0
  235. package/dist/src/panel/tree.d.ts.map +1 -0
  236. package/dist/src/panel/types.gen.d.ts +370 -0
  237. package/dist/src/panel/types.gen.d.ts.map +1 -0
  238. package/dist/src/project/client.d.ts +89 -0
  239. package/dist/src/project/client.d.ts.map +1 -0
  240. package/dist/src/project/external.d.ts.map +1 -0
  241. package/dist/src/project/index.d.ts +2 -0
  242. package/dist/src/project/index.d.ts.map +1 -0
  243. package/dist/src/project/types.gen.d.ts +27 -0
  244. package/dist/src/project/types.gen.d.ts.map +1 -0
  245. package/dist/src/query/cache.d.ts +132 -0
  246. package/dist/src/query/cache.d.ts.map +1 -0
  247. package/dist/src/query/deleted.d.ts +20 -0
  248. package/dist/src/query/deleted.d.ts.map +1 -0
  249. package/dist/src/query/derived.d.ts +33 -0
  250. package/dist/src/query/derived.d.ts.map +1 -0
  251. package/dist/src/query/external.d.ts +10 -0
  252. package/dist/src/query/external.d.ts.map +1 -0
  253. package/dist/src/query/index.d.ts +2 -0
  254. package/dist/src/query/index.d.ts.map +1 -0
  255. package/dist/src/query/query.d.ts +235 -0
  256. package/dist/src/query/query.d.ts.map +1 -0
  257. package/dist/src/query/retriever.d.ts +135 -0
  258. package/dist/src/query/retriever.d.ts.map +1 -0
  259. package/dist/src/query/streamer.d.ts +67 -0
  260. package/dist/src/query/streamer.d.ts.map +1 -0
  261. package/dist/src/query/table.d.ts +219 -0
  262. package/dist/src/query/table.d.ts.map +1 -0
  263. package/dist/src/query/types.d.ts +35 -0
  264. package/dist/src/query/types.d.ts.map +1 -0
  265. package/dist/src/query/write.d.ts +21 -0
  266. package/dist/src/query/write.d.ts.map +1 -0
  267. package/dist/src/rack/client.d.ts +58 -20
  268. package/dist/src/rack/client.d.ts.map +1 -1
  269. package/dist/src/rack/types.gen.d.ts +11 -12
  270. package/dist/src/rack/types.gen.d.ts.map +1 -1
  271. package/dist/src/range/alias/types.gen.d.ts +2 -3
  272. package/dist/src/range/alias/types.gen.d.ts.map +1 -1
  273. package/dist/src/ranger/client.d.ts +138 -27
  274. package/dist/src/ranger/client.d.ts.map +1 -1
  275. package/dist/src/ranger/kv/client.d.ts +7 -4
  276. package/dist/src/ranger/kv/client.d.ts.map +1 -1
  277. package/dist/src/ranger/payload.d.ts +3 -0
  278. package/dist/src/ranger/payload.d.ts.map +1 -1
  279. package/dist/src/ranger/types.gen.d.ts +45 -101
  280. package/dist/src/ranger/types.gen.d.ts.map +1 -1
  281. package/dist/src/ranger/writer.d.ts +2 -74
  282. package/dist/src/ranger/writer.d.ts.map +1 -1
  283. package/dist/src/schematic/actions.d.ts +90 -33
  284. package/dist/src/schematic/actions.d.ts.map +1 -1
  285. package/dist/src/schematic/actions.gen.d.ts +207 -114
  286. package/dist/src/schematic/actions.gen.d.ts.map +1 -1
  287. package/dist/src/schematic/client.d.ts +70 -68
  288. package/dist/src/schematic/client.d.ts.map +1 -1
  289. package/dist/src/schematic/symbol/client.d.ts +133 -27
  290. package/dist/src/schematic/symbol/client.d.ts.map +1 -1
  291. package/dist/src/schematic/symbol/types.gen.d.ts +258 -153
  292. package/dist/src/schematic/symbol/types.gen.d.ts.map +1 -1
  293. package/dist/src/schematic/types.gen.d.ts +17 -96
  294. package/dist/src/schematic/types.gen.d.ts.map +1 -1
  295. package/dist/src/status/client.d.ts +69 -14
  296. package/dist/src/status/client.d.ts.map +1 -1
  297. package/dist/src/status/external.d.ts +2 -0
  298. package/dist/src/status/external.d.ts.map +1 -1
  299. package/dist/src/status/payload.d.ts +2 -36
  300. package/dist/src/status/payload.d.ts.map +1 -1
  301. package/dist/src/status/status.d.ts +65 -0
  302. package/dist/src/status/status.d.ts.map +1 -0
  303. package/dist/src/status/types.gen.d.ts +58 -0
  304. package/dist/src/status/types.gen.d.ts.map +1 -0
  305. package/dist/src/table/actions.d.ts +72 -13
  306. package/dist/src/table/actions.d.ts.map +1 -1
  307. package/dist/src/table/actions.gen.d.ts +221 -137
  308. package/dist/src/table/actions.gen.d.ts.map +1 -1
  309. package/dist/src/table/client.d.ts +64 -40
  310. package/dist/src/table/client.d.ts.map +1 -1
  311. package/dist/src/table/types.gen.d.ts +20 -55
  312. package/dist/src/table/types.gen.d.ts.map +1 -1
  313. package/dist/src/task/client.d.ts +149 -28
  314. package/dist/src/task/client.d.ts.map +1 -1
  315. package/dist/src/task/types.gen.d.ts +71 -89
  316. package/dist/src/task/types.gen.d.ts.map +1 -1
  317. package/dist/src/testutil/access.d.ts +27 -1
  318. package/dist/src/testutil/access.d.ts.map +1 -1
  319. package/dist/src/testutil/channels.d.ts +2 -0
  320. package/dist/src/testutil/channels.d.ts.map +1 -1
  321. package/dist/src/testutil/client.d.ts +5 -0
  322. package/dist/src/testutil/client.d.ts.map +1 -1
  323. package/dist/src/testutil/connection.d.ts +10 -0
  324. package/dist/src/testutil/connection.d.ts.map +1 -0
  325. package/dist/src/testutil/index.d.ts +9 -0
  326. package/dist/src/testutil/index.d.ts.map +1 -0
  327. package/dist/src/testutil/panels.d.ts +8 -0
  328. package/dist/src/testutil/panels.d.ts.map +1 -0
  329. package/dist/src/testutil/proxy.d.ts +29 -0
  330. package/dist/src/testutil/proxy.d.ts.map +1 -0
  331. package/dist/src/testutil/query.d.ts +7 -0
  332. package/dist/src/testutil/query.d.ts.map +1 -0
  333. package/dist/src/testutil/telem.d.ts +4 -0
  334. package/dist/src/testutil/telem.d.ts.map +1 -1
  335. package/dist/src/transport.d.ts +10 -4
  336. package/dist/src/transport.d.ts.map +1 -1
  337. package/dist/src/user/client.d.ts +29 -28
  338. package/dist/src/user/client.d.ts.map +1 -1
  339. package/dist/src/user/external.d.ts +1 -1
  340. package/dist/src/user/external.d.ts.map +1 -1
  341. package/dist/src/user/types.gen.d.ts +4 -4
  342. package/dist/src/util/retrieve.d.ts +2 -2
  343. package/dist/src/util/retrieve.d.ts.map +1 -1
  344. package/dist/src/util/telem.d.ts.map +1 -1
  345. package/dist/src/view/client.d.ts +30 -14
  346. package/dist/src/view/client.d.ts.map +1 -1
  347. package/dist/src/view/types.gen.d.ts +7 -15
  348. package/dist/src/view/types.gen.d.ts.map +1 -1
  349. package/dist/testutil.js +189 -0
  350. package/dist/testutil.js.map +1 -0
  351. package/package.json +39 -16
  352. package/src/access/client.ts +14 -3
  353. package/src/access/enforce.ts +0 -3
  354. package/src/access/external.ts +1 -0
  355. package/src/access/granted.ts +114 -0
  356. package/src/access/policy/client.ts +135 -43
  357. package/src/access/policy/types.gen.ts +9 -11
  358. package/src/access/role/client.ts +160 -38
  359. package/src/access/role/types.gen.ts +8 -12
  360. package/src/actions/actions.ts +5 -6
  361. package/src/actions/controller.ts +626 -0
  362. package/src/actions/external.ts +11 -0
  363. package/src/arc/actions.gen.ts +313 -0
  364. package/src/arc/actions.ts +192 -0
  365. package/src/arc/client.ts +424 -41
  366. package/src/arc/compiler/types.gen.ts +5 -6
  367. package/src/arc/external.ts +2 -0
  368. package/src/arc/graph/types.gen.ts +24 -22
  369. package/src/arc/ir/index.ts +1 -1
  370. package/{eslint.config.ts → src/arc/ir/ir.ts} +1 -4
  371. package/src/arc/ir/types.gen.ts +42 -41
  372. package/src/arc/text/types.gen.ts +21 -2
  373. package/src/arc/types/types.gen.ts +40 -32
  374. package/src/arc/types.gen.ts +31 -29
  375. package/src/auth/auth.ts +40 -8
  376. package/src/channel/client.ts +529 -132
  377. package/src/channel/external.ts +0 -1
  378. package/src/channel/payload.ts +30 -3
  379. package/src/channel/types.gen.ts +37 -48
  380. package/src/channel/writer.ts +2 -11
  381. package/src/client.ts +215 -91
  382. package/src/connection/client.ts +495 -0
  383. package/src/connection/external.ts +34 -0
  384. package/src/connection/index.ts +1 -1
  385. package/src/connection/status.ts +442 -0
  386. package/src/control/client.ts +84 -12
  387. package/src/control/state.ts +17 -36
  388. package/src/device/client.ts +293 -41
  389. package/src/device/types.gen.ts +15 -26
  390. package/src/errors.ts +45 -22
  391. package/src/{workspace → ethercat}/external.ts +1 -2
  392. package/src/{workspace → ethercat}/index.ts +1 -1
  393. package/src/ethercat/types.gen.ts +151 -0
  394. package/src/framer/adapter.ts +60 -37
  395. package/src/framer/benchutil.ts +67 -0
  396. package/src/framer/cache/cache.ts +115 -0
  397. package/src/framer/cache/dynamic.ts +340 -0
  398. package/src/framer/cache/reader.ts +231 -0
  399. package/src/framer/cache/static.ts +215 -0
  400. package/src/framer/cache/streamer.ts +391 -0
  401. package/src/framer/cache/transform.ts +31 -0
  402. package/src/framer/cache/unary.ts +108 -0
  403. package/src/framer/client.ts +71 -43
  404. package/src/framer/codec.ts +55 -18
  405. package/src/framer/deleter.ts +4 -6
  406. package/src/framer/external.ts +10 -0
  407. package/src/framer/feed.ts +108 -0
  408. package/src/framer/frame.ts +13 -23
  409. package/src/framer/hardened.ts +283 -0
  410. package/src/framer/iterator.ts +31 -42
  411. package/src/framer/reader.ts +11 -11
  412. package/src/framer/streamer.ts +18 -178
  413. package/src/framer/writer.ts +39 -59
  414. package/src/group/client.ts +158 -23
  415. package/src/http/external.ts +10 -0
  416. package/src/{cluster → http}/index.ts +1 -1
  417. package/src/http/types.gen.ts +245 -0
  418. package/src/imex/client.ts +125 -0
  419. package/src/imex/index.ts +10 -0
  420. package/src/index.ts +19 -6
  421. package/src/label/client.ts +193 -54
  422. package/src/label/external.ts +2 -0
  423. package/src/label/payload.ts +4 -9
  424. package/src/label/store.ts +28 -0
  425. package/src/label/types.gen.ts +31 -0
  426. package/src/labjack/external.ts +10 -0
  427. package/src/labjack/index.ts +10 -0
  428. package/src/labjack/types.gen.ts +251 -0
  429. package/src/lineplot/actions.gen.ts +880 -0
  430. package/src/lineplot/actions.ts +535 -0
  431. package/src/lineplot/client.ts +224 -52
  432. package/src/lineplot/external.ts +3 -0
  433. package/src/lineplot/line.ts +80 -0
  434. package/src/lineplot/types.gen.ts +225 -12
  435. package/src/log/actions.gen.ts +474 -0
  436. package/src/log/actions.ts +242 -0
  437. package/src/log/client.ts +223 -52
  438. package/src/log/external.ts +2 -0
  439. package/src/log/types.gen.ts +45 -14
  440. package/src/modbus/external.ts +10 -0
  441. package/src/modbus/index.ts +10 -0
  442. package/src/modbus/types.gen.ts +185 -0
  443. package/src/ni/external.ts +10 -0
  444. package/src/ni/index.ts +10 -0
  445. package/src/ni/types.gen.ts +1632 -0
  446. package/src/node/index.ts +10 -0
  447. package/src/{cluster → node}/types.gen.ts +2 -2
  448. package/src/ontology/client.ts +408 -99
  449. package/src/ontology/external.ts +7 -0
  450. package/src/ontology/payload.ts +48 -7
  451. package/src/ontology/store.ts +83 -0
  452. package/src/ontology/types.gen.ts +2 -1
  453. package/src/ontology/writer.ts +1 -0
  454. package/src/opcua/external.ts +10 -0
  455. package/src/opcua/index.ts +10 -0
  456. package/src/opcua/types.gen.ts +65 -0
  457. package/src/pagerduty/external.ts +10 -0
  458. package/src/pagerduty/index.ts +10 -0
  459. package/src/pagerduty/types.gen.ts +41 -0
  460. package/src/panel/actions.gen.ts +267 -0
  461. package/src/panel/actions.ts +357 -0
  462. package/src/panel/client.ts +327 -0
  463. package/src/panel/external.ts +14 -0
  464. package/src/panel/index.ts +10 -0
  465. package/src/panel/tree.ts +163 -0
  466. package/src/panel/types.gen.ts +164 -0
  467. package/src/project/client.ts +273 -0
  468. package/src/project/external.ts +11 -0
  469. package/src/project/index.ts +10 -0
  470. package/src/project/types.gen.ts +40 -0
  471. package/src/query/cache.ts +326 -0
  472. package/src/query/deleted.ts +38 -0
  473. package/src/query/derived.ts +101 -0
  474. package/src/query/external.ts +51 -0
  475. package/src/query/index.ts +10 -0
  476. package/src/query/query.ts +865 -0
  477. package/src/query/retriever.ts +308 -0
  478. package/src/query/streamer.ts +207 -0
  479. package/src/query/table.ts +625 -0
  480. package/src/query/types.ts +54 -0
  481. package/src/query/write.ts +42 -0
  482. package/src/rack/client.ts +233 -45
  483. package/src/rack/types.gen.ts +15 -16
  484. package/src/range/alias/types.gen.ts +2 -3
  485. package/src/ranger/client.ts +581 -70
  486. package/src/ranger/kv/client.ts +52 -21
  487. package/src/ranger/payload.ts +3 -0
  488. package/src/ranger/types.gen.ts +21 -23
  489. package/src/ranger/writer.ts +4 -8
  490. package/src/schematic/actions.gen.ts +62 -53
  491. package/src/schematic/actions.ts +44 -42
  492. package/src/schematic/client.ts +226 -70
  493. package/src/schematic/symbol/client.ts +277 -48
  494. package/src/schematic/symbol/types.gen.ts +22 -34
  495. package/src/schematic/types.gen.ts +22 -29
  496. package/src/status/client.ts +321 -44
  497. package/src/status/external.ts +2 -0
  498. package/src/status/payload.ts +1 -23
  499. package/src/status/status.ts +241 -0
  500. package/src/status/types.gen.ts +108 -0
  501. package/src/table/actions.gen.ts +96 -63
  502. package/src/table/actions.ts +44 -19
  503. package/src/table/client.ts +220 -56
  504. package/src/table/types.gen.ts +24 -31
  505. package/src/task/client.ts +580 -101
  506. package/src/task/types.gen.ts +68 -75
  507. package/src/testutil/access.ts +102 -6
  508. package/src/testutil/channels.ts +29 -0
  509. package/src/testutil/client.ts +27 -2
  510. package/src/testutil/connection.ts +47 -0
  511. package/src/testutil/index.ts +17 -0
  512. package/src/testutil/panels.ts +26 -0
  513. package/src/testutil/proxy.ts +106 -0
  514. package/src/testutil/query.ts +28 -0
  515. package/src/testutil/telem.ts +17 -1
  516. package/src/transport.ts +18 -7
  517. package/src/user/client.ts +165 -64
  518. package/src/user/external.ts +1 -1
  519. package/src/user/types.gen.ts +5 -5
  520. package/src/util/retrieve.ts +4 -4
  521. package/src/util/telem.ts +0 -1
  522. package/src/view/client.ts +120 -37
  523. package/src/view/types.gen.ts +8 -11
  524. package/.turbo/turbo-build.log +0 -20
  525. package/.vscode/settings.json +0 -3
  526. package/CONTRIBUTING.md +0 -47
  527. package/dist/client.cjs +0 -118
  528. package/dist/eslint.config.d.ts +0 -4
  529. package/dist/eslint.config.d.ts.map +0 -1
  530. package/dist/src/access/enforce.spec.d.ts +0 -2
  531. package/dist/src/access/enforce.spec.d.ts.map +0 -1
  532. package/dist/src/access/policy/access.spec.d.ts +0 -2
  533. package/dist/src/access/policy/access.spec.d.ts.map +0 -1
  534. package/dist/src/access/role/role.spec.d.ts +0 -2
  535. package/dist/src/access/role/role.spec.d.ts.map +0 -1
  536. package/dist/src/actions/actions.spec.d.ts +0 -2
  537. package/dist/src/actions/actions.spec.d.ts.map +0 -1
  538. package/dist/src/arc/access.spec.d.ts +0 -2
  539. package/dist/src/arc/access.spec.d.ts.map +0 -1
  540. package/dist/src/arc/arc.spec.d.ts +0 -2
  541. package/dist/src/arc/arc.spec.d.ts.map +0 -1
  542. package/dist/src/arc/lsp.spec.d.ts +0 -2
  543. package/dist/src/arc/lsp.spec.d.ts.map +0 -1
  544. package/dist/src/auth/auth.spec.d.ts +0 -2
  545. package/dist/src/auth/auth.spec.d.ts.map +0 -1
  546. package/dist/src/channel/access.spec.d.ts +0 -2
  547. package/dist/src/channel/access.spec.d.ts.map +0 -1
  548. package/dist/src/channel/batchRetriever.spec.d.ts +0 -2
  549. package/dist/src/channel/batchRetriever.spec.d.ts.map +0 -1
  550. package/dist/src/channel/channel.spec.d.ts +0 -2
  551. package/dist/src/channel/channel.spec.d.ts.map +0 -1
  552. package/dist/src/channel/payload.spec.d.ts +0 -2
  553. package/dist/src/channel/payload.spec.d.ts.map +0 -1
  554. package/dist/src/channel/retriever.d.ts +0 -64
  555. package/dist/src/channel/retriever.d.ts.map +0 -1
  556. package/dist/src/cluster/index.d.ts +0 -2
  557. package/dist/src/cluster/index.d.ts.map +0 -1
  558. package/dist/src/cluster/types.gen.d.ts +0 -4
  559. package/dist/src/cluster/types.gen.d.ts.map +0 -1
  560. package/dist/src/connection/checker.d.ts +0 -86
  561. package/dist/src/connection/checker.d.ts.map +0 -1
  562. package/dist/src/connection/connection.spec.d.ts +0 -2
  563. package/dist/src/connection/connection.spec.d.ts.map +0 -1
  564. package/dist/src/connection.spec.d.ts +0 -2
  565. package/dist/src/connection.spec.d.ts.map +0 -1
  566. package/dist/src/control/state.spec.d.ts +0 -2
  567. package/dist/src/control/state.spec.d.ts.map +0 -1
  568. package/dist/src/device/access.spec.d.ts +0 -2
  569. package/dist/src/device/access.spec.d.ts.map +0 -1
  570. package/dist/src/device/device.spec.d.ts +0 -2
  571. package/dist/src/device/device.spec.d.ts.map +0 -1
  572. package/dist/src/device/payload.spec.d.ts +0 -2
  573. package/dist/src/device/payload.spec.d.ts.map +0 -1
  574. package/dist/src/errors.spec.d.ts +0 -2
  575. package/dist/src/errors.spec.d.ts.map +0 -1
  576. package/dist/src/framer/adapter.spec.d.ts +0 -2
  577. package/dist/src/framer/adapter.spec.d.ts.map +0 -1
  578. package/dist/src/framer/client.spec.d.ts +0 -2
  579. package/dist/src/framer/client.spec.d.ts.map +0 -1
  580. package/dist/src/framer/codec.spec.d.ts +0 -2
  581. package/dist/src/framer/codec.spec.d.ts.map +0 -1
  582. package/dist/src/framer/deleter.spec.d.ts +0 -2
  583. package/dist/src/framer/deleter.spec.d.ts.map +0 -1
  584. package/dist/src/framer/frame.spec.d.ts +0 -2
  585. package/dist/src/framer/frame.spec.d.ts.map +0 -1
  586. package/dist/src/framer/iterator.spec.d.ts +0 -2
  587. package/dist/src/framer/iterator.spec.d.ts.map +0 -1
  588. package/dist/src/framer/reader.spec.d.ts +0 -2
  589. package/dist/src/framer/reader.spec.d.ts.map +0 -1
  590. package/dist/src/framer/streamer.spec.d.ts +0 -2
  591. package/dist/src/framer/streamer.spec.d.ts.map +0 -1
  592. package/dist/src/framer/writer.spec.d.ts +0 -2
  593. package/dist/src/framer/writer.spec.d.ts.map +0 -1
  594. package/dist/src/group/access.spec.d.ts +0 -2
  595. package/dist/src/group/access.spec.d.ts.map +0 -1
  596. package/dist/src/group/group.spec.d.ts +0 -2
  597. package/dist/src/group/group.spec.d.ts.map +0 -1
  598. package/dist/src/label/access.spec.d.ts +0 -2
  599. package/dist/src/label/access.spec.d.ts.map +0 -1
  600. package/dist/src/label/label.spec.d.ts +0 -2
  601. package/dist/src/label/label.spec.d.ts.map +0 -1
  602. package/dist/src/lineplot/access.spec.d.ts +0 -2
  603. package/dist/src/lineplot/access.spec.d.ts.map +0 -1
  604. package/dist/src/lineplot/lineplot.spec.d.ts +0 -2
  605. package/dist/src/lineplot/lineplot.spec.d.ts.map +0 -1
  606. package/dist/src/log/access.spec.d.ts +0 -2
  607. package/dist/src/log/access.spec.d.ts.map +0 -1
  608. package/dist/src/log/log.spec.d.ts +0 -2
  609. package/dist/src/log/log.spec.d.ts.map +0 -1
  610. package/dist/src/ontology/ontology.spec.d.ts +0 -2
  611. package/dist/src/ontology/ontology.spec.d.ts.map +0 -1
  612. package/dist/src/rack/access.spec.d.ts +0 -2
  613. package/dist/src/rack/access.spec.d.ts.map +0 -1
  614. package/dist/src/rack/rack.spec.d.ts +0 -2
  615. package/dist/src/rack/rack.spec.d.ts.map +0 -1
  616. package/dist/src/ranger/access.spec.d.ts +0 -2
  617. package/dist/src/ranger/access.spec.d.ts.map +0 -1
  618. package/dist/src/ranger/alias/payload.spec.d.ts +0 -2
  619. package/dist/src/ranger/alias/payload.spec.d.ts.map +0 -1
  620. package/dist/src/ranger/ranger.spec.d.ts +0 -2
  621. package/dist/src/ranger/ranger.spec.d.ts.map +0 -1
  622. package/dist/src/schematic/access.spec.d.ts +0 -2
  623. package/dist/src/schematic/access.spec.d.ts.map +0 -1
  624. package/dist/src/schematic/actions.spec.d.ts +0 -2
  625. package/dist/src/schematic/actions.spec.d.ts.map +0 -1
  626. package/dist/src/schematic/schematic.spec.d.ts +0 -2
  627. package/dist/src/schematic/schematic.spec.d.ts.map +0 -1
  628. package/dist/src/schematic/symbol/access.spec.d.ts +0 -2
  629. package/dist/src/schematic/symbol/access.spec.d.ts.map +0 -1
  630. package/dist/src/schematic/symbol/client.spec.d.ts +0 -2
  631. package/dist/src/schematic/symbol/client.spec.d.ts.map +0 -1
  632. package/dist/src/status/access.spec.d.ts +0 -2
  633. package/dist/src/status/access.spec.d.ts.map +0 -1
  634. package/dist/src/status/status.spec.d.ts +0 -2
  635. package/dist/src/status/status.spec.d.ts.map +0 -1
  636. package/dist/src/table/access.spec.d.ts +0 -2
  637. package/dist/src/table/access.spec.d.ts.map +0 -1
  638. package/dist/src/table/table.spec.d.ts +0 -2
  639. package/dist/src/table/table.spec.d.ts.map +0 -1
  640. package/dist/src/task/access.spec.d.ts +0 -2
  641. package/dist/src/task/access.spec.d.ts.map +0 -1
  642. package/dist/src/task/payload.spec.d.ts +0 -2
  643. package/dist/src/task/payload.spec.d.ts.map +0 -1
  644. package/dist/src/task/task.spec.d.ts +0 -2
  645. package/dist/src/task/task.spec.d.ts.map +0 -1
  646. package/dist/src/user/access.spec.d.ts +0 -2
  647. package/dist/src/user/access.spec.d.ts.map +0 -1
  648. package/dist/src/user/user.spec.d.ts +0 -2
  649. package/dist/src/user/user.spec.d.ts.map +0 -1
  650. package/dist/src/util/retrieve.spec.d.ts +0 -2
  651. package/dist/src/util/retrieve.spec.d.ts.map +0 -1
  652. package/dist/src/view/view.spec.d.ts +0 -2
  653. package/dist/src/view/view.spec.d.ts.map +0 -1
  654. package/dist/src/workspace/access.spec.d.ts +0 -2
  655. package/dist/src/workspace/access.spec.d.ts.map +0 -1
  656. package/dist/src/workspace/client.d.ts +0 -36
  657. package/dist/src/workspace/client.d.ts.map +0 -1
  658. package/dist/src/workspace/external.d.ts.map +0 -1
  659. package/dist/src/workspace/index.d.ts +0 -2
  660. package/dist/src/workspace/index.d.ts.map +0 -1
  661. package/dist/src/workspace/types.gen.d.ts +0 -34
  662. package/dist/src/workspace/types.gen.d.ts.map +0 -1
  663. package/dist/src/workspace/workspace.spec.d.ts +0 -2
  664. package/dist/src/workspace/workspace.spec.d.ts.map +0 -1
  665. package/examples/node/basicReadWrite.js +0 -86
  666. package/examples/node/createChannels.js +0 -50
  667. package/examples/node/createRange.js +0 -67
  668. package/examples/node/package-lock.json +0 -133
  669. package/examples/node/package.json +0 -17
  670. package/examples/node/readLatest.js +0 -76
  671. package/examples/node/seriesAndFrames.js +0 -173
  672. package/examples/node/streamRead.js +0 -50
  673. package/examples/node/streamWrite.js +0 -87
  674. package/src/access/enforce.spec.ts +0 -188
  675. package/src/access/policy/access.spec.ts +0 -147
  676. package/src/access/role/role.spec.ts +0 -95
  677. package/src/actions/actions.spec.ts +0 -229
  678. package/src/arc/access.spec.ts +0 -149
  679. package/src/arc/arc.spec.ts +0 -44
  680. package/src/arc/lsp.spec.ts +0 -717
  681. package/src/auth/auth.spec.ts +0 -101
  682. package/src/channel/access.spec.ts +0 -116
  683. package/src/channel/batchRetriever.spec.ts +0 -115
  684. package/src/channel/channel.spec.ts +0 -352
  685. package/src/channel/payload.spec.ts +0 -117
  686. package/src/channel/retriever.ts +0 -252
  687. package/src/connection/checker.ts +0 -203
  688. package/src/connection/connection.spec.ts +0 -152
  689. package/src/connection.spec.ts +0 -145
  690. package/src/control/state.spec.ts +0 -22
  691. package/src/device/access.spec.ts +0 -159
  692. package/src/device/device.spec.ts +0 -461
  693. package/src/device/payload.spec.ts +0 -142
  694. package/src/errors.spec.ts +0 -71
  695. package/src/framer/adapter.spec.ts +0 -620
  696. package/src/framer/client.spec.ts +0 -180
  697. package/src/framer/codec.spec.ts +0 -383
  698. package/src/framer/deleter.spec.ts +0 -103
  699. package/src/framer/frame.spec.ts +0 -973
  700. package/src/framer/iterator.spec.ts +0 -169
  701. package/src/framer/reader.spec.ts +0 -865
  702. package/src/framer/streamer.spec.ts +0 -871
  703. package/src/framer/writer.spec.ts +0 -486
  704. package/src/group/access.spec.ts +0 -77
  705. package/src/group/group.spec.ts +0 -65
  706. package/src/label/access.spec.ts +0 -109
  707. package/src/label/label.spec.ts +0 -83
  708. package/src/lineplot/access.spec.ts +0 -134
  709. package/src/lineplot/lineplot.spec.ts +0 -120
  710. package/src/log/access.spec.ts +0 -132
  711. package/src/log/log.spec.ts +0 -106
  712. package/src/ontology/ontology.spec.ts +0 -521
  713. package/src/rack/access.spec.ts +0 -102
  714. package/src/rack/rack.spec.ts +0 -171
  715. package/src/ranger/access.spec.ts +0 -115
  716. package/src/ranger/alias/payload.spec.ts +0 -52
  717. package/src/ranger/ranger.spec.ts +0 -343
  718. package/src/schematic/access.spec.ts +0 -134
  719. package/src/schematic/actions.spec.ts +0 -699
  720. package/src/schematic/schematic.spec.ts +0 -340
  721. package/src/schematic/symbol/access.spec.ts +0 -172
  722. package/src/schematic/symbol/client.spec.ts +0 -160
  723. package/src/status/access.spec.ts +0 -129
  724. package/src/status/status.spec.ts +0 -448
  725. package/src/table/access.spec.ts +0 -128
  726. package/src/table/table.spec.ts +0 -651
  727. package/src/task/access.spec.ts +0 -131
  728. package/src/task/payload.spec.ts +0 -113
  729. package/src/task/task.spec.ts +0 -657
  730. package/src/user/access.spec.ts +0 -107
  731. package/src/user/user.spec.ts +0 -290
  732. package/src/util/retrieve.spec.ts +0 -49
  733. package/src/view/view.spec.ts +0 -165
  734. package/src/workspace/access.spec.ts +0 -108
  735. package/src/workspace/client.ts +0 -112
  736. package/src/workspace/types.gen.ts +0 -46
  737. package/src/workspace/workspace.spec.ts +0 -111
  738. package/tsconfig.json +0 -5
  739. package/tsconfig.vite.json +0 -4
  740. package/vite.config.ts +0 -29
  741. /package/dist/src/{workspace → project}/external.d.ts +0 -0
@@ -10,30 +10,42 @@
10
10
  import { type UnaryClient } from "@synnaxlabs/freighter";
11
11
  import {
12
12
  array,
13
+ binary,
13
14
  caseconv,
14
15
  type CrudeTimeSpan,
16
+ deep,
17
+ type destructor,
15
18
  id,
19
+ primitive,
16
20
  type record,
17
21
  strings,
18
22
  TimeSpan,
23
+ TimeStamp,
19
24
  } from "@synnaxlabs/x";
20
25
  import { z } from "zod";
21
26
 
22
27
  import { type framer } from "@/framer";
23
28
  import { ontology } from "@/ontology";
24
- import { type Key as RackKey, keyZ as rackKeyZ } from "@/rack/types.gen";
29
+ import { query } from "@/query";
30
+ import {
31
+ type Key as RackKey,
32
+ keyZ as rackKeyZ,
33
+ ontologyID as rackOntologyID,
34
+ } from "@/rack/types.gen";
25
35
  import { type ranger } from "@/ranger";
26
36
  import { status } from "@/status";
27
37
  import {
38
+ type Command,
39
+ commandZ,
28
40
  type Key,
29
41
  keyZ,
30
42
  type New,
31
- newZ,
32
43
  ontologyID,
33
44
  type Payload,
34
45
  type PayloadSchemas as Schemas,
35
46
  payloadZ,
36
47
  type Status,
48
+ type StatusDetailsZodObject,
37
49
  statusZ,
38
50
  } from "@/task/types.gen";
39
51
  import { checkForMultipleOrNoResults } from "@/util/retrieve";
@@ -44,31 +56,66 @@ export const COMMAND_CHANNEL_NAME = "sy_task_cmd";
44
56
  export const SET_CHANNEL_NAME = "sy_task_set";
45
57
  export const DELETE_CHANNEL_NAME = "sy_task_delete";
46
58
 
47
- export const rackKey = (key: Key): RackKey => Number(BigInt(key) >> 32n);
59
+ export const setSignalZ = payloadZ().omit({ config: true, status: true });
60
+ export interface SetSignal extends z.infer<typeof setSignalZ> {}
61
+
62
+ export interface DriftedParams extends Pick<
63
+ Payload,
64
+ "configHash" | "rack" | "status"
65
+ > {}
66
+
67
+ /**
68
+ * Reports whether a task's live instance has drifted from its stored task: the task is
69
+ * running and the stored config or rack differs from what the instance was deployed
70
+ * with. Tasks that are not running never drift. Both hashes are server-assigned, so
71
+ * this compares two given values and never hashes a config. A status with an empty
72
+ * deployed hash never drifts: the deployed config is unknown, not different.
73
+ * @returns True when a redeploy (start) would change the running instance.
74
+ */
75
+ export const drifted = (task: DriftedParams): boolean => {
76
+ const details = task.status?.details;
77
+ if (details == null || !details.running || details.configHash === "") return false;
78
+ return details.configHash !== task.configHash || details.rack !== task.rack;
79
+ };
80
+
81
+ // Temporary hack that filters the set of commands that should change the
82
+ // status of a task to loading.
83
+ // Issue: https://linear.app/synnax/issue/SY-2723/fix-handling-of-non-startstop-commands-loading-indicators-in-tasks
84
+ const LOADING_COMMANDS = ["start", "stop"];
48
85
 
49
- export const newKey = (rackKey: RackKey, taskKey: number = 0): Key =>
50
- ((BigInt(rackKey) << 32n) + BigInt(taskKey)).toString();
86
+ // The rack monitor marks a rack whose Driver is alive with one of these.
87
+ const HEALTHY_RACK_VARIANTS: status.Variant[] = ["success", "info"];
88
+
89
+ /** How long a command waits for the Driver before the wait is called off. */
90
+ const COMMAND_DEADLINE = TimeSpan.seconds(10);
91
+
92
+ const STATUS_NAME = "Task Status";
51
93
 
52
94
  const retrieveSnapshottedTo = async (taskKey: Key, ontologyClient: ontology.Client) => {
53
- const parents = await ontologyClient.retrieveParents(ontologyID(taskKey));
95
+ const parents = await ontologyClient.parents.retrieve({ ids: ontologyID(taskKey) });
54
96
  if (parents.length === 0) return null;
55
97
  return parents[0];
56
98
  };
57
99
 
100
+ /** One command sent to a task, as issued from the task itself. */
58
101
  export interface TaskExecuteCommandParams {
59
102
  type: string;
60
103
  args?: record.Unknown;
61
104
  }
62
105
 
106
+ /** One command sent to a task, as issued from the client. */
63
107
  export interface ExecuteCommandParams extends TaskExecuteCommandParams {
64
108
  task: Key;
65
109
  }
66
110
 
111
+ /** Several commands sent in one round trip. */
67
112
  export interface ExecuteCommandsParams {
68
113
  commands: NewCommand[];
69
114
  }
70
115
 
116
+ /** A command awaited to completion, as issued from the task itself. */
71
117
  export interface TaskExecuteCommandSyncParams extends TaskExecuteCommandParams {
118
+ /** How long to wait for the status before giving up. */
72
119
  timeout?: CrudeTimeSpan;
73
120
  }
74
121
 
@@ -82,46 +129,66 @@ export interface ExecuteCommandSyncParams<StatusData extends z.ZodType> extends
82
129
  "frameClient" | "name"
83
130
  > {}
84
131
 
132
+ /**
133
+ * A unit of work a rack runs against hardware: its config, its running status, and the
134
+ * commands it accepts. Get one from `client.hardware.tasks` rather than building it.
135
+ */
85
136
  export class Task<S extends Schemas = Schemas> {
86
137
  readonly key: Key;
138
+ readonly rack: RackKey;
87
139
  name: string;
88
140
  internal: boolean;
89
141
  type: z.infer<S["type"]>;
90
142
  snapshot: boolean;
91
143
  config: z.infer<S["config"]>;
144
+ readonly configHash: string;
92
145
  status?: Status<S["statusData"]>;
93
146
 
94
147
  readonly schemas: S;
95
- private readonly frameClient_?: framer.Client;
96
- private readonly ontologyClient_?: ontology.Client;
97
- private readonly rangeClient_?: ranger.Client;
148
+ private readonly clients?: {
149
+ frame: framer.Client;
150
+ ontology: ontology.Client;
151
+ range: ranger.Client;
152
+ };
98
153
 
99
154
  get frameClient(): framer.Client {
100
- if (this.frameClient_ == null) throw new Error("Task not created");
101
- return this.frameClient_;
155
+ if (this.clients == null) throw new Error("Task not created");
156
+ return this.clients.frame;
102
157
  }
103
158
 
104
159
  get ontologyClient(): ontology.Client {
105
- if (this.ontologyClient_ == null) throw new Error("Task not created");
106
- return this.ontologyClient_;
160
+ if (this.clients == null) throw new Error("Task not created");
161
+ return this.clients.ontology;
107
162
  }
108
163
 
109
164
  get rangeClient(): ranger.Client {
110
- if (this.rangeClient_ == null) throw new Error("Task not created");
111
- return this.rangeClient_;
165
+ if (this.clients == null) throw new Error("Task not created");
166
+ return this.clients.range;
112
167
  }
113
168
 
114
169
  constructor(
115
- { key, type, name, config, internal = false, snapshot = false, status }: Payload<S>,
170
+ {
171
+ key,
172
+ rack,
173
+ type,
174
+ name,
175
+ config,
176
+ configHash = "",
177
+ internal = false,
178
+ snapshot = false,
179
+ status,
180
+ }: Payload<S>,
116
181
  schemas?: S,
117
182
  frameClient?: framer.Client,
118
183
  ontologyClient?: ontology.Client,
119
184
  rangeClient?: ranger.Client,
120
185
  ) {
121
186
  this.key = key;
187
+ this.rack = rack;
122
188
  this.name = name;
123
189
  this.type = type;
124
190
  this.config = config;
191
+ this.configHash = configHash;
125
192
  this.schemas =
126
193
  schemas ??
127
194
  ({
@@ -132,19 +199,25 @@ export class Task<S extends Schemas = Schemas> {
132
199
  this.internal = internal;
133
200
  this.snapshot = snapshot;
134
201
  this.status = status;
135
- this.frameClient_ = frameClient;
136
- this.ontologyClient_ = ontologyClient;
137
- this.rangeClient_ = rangeClient;
202
+ if (frameClient != null && ontologyClient != null && rangeClient != null)
203
+ this.clients = {
204
+ frame: frameClient,
205
+ ontology: ontologyClient,
206
+ range: rangeClient,
207
+ };
138
208
  }
139
209
 
140
210
  get payload(): Payload<S> {
141
211
  return {
142
212
  key: this.key,
213
+ rack: this.rack,
143
214
  name: this.name,
144
215
  type: this.type,
145
216
  config: this.config,
217
+ configHash: this.configHash,
146
218
  status: this.status,
147
219
  internal: this.internal,
220
+ snapshot: this.snapshot,
148
221
  };
149
222
  }
150
223
 
@@ -157,6 +230,7 @@ export class Task<S extends Schemas = Schemas> {
157
230
  ...params,
158
231
  frameClient: this.frameClient,
159
232
  task: this.key,
233
+ configHash: this.configHash,
160
234
  });
161
235
  }
162
236
 
@@ -167,6 +241,7 @@ export class Task<S extends Schemas = Schemas> {
167
241
  ...params,
168
242
  frameClient: this.frameClient,
169
243
  task: this.key,
244
+ configHash: this.configHash,
170
245
  name: this.name,
171
246
  statusDataZ: this.schemas.statusData,
172
247
  });
@@ -210,7 +285,7 @@ const retrieveReqZ = z.object({
210
285
  limit: z.int().optional(),
211
286
  });
212
287
 
213
- const singleRetrieveArgsZ = z.union([
288
+ const singleRetrieveParamsZ = z.union([
214
289
  z
215
290
  .object({ key: keyZ, includeStatus: z.boolean().optional() })
216
291
  .transform(({ key, includeStatus }) => ({ keys: [key], includeStatus })),
@@ -221,25 +296,84 @@ const singleRetrieveArgsZ = z.union([
221
296
  .object({ type: z.string(), rack: rackKeyZ.optional() })
222
297
  .transform(({ type, rack }) => ({ types: [type], rack })),
223
298
  ]);
224
- export type RetrieveSingleParams = z.input<typeof singleRetrieveArgsZ>;
225
-
226
- const multiRetrieveArgsZ = retrieveReqZ;
227
- export type RetrieveMultipleParams = z.input<typeof multiRetrieveArgsZ>;
299
+ /** Names one task: by key, by name, or by type and rack. */
300
+ export type RetrieveSingleParams = z.input<typeof singleRetrieveParamsZ>;
301
+
302
+ const multiRetrieveParamsZ = retrieveReqZ;
303
+ /** Everything a multi-task retrieval can filter on. */
304
+ export type RetrieveMultipleParams = z.input<typeof multiRetrieveParamsZ>;
305
+
306
+ const retrieveParamsZ = z.union([singleRetrieveParamsZ, multiRetrieveParamsZ]);
307
+ /** Params for a task retrieval, single or multiple. */
308
+ export type RetrieveParams = z.input<typeof retrieveParamsZ>;
309
+
310
+ type SingleRequest = Partial<
311
+ Pick<z.infer<typeof retrieveReqZ>, "keys" | "names" | "types" | "rack">
312
+ >;
313
+
314
+ // includeStatus does not change a query's identity: cached fetches always
315
+ // request it, so it is stripped before hashing.
316
+ const normalizeSingle = (params: RetrieveSingleParams): SingleRequest => {
317
+ const parsed = singleRetrieveParamsZ.parse(params);
318
+ if (!("includeStatus" in parsed)) return parsed;
319
+ const { includeStatus: _, ...rest } = parsed;
320
+ return rest;
321
+ };
228
322
 
229
- const retrieveArgsZ = z.union([singleRetrieveArgsZ, multiRetrieveArgsZ]);
230
- export type RetrieveArgs = z.input<typeof retrieveArgsZ>;
323
+ const singleQueryZ = z
324
+ .union([
325
+ z.strictObject({ key: keyZ, includeStatus: z.boolean().optional() }),
326
+ z.strictObject({ name: z.string(), includeStatus: z.boolean().optional() }),
327
+ z.strictObject({ type: z.string(), rack: rackKeyZ.optional() }),
328
+ keyZ.transform((key) => ({ key })),
329
+ ])
330
+ .transform(normalizeSingle);
331
+
332
+ // includeStatus does not change a request's identity either: cached fetches
333
+ // always request it, so the schema strips it before hashing.
334
+ const cacheRetrieveReqZ = retrieveReqZ.transform(
335
+ ({ includeStatus: _, ...rest }) => rest,
336
+ );
337
+ const retrieveMultiParamsZ = cacheRetrieveReqZ.or(query.keyListZ(keyZ));
338
+
339
+ /**
340
+ * Client-side matching for a request: key, name, type, rack, and flag
341
+ * filters. Server-computed shapes (search, pagination) never reach this
342
+ * filter; they refetch instead.
343
+ */
344
+ const requestFilter = (
345
+ req: RetrieveRequest,
346
+ ): ((t: Omit<Task, "status">) => boolean) => {
347
+ const keySet = primitive.isNonZero(req.keys) ? new Set(req.keys) : undefined;
348
+ const nameSet = primitive.isNonZero(req.names) ? new Set(req.names) : undefined;
349
+ const typeSet = primitive.isNonZero(req.types) ? new Set(req.types) : undefined;
350
+ return (t) => {
351
+ if (keySet != null && !keySet.has(t.key)) return false;
352
+ if (nameSet != null && !nameSet.has(t.name)) return false;
353
+ if (typeSet != null && !typeSet.has(t.type)) return false;
354
+ if (req.rack != null && t.rack !== req.rack) return false;
355
+ if (req.internal != null && t.internal !== req.internal) return false;
356
+ if (req.snapshot != null && t.snapshot !== req.snapshot) return false;
357
+ return true;
358
+ };
359
+ };
231
360
 
232
361
  interface RetrieveSchemas<S extends Schemas = Schemas> {
233
362
  schemas?: S;
234
363
  }
235
364
 
236
365
  const retrieveResZ = <S extends Schemas = Schemas>(schemas?: S) =>
237
- z.object({ tasks: array.nullishToEmpty(payloadZ(schemas)) });
366
+ z.object({
367
+ tasks: payloadZ(schemas)
368
+ .array()
369
+ .default(() => []),
370
+ });
238
371
 
372
+ /** A task retrieval on the wire. */
239
373
  export interface RetrieveRequest extends z.infer<typeof retrieveReqZ> {}
240
374
 
241
375
  const createReqZ = <S extends Schemas = Schemas>(schemas?: S) =>
242
- z.object({ tasks: newZ(schemas).array() });
376
+ z.object({ tasks: payloadZ(schemas).array() });
243
377
  const createResZ = <S extends Schemas = Schemas>(schemas?: S) =>
244
378
  z.object({ tasks: payloadZ(schemas).array() });
245
379
  const deleteReqZ = z.object({ keys: keyZ.array() });
@@ -248,22 +382,120 @@ const copyReqZ = z.object({ key: keyZ, name: z.string(), snapshot: z.boolean() }
248
382
  const copyResZ = <S extends Schemas = Schemas>(schemas?: S) =>
249
383
  z.object({ task: payloadZ(schemas) });
250
384
 
251
- export class Client {
252
- private readonly client: UnaryClient;
253
- private readonly frameClient: framer.Client;
254
- private readonly ontologyClient: ontology.Client;
255
- private readonly rangeClient: ranger.Client;
385
+ const matchesSingle = (t: Omit<Task, "status">, query: SingleRequest): boolean => {
386
+ if (primitive.isNonZero(query.keys)) return t.key === query.keys[0];
387
+ if (primitive.isNonZero(query.names)) return t.name === query.names[0];
388
+ if (primitive.isNonZero(query.types))
389
+ return t.type === query.types[0] && (query.rack == null || t.rack === query.rack);
390
+ return false;
391
+ };
256
392
 
257
- constructor(
258
- client: UnaryClient,
259
- frameClient: framer.Client,
260
- ontologyClient: ontology.Client,
261
- rangeClient: ranger.Client,
262
- ) {
263
- this.client = client;
264
- this.frameClient = frameClient;
265
- this.ontologyClient = ontologyClient;
266
- this.rangeClient = rangeClient;
393
+ /** Config for {@link Client}. */
394
+ export interface ClientConfig {
395
+ unary: UnaryClient;
396
+ framer: framer.Client;
397
+ ontology: ontology.Client;
398
+ ranges: ranger.Client;
399
+ cache: query.Cache;
400
+ statusStore: query.Table<status.Key, status.Status>;
401
+ }
402
+
403
+ /**
404
+ * Creates, reads, deletes, and commands tasks on a Core. Reach it through
405
+ * `client.hardware.tasks`. Reads are served from a cache a change stream keeps current.
406
+ */
407
+ export class Client extends query.Retriever<
408
+ typeof retrieveMultiParamsZ,
409
+ Key,
410
+ Omit<Task, "status">,
411
+ Task,
412
+ RetrieveSingleParams,
413
+ SingleRequest
414
+ > {
415
+ /** The task record table; injected into sibling clients at wiring. */
416
+ readonly store: query.Table<Key, Omit<Task, "status">>;
417
+ private readonly cfg: ClientConfig;
418
+ private readonly commandDeadlines = new Map<Key, ReturnType<typeof setTimeout>>();
419
+
420
+ constructor(cfg: ClientConfig) {
421
+ const { cache, statusStore } = cfg;
422
+ const store = cache.createTable<Key, Omit<Task, "status">>({
423
+ name: "tasks",
424
+ equal: (a, b) => deep.equal(a.payload, b.payload),
425
+ fetch: async (keys) => await this.fetchThrough({ keys }),
426
+ listen: [
427
+ {
428
+ bind: (table) => ({
429
+ channel: SET_CHANNEL_NAME,
430
+ schema: setSignalZ,
431
+ // The set signal omits config: a changed hash makes the cached one stale.
432
+ onChange: async (changed: SetSignal[]) => {
433
+ const stale: Key[] = [];
434
+ table.batch(() =>
435
+ changed.forEach((sig) => {
436
+ const cached = table.get(sig.key);
437
+ if (cached == null || cached.configHash !== sig.configHash) {
438
+ stale.push(sig.key);
439
+ return;
440
+ }
441
+ table.set(sig.key, (prev) =>
442
+ prev == null ? undefined : this.sugar({ ...prev.payload, ...sig }),
443
+ );
444
+ }),
445
+ );
446
+ if (stale.length > 0) await table.retrieve(stale, { refresh: true });
447
+ },
448
+ }),
449
+ },
450
+ query.createDeleteListener(DELETE_CHANNEL_NAME, keyZ),
451
+ ],
452
+ });
453
+ cache.listen({
454
+ channel: COMMAND_CHANNEL_NAME,
455
+ schema: commandZ,
456
+ onChange: (commands) =>
457
+ statusStore.batch(() =>
458
+ commands.forEach((changed) => {
459
+ if (!LOADING_COMMANDS.includes(changed.type)) return;
460
+ const key = statusKey(changed.task);
461
+ if (statusStore.get(key) == null) return;
462
+ const optimistic = this.optimisticStatus(changed);
463
+ statusStore.set(key, optimistic);
464
+ if (optimistic.variant === "loading")
465
+ this.armCommandDeadline(changed, optimistic);
466
+ }),
467
+ ),
468
+ });
469
+ const composed = cache.derive<Key, Omit<Task, "status">, Task>({
470
+ name: "task.composed",
471
+ source: store,
472
+ compose: (record) => this.compose(record),
473
+ equal: (a, b) => deep.equal(a.payload, b.payload),
474
+ watch: [query.deriveWatch(statusStore, (event) => affectedTaskKeys(event))],
475
+ });
476
+ const single = cache.queries<SingleRequest, Task, Key, Task>({
477
+ name: "task",
478
+ table: composed,
479
+ fetch: async (q) => [(await this.fetchSingle(q)).key],
480
+ compose: (records) => records[0],
481
+ keyOf: (q) => (primitive.isNonZero(q.keys) ? q.keys[0] : null),
482
+ matches: matchesSingle,
483
+ single: true,
484
+ });
485
+ super(cache, {
486
+ name: "task",
487
+ table: store,
488
+ request: {
489
+ schema: retrieveMultiParamsZ,
490
+ fetch: async (req) => await this.fetchThrough(req),
491
+ matches: (t, req) => requestFilter(req)(t),
492
+ watch: [query.watch(statusStore, (event) => affectedTaskKeys(event))],
493
+ },
494
+ compose: (record) => this.compose(record),
495
+ single: { schema: singleQueryZ, space: single },
496
+ });
497
+ this.cfg = cfg;
498
+ this.store = store;
267
499
  }
268
500
 
269
501
  async create(task: New): Promise<Task>;
@@ -279,59 +511,108 @@ export class Client {
279
511
  const isSingle = !Array.isArray(task);
280
512
  const createReq = createReqZ(schemas);
281
513
  const createRes = createResZ(schemas);
282
- const res = await this.client.send(
514
+ const res = await this.cfg.unary.send(
283
515
  "/task/create",
284
516
  { tasks: array.toArray(task) },
285
517
  createReq,
286
518
  createRes,
287
519
  );
288
520
  const sugared = this.sugar<S>(res.tasks as Payload<S>[], schemas);
521
+ sugared.forEach((t) => this.writeThrough(t));
289
522
  return isSingle ? sugared[0] : sugared;
290
523
  }
291
524
 
292
- async delete(keys: Key | Key[]): Promise<void> {
293
- await this.client.send(
294
- "/task/delete",
295
- { keys: array.toArray(keys) },
296
- deleteReqZ,
297
- deleteResZ,
298
- );
525
+ /**
526
+ * Forgets the tasks locally without deleting them on the cluster, for callers
527
+ * whose own endpoint already deleted them. Keeps a later retrieve from serving
528
+ * a deleted task while the delete signal is still in flight.
529
+ */
530
+ dropCached(keys: Key | Key[]): void {
531
+ this.dropLocal(array.toArray(keys));
532
+ }
533
+
534
+ private dropLocal(keys: Key[]): destructor.Destructor[] {
535
+ return [
536
+ this.cfg.ontology.cache.deleteResources(ontologyID(keys)),
537
+ this.store.delete(keys),
538
+ this.cfg.statusStore.delete(keys.map((k) => statusKey(k))),
539
+ ];
540
+ }
541
+
542
+ async delete(keys: Key | Key[], opts: query.WriteOptions = {}): Promise<void> {
543
+ const keysArr = array.toArray(keys);
544
+ const drop = () => this.dropLocal(keysArr);
545
+ await query.optimistic({
546
+ rollbacks: drop(),
547
+ onOptimistic: opts.onOptimistic,
548
+ commit: async () =>
549
+ await this.cfg.unary.send(
550
+ "/task/delete",
551
+ { keys: keysArr },
552
+ deleteReqZ,
553
+ deleteResZ,
554
+ ),
555
+ });
556
+ drop();
557
+ }
558
+
559
+ async rename(key: Key, name: string, opts: query.WriteOptions = {}): Promise<void> {
560
+ const rename = () => [
561
+ this.store.set(key, (p) =>
562
+ p == null ? undefined : this.sugar({ ...p.payload, name }),
563
+ ),
564
+ this.cfg.ontology.cache.renameResource(ontologyID(key), name),
565
+ ];
566
+ await query.optimistic({
567
+ rollbacks: rename(),
568
+ onOptimistic: opts.onOptimistic,
569
+ commit: async () => {
570
+ const t = await this.retrieve(key);
571
+ await this.create({ ...t.payload, name });
572
+ },
573
+ });
574
+ rename();
299
575
  }
300
576
 
301
577
  async retrieve<S extends Schemas = Schemas>(
302
- args: RetrieveSingleParams & RetrieveSchemas<S>,
578
+ params: RetrieveSingleParams & RetrieveSchemas<S>,
303
579
  ): Promise<Task<S>>;
304
- async retrieve(args: RetrieveSingleParams): Promise<Task>;
580
+ async retrieve(params: Key | RetrieveSingleParams): Promise<Task>;
305
581
  async retrieve<S extends Schemas = Schemas>(
306
- args: RetrieveMultipleParams & RetrieveSchemas<S>,
582
+ params: RetrieveMultipleParams & RetrieveSchemas<S>,
307
583
  ): Promise<Task<S>[]>;
308
- async retrieve(args: RetrieveMultipleParams): Promise<Task[]>;
309
- async retrieve<S extends Schemas = Schemas>({
310
- schemas,
311
- ...args
312
- }: RetrieveArgs & RetrieveSchemas<S>): Promise<Task<S> | Task<S>[]> {
313
- const isSingle = singleRetrieveArgsZ.safeParse(args).success;
314
- const res = await this.client.send(
315
- "/task/retrieve",
316
- args,
317
- retrieveArgsZ,
318
- retrieveResZ(schemas),
319
- );
320
- const tasks = res.tasks as Payload<S>[];
321
- const sugared = this.sugar(tasks, schemas);
322
- checkForMultipleOrNoResults("Task", args, sugared, isSingle);
323
- return isSingle ? sugared[0] : sugared;
584
+ async retrieve(params: RetrieveMultipleParams): Promise<Task[]>;
585
+ async retrieve<S extends Schemas = Schemas>(
586
+ rawParams: Key | (RetrieveParams & RetrieveSchemas<S>),
587
+ ): Promise<Task<S> | Task<S>[]> {
588
+ const { schemas, ...params } =
589
+ typeof rawParams === "string" ? { key: rawParams } : rawParams;
590
+ const isSingle = singleRetrieveParamsZ.safeParse(params).success;
591
+ // Schema-parametrized retrieves validate config/status for one caller;
592
+ // their results are not shared through the cache.
593
+ if (schemas != null) {
594
+ const sugared = await this.execRetrieve<S>(params, schemas);
595
+ checkForMultipleOrNoResults("Task", params, sugared, isSingle);
596
+ return isSingle ? sugared[0] : sugared;
597
+ }
598
+ if (isSingle)
599
+ return (await super.retrieve(params as RetrieveSingleParams)) as Task<S>;
600
+ return (await super.retrieve(
601
+ params as RetrieveMultipleParams,
602
+ )) as unknown as Task<S>[];
324
603
  }
325
604
 
326
605
  async copy(key: Key, name: string, snapshot: boolean): Promise<Task> {
327
606
  const copyRes = copyResZ();
328
- const response = await this.client.send(
607
+ const response = await this.cfg.unary.send(
329
608
  "/task/copy",
330
609
  { key, name, snapshot },
331
610
  copyReqZ,
332
611
  copyRes,
333
612
  );
334
- return this.sugar(response.task);
613
+ const sugared = this.sugar(response.task);
614
+ this.writeThrough(sugared);
615
+ return sugared;
335
616
  }
336
617
 
337
618
  async list(rack?: number): Promise<Task[]> {
@@ -341,8 +622,147 @@ export class Client {
341
622
  }
342
623
 
343
624
  async retrieveSnapshottedTo(taskKey: Key): Promise<ontology.Resource | null> {
344
- if (this.ontologyClient == null) throw new Error("Task not created");
345
- return await retrieveSnapshottedTo(taskKey, this.ontologyClient);
625
+ if (this.cfg.ontology == null) throw new Error("Task not created");
626
+ return await retrieveSnapshottedTo(taskKey, this.cfg.ontology);
627
+ }
628
+
629
+ private async execRetrieve<S extends Schemas = Schemas>(
630
+ params: RetrieveParams,
631
+ schemas?: S,
632
+ ): Promise<Task<S>[]> {
633
+ const res = await this.cfg.unary.send(
634
+ "/task/retrieve",
635
+ params,
636
+ retrieveParamsZ,
637
+ retrieveResZ(schemas),
638
+ );
639
+ return this.sugar(res.tasks as Payload<S>[], schemas);
640
+ }
641
+
642
+ /** Rebuilds a cached task with its cached status attached. */
643
+ private compose(cached: Omit<Task, "status">): Task {
644
+ const st = this.latestStatusOf(cached.key);
645
+ const payload = cached.payload;
646
+ if (st == null) return this.sugar(payload);
647
+ return this.sugar({ ...payload, status: st });
648
+ }
649
+
650
+ // Every domain's statuses share one store, so a rack's status sits beside its
651
+ // tasks' under the rack's ontology ID.
652
+ private downRackStatus(rack: RackKey | undefined): status.Status | undefined {
653
+ if (rack == null || primitive.isZero(rack)) return undefined;
654
+ const stat = this.cfg.statusStore.get(ontology.idToString(rackOntologyID(rack)));
655
+ if (stat == null || HEALTHY_RACK_VARIANTS.includes(stat.variant)) return undefined;
656
+ return stat;
657
+ }
658
+
659
+ /**
660
+ * Builds the status shown while a command is in flight. A rack whose Driver is down
661
+ * answers nothing, so its warning stands in for a wait that would never end.
662
+ */
663
+ private optimisticStatus(cmd: Command): Status {
664
+ // Carry the last known deploy info forward: zeroing it would make this
665
+ // optimistic status claim the task deployed with an empty config/rack.
666
+ const latest = this.latestStatusOf(cmd.task);
667
+ const key = statusKey(cmd.task);
668
+ const details = {
669
+ task: cmd.task,
670
+ cmd: "",
671
+ configHash: latest?.details.configHash ?? "",
672
+ rack: latest?.details.rack ?? 0,
673
+ data: {},
674
+ };
675
+ const down = this.downRackStatus(this.store.get(cmd.task)?.rack);
676
+ if (down == null)
677
+ return status.create<StatusDetailsZodObject>({
678
+ key,
679
+ name: STATUS_NAME,
680
+ variant: "loading",
681
+ message: `Running ${cmd.type} command...`,
682
+ details: { ...details, running: true },
683
+ });
684
+ return status.create<StatusDetailsZodObject>({
685
+ key,
686
+ name: STATUS_NAME,
687
+ variant: "warning",
688
+ message: down.message,
689
+ description: down.description,
690
+ details: { ...details, running: false },
691
+ });
692
+ }
693
+
694
+ // Nothing else retires the loading status: a task on a silent rack waits on the
695
+ // Core's next dead-rack alert, which dampens to once a minute.
696
+ private armCommandDeadline(cmd: Command, optimistic: Status): void {
697
+ const { statusStore } = this.cfg;
698
+ const key = statusKey(cmd.task);
699
+ clearTimeout(this.commandDeadlines.get(cmd.task));
700
+ this.commandDeadlines.set(
701
+ cmd.task,
702
+ setTimeout(() => {
703
+ this.commandDeadlines.delete(cmd.task);
704
+ // Any later write replaced the exact object this deadline was armed for.
705
+ if (statusStore.get(key) !== optimistic) return;
706
+ statusStore.set(
707
+ key,
708
+ status.create<StatusDetailsZodObject>({
709
+ key,
710
+ name: STATUS_NAME,
711
+ variant: "warning",
712
+ message: `No response to the ${cmd.type} command`,
713
+ description: `The Driver did not respond within ${COMMAND_DEADLINE.toString()}.`,
714
+ // Nothing answered, so the command is taken to have had no effect.
715
+ details: { ...optimistic.details, running: cmd.type === "stop" },
716
+ }),
717
+ );
718
+ }, COMMAND_DEADLINE.milliseconds),
719
+ );
720
+ }
721
+
722
+ // A task's status may live under the "task:<key>" row or under any status
723
+ // whose details reference the task; the freshest wins. Rows are parsed
724
+ // because the status table holds every domain's statuses generically.
725
+ private latestStatusOf(key: Key): Status | undefined {
726
+ const taskKey = statusKey(key);
727
+ const candidates = this.cfg.statusStore
728
+ .get((s) => s.key === taskKey || status.detailsOf(s)?.task === key)
729
+ .map((s) => statusZ().safeParse(s))
730
+ .filter((p) => p.success)
731
+ .map((p) => p.data);
732
+ if (candidates.length === 0) return undefined;
733
+ return candidates.reduce((latest, s) =>
734
+ new TimeStamp(s.time).afterEq(new TimeStamp(latest.time)) ? s : latest,
735
+ );
736
+ }
737
+
738
+ /** Writes a fetched task and its included status. */
739
+ private writeThrough(task: Task): void {
740
+ this.store.set(task);
741
+ if (task.status != null) this.cfg.statusStore.set(task.status);
742
+ }
743
+
744
+ /** Fetches tasks with statuses and writes the statuses through. */
745
+ private async fetchThrough(req: RetrieveRequest): Promise<Task[]> {
746
+ const tasks = await this.execRetrieve({ ...req, includeStatus: true });
747
+ tasks.forEach((t) => {
748
+ if (t.status != null) this.cfg.statusStore.set(t.status);
749
+ });
750
+ return tasks;
751
+ }
752
+
753
+ private async fetchSingle(q: SingleRequest): Promise<Task> {
754
+ let cached: Omit<Task, "status"> | undefined;
755
+ if (primitive.isNonZero(q.keys)) cached = this.store.get(q.keys[0]);
756
+ else if (primitive.isNonZero(q.names))
757
+ [cached] = this.store.get((t) => t.name === q.names?.[0]);
758
+ // A cached task without a cached status is ambiguous: the task may have
759
+ // no status or the status may not have synced. Only both count as a hit.
760
+ if (cached != null && this.cfg.statusStore.has(statusKey(cached.key)))
761
+ return this.compose(cached);
762
+ const tasks = await this.execRetrieve({ ...q, includeStatus: true });
763
+ checkForMultipleOrNoResults("Task", q, tasks, true);
764
+ this.writeThrough(tasks[0]);
765
+ return tasks[0];
346
766
  }
347
767
 
348
768
  sugar<S extends Schemas = Schemas>(payloads: Payload<S>[], schemas?: S): Task<S>[];
@@ -355,26 +775,37 @@ export class Client {
355
775
  ): Task<S>[] | Task<S> {
356
776
  const isSingle = !Array.isArray(payloads);
357
777
  const res = array.toArray(payloads).map(
358
- ({ key, name, type, config, status, internal, snapshot }) =>
778
+ ({ key, rack, name, type, config, configHash, status, internal, snapshot }) =>
359
779
  new Task(
360
780
  {
361
781
  key,
782
+ rack,
362
783
  name,
363
784
  type,
364
785
  config,
786
+ configHash,
365
787
  internal,
366
788
  snapshot,
367
789
  status,
368
790
  },
369
791
  schemas,
370
- this.frameClient,
371
- this.ontologyClient,
372
- this.rangeClient,
792
+ this.cfg.framer,
793
+ this.cfg.ontology,
794
+ this.cfg.ranges,
373
795
  ),
374
796
  );
375
797
  return isSingle ? res[0] : res;
376
798
  }
377
799
 
800
+ /**
801
+ * Fills a command's config hash from the cached task row. A command that carries
802
+ * the hash lets the Driver reuse its live instance instead of redeploying.
803
+ */
804
+ private stampConfigHash(cmd: NewCommand): NewCommand {
805
+ if (cmd.configHash != null) return cmd;
806
+ return { ...cmd, configHash: this.store.get(cmd.task)?.configHash };
807
+ }
808
+
378
809
  async executeCommand(params: ExecuteCommandParams): Promise<string>;
379
810
 
380
811
  async executeCommand(params: ExecuteCommandsParams): Promise<string[]>;
@@ -383,8 +814,14 @@ export class Client {
383
814
  params: ExecuteCommandParams | ExecuteCommandsParams,
384
815
  ): Promise<string | string[]> {
385
816
  if ("commands" in params)
386
- return await executeCommands({ ...params, frameClient: this.frameClient });
387
- return await executeCommand({ ...params, frameClient: this.frameClient });
817
+ return await executeCommands({
818
+ commands: params.commands.map((c) => this.stampConfigHash(c)),
819
+ frameClient: this.cfg.framer,
820
+ });
821
+ return await executeCommand({
822
+ ...this.stampConfigHash(params),
823
+ frameClient: this.cfg.framer,
824
+ });
388
825
  }
389
826
 
390
827
  async executeCommandSync<StatusData extends z.ZodType = z.ZodNever>(
@@ -397,8 +834,7 @@ export class Client {
397
834
 
398
835
  async executeCommandSync<StatusData extends z.ZodType = z.ZodNever>(
399
836
  params:
400
- | ExecuteCommandsSyncParams<StatusData>
401
- | ExecuteCommandSyncParams<StatusData>,
837
+ ExecuteCommandsSyncParams<StatusData> | ExecuteCommandSyncParams<StatusData>,
402
838
  ): Promise<Status<StatusData> | Status<StatusData>[]> {
403
839
  if ("commands" in params) {
404
840
  const retrieveNames = async () => {
@@ -408,30 +844,52 @@ export class Client {
408
844
  };
409
845
  return await executeCommandsSync({
410
846
  ...params,
411
- frameClient: this.frameClient,
847
+ commands: params.commands.map((c) => this.stampConfigHash(c)),
848
+ frameClient: this.cfg.framer,
412
849
  name: retrieveNames,
413
850
  });
414
851
  }
415
852
  const retrieveName = async () => {
416
853
  const { task } = params;
417
- const t = await this.retrieve({ key: task });
854
+ const t = await this.retrieve(task);
418
855
  return t.name;
419
856
  };
420
857
  return await executeCommandSync({
421
- frameClient: this.frameClient,
858
+ frameClient: this.cfg.framer,
422
859
  name: retrieveName,
423
860
  ...params,
861
+ configHash: params.configHash ?? this.store.get(params.task)?.configHash,
424
862
  });
425
863
  }
426
864
  }
427
865
 
866
+ /** @returns the key of the status that reports on the given task. */
428
867
  export const statusKey = (key: Key): string => ontology.idToString(ontologyID(key));
429
868
 
869
+ const taskStatusZ = z.object({ details: z.object({ task: keyZ }) });
870
+
871
+ // Task statuses may arrive under any status key; the referenced task lives in
872
+ // the details, with the "task:<key>" status key as a fallback.
873
+ const affectedTaskKeys = (
874
+ event: query.TableEvent<status.Key, status.Status>,
875
+ ): Key[] | null => {
876
+ const keys: Key[] = [];
877
+ if (event.variant === "set") {
878
+ const parsed = taskStatusZ.safeParse(event.value);
879
+ if (parsed.success) keys.push(parsed.data.details.task);
880
+ }
881
+ const [type, key] = event.key.split(":");
882
+ if (type === "task" && primitive.isNonZero(key) && !keys.includes(key))
883
+ keys.push(key);
884
+ return keys.length === 0 ? null : keys;
885
+ };
886
+
430
887
  interface ExecuteCommandInternalParams {
431
888
  frameClient: framer.Client | null;
432
889
  task: Key;
433
890
  type: string;
434
891
  args?: {};
892
+ configHash?: string;
435
893
  }
436
894
 
437
895
  const executeCommand = async ({
@@ -439,13 +897,25 @@ const executeCommand = async ({
439
897
  task,
440
898
  type,
441
899
  args,
900
+ configHash,
442
901
  }: ExecuteCommandInternalParams): Promise<string> =>
443
- (await executeCommands({ frameClient, commands: [{ args, task, type }] }))[0];
902
+ (
903
+ await executeCommands({
904
+ frameClient,
905
+ commands: [{ args, task, type, configHash }],
906
+ })
907
+ )[0];
444
908
 
909
+ /** A command queued for a task. */
445
910
  export interface NewCommand {
446
911
  task: Key;
447
912
  type: string;
448
913
  args?: {};
914
+ /**
915
+ * The config hash the sender wants running. Left unset, the client fills it from
916
+ * its cached task row.
917
+ */
918
+ configHash?: string;
449
919
  }
450
920
 
451
921
  interface ExecuteCommandsInternalParams {
@@ -459,7 +929,11 @@ const executeCommands = async ({
459
929
  }: ExecuteCommandsInternalParams): Promise<string[]> => {
460
930
  if (frameClient == null) throw new Error("Task not created");
461
931
  const w = await frameClient.openWriter(COMMAND_CHANNEL_NAME);
462
- const cmds = commands.map((c) => ({ ...c, key: id.create() }));
932
+ const cmds = commands.map((c) => ({
933
+ ...c,
934
+ configHash: c.configHash ?? "",
935
+ key: id.create(),
936
+ }));
463
937
  await w.write(COMMAND_CHANNEL_NAME, cmds);
464
938
  await w.close();
465
939
  return cmds.map((c) => c.key);
@@ -470,6 +944,7 @@ interface ExecuteCommandSyncInternalParams<StatusData extends z.ZodType = z.ZodN
470
944
  Omit<ExecuteCommandsSyncInternalParams<StatusData>, "commands">,
471
945
  TaskExecuteCommandSyncParams {
472
946
  task: Key;
947
+ configHash?: string;
473
948
  }
474
949
 
475
950
  const executeCommandSync = async <StatusData extends z.ZodType = z.ZodNever>({
@@ -480,11 +955,12 @@ const executeCommandSync = async <StatusData extends z.ZodType = z.ZodNever>({
480
955
  name: taskName,
481
956
  statusDataZ,
482
957
  args,
958
+ configHash,
483
959
  }: ExecuteCommandSyncInternalParams<StatusData>): Promise<Status<StatusData>> =>
484
960
  (
485
961
  await executeCommandsSync({
486
962
  frameClient,
487
- commands: [{ args, task, type }],
963
+ commands: [{ args, task, type, configHash }],
488
964
  timeout,
489
965
  statusDataZ,
490
966
  name: taskName,
@@ -502,7 +978,7 @@ interface ExecuteCommandsSyncInternalParams<StatusData extends z.ZodType = z.Zod
502
978
  const executeCommandsSync = async <StatusData extends z.ZodType = z.ZodNever>({
503
979
  frameClient,
504
980
  commands,
505
- timeout = TimeSpan.seconds(10),
981
+ timeout = COMMAND_DEADLINE,
506
982
  statusDataZ,
507
983
  name: taskName,
508
984
  }: ExecuteCommandsSyncInternalParams<StatusData>): Promise<Status<StatusData>[]> => {
@@ -514,23 +990,26 @@ const executeCommandsSync = async <StatusData extends z.ZodType = z.ZodNever>({
514
990
  let timeoutID: NodeJS.Timeout | undefined;
515
991
  const timeoutPromise = new Promise<never>((_, reject) => {
516
992
  timeoutID = setTimeout(() => {
517
- void (async () => {
518
- const taskKeys = commands.map((c) => c.task);
519
- reject(await formatTimeoutError("command", taskName, parsedTimeout, taskKeys));
520
- })();
993
+ const taskKeys = commands.map((c) => c.task);
994
+ formatTimeoutError("command", taskName, parsedTimeout, taskKeys).then(
995
+ reject,
996
+ reject,
997
+ );
521
998
  }, parsedTimeout.milliseconds);
522
999
  });
523
1000
  try {
524
1001
  while (true) {
525
1002
  const frame = await Promise.race([streamer.read(), timeoutPromise]);
526
- const parseResult = statusZ(statusDataZ).safeParse(
527
- frame.at(-1)[status.SET_CHANNEL_NAME],
528
- );
529
- if (!parseResult.success) continue;
530
- const state = parseResult.data;
531
- if (state.details.cmd == null || !cmdKeys.includes(state.details.cmd)) continue;
532
- states = [...states.filter((s) => s.key !== state.key), state];
533
- if (states.length === cmdKeys.length) return states;
1003
+ // A frame can hold statuses for other tasks and racks, which have a different
1004
+ // shape and fail to parse.
1005
+ for (const str of frame.get(status.SET_CHANNEL_NAME).toStrings()) {
1006
+ const res = statusZ(statusDataZ).safeParse(binary.JSON_CODEC.decodeString(str));
1007
+ if (!res.success) continue;
1008
+ const state = res.data;
1009
+ if (state.details.cmd == null || !cmdKeys.includes(state.details.cmd)) continue;
1010
+ states = [...states.filter((s) => s.key !== state.key), state];
1011
+ if (states.length === cmdKeys.length) return states;
1012
+ }
534
1013
  }
535
1014
  } finally {
536
1015
  clearTimeout(timeoutID);