@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,169 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ import type { RackLeaseStatus } from './rack-dispatch.js';
6
+ import type { RackLeaseAttempt, RackLeaseEvent, RackLeaseResult } from '../protocol/task-envelope.js';
7
+ /**
8
+ * The most object keys a lease may be issued write targets for (#214): its
9
+ * row records each, and a failed or expired lease deletes the uncatalogued
10
+ * versions of each. A unit that writes more new objects than this falls back
11
+ * to the cloud.
12
+ */
13
+ export declare const MAX_LEASE_TARGETS = 4096;
14
+ /** A stored lease — the persistent shape behind the RackDispatch seam. */
15
+ export interface RackLeaseRecord {
16
+ /** `{taskHash}#{inputsHash}#{uuidv7}` — see {@link makeLeaseId}. */
17
+ leaseId: string;
18
+ repo: string;
19
+ workspace: string;
20
+ taskHash: string;
21
+ inputsHash: string;
22
+ /** The rack tier the task needs (node | py | c | ...). */
23
+ tier: string;
24
+ /** The task's compute size tag — the agent's VM shape (default serverless). */
25
+ computeSize?: string;
26
+ status: RackLeaseStatus;
27
+ /** The rack that claimed it (set on claim and preserved after). */
28
+ claimedBy?: string;
29
+ /** Epoch ms of the (latest) claim — the rack-activity timeline (D12 UI). */
30
+ claimedAtMs?: number;
31
+ /** Epoch ms of completion. */
32
+ completedAtMs?: number;
33
+ /** Epoch ms; while `claimed`, past-deadline means reclaimable. */
34
+ visibilityDeadlineMs?: number;
35
+ /** The task envelope the agent executes. */
36
+ event: RackLeaseEvent;
37
+ /** The attempt the latest claim runs: minted by the claim, for a task or
38
+ * unit lease (#214) */
39
+ attempt?: RackLeaseAttempt;
40
+ /** The object hashes the lease was issued write targets for (#214): what
41
+ * its end deletes the uncatalogued versions of */
42
+ targets?: readonly string[];
43
+ /** Terminal result (set on `completed`). */
44
+ result?: RackLeaseResult;
45
+ createdAtMs: number;
46
+ }
47
+ /** Disposition of a completion attempt (accepted-and-discarded semantics). */
48
+ export type CompleteDisposition = 'recorded' | 'idempotent' | 'discarded';
49
+ /**
50
+ * Build a lease id embedding the re-attachment key.
51
+ *
52
+ * @param taskHash - The task's content hash
53
+ * @param inputsHash - Hash of the resolved input set
54
+ * @returns `{taskHash}#{inputsHash}#{uuidv7}`: a fresh id, which sorts after every earlier lease of the task
55
+ * @example
56
+ * const leaseId = makeLeaseId(taskHash, inputsHash);
57
+ */
58
+ export declare function makeLeaseId(taskHash: string, inputsHash: string): string;
59
+ /**
60
+ * The key prefix all leases for a task identity share.
61
+ *
62
+ * @param taskHash - The task's content hash
63
+ * @param inputsHash - Hash of the resolved input set
64
+ * @returns `{taskHash}#{inputsHash}#`
65
+ * @example
66
+ * const ofTask = ids.filter((id) => id.startsWith(leaseIdPrefix(taskHash, inputsHash)));
67
+ */
68
+ export declare function leaseIdPrefix(taskHash: string, inputsHash: string): string;
69
+ /**
70
+ * Whether a lease can be claimed right now: pending, or claimed with an
71
+ * expired visibility deadline (the claimant went quiet).
72
+ *
73
+ * @param record - The stored lease
74
+ * @param nowMs - Current epoch ms
75
+ * @returns Whether a claim would take it
76
+ * @example
77
+ * const candidates = records.filter((record) => isClaimable(record, Date.now()));
78
+ */
79
+ export declare function isClaimable(record: RackLeaseRecord, nowMs: number): boolean;
80
+ /**
81
+ * Whether a rack lease is still held: claimed within its visibility deadline,
82
+ * which the claimant's heartbeat extends, or pending a claim. A rack
83
+ * attempt's liveness (#206, `launchLiveness`): the attempt can still finish
84
+ * while its lease is held.
85
+ *
86
+ * @param leases - The lease store
87
+ * @param now - The time, in ms since the epoch (default `Date.now`)
88
+ * @returns Whether a repository's lease is held
89
+ */
90
+ export declare function rackLeaseHeld(leases: Pick<RackLeaseStore, 'get'>, now?: () => number): (repo: string, leaseId: string) => Promise<boolean>;
91
+ /**
92
+ * Rack lease persistence seam. Implementations: `InMemoryRackLeaseStore`
93
+ * (testing) and `DynamoRackLeaseStore` (e3-aws; lease rows under
94
+ * `PK=RACKLEASE/{repo}` plus a small `PK=RACKQUEUE` discovery partition).
95
+ */
96
+ export interface RackLeaseStore {
97
+ /** Persist a new pending lease (and its queue-discovery entry). */
98
+ put(record: RackLeaseRecord): Promise<void>;
99
+ /** Read one lease. */
100
+ get(repo: string, leaseId: string): Promise<RackLeaseRecord | null>;
101
+ /**
102
+ * Latest lease for a task identity that is not superseded/cancelled —
103
+ * the yield re-attachment lookup (prefix query on the lease id).
104
+ */
105
+ findByTask(repo: string, taskHash: string, inputsHash: string): Promise<RackLeaseRecord | null>;
106
+ /**
107
+ * Leases an agent with the given tiers could claim right now (pending or
108
+ * visibility-expired), oldest first.
109
+ *
110
+ * @param tiers - The tiers the agent has rootfs for
111
+ * @param nowMs - Current epoch ms
112
+ * @param limit - Max candidates to return
113
+ */
114
+ listClaimable(tiers: string[], nowMs: number, limit: number): Promise<RackLeaseRecord[]>;
115
+ /**
116
+ * Conditionally claim a lease: succeeds only while {@link isClaimable}.
117
+ * Exactly one racing claimant wins.
118
+ *
119
+ * @param attempt - The attempt the claim runs, for a task or unit lease
120
+ * (#214): it replaces the one an earlier claim ran
121
+ * @returns The claimed record, or null when the condition lost
122
+ */
123
+ claim(repo: string, leaseId: string, rackId: string, visibilityDeadlineMs: number, attempt?: RackLeaseAttempt): Promise<RackLeaseRecord | null>;
124
+ /**
125
+ * Record object hashes a lease was issued write targets for (#214), only
126
+ * by its claimant while it holds the lease. The lease keeps each once.
127
+ *
128
+ * @returns Whether they were recorded: false when the lease is not held by
129
+ * the rack
130
+ */
131
+ recordTargets(repo: string, leaseId: string, rackId: string, hashes: readonly string[]): Promise<boolean>;
132
+ /**
133
+ * Recent leases claimed by a rack, newest first — the fleet-table
134
+ * activity view ("what has this rack done"). A lease reclaimed by
135
+ * ANOTHER rack after visibility expiry leaves this rack's list (the
136
+ * record tracks its latest claimant only).
137
+ *
138
+ * @param rackId - The rack whose activity is listed
139
+ * @param limit - Max records
140
+ */
141
+ listRecentByRack(rackId: string, limit: number): Promise<RackLeaseRecord[]>;
142
+ /**
143
+ * Extend a claimed lease's visibility — only by its claimant.
144
+ *
145
+ * @returns Whether the extension applied
146
+ */
147
+ extend(repo: string, leaseId: string, rackId: string, visibilityDeadlineMs: number): Promise<boolean>;
148
+ /**
149
+ * Record a terminal result — only transitions `claimed → completed` by
150
+ * the claimant. Anything else is 'idempotent' (already completed) or
151
+ * 'discarded' (superseded/cancelled/expired-and-reclaimed/unknown).
152
+ */
153
+ complete(repo: string, leaseId: string, rackId: string, result: RackLeaseResult): Promise<CompleteDisposition>;
154
+ /**
155
+ * CAS supersede (runner falling back to cloud): `pending|claimed →
156
+ * superseded`; a completed lease stays completed.
157
+ *
158
+ * @returns The lease's state after the attempt
159
+ */
160
+ supersede(repo: string, leaseId: string): Promise<RackLeaseRecord | null>;
161
+ /**
162
+ * CAS cancel: `pending|claimed → cancelled`; a completed lease stays
163
+ * completed. Heartbeats deliver the signal to the running agent.
164
+ *
165
+ * @returns The lease's state after the attempt
166
+ */
167
+ cancel(repo: string, leaseId: string): Promise<RackLeaseRecord | null>;
168
+ }
169
+ //# sourceMappingURL=lease-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lease-store.d.ts","sourceRoot":"","sources":["../../../src/lease/lease-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ /**
6
+ * Rack lease persistence (#73, epic #67 design §9.2–9.3) — the DynamoDB-
7
+ * layered pull queue behind {@link StoreRackDispatch} and the /rack
8
+ * dispatch routes.
9
+ *
10
+ * Lease state machine (review F3), every transition a conditional write:
11
+ *
12
+ * pending ──claim──▶ claimed ──complete──▶ completed
13
+ * │ │ ▲
14
+ * │ │ └─ extend (visibility)
15
+ * │ visibility expires (lazily observed: the lease becomes
16
+ * │ claimable again; a claim retakes it)
17
+ * ├──supersede──▶ superseded (runner fell back to cloud)
18
+ * └──cancel─────▶ cancelled (heartbeat delivers; agent kills the VM)
19
+ *
20
+ * `complete` against superseded/cancelled (or by a non-claimant) is
21
+ * **accepted-and-discarded** — never an error, the response just tells the
22
+ * agent to drop local state. `complete` on completed is idempotent-success.
23
+ * Supersede/cancel are CAS: an already-completed lease stays completed and
24
+ * the caller receives it (completed-wins).
25
+ *
26
+ * The lease id embeds the task identity (`{taskHash}#{inputsHash}#{uuid}`)
27
+ * so the store can find re-attachable leases with a key-prefix query — no
28
+ * scans, no extra index.
29
+ */
30
+ import { uuidv7 } from '@elaraai/e3-core';
31
+ /**
32
+ * The most object keys a lease may be issued write targets for (#214): its
33
+ * row records each, and a failed or expired lease deletes the uncatalogued
34
+ * versions of each. A unit that writes more new objects than this falls back
35
+ * to the cloud.
36
+ */
37
+ export const MAX_LEASE_TARGETS = 4096;
38
+ /**
39
+ * Build a lease id embedding the re-attachment key.
40
+ *
41
+ * @param taskHash - The task's content hash
42
+ * @param inputsHash - Hash of the resolved input set
43
+ * @returns `{taskHash}#{inputsHash}#{uuidv7}`: a fresh id, which sorts after every earlier lease of the task
44
+ * @example
45
+ * const leaseId = makeLeaseId(taskHash, inputsHash);
46
+ */
47
+ export function makeLeaseId(taskHash, inputsHash) {
48
+ return `${taskHash}#${inputsHash}#${uuidv7()}`;
49
+ }
50
+ /**
51
+ * The key prefix all leases for a task identity share.
52
+ *
53
+ * @param taskHash - The task's content hash
54
+ * @param inputsHash - Hash of the resolved input set
55
+ * @returns `{taskHash}#{inputsHash}#`
56
+ * @example
57
+ * const ofTask = ids.filter((id) => id.startsWith(leaseIdPrefix(taskHash, inputsHash)));
58
+ */
59
+ export function leaseIdPrefix(taskHash, inputsHash) {
60
+ return `${taskHash}#${inputsHash}#`;
61
+ }
62
+ /**
63
+ * Whether a lease can be claimed right now: pending, or claimed with an
64
+ * expired visibility deadline (the claimant went quiet).
65
+ *
66
+ * @param record - The stored lease
67
+ * @param nowMs - Current epoch ms
68
+ * @returns Whether a claim would take it
69
+ * @example
70
+ * const candidates = records.filter((record) => isClaimable(record, Date.now()));
71
+ */
72
+ export function isClaimable(record, nowMs) {
73
+ return (record.status === 'pending' ||
74
+ (record.status === 'claimed' && (record.visibilityDeadlineMs ?? 0) < nowMs));
75
+ }
76
+ /**
77
+ * Whether a rack lease is still held: claimed within its visibility deadline,
78
+ * which the claimant's heartbeat extends, or pending a claim. A rack
79
+ * attempt's liveness (#206, `launchLiveness`): the attempt can still finish
80
+ * while its lease is held.
81
+ *
82
+ * @param leases - The lease store
83
+ * @param now - The time, in ms since the epoch (default `Date.now`)
84
+ * @returns Whether a repository's lease is held
85
+ */
86
+ export function rackLeaseHeld(leases, now = Date.now) {
87
+ return async (repo, leaseId) => {
88
+ const record = await leases.get(repo, leaseId);
89
+ if (record === null)
90
+ return false;
91
+ return record.status === 'pending' || (record.status === 'claimed' && (record.visibilityDeadlineMs ?? 0) >= now());
92
+ };
93
+ }
94
+ //# sourceMappingURL=lease-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lease-store.js","sourceRoot":"","sources":["../../../src/lease/lease-store.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAI1C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,CAAC;AAuCtC;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAC,QAAgB,EAAE,UAAkB;IAC9D,OAAO,GAAG,QAAQ,IAAI,UAAU,IAAI,MAAM,EAAE,EAAE,CAAC;AACjD,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAAC,QAAgB,EAAE,UAAkB;IAChE,OAAO,GAAG,QAAQ,IAAI,UAAU,GAAG,CAAC;AACtC,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,WAAW,CAAC,MAAuB,EAAE,KAAa;IAChE,OAAO,CACL,MAAM,CAAC,MAAM,KAAK,SAAS;QAC3B,CAAC,MAAM,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,oBAAoB,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC,CAC5E,CAAC;AACJ,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,aAAa,CAC3B,MAAmC,EACnC,MAAoB,IAAI,CAAC,GAAG;IAE5B,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE;QAC7B,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC/C,IAAI,MAAM,KAAK,IAAI;YAAE,OAAO,KAAK,CAAC;QAClC,OAAO,MAAM,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,oBAAoB,IAAI,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;IACrH,CAAC,CAAC;AACJ,CAAC"}
@@ -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=lease-store.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lease-store.spec.d.ts","sourceRoot":"","sources":["../../../src/lease/lease-store.spec.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ import { InMemoryRackLeaseStore } from './in-memory-lease-store.js';
6
+ import { leaseStoreContract } from '../testing/lease-store-contract.js';
7
+ leaseStoreContract('memory', () => new InMemoryRackLeaseStore());
8
+ //# sourceMappingURL=lease-store.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lease-store.spec.js","sourceRoot":"","sources":["../../../src/lease/lease-store.spec.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAExE,kBAAkB,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,sBAAsB,EAAE,CAAC,CAAC"}
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ /**
6
+ * The rack dispatch seam DelegatingTaskRunner drives (epic #67 design §7.3,
7
+ * §9.2 rev. 2026-07-11). #73 implements it over the RackLease store +
8
+ * registry; FakeRackDispatch (testing) lets #70 land and test independently.
9
+ *
10
+ * Lease lifecycle (every transition a conditional write):
11
+ * `pending → claimed → completed | superseded | cancelled`, with visibility
12
+ * expiry making a claimed lease reclaimable. A completion against a
13
+ * superseded/cancelled lease is accepted-and-discarded by the store. The
14
+ * cloud records a task or unit lease's attempt itself (#214): `running` when
15
+ * a rack claims it, its outcome when the rack completes it, and `interrupted`
16
+ * or `cancelled` when it is superseded or cancelled while claimed.
17
+ */
18
+ import type { RackLeaseAttempt, RackLeaseEvent, RackLeaseResult } from '../protocol/task-envelope.js';
19
+ /** A lease's lifecycle state. */
20
+ export type RackLeaseStatus = 'pending' | 'claimed' | 'completed' | 'superseded' | 'cancelled';
21
+ /** One delegated task hand-off. */
22
+ export interface RackLease {
23
+ leaseId: string;
24
+ repo: string;
25
+ workspace: string;
26
+ /** Task identity — the re-attachment key across orchestrator yields. */
27
+ taskHash: string;
28
+ inputsHash: string;
29
+ /** The dataflow run this lease belongs to, a UUIDv7: re-attach is scoped
30
+ * to it (a lease from a prior run is never a cache; #67) */
31
+ runId?: string;
32
+ /** The rack tier it runs on */
33
+ tier: string;
34
+ /** The compute size tag its VM is shaped by */
35
+ computeSize: string;
36
+ status: RackLeaseStatus;
37
+ /** The rack that claimed it (set on `claimed` and beyond). */
38
+ claimedBy?: string;
39
+ /** The attempt its latest claim runs, for a task or unit lease (#214) */
40
+ attempt?: RackLeaseAttempt;
41
+ /** Terminal result (set on `completed`). */
42
+ result?: RackLeaseResult;
43
+ }
44
+ /**
45
+ * What DelegatingTaskRunner needs from the rack control plane. Implemented
46
+ * over the lease store + rack registry (#73); faked in tests.
47
+ */
48
+ export interface RackDispatch {
49
+ /**
50
+ * Whether any healthy enrolled rack advertises the tier and runs an agent
51
+ * that runs a v2 lease (0.5.0 and later, #214): the prefer-rack
52
+ * availability check. NOT per-rack targeting: the v1 lease pool is
53
+ * repo-global and any matching agent claims.
54
+ *
55
+ * @param tier - The work's rack tier (node | py | c | full | env base)
56
+ */
57
+ anyHealthyRackWithTier(tier: string): Promise<boolean>;
58
+ /**
59
+ * The rack tier (base image) a PUBLISHED environment was built on, or
60
+ * null when the env is not published for rack execution (#94 Slice D).
61
+ * Also the delegability gate for env/custom tasks: null ⇒ cloud.
62
+ *
63
+ * @param envHash - The task's declared environment hash
64
+ */
65
+ envBaseTier(envHash: string): Promise<string | null>;
66
+ /**
67
+ * Find a live (pending/claimed) or completed lease for a task — the
68
+ * re-attachment path a resumed orchestrator cycle takes instead of
69
+ * creating a duplicate.
70
+ */
71
+ findLease(repo: string, taskHash: string, inputsHash: string): Promise<RackLease | null>;
72
+ /**
73
+ * Create a pending lease carrying the work's event.
74
+ *
75
+ * @param event - The v2 lease event the agent will run
76
+ * @param tier - The rack tier the work requires
77
+ * @param computeSize - The work's resolved compute size tag (VM shape)
78
+ */
79
+ createLease(event: RackLeaseEvent, tier: string, computeSize?: string): Promise<RackLease>;
80
+ /** Re-read a lease's current state. */
81
+ getLease(repo: string, leaseId: string): Promise<RackLease | null>;
82
+ /**
83
+ * Terminally supersede a lease (runner falling back to cloud). A CAS —
84
+ * a lease already `completed` stays completed (the store returns the
85
+ * final state so the caller can still use a result that won the race).
86
+ * A claimed lease's attempt is recorded `interrupted` (#214).
87
+ *
88
+ * @returns The lease's state after the attempt
89
+ */
90
+ supersede(repo: string, leaseId: string): Promise<RackLease | null>;
91
+ /**
92
+ * Terminally cancel a lease: its run was cancelled. A CAS, as
93
+ * {@link supersede}; the rack's next heartbeat stops it, and a claimed
94
+ * lease's attempt is recorded `cancelled` (#214).
95
+ *
96
+ * @returns The lease's state after the attempt
97
+ */
98
+ cancel(repo: string, leaseId: string): Promise<RackLease | null>;
99
+ /**
100
+ * Whether a lease is still held: pending a claim, or claimed within its
101
+ * visibility deadline. A rack attempt's liveness (#206, #214).
102
+ */
103
+ leaseHeld(repo: string, leaseId: string): Promise<boolean>;
104
+ }
105
+ //# sourceMappingURL=rack-dispatch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rack-dispatch.d.ts","sourceRoot":"","sources":["../../../src/lease/rack-dispatch.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAEtG,iCAAiC;AACjC,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,YAAY,GAAG,WAAW,CAAC;AAE/F,mCAAmC;AACnC,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB;iEAC6D;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,eAAe,CAAC;IACxB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yEAAyE;IACzE,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,4CAA4C;IAC5C,MAAM,CAAC,EAAE,eAAe,CAAC;CAC1B;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;;;OAOG;IACH,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAEvD;;;;;;OAMG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAErD;;;;OAIG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;IAEzF;;;;;;OAMG;IACH,WAAW,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAE3F,uCAAuC;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;IAEnE;;;;;;;OAOG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;IAEpE;;;;;;OAMG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;IAEjE;;;OAGG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC5D"}
@@ -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=rack-dispatch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rack-dispatch.js","sourceRoot":"","sources":["../../../src/lease/rack-dispatch.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ /** Serializes a store's mutations; failed mutations do not poison the queue. @internal */
6
+ export declare class MutationQueue {
7
+ private tail;
8
+ /** Runs the operation after every preceding operation has settled. */
9
+ run<T>(operation: () => Promise<T>): Promise<T>;
10
+ /** Waits for all operations already queued. */
11
+ idle(): Promise<void>;
12
+ }
13
+ //# sourceMappingURL=mutation-queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutation-queue.d.ts","sourceRoot":"","sources":["../../src/mutation-queue.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,0FAA0F;AAC1F,qBAAa,aAAa;IACxB,OAAO,CAAC,IAAI,CAAuC;IAEnD,sEAAsE;IACtE,GAAG,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAM/C,+CAA+C;IACzC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAC5B"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ /** Serializes a store's mutations; failed mutations do not poison the queue. @internal */
6
+ export class MutationQueue {
7
+ tail = Promise.resolve();
8
+ /** Runs the operation after every preceding operation has settled. */
9
+ run(operation) {
10
+ const result = this.tail.then(operation);
11
+ this.tail = result.catch(() => undefined);
12
+ return result;
13
+ }
14
+ /** Waits for all operations already queued. */
15
+ async idle() { await this.tail; }
16
+ }
17
+ //# sourceMappingURL=mutation-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutation-queue.js","sourceRoot":"","sources":["../../src/mutation-queue.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,0FAA0F;AAC1F,MAAM,OAAO,aAAa;IAChB,IAAI,GAAqB,OAAO,CAAC,OAAO,EAAE,CAAC;IAEnD,sEAAsE;IACtE,GAAG,CAAI,SAA2B;QAChC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACzC,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC1C,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,+CAA+C;IAC/C,KAAK,CAAC,IAAI,KAAoB,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;CACjD"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ /** The hashed machine credentials, under the rack home. */
6
+ export declare const IDENTITY_FILE = "identity.beast2";
7
+ /** The enrolled machines and their security policy. */
8
+ export declare const RACKS_FILE = "racks.beast2";
9
+ /** The hub's listening address and advertised origin. */
10
+ export declare const HUB_CONFIG_FILE = "hub-config.beast2";
11
+ /** The hub's TLS certificate and private key, created when its listener first serves TLS. */
12
+ export declare const HUB_TLS_FILE = "hub-tls.beast2";
13
+ /** The single hub's ownership record. */
14
+ export declare const HUB_LOCK_FILE = "hub.lock";
15
+ /** The hub process's diagnostic log. */
16
+ export declare const HUB_LOG_FILE = "hub.log";
17
+ /**
18
+ * Resolves this user's rack home, respecting `E3_RACK_HOME`.
19
+ * @returns An absolute path
20
+ * @example
21
+ * const home = rackHome();
22
+ */
23
+ export declare function rackHome(): string;
24
+ /**
25
+ * Creates the private rack home, tightening its existing permissions too.
26
+ * @param home - The rack home (default: this user's)
27
+ * @returns Its path
28
+ * @example
29
+ * const home = ensureRackHome();
30
+ */
31
+ export declare function ensureRackHome(home?: string): string;
32
+ /**
33
+ * Checks a socket path against the shortest supported Unix socket limit.
34
+ * @param path - The socket's path
35
+ * @throws {Error} When it exceeds 100 bytes on POSIX
36
+ * @example
37
+ * socketPathOk('/tmp/e3r/hub.sock');
38
+ */
39
+ export declare function socketPathOk(path: string): void;
40
+ /**
41
+ * Names this rack home's hub socket or Windows named pipe.
42
+ * @param home - The rack home
43
+ * @returns Its socket path
44
+ * @example
45
+ * const socket = hubSocketPath(rackHome());
46
+ */
47
+ export declare function hubSocketPath(home?: string): string;
48
+ /**
49
+ * Names a fresh session socket or Windows named pipe.
50
+ * @param home - The rack home
51
+ * @returns Its socket path
52
+ * @example
53
+ * const socket = sessionSocketPath(rackHome());
54
+ */
55
+ export declare function sessionSocketPath(home?: string): string;
56
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/paths.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,2DAA2D;AAC3D,eAAO,MAAM,aAAa,oBAAoB,CAAC;AAC/C,uDAAuD;AACvD,eAAO,MAAM,UAAU,iBAAiB,CAAC;AACzC,yDAAyD;AACzD,eAAO,MAAM,eAAe,sBAAsB,CAAC;AACnD,6FAA6F;AAC7F,eAAO,MAAM,YAAY,mBAAmB,CAAC;AAC7C,yCAAyC;AACzC,eAAO,MAAM,aAAa,aAAa,CAAC;AACxC,wCAAwC;AACxC,eAAO,MAAM,YAAY,YAAY,CAAC;AAEtC;;;;;GAKG;AACH,wBAAgB,QAAQ,IAAI,MAAM,CAEjC;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,IAAI,SAAa,GAAG,MAAM,CAIxD;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAI/C;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,SAAa,GAAG,MAAM,CAMvD;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,SAAa,GAAG,MAAM,CAK3D"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ import { createHash, randomBytes } from 'node:crypto';
6
+ import { chmodSync, mkdirSync } from 'node:fs';
7
+ import { homedir } from 'node:os';
8
+ import { join, resolve } from 'node:path';
9
+ /** The hashed machine credentials, under the rack home. */
10
+ export const IDENTITY_FILE = 'identity.beast2';
11
+ /** The enrolled machines and their security policy. */
12
+ export const RACKS_FILE = 'racks.beast2';
13
+ /** The hub's listening address and advertised origin. */
14
+ export const HUB_CONFIG_FILE = 'hub-config.beast2';
15
+ /** The hub's TLS certificate and private key, created when its listener first serves TLS. */
16
+ export const HUB_TLS_FILE = 'hub-tls.beast2';
17
+ /** The single hub's ownership record. */
18
+ export const HUB_LOCK_FILE = 'hub.lock';
19
+ /** The hub process's diagnostic log. */
20
+ export const HUB_LOG_FILE = 'hub.log';
21
+ /**
22
+ * Resolves this user's rack home, respecting `E3_RACK_HOME`.
23
+ * @returns An absolute path
24
+ * @example
25
+ * const home = rackHome();
26
+ */
27
+ export function rackHome() {
28
+ return resolve(process.env.E3_RACK_HOME ?? join(homedir(), '.e3', 'rack'));
29
+ }
30
+ /**
31
+ * Creates the private rack home, tightening its existing permissions too.
32
+ * @param home - The rack home (default: this user's)
33
+ * @returns Its path
34
+ * @example
35
+ * const home = ensureRackHome();
36
+ */
37
+ export function ensureRackHome(home = rackHome()) {
38
+ mkdirSync(home, { recursive: true, mode: 0o700 });
39
+ if (process.platform !== 'win32')
40
+ chmodSync(home, 0o700);
41
+ return home;
42
+ }
43
+ /**
44
+ * Checks a socket path against the shortest supported Unix socket limit.
45
+ * @param path - The socket's path
46
+ * @throws {Error} When it exceeds 100 bytes on POSIX
47
+ * @example
48
+ * socketPathOk('/tmp/e3r/hub.sock');
49
+ */
50
+ export function socketPathOk(path) {
51
+ if (process.platform !== 'win32' && Buffer.byteLength(path) > 100) {
52
+ throw new Error('Rack socket path exceeds 100 bytes; set E3_RACK_HOME to a shorter path');
53
+ }
54
+ }
55
+ /**
56
+ * Names this rack home's hub socket or Windows named pipe.
57
+ * @param home - The rack home
58
+ * @returns Its socket path
59
+ * @example
60
+ * const socket = hubSocketPath(rackHome());
61
+ */
62
+ export function hubSocketPath(home = rackHome()) {
63
+ const path = process.platform === 'win32'
64
+ ? `\\\\.\\pipe\\e3-rack-hub-${createHash('sha256').update(resolve(home)).digest('hex').slice(0, 12)}`
65
+ : join(home, 'hub.sock');
66
+ socketPathOk(path);
67
+ return path;
68
+ }
69
+ /**
70
+ * Names a fresh session socket or Windows named pipe.
71
+ * @param home - The rack home
72
+ * @returns Its socket path
73
+ * @example
74
+ * const socket = sessionSocketPath(rackHome());
75
+ */
76
+ export function sessionSocketPath(home = rackHome()) {
77
+ const id = randomBytes(6).toString('hex');
78
+ const path = process.platform === 'win32' ? `\\\\.\\pipe\\e3-rack-s-${id}` : join(home, `s-${id}.sock`);
79
+ socketPathOk(path);
80
+ return path;
81
+ }
82
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/paths.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE1C,2DAA2D;AAC3D,MAAM,CAAC,MAAM,aAAa,GAAG,iBAAiB,CAAC;AAC/C,uDAAuD;AACvD,MAAM,CAAC,MAAM,UAAU,GAAG,cAAc,CAAC;AACzC,yDAAyD;AACzD,MAAM,CAAC,MAAM,eAAe,GAAG,mBAAmB,CAAC;AACnD,6FAA6F;AAC7F,MAAM,CAAC,MAAM,YAAY,GAAG,gBAAgB,CAAC;AAC7C,yCAAyC;AACzC,MAAM,CAAC,MAAM,aAAa,GAAG,UAAU,CAAC;AACxC,wCAAwC;AACxC,MAAM,CAAC,MAAM,YAAY,GAAG,SAAS,CAAC;AAEtC;;;;;GAKG;AACH,MAAM,UAAU,QAAQ;IACtB,OAAO,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;AAC7E,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,IAAI,GAAG,QAAQ,EAAE;IAC9C,SAAS,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAClD,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO;QAAE,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACzD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC;QAClE,MAAM,IAAI,KAAK,CAAC,wEAAwE,CAAC,CAAC;IAC5F,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,IAAI,GAAG,QAAQ,EAAE;IAC7C,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO;QACvC,CAAC,CAAC,4BAA4B,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE;QACrG,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IAC3B,YAAY,CAAC,IAAI,CAAC,CAAC;IACnB,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAI,GAAG,QAAQ,EAAE;IACjD,MAAM,EAAE,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,0BAA0B,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IACxG,YAAY,CAAC,IAAI,CAAC,CAAC;IACnB,OAAO,IAAI,CAAC;AACd,CAAC"}