@elaraai/e3-rack 0.0.0-bootstrap.0 → 1.0.94

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 (306) hide show
  1. package/README.md +407 -2
  2. package/dist/src/client/client.spec.d.ts +6 -0
  3. package/dist/src/client/client.spec.d.ts.map +1 -0
  4. package/dist/src/client/client.spec.js +150 -0
  5. package/dist/src/client/client.spec.js.map +1 -0
  6. package/dist/src/client/connect.d.ts +52 -0
  7. package/dist/src/client/connect.d.ts.map +1 -0
  8. package/dist/src/client/connect.js +112 -0
  9. package/dist/src/client/connect.js.map +1 -0
  10. package/dist/src/client/hub-client.d.ts +57 -0
  11. package/dist/src/client/hub-client.d.ts.map +1 -0
  12. package/dist/src/client/hub-client.js +87 -0
  13. package/dist/src/client/hub-client.js.map +1 -0
  14. package/dist/src/client/local-http.d.ts +78 -0
  15. package/dist/src/client/local-http.d.ts.map +1 -0
  16. package/dist/src/client/local-http.js +149 -0
  17. package/dist/src/client/local-http.js.map +1 -0
  18. package/dist/src/client/session-attempts.d.ts +20 -0
  19. package/dist/src/client/session-attempts.d.ts.map +1 -0
  20. package/dist/src/client/session-attempts.js +88 -0
  21. package/dist/src/client/session-attempts.js.map +1 -0
  22. package/dist/src/client/session-data-server.d.ts +37 -0
  23. package/dist/src/client/session-data-server.d.ts.map +1 -0
  24. package/dist/src/client/session-data-server.js +280 -0
  25. package/dist/src/client/session-data-server.js.map +1 -0
  26. package/dist/src/client/session-data-server.spec.d.ts +6 -0
  27. package/dist/src/client/session-data-server.spec.d.ts.map +1 -0
  28. package/dist/src/client/session-data-server.spec.js +192 -0
  29. package/dist/src/client/session-data-server.spec.js.map +1 -0
  30. package/dist/src/client/session.d.ts +119 -0
  31. package/dist/src/client/session.d.ts.map +1 -0
  32. package/dist/src/client/session.js +290 -0
  33. package/dist/src/client/session.js.map +1 -0
  34. package/dist/src/hub/config.d.ts +74 -0
  35. package/dist/src/hub/config.d.ts.map +1 -0
  36. package/dist/src/hub/config.js +159 -0
  37. package/dist/src/hub/config.js.map +1 -0
  38. package/dist/src/hub/fair-lease-store.d.ts +36 -0
  39. package/dist/src/hub/fair-lease-store.d.ts.map +1 -0
  40. package/dist/src/hub/fair-lease-store.js +73 -0
  41. package/dist/src/hub/fair-lease-store.js.map +1 -0
  42. package/dist/src/hub/hub.d.ts +91 -0
  43. package/dist/src/hub/hub.d.ts.map +1 -0
  44. package/dist/src/hub/hub.js +641 -0
  45. package/dist/src/hub/hub.js.map +1 -0
  46. package/dist/src/hub/hub.spec.d.ts +6 -0
  47. package/dist/src/hub/hub.spec.d.ts.map +1 -0
  48. package/dist/src/hub/hub.spec.js +363 -0
  49. package/dist/src/hub/hub.spec.js.map +1 -0
  50. package/dist/src/hub/infrastructure.spec.d.ts +6 -0
  51. package/dist/src/hub/infrastructure.spec.d.ts.map +1 -0
  52. package/dist/src/hub/infrastructure.spec.js +211 -0
  53. package/dist/src/hub/infrastructure.spec.js.map +1 -0
  54. package/dist/src/hub/lock.d.ts +62 -0
  55. package/dist/src/hub/lock.d.ts.map +1 -0
  56. package/dist/src/hub/lock.js +165 -0
  57. package/dist/src/hub/lock.js.map +1 -0
  58. package/dist/src/hub/main.d.ts +16 -0
  59. package/dist/src/hub/main.d.ts.map +1 -0
  60. package/dist/src/hub/main.js +56 -0
  61. package/dist/src/hub/main.js.map +1 -0
  62. package/dist/src/hub/session-bridge.d.ts +116 -0
  63. package/dist/src/hub/session-bridge.d.ts.map +1 -0
  64. package/dist/src/hub/session-bridge.js +336 -0
  65. package/dist/src/hub/session-bridge.js.map +1 -0
  66. package/dist/src/identity/file-identity-store.d.ts +18 -0
  67. package/dist/src/identity/file-identity-store.d.ts.map +1 -0
  68. package/dist/src/identity/file-identity-store.js +34 -0
  69. package/dist/src/identity/file-identity-store.js.map +1 -0
  70. package/dist/src/identity/file-identity-store.spec.d.ts +6 -0
  71. package/dist/src/identity/file-identity-store.spec.d.ts.map +1 -0
  72. package/dist/src/identity/file-identity-store.spec.js +59 -0
  73. package/dist/src/identity/file-identity-store.spec.js.map +1 -0
  74. package/dist/src/identity/in-memory-identity-store.d.ts +48 -0
  75. package/dist/src/identity/in-memory-identity-store.d.ts.map +1 -0
  76. package/dist/src/identity/in-memory-identity-store.js +102 -0
  77. package/dist/src/identity/in-memory-identity-store.js.map +1 -0
  78. package/dist/src/identity/machine-identity.d.ts +134 -0
  79. package/dist/src/identity/machine-identity.d.ts.map +1 -0
  80. package/dist/src/identity/machine-identity.js +65 -0
  81. package/dist/src/identity/machine-identity.js.map +1 -0
  82. package/dist/src/index.d.ts +34 -0
  83. package/dist/src/index.d.ts.map +1 -0
  84. package/dist/src/index.js +34 -0
  85. package/dist/src/index.js.map +1 -0
  86. package/dist/src/lease/closure.d.ts +96 -0
  87. package/dist/src/lease/closure.d.ts.map +1 -0
  88. package/dist/src/lease/closure.js +192 -0
  89. package/dist/src/lease/closure.js.map +1 -0
  90. package/dist/src/lease/closure.spec.d.ts +6 -0
  91. package/dist/src/lease/closure.spec.d.ts.map +1 -0
  92. package/dist/src/lease/closure.spec.js +35 -0
  93. package/dist/src/lease/closure.spec.js.map +1 -0
  94. package/dist/src/lease/coordinator.d.ts +34 -0
  95. package/dist/src/lease/coordinator.d.ts.map +1 -0
  96. package/dist/src/lease/coordinator.js +42 -0
  97. package/dist/src/lease/coordinator.js.map +1 -0
  98. package/dist/src/lease/in-memory-lease-store.d.ts +58 -0
  99. package/dist/src/lease/in-memory-lease-store.d.ts.map +1 -0
  100. package/dist/src/lease/in-memory-lease-store.js +132 -0
  101. package/dist/src/lease/in-memory-lease-store.js.map +1 -0
  102. package/dist/src/lease/lease-store.d.ts +169 -0
  103. package/dist/src/lease/lease-store.d.ts.map +1 -0
  104. package/dist/src/lease/lease-store.js +94 -0
  105. package/dist/src/lease/lease-store.js.map +1 -0
  106. package/dist/src/lease/lease-store.spec.d.ts +6 -0
  107. package/dist/src/lease/lease-store.spec.d.ts.map +1 -0
  108. package/dist/src/lease/lease-store.spec.js +8 -0
  109. package/dist/src/lease/lease-store.spec.js.map +1 -0
  110. package/dist/src/lease/rack-dispatch.d.ts +105 -0
  111. package/dist/src/lease/rack-dispatch.d.ts.map +1 -0
  112. package/dist/src/lease/rack-dispatch.js +6 -0
  113. package/dist/src/lease/rack-dispatch.js.map +1 -0
  114. package/dist/src/mutation-queue.d.ts +13 -0
  115. package/dist/src/mutation-queue.d.ts.map +1 -0
  116. package/dist/src/mutation-queue.js +17 -0
  117. package/dist/src/mutation-queue.js.map +1 -0
  118. package/dist/src/paths.d.ts +56 -0
  119. package/dist/src/paths.d.ts.map +1 -0
  120. package/dist/src/paths.js +82 -0
  121. package/dist/src/paths.js.map +1 -0
  122. package/dist/src/protocol/control.d.ts +295 -0
  123. package/dist/src/protocol/control.d.ts.map +1 -0
  124. package/dist/src/protocol/control.js +74 -0
  125. package/dist/src/protocol/control.js.map +1 -0
  126. package/dist/src/protocol/index.d.ts +9 -0
  127. package/dist/src/protocol/index.d.ts.map +1 -0
  128. package/dist/src/protocol/index.js +9 -0
  129. package/dist/src/protocol/index.js.map +1 -0
  130. package/dist/src/protocol/rack-wire.d.ts +357 -0
  131. package/dist/src/protocol/rack-wire.d.ts.map +1 -0
  132. package/dist/src/protocol/rack-wire.js +262 -0
  133. package/dist/src/protocol/rack-wire.js.map +1 -0
  134. package/dist/src/protocol/rack-wire.spec.d.ts +6 -0
  135. package/dist/src/protocol/rack-wire.spec.d.ts.map +1 -0
  136. package/dist/src/protocol/rack-wire.spec.js +14 -0
  137. package/dist/src/protocol/rack-wire.spec.js.map +1 -0
  138. package/dist/src/protocol/registration.d.ts +70 -0
  139. package/dist/src/protocol/registration.d.ts.map +1 -0
  140. package/dist/src/protocol/registration.js +67 -0
  141. package/dist/src/protocol/registration.js.map +1 -0
  142. package/dist/src/protocol/session-data.d.ts +69 -0
  143. package/dist/src/protocol/session-data.d.ts.map +1 -0
  144. package/dist/src/protocol/session-data.js +26 -0
  145. package/dist/src/protocol/session-data.js.map +1 -0
  146. package/dist/src/protocol/task-envelope.d.ts +198 -0
  147. package/dist/src/protocol/task-envelope.d.ts.map +1 -0
  148. package/dist/src/protocol/task-envelope.js +93 -0
  149. package/dist/src/protocol/task-envelope.js.map +1 -0
  150. package/dist/src/protocol/wire-golden.d.ts +8 -0
  151. package/dist/src/protocol/wire-golden.d.ts.map +1 -0
  152. package/dist/src/protocol/wire-golden.js +34 -0
  153. package/dist/src/protocol/wire-golden.js.map +1 -0
  154. package/dist/src/protocol/wire-samples.d.ts +11 -0
  155. package/dist/src/protocol/wire-samples.d.ts.map +1 -0
  156. package/dist/src/protocol/wire-samples.js +52 -0
  157. package/dist/src/protocol/wire-samples.js.map +1 -0
  158. package/dist/src/registry/file-rack-registry.d.ts +68 -0
  159. package/dist/src/registry/file-rack-registry.d.ts.map +1 -0
  160. package/dist/src/registry/file-rack-registry.js +138 -0
  161. package/dist/src/registry/file-rack-registry.js.map +1 -0
  162. package/dist/src/registry/file-rack-registry.spec.d.ts +6 -0
  163. package/dist/src/registry/file-rack-registry.spec.d.ts.map +1 -0
  164. package/dist/src/registry/file-rack-registry.spec.js +50 -0
  165. package/dist/src/registry/file-rack-registry.spec.js.map +1 -0
  166. package/dist/src/registry/rack-registry.d.ts +64 -0
  167. package/dist/src/registry/rack-registry.d.ts.map +1 -0
  168. package/dist/src/registry/rack-registry.js +65 -0
  169. package/dist/src/registry/rack-registry.js.map +1 -0
  170. package/dist/src/registry/rack-registry.spec.d.ts +6 -0
  171. package/dist/src/registry/rack-registry.spec.d.ts.map +1 -0
  172. package/dist/src/registry/rack-registry.spec.js +8 -0
  173. package/dist/src/registry/rack-registry.spec.js.map +1 -0
  174. package/dist/src/routing/eligibility.d.ts +38 -0
  175. package/dist/src/routing/eligibility.d.ts.map +1 -0
  176. package/dist/src/routing/eligibility.js +78 -0
  177. package/dist/src/routing/eligibility.js.map +1 -0
  178. package/dist/src/routing/host-coupling.d.ts +26 -0
  179. package/dist/src/routing/host-coupling.d.ts.map +1 -0
  180. package/dist/src/routing/host-coupling.js +62 -0
  181. package/dist/src/routing/host-coupling.js.map +1 -0
  182. package/dist/src/routing/policy.d.ts +188 -0
  183. package/dist/src/routing/policy.d.ts.map +1 -0
  184. package/dist/src/routing/policy.js +212 -0
  185. package/dist/src/routing/policy.js.map +1 -0
  186. package/dist/src/routing/routing.spec.d.ts +6 -0
  187. package/dist/src/routing/routing.spec.d.ts.map +1 -0
  188. package/dist/src/routing/routing.spec.js +100 -0
  189. package/dist/src/routing/routing.spec.js.map +1 -0
  190. package/dist/src/routing/tiers.d.ts +22 -0
  191. package/dist/src/routing/tiers.d.ts.map +1 -0
  192. package/dist/src/routing/tiers.js +26 -0
  193. package/dist/src/routing/tiers.js.map +1 -0
  194. package/dist/src/runner/api-server.d.ts +45 -0
  195. package/dist/src/runner/api-server.d.ts.map +1 -0
  196. package/dist/src/runner/api-server.js +21 -0
  197. package/dist/src/runner/api-server.js.map +1 -0
  198. package/dist/src/runner/capacity.d.ts +13 -0
  199. package/dist/src/runner/capacity.d.ts.map +1 -0
  200. package/dist/src/runner/capacity.js +18 -0
  201. package/dist/src/runner/capacity.js.map +1 -0
  202. package/dist/src/runner/rack-body.d.ts +43 -0
  203. package/dist/src/runner/rack-body.d.ts.map +1 -0
  204. package/dist/src/runner/rack-body.js +208 -0
  205. package/dist/src/runner/rack-body.js.map +1 -0
  206. package/dist/src/runner/rack-runner.d.ts +62 -0
  207. package/dist/src/runner/rack-runner.d.ts.map +1 -0
  208. package/dist/src/runner/rack-runner.js +75 -0
  209. package/dist/src/runner/rack-runner.js.map +1 -0
  210. package/dist/src/runner/rack-runner.spec.d.ts +6 -0
  211. package/dist/src/runner/rack-runner.spec.d.ts.map +1 -0
  212. package/dist/src/runner/rack-runner.spec.js +302 -0
  213. package/dist/src/runner/rack-runner.spec.js.map +1 -0
  214. package/dist/src/runner/split.spec.d.ts +6 -0
  215. package/dist/src/runner/split.spec.d.ts.map +1 -0
  216. package/dist/src/runner/split.spec.js +188 -0
  217. package/dist/src/runner/split.spec.js.map +1 -0
  218. package/dist/src/runner-event.d.ts +261 -0
  219. package/dist/src/runner-event.d.ts.map +1 -0
  220. package/dist/src/runner-event.js +332 -0
  221. package/dist/src/runner-event.js.map +1 -0
  222. package/dist/src/server/beast2.d.ts +19 -0
  223. package/dist/src/server/beast2.d.ts.map +1 -0
  224. package/dist/src/server/beast2.js +18 -0
  225. package/dist/src/server/beast2.js.map +1 -0
  226. package/dist/src/server/body-limit.d.ts +16 -0
  227. package/dist/src/server/body-limit.d.ts.map +1 -0
  228. package/dist/src/server/body-limit.js +53 -0
  229. package/dist/src/server/body-limit.js.map +1 -0
  230. package/dist/src/server/body-limit.spec.d.ts +2 -0
  231. package/dist/src/server/body-limit.spec.d.ts.map +1 -0
  232. package/dist/src/server/body-limit.spec.js +32 -0
  233. package/dist/src/server/body-limit.spec.js.map +1 -0
  234. package/dist/src/server/bounded.d.ts +16 -0
  235. package/dist/src/server/bounded.d.ts.map +1 -0
  236. package/dist/src/server/bounded.js +39 -0
  237. package/dist/src/server/bounded.js.map +1 -0
  238. package/dist/src/server/dispatch.d.ts +137 -0
  239. package/dist/src/server/dispatch.d.ts.map +1 -0
  240. package/dist/src/server/dispatch.js +267 -0
  241. package/dist/src/server/dispatch.js.map +1 -0
  242. package/dist/src/server/env-publication.d.ts +45 -0
  243. package/dist/src/server/env-publication.d.ts.map +1 -0
  244. package/dist/src/server/env-publication.js +10 -0
  245. package/dist/src/server/env-publication.js.map +1 -0
  246. package/dist/src/server/index.d.ts +16 -0
  247. package/dist/src/server/index.d.ts.map +1 -0
  248. package/dist/src/server/index.js +17 -0
  249. package/dist/src/server/index.js.map +1 -0
  250. package/dist/src/server/protocol.spec.d.ts +6 -0
  251. package/dist/src/server/protocol.spec.d.ts.map +1 -0
  252. package/dist/src/server/protocol.spec.js +78 -0
  253. package/dist/src/server/protocol.spec.js.map +1 -0
  254. package/dist/src/server/rack-routes.d.ts +175 -0
  255. package/dist/src/server/rack-routes.d.ts.map +1 -0
  256. package/dist/src/server/rack-routes.js +755 -0
  257. package/dist/src/server/rack-routes.js.map +1 -0
  258. package/dist/src/server/rack-routes.spec.d.ts +6 -0
  259. package/dist/src/server/rack-routes.spec.d.ts.map +1 -0
  260. package/dist/src/server/rack-routes.spec.js +477 -0
  261. package/dist/src/server/rack-routes.spec.js.map +1 -0
  262. package/dist/src/server/storage-bridge.d.ts +140 -0
  263. package/dist/src/server/storage-bridge.d.ts.map +1 -0
  264. package/dist/src/server/storage-bridge.js +6 -0
  265. package/dist/src/server/storage-bridge.js.map +1 -0
  266. package/dist/src/state-file.d.ts +10 -0
  267. package/dist/src/state-file.d.ts.map +1 -0
  268. package/dist/src/state-file.js +38 -0
  269. package/dist/src/state-file.js.map +1 -0
  270. package/dist/src/testing/in-memory.d.ts +116 -0
  271. package/dist/src/testing/in-memory.d.ts.map +1 -0
  272. package/dist/src/testing/in-memory.js +193 -0
  273. package/dist/src/testing/in-memory.js.map +1 -0
  274. package/dist/src/testing/index.d.ts +14 -0
  275. package/dist/src/testing/index.d.ts.map +1 -0
  276. package/dist/src/testing/index.js +14 -0
  277. package/dist/src/testing/index.js.map +1 -0
  278. package/dist/src/testing/lease-store-contract.d.ts +14 -0
  279. package/dist/src/testing/lease-store-contract.d.ts.map +1 -0
  280. package/dist/src/testing/lease-store-contract.js +78 -0
  281. package/dist/src/testing/lease-store-contract.js.map +1 -0
  282. package/dist/src/testing/protocol-suite.d.ts +38 -0
  283. package/dist/src/testing/protocol-suite.d.ts.map +1 -0
  284. package/dist/src/testing/protocol-suite.js +207 -0
  285. package/dist/src/testing/protocol-suite.js.map +1 -0
  286. package/dist/src/testing/rack-registry-contract.d.ts +15 -0
  287. package/dist/src/testing/rack-registry-contract.d.ts.map +1 -0
  288. package/dist/src/testing/rack-registry-contract.js +106 -0
  289. package/dist/src/testing/rack-registry-contract.js.map +1 -0
  290. package/dist/src/testing/test-rack-agent.d.ts +121 -0
  291. package/dist/src/testing/test-rack-agent.d.ts.map +1 -0
  292. package/dist/src/testing/test-rack-agent.js +316 -0
  293. package/dist/src/testing/test-rack-agent.js.map +1 -0
  294. package/dist/src/tls/tls.d.ts +67 -0
  295. package/dist/src/tls/tls.d.ts.map +1 -0
  296. package/dist/src/tls/tls.js +200 -0
  297. package/dist/src/tls/tls.js.map +1 -0
  298. package/dist/src/tls/tls.spec.d.ts +6 -0
  299. package/dist/src/tls/tls.spec.d.ts.map +1 -0
  300. package/dist/src/tls/tls.spec.js +101 -0
  301. package/dist/src/tls/tls.spec.js.map +1 -0
  302. package/dist/src/version.d.ts +9 -0
  303. package/dist/src/version.d.ts.map +1 -0
  304. package/dist/src/version.js +10 -0
  305. package/dist/src/version.js.map +1 -0
  306. package/package.json +67 -7
@@ -0,0 +1,192 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ /**
6
+ * A lease's closure (#214): every object its guest's execution reads, which
7
+ * the cloud computes when it grants the lease. The agent fetches exactly
8
+ * these into its cache and links them into the guest's scratch, and
9
+ * `/rack/storage` admits exactly these: a rack reaches no other object of the
10
+ * repository.
11
+ *
12
+ * What e3-core's execution reads over a staged store:
13
+ * - a task or a unit: its task object; its program, or its command IR; what
14
+ * its output kind folds with (a dict's merge, a fold's zero and combine);
15
+ * its environment's spec and the files that names; and each object it
16
+ * stages (a task's inputs, a piece's inputs, a merge's range and parts);
17
+ * - a function call: its program, its environment, and each stored dataset
18
+ * argument;
19
+ * - a staged dataset: the object, and, for a record state, its primary; for a
20
+ * manifest, its header and its segments.
21
+ *
22
+ * A closure larger than {@link INLINE_CLOSURE_MAX} hashes is recorded as an
23
+ * object in the repository's store, whose hash the lease carries.
24
+ */
25
+ import { ArrayType, StringType, decodeBeast2For, encodeBeast2For } from '@elaraai/east';
26
+ import { openDatasetObject } from '@elaraai/e3-core';
27
+ import { EnvironmentSpecType, environmentSpecObjectHashes } from '@elaraai/e3-types';
28
+ /** The most hashes a lease's event carries inline: past it, the closure is an object. */
29
+ export const INLINE_CLOSURE_MAX = 512;
30
+ /** A closure object: the hashes, as a beast2 `Array<String>`. */
31
+ const ClosureListType = ArrayType(StringType);
32
+ const encodeList = encodeBeast2For(ClosureListType);
33
+ const decodeList = decodeBeast2For(ClosureListType);
34
+ const decodeEnvironmentSpec = decodeBeast2For(EnvironmentSpecType);
35
+ /**
36
+ * A closure object's bytes.
37
+ *
38
+ * @param hashes - The closure's hashes
39
+ * @returns The object's bytes
40
+ */
41
+ export function encodeClosure(hashes) {
42
+ return encodeList([...hashes]);
43
+ }
44
+ /**
45
+ * The hashes a closure object lists.
46
+ *
47
+ * @param bytes - The object's bytes
48
+ * @returns The hashes
49
+ * @throws {Error} When the bytes are not a closure object
50
+ */
51
+ export function decodeClosure(bytes) {
52
+ return decodeList(bytes);
53
+ }
54
+ /**
55
+ * What a unit's execution stages: a piece's inputs, or a merge's key range
56
+ * and its parts (e3-core's `taskExecuteBody`).
57
+ *
58
+ * @param inputs - The unit's inputs, as its record names them
59
+ * @param merge - What a merge unit merges, or null for a piece
60
+ * @returns The staged objects' hashes
61
+ */
62
+ export function stagedObjects(inputs, merge) {
63
+ return merge === null ? [...inputs] : [...(merge.range === null ? [] : [merge.range]), ...merge.parts];
64
+ }
65
+ /**
66
+ * The closure of a task's or a unit's execution.
67
+ *
68
+ * @param storage - The repository's storage
69
+ * @param repo - Repository identifier
70
+ * @param taskHash - The task object's hash
71
+ * @param task - The task object
72
+ * @param staged - What the execution stages ({@link stagedObjects})
73
+ * @param parts - Collects the closure's collection parts (each staged
74
+ * manifest's entries): what a unit fetches only as it reads them
75
+ * @returns The objects it reads, sorted
76
+ * @throws {Error} When an object it names cannot be read
77
+ */
78
+ export async function taskClosure(storage, repo, taskHash, task, staged, parts) {
79
+ const into = new Set([taskHash]);
80
+ into.add(task.body.type === 'east' ? task.body.value.program : task.body.value.commandIr);
81
+ const kind = task.output.kind;
82
+ if (kind.type === 'dict' && kind.value.merge.type === 'some')
83
+ into.add(kind.value.merge.value);
84
+ if (kind.type === 'fold') {
85
+ into.add(kind.value.zero);
86
+ into.add(kind.value.combine);
87
+ }
88
+ if (task.environment.type === 'some')
89
+ await addEnvironment(storage, repo, task.environment.value, into);
90
+ for (const hash of new Set(staged))
91
+ await addValue(storage, repo, hash, into, parts);
92
+ return [...into].sort();
93
+ }
94
+ /**
95
+ * The closure of a function call's execution.
96
+ *
97
+ * @param storage - The repository's storage
98
+ * @param repo - Repository identifier
99
+ * @param program - The program's object hash
100
+ * @param args - The call's arguments: a stored dataset's objects are staged
101
+ * @param environment - The environment the call declares
102
+ * @returns The objects it reads, sorted
103
+ * @throws {Error} When an object it names cannot be read
104
+ */
105
+ export async function detachedClosure(storage, repo, program, args, environment) {
106
+ return [...new Set([program, ...await callClosure(storage, repo, args, environment)])].sort();
107
+ }
108
+ /**
109
+ * The closure of a function call whose program travels with it, not as an
110
+ * object: its environment, and each stored dataset argument (#225, a
111
+ * sandbox's call).
112
+ *
113
+ * @param storage - The repository's storage
114
+ * @param repo - Repository identifier
115
+ * @param args - The call's arguments: a stored dataset's objects are staged
116
+ * @param environment - The environment the call declares
117
+ * @param parts - Collects the closure's collection parts, as {@link taskClosure}'s
118
+ * @returns The objects it reads, sorted
119
+ * @throws {Error} When an object it names cannot be read
120
+ */
121
+ export async function callClosure(storage, repo, args, environment, parts) {
122
+ const into = new Set();
123
+ if (environment !== undefined)
124
+ await addEnvironment(storage, repo, environment, into);
125
+ for (const arg of args) {
126
+ if (!(arg instanceof Uint8Array))
127
+ await addValue(storage, repo, arg.dataset, into, parts);
128
+ }
129
+ return [...into].sort();
130
+ }
131
+ /**
132
+ * Records a closure on a lease: its hashes inline, or, when there are more
133
+ * than {@link INLINE_CLOSURE_MAX}, an object in the repository's store that
134
+ * lists them.
135
+ *
136
+ * @param storage - The repository's storage
137
+ * @param repo - Repository identifier
138
+ * @param hashes - The closure
139
+ * @returns What the lease's event carries
140
+ */
141
+ export async function recordClosure(storage, repo, hashes) {
142
+ if (hashes.length <= INLINE_CLOSURE_MAX)
143
+ return { hashes: [...hashes] };
144
+ const object = await storage.objects.write(repo, encodeClosure(hashes));
145
+ return { object, count: hashes.length };
146
+ }
147
+ /**
148
+ * Every object a lease may read, as its closure names them: the hashes, and,
149
+ * for a closure recorded as an object, that object too.
150
+ *
151
+ * @param closure - The lease's closure
152
+ * @param read - Reads the closure object, for one recorded as an object
153
+ * @returns The hashes
154
+ * @throws {Error} When the closure object cannot be read, or lists another
155
+ * number of hashes than the lease says
156
+ */
157
+ export async function closureHashes(closure, read) {
158
+ if ('hashes' in closure)
159
+ return [...closure.hashes];
160
+ const hashes = decodeClosure(await read(closure.object));
161
+ if (hashes.length !== closure.count) {
162
+ throw new Error(`closure object ${closure.object} lists ${hashes.length} hashes, and its lease ${closure.count}`);
163
+ }
164
+ return [closure.object, ...hashes];
165
+ }
166
+ /** A staged dataset's objects: the object, a record state's primary, a manifest's header and segments (its parts). */
167
+ async function addValue(storage, repo, hash, into, parts) {
168
+ if (into.has(hash))
169
+ return;
170
+ into.add(hash);
171
+ const opened = await openDatasetObject(storage, repo, hash);
172
+ into.add(opened.hash);
173
+ if (opened.manifest === null)
174
+ return;
175
+ into.add(opened.manifest.header);
176
+ for (const entry of opened.manifest.entries) {
177
+ if (opened.manifest.level === 0n) {
178
+ into.add(entry.hash);
179
+ parts?.add(entry.hash);
180
+ }
181
+ else
182
+ await addValue(storage, repo, entry.hash, into, parts);
183
+ }
184
+ }
185
+ /** An environment's spec and the files it names. */
186
+ async function addEnvironment(storage, repo, hash, into) {
187
+ into.add(hash);
188
+ const spec = decodeEnvironmentSpec(await storage.objects.read(repo, hash));
189
+ for (const file of environmentSpecObjectHashes(spec))
190
+ into.add(file);
191
+ }
192
+ //# sourceMappingURL=closure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"closure.js","sourceRoot":"","sources":["../../../src/lease/closure.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=closure.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"closure.spec.d.ts","sourceRoot":"","sources":["../../../src/lease/closure.spec.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ import { afterEach, it } from 'node:test';
6
+ import assert from 'node:assert/strict';
7
+ import { mkdtemp, rm } from 'node:fs/promises';
8
+ import { tmpdir } from 'node:os';
9
+ import { join } from 'node:path';
10
+ import { ArrayType, IntegerType, encodeCollectionManifest } from '@elaraai/east';
11
+ import { LocalStorage, datasetWrite, openDatasetObject, repoInit } from '@elaraai/e3-core';
12
+ import { callClosure, closureHashes, recordClosure } from './closure.js';
13
+ const homes = [];
14
+ afterEach(async () => { for (const home of homes.splice(0))
15
+ await rm(home, { recursive: true, force: true }); });
16
+ it('includes every descendant of a nested collection manifest and records large closures', async () => {
17
+ const repo = await mkdtemp(join(tmpdir(), 'e3-closure-'));
18
+ homes.push(repo);
19
+ assert(repoInit(repo).success);
20
+ const storage = new LocalStorage();
21
+ const leaf = await datasetWrite(storage, repo, [1n, 2n], ArrayType(IntegerType));
22
+ const opened = await openDatasetObject(storage, repo, leaf);
23
+ assert(opened.manifest);
24
+ const root = await storage.objects.write(repo, encodeCollectionManifest({ ...opened.manifest, level: 1n,
25
+ entries: [{ hash: leaf, count: 2n, bytes: BigInt((await storage.objects.stat(repo, leaf)).size), fence: new Uint8Array() }] }));
26
+ const parts = new Set();
27
+ const hashes = await callClosure(storage, repo, [{ dataset: root }], undefined, parts);
28
+ assert.deepEqual(hashes, [...new Set([root, leaf, opened.manifest.header, ...opened.manifest.entries.map((entry) => entry.hash)])].sort());
29
+ assert.deepEqual([...parts], opened.manifest.entries.map((entry) => entry.hash));
30
+ const large = Array.from({ length: 513 }, (_, n) => n.toString(16).padStart(64, '0'));
31
+ const closure = await recordClosure(storage, repo, large);
32
+ assert('object' in closure);
33
+ assert.deepEqual(await closureHashes(closure, (hash) => storage.objects.read(repo, hash)), [closure.object, ...large]);
34
+ });
35
+ //# sourceMappingURL=closure.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"closure.spec.js","sourceRoot":"","sources":["../../../src/lease/closure.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ /**
6
+ * Serializes a lease transition together with its repository side effects.
7
+ * A host shares one coordinator between its routes and dispatcher. A
8
+ * distributed host supplies the equivalent fencing at its storage boundary.
9
+ */
10
+ export interface LeaseCoordinator {
11
+ /** Runs a transition exclusively for one repository and lease. */
12
+ run<T>(repo: string, leaseId: string, operation: () => Promise<T>): Promise<T>;
13
+ }
14
+ /**
15
+ * Serializes transitions in a single hub without blocking unrelated leases.
16
+ * Operations must not recursively acquire the same lease.
17
+ * @example
18
+ * const coordinator = new InMemoryLeaseCoordinator();
19
+ * await coordinator.run(repo, leaseId, () => completeAttempt());
20
+ */
21
+ export declare class InMemoryLeaseCoordinator implements LeaseCoordinator {
22
+ private readonly tails;
23
+ /**
24
+ * Runs after prior transitions, even if a prior transition rejected.
25
+ * @param repo - Repository alias
26
+ * @param leaseId - Lease identity
27
+ * @param operation - Transition and its side effects
28
+ * @returns The operation's result
29
+ */
30
+ run<T>(repo: string, leaseId: string, operation: () => Promise<T>): Promise<T>;
31
+ }
32
+ /** Runs unfenced operations for hosts whose backend supplies fencing. */
33
+ export declare const backendLeaseCoordinator: LeaseCoordinator;
34
+ //# sourceMappingURL=coordinator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coordinator.d.ts","sourceRoot":"","sources":["../../../src/lease/coordinator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,kEAAkE;IAClE,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAChF;AAED;;;;;;GAMG;AACH,qBAAa,wBAAyB,YAAW,gBAAgB;IAC/D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAoC;IAE1D;;;;;;OAMG;IACG,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;CAcrF;AAED,yEAAyE;AACzE,eAAO,MAAM,uBAAuB,EAAE,gBAErC,CAAC"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ /**
6
+ * Serializes transitions in a single hub without blocking unrelated leases.
7
+ * Operations must not recursively acquire the same lease.
8
+ * @example
9
+ * const coordinator = new InMemoryLeaseCoordinator();
10
+ * await coordinator.run(repo, leaseId, () => completeAttempt());
11
+ */
12
+ export class InMemoryLeaseCoordinator {
13
+ tails = new Map();
14
+ /**
15
+ * Runs after prior transitions, even if a prior transition rejected.
16
+ * @param repo - Repository alias
17
+ * @param leaseId - Lease identity
18
+ * @param operation - Transition and its side effects
19
+ * @returns The operation's result
20
+ */
21
+ async run(repo, leaseId, operation) {
22
+ const key = JSON.stringify([repo, leaseId]);
23
+ const before = this.tails.get(key) ?? Promise.resolve();
24
+ let release;
25
+ const after = new Promise((resolve) => { release = resolve; });
26
+ this.tails.set(key, after);
27
+ await before;
28
+ try {
29
+ return await operation();
30
+ }
31
+ finally {
32
+ release();
33
+ if (this.tails.get(key) === after)
34
+ this.tails.delete(key);
35
+ }
36
+ }
37
+ }
38
+ /** Runs unfenced operations for hosts whose backend supplies fencing. */
39
+ export const backendLeaseCoordinator = {
40
+ run: (_repo, _leaseId, operation) => operation(),
41
+ };
42
+ //# sourceMappingURL=coordinator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coordinator.js","sourceRoot":"","sources":["../../../src/lease/coordinator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAYH;;;;;;GAMG;AACH,MAAM,OAAO,wBAAwB;IAClB,KAAK,GAAG,IAAI,GAAG,EAAyB,CAAC;IAE1D;;;;;;OAMG;IACH,KAAK,CAAC,GAAG,CAAI,IAAY,EAAE,OAAe,EAAE,SAA2B;QACrE,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;QAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACxD,IAAI,OAAoB,CAAC;QACzB,MAAM,KAAK,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,GAAG,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QACrE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC3B,MAAM,MAAM,CAAC;QACb,IAAI,CAAC;YACH,OAAO,MAAM,SAAS,EAAE,CAAC;QAC3B,CAAC;gBAAS,CAAC;YACT,OAAO,EAAE,CAAC;YACV,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,KAAK;gBAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;CACF;AAED,yEAAyE;AACzE,MAAM,CAAC,MAAM,uBAAuB,GAAqB;IACvD,GAAG,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,CAAC,SAAS,EAAE;CACjD,CAAC"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ import type { RackLeaseAttempt, RackLeaseResult } from '../protocol/task-envelope.js';
6
+ import { type CompleteDisposition, type RackLeaseRecord, type RackLeaseStore } from './lease-store.js';
7
+ /**
8
+ * Keeps leases in memory with the cloud store's conditional transitions.
9
+ * Each mutation completes synchronously before resolving its promise, so
10
+ * concurrent claims have one winner. Returned records are independent copies.
11
+ * @example
12
+ * const leases = new InMemoryRackLeaseStore();
13
+ * await leases.put(pending);
14
+ */
15
+ export declare class InMemoryRackLeaseStore implements RackLeaseStore {
16
+ private readonly now;
17
+ private readonly records;
18
+ /** @param now - The clock for visibility and activity timestamps */
19
+ constructor(now?: () => number);
20
+ private key;
21
+ /** Forgets a terminal lease after its subscribers and retry window have ended. */
22
+ forget(repo: string, id: string): void;
23
+ put(record: RackLeaseRecord): Promise<void>;
24
+ get(repo: string, id: string): Promise<RackLeaseRecord | null>;
25
+ /**
26
+ * Reads a lease without copying it: for a count or a status check, never
27
+ * for a change, and not kept past the next transition. A copy per read is
28
+ * what {@link get} is for.
29
+ * @param repo - The lease's repository
30
+ * @param id - The lease
31
+ * @returns The store's own record, or null
32
+ * @example
33
+ * if (leases.peek(repo, id)?.status === 'claimed') busy++;
34
+ */
35
+ peek(repo: string, id: string): Readonly<RackLeaseRecord> | null;
36
+ /**
37
+ * The leases an agent with these tiers could claim now, oldest first,
38
+ * without copying them: the same caution as {@link peek}.
39
+ * @param tiers - The tiers the agent runs
40
+ * @param now - The time, in ms since the epoch
41
+ * @returns The store's own records
42
+ * @example
43
+ * const queued = leases.peekClaimable(['node'], Date.now()).length;
44
+ */
45
+ peekClaimable(tiers: readonly string[], now: number): ReadonlyArray<Readonly<RackLeaseRecord>>;
46
+ findByTask(repo: string, taskHash: string, inputsHash: string): Promise<RackLeaseRecord | null>;
47
+ listClaimable(tiers: string[], now: number, limit: number): Promise<RackLeaseRecord[]>;
48
+ claim(repo: string, id: string, rackId: string, deadline: number, attempt?: RackLeaseAttempt): Promise<RackLeaseRecord | null>;
49
+ recordTargets(repo: string, id: string, rackId: string, hashes: readonly string[]): Promise<boolean>;
50
+ extend(repo: string, id: string, rackId: string, deadline: number): Promise<boolean>;
51
+ complete(repo: string, id: string, rackId: string, result: RackLeaseResult): Promise<CompleteDisposition>;
52
+ listRecentByRack(rackId: string, limit: number): Promise<RackLeaseRecord[]>;
53
+ supersede(repo: string, id: string): Promise<RackLeaseRecord | null>;
54
+ cancel(repo: string, id: string): Promise<RackLeaseRecord | null>;
55
+ private terminal;
56
+ private held;
57
+ }
58
+ //# sourceMappingURL=in-memory-lease-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"in-memory-lease-store.d.ts","sourceRoot":"","sources":["../../../src/lease/in-memory-lease-store.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACtF,OAAO,EAA8B,KAAK,mBAAmB,EAAE,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEnI;;;;;;;GAOG;AACH,qBAAa,sBAAuB,YAAW,cAAc;IAI/C,OAAO,CAAC,QAAQ,CAAC,GAAG;IAHhC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsC;IAE9D,oEAAoE;gBACvC,GAAG,GAAE,MAAM,MAAiB;IAEzD,OAAO,CAAC,GAAG;IAEX,kFAAkF;IAClF,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAMtC,GAAG,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAK3C,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAI9D;;;;;;;;;OASG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,QAAQ,CAAC,eAAe,CAAC,GAAG,IAAI;IAIhE;;;;;;;;OAQG;IACH,aAAa,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,aAAa,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;IAK9F,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAQ/F,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAItF,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAW9H,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAOpG,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAOpF,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAUzG,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAK3E,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAIpE,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAIjE,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,IAAI;CAIb"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ import { isClaimable, leaseIdPrefix } from './lease-store.js';
6
+ /**
7
+ * Keeps leases in memory with the cloud store's conditional transitions.
8
+ * Each mutation completes synchronously before resolving its promise, so
9
+ * concurrent claims have one winner. Returned records are independent copies.
10
+ * @example
11
+ * const leases = new InMemoryRackLeaseStore();
12
+ * await leases.put(pending);
13
+ */
14
+ export class InMemoryRackLeaseStore {
15
+ now;
16
+ records = new Map();
17
+ /** @param now - The clock for visibility and activity timestamps */
18
+ constructor(now = Date.now) {
19
+ this.now = now;
20
+ }
21
+ key(repo, id) { return JSON.stringify([repo, id]); }
22
+ /** Forgets a terminal lease after its subscribers and retry window have ended. */
23
+ forget(repo, id) {
24
+ const key = this.key(repo, id);
25
+ const record = this.records.get(key);
26
+ if (record !== undefined && record.status !== 'pending' && record.status !== 'claimed')
27
+ this.records.delete(key);
28
+ }
29
+ put(record) {
30
+ this.records.set(this.key(record.repo, record.leaseId), structuredClone(record));
31
+ return Promise.resolve();
32
+ }
33
+ get(repo, id) {
34
+ return Promise.resolve(structuredClone(this.records.get(this.key(repo, id)) ?? null));
35
+ }
36
+ /**
37
+ * Reads a lease without copying it: for a count or a status check, never
38
+ * for a change, and not kept past the next transition. A copy per read is
39
+ * what {@link get} is for.
40
+ * @param repo - The lease's repository
41
+ * @param id - The lease
42
+ * @returns The store's own record, or null
43
+ * @example
44
+ * if (leases.peek(repo, id)?.status === 'claimed') busy++;
45
+ */
46
+ peek(repo, id) {
47
+ return this.records.get(this.key(repo, id)) ?? null;
48
+ }
49
+ /**
50
+ * The leases an agent with these tiers could claim now, oldest first,
51
+ * without copying them: the same caution as {@link peek}.
52
+ * @param tiers - The tiers the agent runs
53
+ * @param now - The time, in ms since the epoch
54
+ * @returns The store's own records
55
+ * @example
56
+ * const queued = leases.peekClaimable(['node'], Date.now()).length;
57
+ */
58
+ peekClaimable(tiers, now) {
59
+ return [...this.records.values()].filter((r) => tiers.includes(r.tier) && isClaimable(r, now))
60
+ .sort((a, b) => a.createdAtMs - b.createdAtMs || a.leaseId.localeCompare(b.leaseId));
61
+ }
62
+ findByTask(repo, taskHash, inputsHash) {
63
+ const prefix = leaseIdPrefix(taskHash, inputsHash);
64
+ const records = [...this.records.values()].filter((r) => r.repo === repo && r.leaseId.startsWith(prefix)
65
+ && r.status !== 'superseded' && r.status !== 'cancelled');
66
+ records.sort((a, b) => b.createdAtMs - a.createdAtMs || b.leaseId.localeCompare(a.leaseId));
67
+ return Promise.resolve(structuredClone(records[0] ?? null));
68
+ }
69
+ listClaimable(tiers, now, limit) {
70
+ return Promise.resolve(this.peekClaimable(tiers, now).slice(0, limit).map((r) => structuredClone(r)));
71
+ }
72
+ claim(repo, id, rackId, deadline, attempt) {
73
+ const record = this.records.get(this.key(repo, id));
74
+ if (record === undefined || !isClaimable(record, this.now()))
75
+ return Promise.resolve(null);
76
+ record.status = 'claimed';
77
+ record.claimedBy = rackId;
78
+ record.claimedAtMs = this.now();
79
+ record.visibilityDeadlineMs = deadline;
80
+ if (attempt !== undefined)
81
+ record.attempt = structuredClone(attempt);
82
+ return Promise.resolve(structuredClone(record));
83
+ }
84
+ recordTargets(repo, id, rackId, hashes) {
85
+ const record = this.held(repo, id, rackId);
86
+ if (record === null)
87
+ return Promise.resolve(false);
88
+ record.targets = [...new Set([...(record.targets ?? []), ...hashes])];
89
+ return Promise.resolve(true);
90
+ }
91
+ extend(repo, id, rackId, deadline) {
92
+ const record = this.held(repo, id, rackId);
93
+ if (record === null)
94
+ return Promise.resolve(false);
95
+ record.visibilityDeadlineMs = deadline;
96
+ return Promise.resolve(true);
97
+ }
98
+ complete(repo, id, rackId, result) {
99
+ const record = this.records.get(this.key(repo, id));
100
+ if (record?.status === 'completed')
101
+ return Promise.resolve('idempotent');
102
+ if (record === undefined || record.status !== 'claimed' || record.claimedBy !== rackId)
103
+ return Promise.resolve('discarded');
104
+ record.status = 'completed';
105
+ record.result = structuredClone(result);
106
+ record.completedAtMs = this.now();
107
+ return Promise.resolve('recorded');
108
+ }
109
+ listRecentByRack(rackId, limit) {
110
+ return Promise.resolve([...this.records.values()].filter((r) => r.claimedBy === rackId && r.claimedAtMs !== undefined)
111
+ .sort((a, b) => b.claimedAtMs - a.claimedAtMs).slice(0, limit).map((r) => structuredClone(r)));
112
+ }
113
+ supersede(repo, id) {
114
+ return this.terminal(repo, id, 'superseded');
115
+ }
116
+ cancel(repo, id) {
117
+ return this.terminal(repo, id, 'cancelled');
118
+ }
119
+ terminal(repo, id, status) {
120
+ const record = this.records.get(this.key(repo, id));
121
+ if (record === undefined)
122
+ return Promise.resolve(null);
123
+ if (record.status === 'pending' || record.status === 'claimed')
124
+ record.status = status;
125
+ return Promise.resolve(structuredClone(record));
126
+ }
127
+ held(repo, id, rackId) {
128
+ const record = this.records.get(this.key(repo, id));
129
+ return record?.status === 'claimed' && record.claimedBy === rackId ? record : null;
130
+ }
131
+ }
132
+ //# sourceMappingURL=in-memory-lease-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"in-memory-lease-store.js","sourceRoot":"","sources":["../../../src/lease/in-memory-lease-store.ts"],"names":[],"mappings":"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"}