@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.
- package/README.md +407 -2
- package/dist/src/client/client.spec.d.ts +6 -0
- package/dist/src/client/client.spec.d.ts.map +1 -0
- package/dist/src/client/client.spec.js +150 -0
- package/dist/src/client/client.spec.js.map +1 -0
- package/dist/src/client/connect.d.ts +52 -0
- package/dist/src/client/connect.d.ts.map +1 -0
- package/dist/src/client/connect.js +112 -0
- package/dist/src/client/connect.js.map +1 -0
- package/dist/src/client/hub-client.d.ts +57 -0
- package/dist/src/client/hub-client.d.ts.map +1 -0
- package/dist/src/client/hub-client.js +87 -0
- package/dist/src/client/hub-client.js.map +1 -0
- package/dist/src/client/local-http.d.ts +78 -0
- package/dist/src/client/local-http.d.ts.map +1 -0
- package/dist/src/client/local-http.js +149 -0
- package/dist/src/client/local-http.js.map +1 -0
- package/dist/src/client/session-attempts.d.ts +20 -0
- package/dist/src/client/session-attempts.d.ts.map +1 -0
- package/dist/src/client/session-attempts.js +88 -0
- package/dist/src/client/session-attempts.js.map +1 -0
- package/dist/src/client/session-data-server.d.ts +37 -0
- package/dist/src/client/session-data-server.d.ts.map +1 -0
- package/dist/src/client/session-data-server.js +280 -0
- package/dist/src/client/session-data-server.js.map +1 -0
- package/dist/src/client/session-data-server.spec.d.ts +6 -0
- package/dist/src/client/session-data-server.spec.d.ts.map +1 -0
- package/dist/src/client/session-data-server.spec.js +192 -0
- package/dist/src/client/session-data-server.spec.js.map +1 -0
- package/dist/src/client/session.d.ts +119 -0
- package/dist/src/client/session.d.ts.map +1 -0
- package/dist/src/client/session.js +290 -0
- package/dist/src/client/session.js.map +1 -0
- package/dist/src/hub/config.d.ts +74 -0
- package/dist/src/hub/config.d.ts.map +1 -0
- package/dist/src/hub/config.js +159 -0
- package/dist/src/hub/config.js.map +1 -0
- package/dist/src/hub/fair-lease-store.d.ts +36 -0
- package/dist/src/hub/fair-lease-store.d.ts.map +1 -0
- package/dist/src/hub/fair-lease-store.js +73 -0
- package/dist/src/hub/fair-lease-store.js.map +1 -0
- package/dist/src/hub/hub.d.ts +91 -0
- package/dist/src/hub/hub.d.ts.map +1 -0
- package/dist/src/hub/hub.js +641 -0
- package/dist/src/hub/hub.js.map +1 -0
- package/dist/src/hub/hub.spec.d.ts +6 -0
- package/dist/src/hub/hub.spec.d.ts.map +1 -0
- package/dist/src/hub/hub.spec.js +363 -0
- package/dist/src/hub/hub.spec.js.map +1 -0
- package/dist/src/hub/infrastructure.spec.d.ts +6 -0
- package/dist/src/hub/infrastructure.spec.d.ts.map +1 -0
- package/dist/src/hub/infrastructure.spec.js +211 -0
- package/dist/src/hub/infrastructure.spec.js.map +1 -0
- package/dist/src/hub/lock.d.ts +62 -0
- package/dist/src/hub/lock.d.ts.map +1 -0
- package/dist/src/hub/lock.js +165 -0
- package/dist/src/hub/lock.js.map +1 -0
- package/dist/src/hub/main.d.ts +16 -0
- package/dist/src/hub/main.d.ts.map +1 -0
- package/dist/src/hub/main.js +56 -0
- package/dist/src/hub/main.js.map +1 -0
- package/dist/src/hub/session-bridge.d.ts +116 -0
- package/dist/src/hub/session-bridge.d.ts.map +1 -0
- package/dist/src/hub/session-bridge.js +336 -0
- package/dist/src/hub/session-bridge.js.map +1 -0
- package/dist/src/identity/file-identity-store.d.ts +18 -0
- package/dist/src/identity/file-identity-store.d.ts.map +1 -0
- package/dist/src/identity/file-identity-store.js +34 -0
- package/dist/src/identity/file-identity-store.js.map +1 -0
- package/dist/src/identity/file-identity-store.spec.d.ts +6 -0
- package/dist/src/identity/file-identity-store.spec.d.ts.map +1 -0
- package/dist/src/identity/file-identity-store.spec.js +59 -0
- package/dist/src/identity/file-identity-store.spec.js.map +1 -0
- package/dist/src/identity/in-memory-identity-store.d.ts +48 -0
- package/dist/src/identity/in-memory-identity-store.d.ts.map +1 -0
- package/dist/src/identity/in-memory-identity-store.js +102 -0
- package/dist/src/identity/in-memory-identity-store.js.map +1 -0
- package/dist/src/identity/machine-identity.d.ts +134 -0
- package/dist/src/identity/machine-identity.d.ts.map +1 -0
- package/dist/src/identity/machine-identity.js +65 -0
- package/dist/src/identity/machine-identity.js.map +1 -0
- package/dist/src/index.d.ts +34 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +34 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/lease/closure.d.ts +96 -0
- package/dist/src/lease/closure.d.ts.map +1 -0
- package/dist/src/lease/closure.js +192 -0
- package/dist/src/lease/closure.js.map +1 -0
- package/dist/src/lease/closure.spec.d.ts +6 -0
- package/dist/src/lease/closure.spec.d.ts.map +1 -0
- package/dist/src/lease/closure.spec.js +35 -0
- package/dist/src/lease/closure.spec.js.map +1 -0
- package/dist/src/lease/coordinator.d.ts +34 -0
- package/dist/src/lease/coordinator.d.ts.map +1 -0
- package/dist/src/lease/coordinator.js +42 -0
- package/dist/src/lease/coordinator.js.map +1 -0
- package/dist/src/lease/in-memory-lease-store.d.ts +58 -0
- package/dist/src/lease/in-memory-lease-store.d.ts.map +1 -0
- package/dist/src/lease/in-memory-lease-store.js +132 -0
- package/dist/src/lease/in-memory-lease-store.js.map +1 -0
- package/dist/src/lease/lease-store.d.ts +169 -0
- package/dist/src/lease/lease-store.d.ts.map +1 -0
- package/dist/src/lease/lease-store.js +94 -0
- package/dist/src/lease/lease-store.js.map +1 -0
- package/dist/src/lease/lease-store.spec.d.ts +6 -0
- package/dist/src/lease/lease-store.spec.d.ts.map +1 -0
- package/dist/src/lease/lease-store.spec.js +8 -0
- package/dist/src/lease/lease-store.spec.js.map +1 -0
- package/dist/src/lease/rack-dispatch.d.ts +105 -0
- package/dist/src/lease/rack-dispatch.d.ts.map +1 -0
- package/dist/src/lease/rack-dispatch.js +6 -0
- package/dist/src/lease/rack-dispatch.js.map +1 -0
- package/dist/src/mutation-queue.d.ts +13 -0
- package/dist/src/mutation-queue.d.ts.map +1 -0
- package/dist/src/mutation-queue.js +17 -0
- package/dist/src/mutation-queue.js.map +1 -0
- package/dist/src/paths.d.ts +56 -0
- package/dist/src/paths.d.ts.map +1 -0
- package/dist/src/paths.js +82 -0
- package/dist/src/paths.js.map +1 -0
- package/dist/src/protocol/control.d.ts +295 -0
- package/dist/src/protocol/control.d.ts.map +1 -0
- package/dist/src/protocol/control.js +74 -0
- package/dist/src/protocol/control.js.map +1 -0
- package/dist/src/protocol/index.d.ts +9 -0
- package/dist/src/protocol/index.d.ts.map +1 -0
- package/dist/src/protocol/index.js +9 -0
- package/dist/src/protocol/index.js.map +1 -0
- package/dist/src/protocol/rack-wire.d.ts +357 -0
- package/dist/src/protocol/rack-wire.d.ts.map +1 -0
- package/dist/src/protocol/rack-wire.js +262 -0
- package/dist/src/protocol/rack-wire.js.map +1 -0
- package/dist/src/protocol/rack-wire.spec.d.ts +6 -0
- package/dist/src/protocol/rack-wire.spec.d.ts.map +1 -0
- package/dist/src/protocol/rack-wire.spec.js +14 -0
- package/dist/src/protocol/rack-wire.spec.js.map +1 -0
- package/dist/src/protocol/registration.d.ts +70 -0
- package/dist/src/protocol/registration.d.ts.map +1 -0
- package/dist/src/protocol/registration.js +67 -0
- package/dist/src/protocol/registration.js.map +1 -0
- package/dist/src/protocol/session-data.d.ts +69 -0
- package/dist/src/protocol/session-data.d.ts.map +1 -0
- package/dist/src/protocol/session-data.js +26 -0
- package/dist/src/protocol/session-data.js.map +1 -0
- package/dist/src/protocol/task-envelope.d.ts +198 -0
- package/dist/src/protocol/task-envelope.d.ts.map +1 -0
- package/dist/src/protocol/task-envelope.js +93 -0
- package/dist/src/protocol/task-envelope.js.map +1 -0
- package/dist/src/protocol/wire-golden.d.ts +8 -0
- package/dist/src/protocol/wire-golden.d.ts.map +1 -0
- package/dist/src/protocol/wire-golden.js +34 -0
- package/dist/src/protocol/wire-golden.js.map +1 -0
- package/dist/src/protocol/wire-samples.d.ts +11 -0
- package/dist/src/protocol/wire-samples.d.ts.map +1 -0
- package/dist/src/protocol/wire-samples.js +52 -0
- package/dist/src/protocol/wire-samples.js.map +1 -0
- package/dist/src/registry/file-rack-registry.d.ts +68 -0
- package/dist/src/registry/file-rack-registry.d.ts.map +1 -0
- package/dist/src/registry/file-rack-registry.js +138 -0
- package/dist/src/registry/file-rack-registry.js.map +1 -0
- package/dist/src/registry/file-rack-registry.spec.d.ts +6 -0
- package/dist/src/registry/file-rack-registry.spec.d.ts.map +1 -0
- package/dist/src/registry/file-rack-registry.spec.js +50 -0
- package/dist/src/registry/file-rack-registry.spec.js.map +1 -0
- package/dist/src/registry/rack-registry.d.ts +64 -0
- package/dist/src/registry/rack-registry.d.ts.map +1 -0
- package/dist/src/registry/rack-registry.js +65 -0
- package/dist/src/registry/rack-registry.js.map +1 -0
- package/dist/src/registry/rack-registry.spec.d.ts +6 -0
- package/dist/src/registry/rack-registry.spec.d.ts.map +1 -0
- package/dist/src/registry/rack-registry.spec.js +8 -0
- package/dist/src/registry/rack-registry.spec.js.map +1 -0
- package/dist/src/routing/eligibility.d.ts +38 -0
- package/dist/src/routing/eligibility.d.ts.map +1 -0
- package/dist/src/routing/eligibility.js +78 -0
- package/dist/src/routing/eligibility.js.map +1 -0
- package/dist/src/routing/host-coupling.d.ts +26 -0
- package/dist/src/routing/host-coupling.d.ts.map +1 -0
- package/dist/src/routing/host-coupling.js +62 -0
- package/dist/src/routing/host-coupling.js.map +1 -0
- package/dist/src/routing/policy.d.ts +188 -0
- package/dist/src/routing/policy.d.ts.map +1 -0
- package/dist/src/routing/policy.js +212 -0
- package/dist/src/routing/policy.js.map +1 -0
- package/dist/src/routing/routing.spec.d.ts +6 -0
- package/dist/src/routing/routing.spec.d.ts.map +1 -0
- package/dist/src/routing/routing.spec.js +100 -0
- package/dist/src/routing/routing.spec.js.map +1 -0
- package/dist/src/routing/tiers.d.ts +22 -0
- package/dist/src/routing/tiers.d.ts.map +1 -0
- package/dist/src/routing/tiers.js +26 -0
- package/dist/src/routing/tiers.js.map +1 -0
- package/dist/src/runner/api-server.d.ts +45 -0
- package/dist/src/runner/api-server.d.ts.map +1 -0
- package/dist/src/runner/api-server.js +21 -0
- package/dist/src/runner/api-server.js.map +1 -0
- package/dist/src/runner/capacity.d.ts +13 -0
- package/dist/src/runner/capacity.d.ts.map +1 -0
- package/dist/src/runner/capacity.js +18 -0
- package/dist/src/runner/capacity.js.map +1 -0
- package/dist/src/runner/rack-body.d.ts +43 -0
- package/dist/src/runner/rack-body.d.ts.map +1 -0
- package/dist/src/runner/rack-body.js +208 -0
- package/dist/src/runner/rack-body.js.map +1 -0
- package/dist/src/runner/rack-runner.d.ts +62 -0
- package/dist/src/runner/rack-runner.d.ts.map +1 -0
- package/dist/src/runner/rack-runner.js +75 -0
- package/dist/src/runner/rack-runner.js.map +1 -0
- package/dist/src/runner/rack-runner.spec.d.ts +6 -0
- package/dist/src/runner/rack-runner.spec.d.ts.map +1 -0
- package/dist/src/runner/rack-runner.spec.js +302 -0
- package/dist/src/runner/rack-runner.spec.js.map +1 -0
- package/dist/src/runner/split.spec.d.ts +6 -0
- package/dist/src/runner/split.spec.d.ts.map +1 -0
- package/dist/src/runner/split.spec.js +188 -0
- package/dist/src/runner/split.spec.js.map +1 -0
- package/dist/src/runner-event.d.ts +261 -0
- package/dist/src/runner-event.d.ts.map +1 -0
- package/dist/src/runner-event.js +332 -0
- package/dist/src/runner-event.js.map +1 -0
- package/dist/src/server/beast2.d.ts +19 -0
- package/dist/src/server/beast2.d.ts.map +1 -0
- package/dist/src/server/beast2.js +18 -0
- package/dist/src/server/beast2.js.map +1 -0
- package/dist/src/server/body-limit.d.ts +16 -0
- package/dist/src/server/body-limit.d.ts.map +1 -0
- package/dist/src/server/body-limit.js +53 -0
- package/dist/src/server/body-limit.js.map +1 -0
- package/dist/src/server/body-limit.spec.d.ts +2 -0
- package/dist/src/server/body-limit.spec.d.ts.map +1 -0
- package/dist/src/server/body-limit.spec.js +32 -0
- package/dist/src/server/body-limit.spec.js.map +1 -0
- package/dist/src/server/bounded.d.ts +16 -0
- package/dist/src/server/bounded.d.ts.map +1 -0
- package/dist/src/server/bounded.js +39 -0
- package/dist/src/server/bounded.js.map +1 -0
- package/dist/src/server/dispatch.d.ts +137 -0
- package/dist/src/server/dispatch.d.ts.map +1 -0
- package/dist/src/server/dispatch.js +267 -0
- package/dist/src/server/dispatch.js.map +1 -0
- package/dist/src/server/env-publication.d.ts +45 -0
- package/dist/src/server/env-publication.d.ts.map +1 -0
- package/dist/src/server/env-publication.js +10 -0
- package/dist/src/server/env-publication.js.map +1 -0
- package/dist/src/server/index.d.ts +16 -0
- package/dist/src/server/index.d.ts.map +1 -0
- package/dist/src/server/index.js +17 -0
- package/dist/src/server/index.js.map +1 -0
- package/dist/src/server/protocol.spec.d.ts +6 -0
- package/dist/src/server/protocol.spec.d.ts.map +1 -0
- package/dist/src/server/protocol.spec.js +78 -0
- package/dist/src/server/protocol.spec.js.map +1 -0
- package/dist/src/server/rack-routes.d.ts +175 -0
- package/dist/src/server/rack-routes.d.ts.map +1 -0
- package/dist/src/server/rack-routes.js +755 -0
- package/dist/src/server/rack-routes.js.map +1 -0
- package/dist/src/server/rack-routes.spec.d.ts +6 -0
- package/dist/src/server/rack-routes.spec.d.ts.map +1 -0
- package/dist/src/server/rack-routes.spec.js +477 -0
- package/dist/src/server/rack-routes.spec.js.map +1 -0
- package/dist/src/server/storage-bridge.d.ts +140 -0
- package/dist/src/server/storage-bridge.d.ts.map +1 -0
- package/dist/src/server/storage-bridge.js +6 -0
- package/dist/src/server/storage-bridge.js.map +1 -0
- package/dist/src/state-file.d.ts +10 -0
- package/dist/src/state-file.d.ts.map +1 -0
- package/dist/src/state-file.js +38 -0
- package/dist/src/state-file.js.map +1 -0
- package/dist/src/testing/in-memory.d.ts +116 -0
- package/dist/src/testing/in-memory.d.ts.map +1 -0
- package/dist/src/testing/in-memory.js +193 -0
- package/dist/src/testing/in-memory.js.map +1 -0
- package/dist/src/testing/index.d.ts +14 -0
- package/dist/src/testing/index.d.ts.map +1 -0
- package/dist/src/testing/index.js +14 -0
- package/dist/src/testing/index.js.map +1 -0
- package/dist/src/testing/lease-store-contract.d.ts +14 -0
- package/dist/src/testing/lease-store-contract.d.ts.map +1 -0
- package/dist/src/testing/lease-store-contract.js +78 -0
- package/dist/src/testing/lease-store-contract.js.map +1 -0
- package/dist/src/testing/protocol-suite.d.ts +38 -0
- package/dist/src/testing/protocol-suite.d.ts.map +1 -0
- package/dist/src/testing/protocol-suite.js +207 -0
- package/dist/src/testing/protocol-suite.js.map +1 -0
- package/dist/src/testing/rack-registry-contract.d.ts +15 -0
- package/dist/src/testing/rack-registry-contract.d.ts.map +1 -0
- package/dist/src/testing/rack-registry-contract.js +106 -0
- package/dist/src/testing/rack-registry-contract.js.map +1 -0
- package/dist/src/testing/test-rack-agent.d.ts +121 -0
- package/dist/src/testing/test-rack-agent.d.ts.map +1 -0
- package/dist/src/testing/test-rack-agent.js +316 -0
- package/dist/src/testing/test-rack-agent.js.map +1 -0
- package/dist/src/tls/tls.d.ts +67 -0
- package/dist/src/tls/tls.d.ts.map +1 -0
- package/dist/src/tls/tls.js +200 -0
- package/dist/src/tls/tls.js.map +1 -0
- package/dist/src/tls/tls.spec.d.ts +6 -0
- package/dist/src/tls/tls.spec.d.ts.map +1 -0
- package/dist/src/tls/tls.spec.js +101 -0
- package/dist/src/tls/tls.spec.js.map +1 -0
- package/dist/src/version.d.ts +9 -0
- package/dist/src/version.d.ts.map +1 -0
- package/dist/src/version.js +10 -0
- package/dist/src/version.js.map +1 -0
- package/package.json +67 -7
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
import { type RackHeartbeatRequest, type RackRegistration } from '../protocol/index.js';
|
|
6
|
+
import type { RackDispatch, RackLease } from '../lease/rack-dispatch.js';
|
|
7
|
+
import { type RackLeaseRecord, type RackLeaseStore } from '../lease/lease-store.js';
|
|
8
|
+
import type { RackRegistry } from '../registry/rack-registry.js';
|
|
9
|
+
import { type RackLeaseEvent } from '../protocol/task-envelope.js';
|
|
10
|
+
import type { EnvIndexStore } from './env-publication.js';
|
|
11
|
+
import type { RackStorageBridge } from './storage-bridge.js';
|
|
12
|
+
import { type LeaseCoordinator } from '../lease/coordinator.js';
|
|
13
|
+
/**
|
|
14
|
+
* Whether a registration's latest boot lacks approval (D12 start
|
|
15
|
+
* approval): the reported and approved boot ids differ. Both-none is NOT
|
|
16
|
+
* pending — a freshly enrolled rack adopts its first boot on first
|
|
17
|
+
* heartbeat. Enrollment is unhealthy until that heartbeat authorizes work.
|
|
18
|
+
* @param registration - The rack's registration
|
|
19
|
+
* @returns Whether its latest boot awaits approval
|
|
20
|
+
* @example
|
|
21
|
+
* const quarantined = policy.requireStartApproval && bootPendingApproval(rack);
|
|
22
|
+
*/
|
|
23
|
+
export declare function bootPendingApproval(registration: RackRegistration): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* What a lease that ends while a rack holds it leaves (#214): its attempt's
|
|
26
|
+
* record, and the uncatalogued versions of the keys it was issued.
|
|
27
|
+
*/
|
|
28
|
+
export interface RackLeaseEndings {
|
|
29
|
+
/** Where its attempt's record goes: `interrupted` or `cancelled` */
|
|
30
|
+
readonly stopped: (record: RackLeaseRecord, how: 'interrupted' | 'cancelled', cause: string) => Promise<void>;
|
|
31
|
+
/** Discards the versions it wrote and never committed */
|
|
32
|
+
readonly writes?: Pick<RackStorageBridge, 'discardWrites'>;
|
|
33
|
+
}
|
|
34
|
+
/** Runtime collaborators of the shared dispatcher. */
|
|
35
|
+
export interface StoreRackDispatchOptions {
|
|
36
|
+
/** Shares the routes' fence for transitions and their repository effects. */
|
|
37
|
+
coordinator?: LeaseCoordinator;
|
|
38
|
+
/** Clock for health and visibility. */
|
|
39
|
+
now?: () => number;
|
|
40
|
+
/** How stale a heartbeat may be before a rack stops counting as healthy. */
|
|
41
|
+
healthyWindowMs?: number;
|
|
42
|
+
/** Visibility window granted on claim (and per extension). */
|
|
43
|
+
visibilityMs?: number;
|
|
44
|
+
/** Published-env index — env/custom delegation is disabled without it
|
|
45
|
+
* (env tasks fall back to cloud). #94 Slice D. */
|
|
46
|
+
envIndex?: EnvIndexStore;
|
|
47
|
+
/** The deployment's e3 version (selects the published env build). */
|
|
48
|
+
e3Version?: string;
|
|
49
|
+
/** What a lease superseded or cancelled while claimed leaves (#214):
|
|
50
|
+
* absent, nothing is recorded or discarded, as a function lease writes
|
|
51
|
+
* nothing */
|
|
52
|
+
endings?: RackLeaseEndings;
|
|
53
|
+
}
|
|
54
|
+
/** Three missed heartbeats make a rack unavailable for new work. */
|
|
55
|
+
export declare const DEFAULT_HEALTHY_WINDOW_MS = 45000;
|
|
56
|
+
/** Visibility granted by a claim or extension. */
|
|
57
|
+
export declare const DEFAULT_VISIBILITY_MS = 60000;
|
|
58
|
+
/**
|
|
59
|
+
* Capacity advertised by a heartbeat: occupied plus free slots while ready,
|
|
60
|
+
* zero while fenced, draining or unhealthy. Busy workers remain available.
|
|
61
|
+
* @param heartbeat - Decoded machine heartbeat
|
|
62
|
+
* @returns Effective concurrent capacity, safe for the scheduler's number arithmetic
|
|
63
|
+
* @throws If slot counts are negative, unsafe, or contain duplicate lease references
|
|
64
|
+
* @example
|
|
65
|
+
* const capacity = heartbeatCapacity(heartbeat);
|
|
66
|
+
*/
|
|
67
|
+
export declare function heartbeatCapacity(heartbeat: RackHeartbeatRequest): bigint;
|
|
68
|
+
export { LEASE_MIN_AGENT, agentVersionAtLeast } from '../protocol/index.js';
|
|
69
|
+
/**
|
|
70
|
+
* Why an agent is refused leases, or null when it is leased work: an agent
|
|
71
|
+
* older than {@link LEASE_MIN_AGENT}.
|
|
72
|
+
*
|
|
73
|
+
* @param agentVersion - The agent build its registration reports
|
|
74
|
+
* @returns The refusal, naming the upgrade, or null
|
|
75
|
+
*/
|
|
76
|
+
export declare function leaseRefusal(agentVersion: string): string | null;
|
|
77
|
+
/**
|
|
78
|
+
* Dispatches rack work through the shared registry and lease state machine.
|
|
79
|
+
* @example
|
|
80
|
+
* const dispatch = new StoreRackDispatch(leases, registry);
|
|
81
|
+
*/
|
|
82
|
+
export declare class StoreRackDispatch implements RackDispatch {
|
|
83
|
+
private readonly leases;
|
|
84
|
+
private readonly settings;
|
|
85
|
+
private readonly now;
|
|
86
|
+
private readonly healthyWindowMs;
|
|
87
|
+
private readonly visibilityMs;
|
|
88
|
+
private readonly envIndex?;
|
|
89
|
+
private readonly e3Version?;
|
|
90
|
+
private readonly endings?;
|
|
91
|
+
private readonly held;
|
|
92
|
+
private readonly coordinator;
|
|
93
|
+
/**
|
|
94
|
+
* @param leases - Lease persistence
|
|
95
|
+
* @param settings - Enrolled machines and security policy
|
|
96
|
+
* @param options - Clocks, visibility and callbacks for stopped attempts
|
|
97
|
+
*/
|
|
98
|
+
constructor(leases: RackLeaseStore, settings: RackRegistry, options?: StoreRackDispatchOptions);
|
|
99
|
+
anyHealthyRackWithTier(tier: string): Promise<boolean>;
|
|
100
|
+
/**
|
|
101
|
+
* Lists healthy, approved, compatible racks matching an optional tier/floor.
|
|
102
|
+
* @param filter - Required tier and minimum bundled e3 release
|
|
103
|
+
* @returns Matching registrations
|
|
104
|
+
*/
|
|
105
|
+
listHealthyRacks(filter?: {
|
|
106
|
+
tier?: string;
|
|
107
|
+
minBundledE3?: string;
|
|
108
|
+
}): Promise<RackRegistration[]>;
|
|
109
|
+
envBaseTier(envHash: string): Promise<string | null>;
|
|
110
|
+
findLease(repo: string, taskHash: string, inputsHash: string): Promise<RackLease | null>;
|
|
111
|
+
createLease(event: RackLeaseEvent, tier: string, computeSize?: string): Promise<RackLease>;
|
|
112
|
+
getLease(repo: string, leaseId: string): Promise<RackLease | null>;
|
|
113
|
+
supersede(repo: string, leaseId: string): Promise<RackLease | null>;
|
|
114
|
+
cancel(repo: string, leaseId: string): Promise<RackLease | null>;
|
|
115
|
+
leaseHeld(repo: string, leaseId: string): Promise<boolean>;
|
|
116
|
+
/**
|
|
117
|
+
* What a lease that ended while a rack held it leaves: its attempt recorded
|
|
118
|
+
* as it ended, when it recorded no outcome, and the versions it wrote and
|
|
119
|
+
* never committed discarded. Neither fails the transition, which stands.
|
|
120
|
+
*/
|
|
121
|
+
private ended;
|
|
122
|
+
/**
|
|
123
|
+
* Map a stored record to the runner's seam view, deriving visibility
|
|
124
|
+
* expiry: expired-claimed reads as `pending` for one reclaim window,
|
|
125
|
+
* then as lost (`null`).
|
|
126
|
+
*/
|
|
127
|
+
private toLease;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Reads the bundled e3 release from an agent's semver build metadata.
|
|
131
|
+
* @param agentVersion - An agent version such as 0.5.0+e3.1.0.85
|
|
132
|
+
* @returns Its e3 version, or null when absent/malformed
|
|
133
|
+
* @example
|
|
134
|
+
* bundledE3Version('0.5.0+e3.1.0.85'); // '1.0.85'
|
|
135
|
+
*/
|
|
136
|
+
export declare function bundledE3Version(agentVersion: string): string | null;
|
|
137
|
+
//# sourceMappingURL=dispatch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../../../src/server/dispatch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* StoreRackDispatch (#73) — the real {@link RackDispatch} the
|
|
7
|
+
* DelegatingTaskRunner drives, layered on the lease store + rack registry.
|
|
8
|
+
*
|
|
9
|
+
* Status derivation for the runner's view:
|
|
10
|
+
* - a `claimed` lease past its visibility deadline is reported `pending`
|
|
11
|
+
* for one reclaim window (another agent may retake it), then `null`
|
|
12
|
+
* (lost) — which makes the runner supersede and fall back to cloud;
|
|
13
|
+
* - everything else passes through.
|
|
14
|
+
*
|
|
15
|
+
* Rack health for `anyHealthyRackWithTier` is heartbeat freshness: the
|
|
16
|
+
* stored `healthy` flag AND `lastSeenAt` within the healthy window (a rack
|
|
17
|
+
* that stops heartbeating fails safe — it just stops receiving work), and an
|
|
18
|
+
* agent that runs a v2 lease ({@link LEASE_MIN_AGENT}).
|
|
19
|
+
*
|
|
20
|
+
* A lease superseded or cancelled while a rack held it leaves its attempt
|
|
21
|
+
* recorded (`interrupted`, `cancelled`) and what it wrote and never committed
|
|
22
|
+
* discarded (#214), through {@link StoreRackDispatchOptions.endings}.
|
|
23
|
+
*/
|
|
24
|
+
import { inputsHash as computeInputsHash } from '@elaraai/e3-core';
|
|
25
|
+
import { IntegerType, OptionType, StringType, compareFor, equalFor } from '@elaraai/east';
|
|
26
|
+
import { LEASE_MIN_AGENT, agentVersionAtLeast } from '../protocol/index.js';
|
|
27
|
+
import { makeLeaseId, rackLeaseHeld, } from '../lease/lease-store.js';
|
|
28
|
+
import { leaseInputs, leaseRun, leaseTaskHash } from '../protocol/task-envelope.js';
|
|
29
|
+
import { backendLeaseCoordinator } from '../lease/coordinator.js';
|
|
30
|
+
/**
|
|
31
|
+
* Whether a registration's latest boot lacks approval (D12 start
|
|
32
|
+
* approval): the reported and approved boot ids differ. Both-none is NOT
|
|
33
|
+
* pending — a freshly enrolled rack adopts its first boot on first
|
|
34
|
+
* heartbeat. Enrollment is unhealthy until that heartbeat authorizes work.
|
|
35
|
+
* @param registration - The rack's registration
|
|
36
|
+
* @returns Whether its latest boot awaits approval
|
|
37
|
+
* @example
|
|
38
|
+
* const quarantined = policy.requireStartApproval && bootPendingApproval(rack);
|
|
39
|
+
*/
|
|
40
|
+
export function bootPendingApproval(registration) {
|
|
41
|
+
const { lastBootId, approvedBootId } = registration;
|
|
42
|
+
return !equalFor(OptionType(StringType))(lastBootId, approvedBootId);
|
|
43
|
+
}
|
|
44
|
+
/** Three missed heartbeats make a rack unavailable for new work. */
|
|
45
|
+
export const DEFAULT_HEALTHY_WINDOW_MS = 45_000;
|
|
46
|
+
/** Visibility granted by a claim or extension. */
|
|
47
|
+
export const DEFAULT_VISIBILITY_MS = 60_000;
|
|
48
|
+
/**
|
|
49
|
+
* Capacity advertised by a heartbeat: occupied plus free slots while ready,
|
|
50
|
+
* zero while fenced, draining or unhealthy. Busy workers remain available.
|
|
51
|
+
* @param heartbeat - Decoded machine heartbeat
|
|
52
|
+
* @returns Effective concurrent capacity, safe for the scheduler's number arithmetic
|
|
53
|
+
* @throws If slot counts are negative, unsafe, or contain duplicate lease references
|
|
54
|
+
* @example
|
|
55
|
+
* const capacity = heartbeatCapacity(heartbeat);
|
|
56
|
+
*/
|
|
57
|
+
export function heartbeatCapacity(heartbeat) {
|
|
58
|
+
const capacity = heartbeat.freeCapacity + BigInt(heartbeat.runningLeases.length);
|
|
59
|
+
if (heartbeat.freeCapacity < 0n || capacity > BigInt(Number.MAX_SAFE_INTEGER))
|
|
60
|
+
throw new Error('Invalid capacity');
|
|
61
|
+
const seen = new Map();
|
|
62
|
+
for (const { repo, leaseId } of heartbeat.runningLeases) {
|
|
63
|
+
const leases = seen.get(repo) ?? new Set();
|
|
64
|
+
if (leases.has(leaseId))
|
|
65
|
+
throw new Error('Duplicate running lease');
|
|
66
|
+
leases.add(leaseId);
|
|
67
|
+
seen.set(repo, leases);
|
|
68
|
+
}
|
|
69
|
+
return heartbeat.healthy ? capacity : 0n;
|
|
70
|
+
}
|
|
71
|
+
// The oldest agent the cloud leases work to (#214) is part of the rack
|
|
72
|
+
// protocol: e3-cloud-types', where the agent and the suites read it too
|
|
73
|
+
export { LEASE_MIN_AGENT, agentVersionAtLeast } from '../protocol/index.js';
|
|
74
|
+
/**
|
|
75
|
+
* Why an agent is refused leases, or null when it is leased work: an agent
|
|
76
|
+
* older than {@link LEASE_MIN_AGENT}.
|
|
77
|
+
*
|
|
78
|
+
* @param agentVersion - The agent build its registration reports
|
|
79
|
+
* @returns The refusal, naming the upgrade, or null
|
|
80
|
+
*/
|
|
81
|
+
export function leaseRefusal(agentVersion) {
|
|
82
|
+
if (agentVersionAtLeast(agentVersion, LEASE_MIN_AGENT))
|
|
83
|
+
return null;
|
|
84
|
+
return `this rack's agent (${agentVersion}) is older than ${LEASE_MIN_AGENT}, the oldest this deployment leases work to: ` +
|
|
85
|
+
`its guest cannot run e3-core's own execution (elaraai/e3-cloud#214). Upgrade it to rack-v${LEASE_MIN_AGENT} or later ` +
|
|
86
|
+
'(download the release and re-run `e3-rack install --api-url …`); until then its work runs in the cloud';
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Dispatches rack work through the shared registry and lease state machine.
|
|
90
|
+
* @example
|
|
91
|
+
* const dispatch = new StoreRackDispatch(leases, registry);
|
|
92
|
+
*/
|
|
93
|
+
export class StoreRackDispatch {
|
|
94
|
+
leases;
|
|
95
|
+
settings;
|
|
96
|
+
now;
|
|
97
|
+
healthyWindowMs;
|
|
98
|
+
visibilityMs;
|
|
99
|
+
envIndex;
|
|
100
|
+
e3Version;
|
|
101
|
+
endings;
|
|
102
|
+
held;
|
|
103
|
+
coordinator;
|
|
104
|
+
/**
|
|
105
|
+
* @param leases - Lease persistence
|
|
106
|
+
* @param settings - Enrolled machines and security policy
|
|
107
|
+
* @param options - Clocks, visibility and callbacks for stopped attempts
|
|
108
|
+
*/
|
|
109
|
+
constructor(leases, settings, options) {
|
|
110
|
+
this.leases = leases;
|
|
111
|
+
this.settings = settings;
|
|
112
|
+
this.now = options?.now ?? Date.now;
|
|
113
|
+
this.healthyWindowMs = options?.healthyWindowMs ?? DEFAULT_HEALTHY_WINDOW_MS;
|
|
114
|
+
this.visibilityMs = options?.visibilityMs ?? DEFAULT_VISIBILITY_MS;
|
|
115
|
+
this.envIndex = options?.envIndex;
|
|
116
|
+
this.e3Version = options?.e3Version;
|
|
117
|
+
this.endings = options?.endings;
|
|
118
|
+
this.held = rackLeaseHeld(leases, this.now);
|
|
119
|
+
this.coordinator = options?.coordinator ?? backendLeaseCoordinator;
|
|
120
|
+
}
|
|
121
|
+
async anyHealthyRackWithTier(tier) {
|
|
122
|
+
return (await this.listHealthyRacks({ tier })).length > 0;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Lists healthy, approved, compatible racks matching an optional tier/floor.
|
|
126
|
+
* @param filter - Required tier and minimum bundled e3 release
|
|
127
|
+
* @returns Matching registrations
|
|
128
|
+
*/
|
|
129
|
+
async listHealthyRacks(filter = {}) {
|
|
130
|
+
const cutoff = this.now() - this.healthyWindowMs;
|
|
131
|
+
const [racks, security] = await Promise.all([
|
|
132
|
+
this.settings.listRacks(),
|
|
133
|
+
this.settings.getRackSecurityPolicy(),
|
|
134
|
+
]);
|
|
135
|
+
// Quarantined boots (D12 start approval) don't count as available —
|
|
136
|
+
// otherwise the runner would route work at a rack whose lease poll is
|
|
137
|
+
// answered 204, and every such task would ride the fallback timeout.
|
|
138
|
+
const requireApproval = security?.requireStartApproval === true;
|
|
139
|
+
return racks.filter((rack) => rack.healthy &&
|
|
140
|
+
compareFor(IntegerType)(rack.capacity, 0n) > 0 &&
|
|
141
|
+
rack.lastSeenAt.getTime() >= cutoff &&
|
|
142
|
+
(filter.tier === undefined || rack.tiers.includes(filter.tier)) &&
|
|
143
|
+
!(requireApproval && bootPendingApproval(rack)) &&
|
|
144
|
+
// #214: only an agent that runs a v2 lease is leased work
|
|
145
|
+
agentVersionAtLeast(rack.agentVersion, LEASE_MIN_AGENT) &&
|
|
146
|
+
(filter.minBundledE3 === undefined || (bundledE3Version(rack.agentVersion) !== null &&
|
|
147
|
+
agentVersionAtLeast(bundledE3Version(rack.agentVersion), filter.minBundledE3))));
|
|
148
|
+
}
|
|
149
|
+
async envBaseTier(envHash) {
|
|
150
|
+
if (this.envIndex === undefined || this.e3Version === undefined)
|
|
151
|
+
return null;
|
|
152
|
+
const record = await this.envIndex.get(envHash, this.e3Version);
|
|
153
|
+
return record?.baseTier ?? null;
|
|
154
|
+
}
|
|
155
|
+
async findLease(repo, taskHash, inputsHash) {
|
|
156
|
+
const record = await this.leases.findByTask(repo, taskHash, inputsHash);
|
|
157
|
+
return record === null ? null : this.toLease(record);
|
|
158
|
+
}
|
|
159
|
+
async createLease(event, tier, computeSize) {
|
|
160
|
+
const taskHash = leaseTaskHash(event);
|
|
161
|
+
const inputsHash = computeInputsHash(leaseInputs(event));
|
|
162
|
+
const record = {
|
|
163
|
+
leaseId: makeLeaseId(taskHash, inputsHash),
|
|
164
|
+
repo: event.runnerEvent.repo,
|
|
165
|
+
workspace: event.workspace,
|
|
166
|
+
taskHash,
|
|
167
|
+
inputsHash,
|
|
168
|
+
tier,
|
|
169
|
+
...(computeSize !== undefined ? { computeSize } : {}),
|
|
170
|
+
status: 'pending',
|
|
171
|
+
event,
|
|
172
|
+
createdAtMs: this.now(),
|
|
173
|
+
};
|
|
174
|
+
await this.leases.put(record);
|
|
175
|
+
return this.toLease(record);
|
|
176
|
+
}
|
|
177
|
+
async getLease(repo, leaseId) {
|
|
178
|
+
const record = await this.leases.get(repo, leaseId);
|
|
179
|
+
return record === null ? null : this.toLease(record);
|
|
180
|
+
}
|
|
181
|
+
async supersede(repo, leaseId) {
|
|
182
|
+
return this.coordinator.run(repo, leaseId, async () => {
|
|
183
|
+
const record = await this.leases.supersede(repo, leaseId);
|
|
184
|
+
if (record?.status === 'superseded') {
|
|
185
|
+
await this.ended(record, 'interrupted', 'its rack lease was superseded before the rack recorded an outcome: the work falls back to its originating host');
|
|
186
|
+
}
|
|
187
|
+
return record === null ? null : this.toLease(record);
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
async cancel(repo, leaseId) {
|
|
191
|
+
return this.coordinator.run(repo, leaseId, async () => {
|
|
192
|
+
const record = await this.leases.cancel(repo, leaseId);
|
|
193
|
+
if (record?.status === 'cancelled')
|
|
194
|
+
await this.ended(record, 'cancelled', 'its run was cancelled, so its rack lease was cancelled');
|
|
195
|
+
return record === null ? null : this.toLease(record);
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
leaseHeld(repo, leaseId) {
|
|
199
|
+
return this.held(repo, leaseId);
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* What a lease that ended while a rack held it leaves: its attempt recorded
|
|
203
|
+
* as it ended, when it recorded no outcome, and the versions it wrote and
|
|
204
|
+
* never committed discarded. Neither fails the transition, which stands.
|
|
205
|
+
*/
|
|
206
|
+
async ended(record, how, cause) {
|
|
207
|
+
const endings = this.endings;
|
|
208
|
+
if (endings === undefined)
|
|
209
|
+
return;
|
|
210
|
+
if (record.attempt !== undefined) {
|
|
211
|
+
await endings.stopped(record, how, cause).catch((err) => {
|
|
212
|
+
console.warn(`rack lease ${record.leaseId}: its attempt ${record.attempt.executionId} was not recorded ${how}: ${messageOf(err)}`);
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
if (endings.writes !== undefined && (record.targets?.length ?? 0) > 0) {
|
|
216
|
+
await endings.writes.discardWrites(record.repo, record.leaseId, record.targets).catch((err) => {
|
|
217
|
+
console.warn(`rack lease ${record.leaseId}: the versions it wrote were not discarded: ${messageOf(err)}`);
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Map a stored record to the runner's seam view, deriving visibility
|
|
223
|
+
* expiry: expired-claimed reads as `pending` for one reclaim window,
|
|
224
|
+
* then as lost (`null`).
|
|
225
|
+
*/
|
|
226
|
+
toLease(record) {
|
|
227
|
+
let status = record.status;
|
|
228
|
+
if (record.status === 'claimed' && record.visibilityDeadlineMs !== undefined) {
|
|
229
|
+
const now = this.now();
|
|
230
|
+
if (record.visibilityDeadlineMs + this.visibilityMs < now) {
|
|
231
|
+
return null; // claimant gone and nobody retook it — lost
|
|
232
|
+
}
|
|
233
|
+
if (record.visibilityDeadlineMs < now) {
|
|
234
|
+
status = 'pending'; // reclaim window: another agent may take it
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
const runId = leaseRun(record.event)?.id;
|
|
238
|
+
return {
|
|
239
|
+
leaseId: record.leaseId,
|
|
240
|
+
repo: record.repo,
|
|
241
|
+
workspace: record.workspace,
|
|
242
|
+
taskHash: record.taskHash,
|
|
243
|
+
inputsHash: record.inputsHash,
|
|
244
|
+
...(runId !== undefined ? { runId } : {}),
|
|
245
|
+
tier: record.tier,
|
|
246
|
+
computeSize: record.computeSize ?? 'serverless',
|
|
247
|
+
status,
|
|
248
|
+
...(record.claimedBy !== undefined ? { claimedBy: record.claimedBy } : {}),
|
|
249
|
+
...(record.attempt !== undefined ? { attempt: record.attempt } : {}),
|
|
250
|
+
...(record.result !== undefined ? { result: record.result } : {}),
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Reads the bundled e3 release from an agent's semver build metadata.
|
|
256
|
+
* @param agentVersion - An agent version such as 0.5.0+e3.1.0.85
|
|
257
|
+
* @returns Its e3 version, or null when absent/malformed
|
|
258
|
+
* @example
|
|
259
|
+
* bundledE3Version('0.5.0+e3.1.0.85'); // '1.0.85'
|
|
260
|
+
*/
|
|
261
|
+
export function bundledE3Version(agentVersion) {
|
|
262
|
+
return /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?\+e3\.(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)$/.exec(agentVersion)?.[1] ?? null;
|
|
263
|
+
}
|
|
264
|
+
function messageOf(err) {
|
|
265
|
+
return err instanceof Error ? err.message : String(err);
|
|
266
|
+
}
|
|
267
|
+
//# sourceMappingURL=dispatch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatch.js","sourceRoot":"","sources":["../../../src/server/dispatch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
/** One OCI layer of a published environment. */
|
|
6
|
+
export interface EnvLayerDescriptor {
|
|
7
|
+
/** Registry digest (`sha256:…`) — the content address of the blob. */
|
|
8
|
+
digest: string;
|
|
9
|
+
sizeBytes: number;
|
|
10
|
+
mediaType: string;
|
|
11
|
+
}
|
|
12
|
+
/** The manifest published beside the layer blobs (JSON, small). */
|
|
13
|
+
export interface EnvLayerManifest {
|
|
14
|
+
envHash: string;
|
|
15
|
+
e3Version: string;
|
|
16
|
+
/** The tier base image ref the env was built FROM. */
|
|
17
|
+
baseImage: string;
|
|
18
|
+
/** The rack tier vocabulary word derived from the base image. */
|
|
19
|
+
baseTier: string;
|
|
20
|
+
/** The env's OWN layers (delta above the base), in application order. */
|
|
21
|
+
layers: EnvLayerDescriptor[];
|
|
22
|
+
}
|
|
23
|
+
/** Cloud-side "this env is rack-fetchable" record (NEW row key — stored
|
|
24
|
+
* structs cannot grow fields, so this is its own kind). */
|
|
25
|
+
export interface EnvIndexRecord {
|
|
26
|
+
envHash: string;
|
|
27
|
+
e3Version: string;
|
|
28
|
+
baseImage: string;
|
|
29
|
+
baseTier: string;
|
|
30
|
+
/** Object key of the manifest in the data bucket. */
|
|
31
|
+
manifestKey: string;
|
|
32
|
+
layerCount: number;
|
|
33
|
+
publishedAtMs: number;
|
|
34
|
+
}
|
|
35
|
+
/** Finds environment publications compatible with a runtime release. */
|
|
36
|
+
export interface EnvIndexStore {
|
|
37
|
+
/** Publishes the metadata for an available environment. */
|
|
38
|
+
put(record: EnvIndexRecord): Promise<void>;
|
|
39
|
+
/** Reads one environment publication for the requested release. */
|
|
40
|
+
get(envHash: string, e3Version: string): Promise<EnvIndexRecord | null>;
|
|
41
|
+
}
|
|
42
|
+
/** Data-bucket key of a published layer blob (content-addressed, shared
|
|
43
|
+
* across envs — identical layers publish once). */
|
|
44
|
+
export declare function envLayerBlobKey(digest: string): string;
|
|
45
|
+
//# sourceMappingURL=env-publication.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-publication.d.ts","sourceRoot":"","sources":["../../../src/server/env-publication.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,gDAAgD;AAChD,MAAM,WAAW,kBAAkB;IACjC,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,mEAAmE;AACnE,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,sDAAsD;IACtD,SAAS,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,MAAM,EAAE,kBAAkB,EAAE,CAAC;CAC9B;AAED;4DAC4D;AAC5D,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,wEAAwE;AACxE,MAAM,WAAW,aAAa;IAC5B,2DAA2D;IAC3D,GAAG,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,mEAAmE;IACnE,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;CACzE;AAED;oDACoD;AACpD,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEtD"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
/** Data-bucket key of a published layer blob (content-addressed, shared
|
|
6
|
+
* across envs — identical layers publish once). */
|
|
7
|
+
export function envLayerBlobKey(digest) {
|
|
8
|
+
return `env-layers/blobs/${digest.replace(':', '-')}`;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=env-publication.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-publication.js","sourceRoot":"","sources":["../../../src/server/env-publication.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA2CH;oDACoD;AACpD,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,OAAO,oBAAoB,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC;AACxD,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
export * from '../lease/lease-store.js';
|
|
6
|
+
export * from '../lease/rack-dispatch.js';
|
|
7
|
+
export * from '../lease/coordinator.js';
|
|
8
|
+
export * from '../lease/closure.js';
|
|
9
|
+
export * from '../identity/machine-identity.js';
|
|
10
|
+
export * from '../registry/rack-registry.js';
|
|
11
|
+
export * from './dispatch.js';
|
|
12
|
+
export * from './rack-routes.js';
|
|
13
|
+
export * from './storage-bridge.js';
|
|
14
|
+
export * from './env-publication.js';
|
|
15
|
+
export * from './body-limit.js';
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iCAAiC,CAAC;AAChD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC"}
|
|
@@ -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
|
+
// Shared control-plane mechanisms without the local hub, files or task runner.
|
|
6
|
+
export * from '../lease/lease-store.js';
|
|
7
|
+
export * from '../lease/rack-dispatch.js';
|
|
8
|
+
export * from '../lease/coordinator.js';
|
|
9
|
+
export * from '../lease/closure.js';
|
|
10
|
+
export * from '../identity/machine-identity.js';
|
|
11
|
+
export * from '../registry/rack-registry.js';
|
|
12
|
+
export * from './dispatch.js';
|
|
13
|
+
export * from './rack-routes.js';
|
|
14
|
+
export * from './storage-bridge.js';
|
|
15
|
+
export * from './env-publication.js';
|
|
16
|
+
export * from './body-limit.js';
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/server/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,+EAA+E;AAC/E,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iCAAiC,CAAC;AAChD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.spec.d.ts","sourceRoot":"","sources":["../../../src/server/protocol.spec.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
import assert from 'node:assert/strict';
|
|
6
|
+
import { mkdtemp, rm } from 'node:fs/promises';
|
|
7
|
+
import { tmpdir } from 'node:os';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
import { Server } from 'node:http';
|
|
10
|
+
import { once } from 'node:events';
|
|
11
|
+
import { createAdaptorServer } from '@hono/node-server';
|
|
12
|
+
import { LocalStorage, processOwner, repoInit } from '@elaraai/e3-core';
|
|
13
|
+
import { InMemoryMachineIdentityStore, generateEnrollmentToken, InMemoryRackRegistry, InMemoryRackLeaseStore, InMemoryLeaseCoordinator, StoreRackDispatch, createRackRoutes } from '@elaraai/e3-rack';
|
|
14
|
+
import { InMemoryRackStorageBridge, RecordingLogStore, rackProtocolSuite } from '@elaraai/e3-rack/testing';
|
|
15
|
+
import { sessionAttempts } from '../client/session-attempts.js';
|
|
16
|
+
rackProtocolSuite('memory dispatch, real repository', async () => {
|
|
17
|
+
const repo = await mkdtemp(join(tmpdir(), 'e3-contract-'));
|
|
18
|
+
let server;
|
|
19
|
+
const teardown = async () => {
|
|
20
|
+
if (server?.listening)
|
|
21
|
+
await new Promise((resolve, reject) => {
|
|
22
|
+
server.close((error) => error ? reject(error) : resolve());
|
|
23
|
+
server.closeAllConnections();
|
|
24
|
+
});
|
|
25
|
+
await rm(repo, { recursive: true, force: true });
|
|
26
|
+
};
|
|
27
|
+
try {
|
|
28
|
+
assert(repoInit(repo).success);
|
|
29
|
+
let time = Date.now();
|
|
30
|
+
const now = () => time;
|
|
31
|
+
const storage = new LocalStorage();
|
|
32
|
+
const identities = new InMemoryMachineIdentityStore();
|
|
33
|
+
const registry = new InMemoryRackRegistry();
|
|
34
|
+
const leases = new InMemoryRackLeaseStore(now);
|
|
35
|
+
const bridge = new InMemoryRackStorageBridge(storage, leases);
|
|
36
|
+
const logs = new RecordingLogStore();
|
|
37
|
+
const owner = await processOwner();
|
|
38
|
+
const attempts = { ...sessionAttempts(storage, repo, () => owner), logs };
|
|
39
|
+
const coordinator = new InMemoryLeaseCoordinator();
|
|
40
|
+
const dispatch = new StoreRackDispatch(leases, registry, { now, coordinator, endings: { stopped: attempts.stopped, writes: bridge } });
|
|
41
|
+
const app = createRackRoutes(identities, registry, leases, bridge, attempts, { now, coordinator, leaseWindowMs: 20, pollIntervalMs: 5 });
|
|
42
|
+
const listener = createAdaptorServer({ fetch: app.fetch });
|
|
43
|
+
assert(listener instanceof Server);
|
|
44
|
+
server = listener;
|
|
45
|
+
server.listen(0, '127.0.0.1');
|
|
46
|
+
await once(server, 'listening');
|
|
47
|
+
const address = server.address();
|
|
48
|
+
assert(address && typeof address !== 'string');
|
|
49
|
+
const transport = async (input, init) => {
|
|
50
|
+
const url = input instanceof Request ? input.url : String(input);
|
|
51
|
+
if (!url.startsWith('mem://'))
|
|
52
|
+
return fetch(input, init);
|
|
53
|
+
const request = new Request(input, init);
|
|
54
|
+
if (request.method === 'PUT') {
|
|
55
|
+
const result = bridge.put(url, new Uint8Array(await request.arrayBuffer()), Object.fromEntries(request.headers));
|
|
56
|
+
return 'refused' in result ? new Response(result.refused, { status: 400 }) : new Response(null, { headers: { 'x-amz-version-id': result.version } });
|
|
57
|
+
}
|
|
58
|
+
const bytes = await bridge.fetch(url);
|
|
59
|
+
return bytes === null ? new Response(null, { status: 404 }) : new Response(bytes);
|
|
60
|
+
};
|
|
61
|
+
return { repo, baseUrl: `http://127.0.0.1:${address.port}`, fetch: transport, dispatch,
|
|
62
|
+
async mintEnrollmentToken() {
|
|
63
|
+
const token = generateEnrollmentToken();
|
|
64
|
+
await identities.putEnrollmentToken(token.tokenHash, new Date(time + 60000));
|
|
65
|
+
return token.token;
|
|
66
|
+
},
|
|
67
|
+
seedObject: (repo, bytes) => storage.objects.write(repo, bytes),
|
|
68
|
+
readObject: async (repo, hash) => await storage.objects.exists(repo, hash) ? storage.objects.read(repo, hash) : null,
|
|
69
|
+
readLog: async (repo, taskHash, inputsHash, executionId, stream) => logs.entries.filter((entry) => entry.repo === repo && entry.taskHash === taskHash && entry.inputsHash === inputsHash && entry.executionId === executionId && entry.stream === stream).map((entry) => entry.data).join(''),
|
|
70
|
+
advanceClock: (ms) => { time += ms; }, teardown,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
await teardown();
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
//# sourceMappingURL=protocol.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.spec.js","sourceRoot":"","sources":["../../../src/server/protocol.spec.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACnC,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,4BAA4B,EAAE,uBAAuB,EAAE,oBAAoB,EAClF,sBAAsB,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAClH,OAAO,EAAE,yBAAyB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC3G,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAEhE,iBAAiB,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;IAC/D,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,cAAc,CAAC,CAAC,CAAC;IAC3D,IAAI,MAA0B,CAAC;IAC/B,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;QAC1B,IAAI,MAAM,EAAE,SAAS;YAAE,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBACjE,MAAO,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;gBAAC,MAAO,CAAC,mBAAmB,EAAE,CAAC;YAC7F,CAAC,CAAC,CAAC;QACH,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACnD,CAAC,CAAC;IACF,IAAI,CAAC;QACH,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC;QAC/B,IAAI,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAAC,MAAM,GAAG,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC;QAC9C,MAAM,OAAO,GAAG,IAAI,YAAY,EAAE,CAAC;QAAC,MAAM,UAAU,GAAG,IAAI,4BAA4B,EAAE,CAAC;QAC1F,MAAM,QAAQ,GAAG,IAAI,oBAAoB,EAAE,CAAC;QAAC,MAAM,MAAM,GAAG,IAAI,sBAAsB,CAAC,GAAG,CAAC,CAAC;QAC5F,MAAM,MAAM,GAAG,IAAI,yBAAyB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAAC,MAAM,IAAI,GAAG,IAAI,iBAAiB,EAAE,CAAC;QACpG,MAAM,KAAK,GAAG,MAAM,YAAY,EAAE,CAAC;QAAC,MAAM,QAAQ,GAAG,EAAE,GAAG,eAAe,CAAC,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;QAC9G,MAAM,WAAW,GAAG,IAAI,wBAAwB,EAAE,CAAC;QACnD,MAAM,QAAQ,GAAG,IAAI,iBAAiB,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;QACvI,MAAM,GAAG,GAAG,gBAAgB,CAAC,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,GAAG,EAAE,WAAW,EAAE,aAAa,EAAE,EAAE,EAAE,cAAc,EAAE,CAAC,EAAE,CAAC,CAAC;QACzI,MAAM,QAAQ,GAAG,mBAAmB,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;QAAC,MAAM,CAAC,QAAQ,YAAY,MAAM,CAAC,CAAC;QAAC,MAAM,GAAG,QAAQ,CAAC;QAClH,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;QAAC,MAAM,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;QAC/D,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;QAAC,MAAM,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC;QACjF,MAAM,SAAS,GAAiB,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;YACpD,MAAM,GAAG,GAAG,KAAK,YAAY,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACjE,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC;gBAAE,OAAO,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YACzD,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YACzC,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;gBAC7B,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,UAAU,CAAC,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC,EAAE,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;gBACjH,OAAO,SAAS,IAAI,MAAM,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,kBAAkB,EAAE,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YACvJ,CAAC;YACD,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACtC,OAAO,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC;QACpF,CAAC,CAAC;QACF,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,oBAAoB,OAAO,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ;YACpF,KAAK,CAAC,mBAAmB;gBACvB,MAAM,KAAK,GAAG,uBAAuB,EAAE,CAAC;gBAAC,MAAM,UAAU,CAAC,kBAAkB,CAAC,KAAK,CAAC,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC;gBAAC,OAAO,KAAK,CAAC,KAAK,CAAC;YAC5I,CAAC;YACD,UAAU,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC;YAC/D,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,MAAM,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI;YACpH,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAChG,KAAK,CAAC,IAAI,KAAK,IAAI,IAAI,KAAK,CAAC,QAAQ,KAAK,QAAQ,IAAI,KAAK,CAAC,UAAU,KAAK,UAAU,IAAI,KAAK,CAAC,WAAW,KAAK,WAAW,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5L,YAAY,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ;SAChD,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAAC,MAAM,QAAQ,EAAE,CAAC;QAAC,MAAM,KAAK,CAAC;IAAC,CAAC;AACpD,CAAC,CAAC,CAAC"}
|