@aloud/runner 0.3.0 → 0.3.2

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/src/version.ts CHANGED
@@ -10,7 +10,62 @@
10
10
  * package.json beside it to read, and importing one into the source trips the composite build's
11
11
  * rootDir. `version.test.ts` asserts this matches, so the drift this invites cannot survive CI.
12
12
  */
13
- export const RUNNER_VERSION = "0.3.0";
13
+ export const RUNNER_VERSION = "0.3.2";
14
14
 
15
15
  /** The header the server reads it from. */
16
16
  export const RUNNER_VERSION_HEADER = "x-aloud-runner-version";
17
+
18
+ export interface RunnerVersionPolicy {
19
+ /** The oldest release that may claim new work. */
20
+ minimum: string;
21
+ /** The exact official release a start should move to when it can. */
22
+ recommended: string;
23
+ }
24
+
25
+ /** Strict because a server response eventually becomes part of an npm package specifier. */
26
+ function versionParts(value: string): [number, number, number] | null {
27
+ const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(value);
28
+ if (!match) return null;
29
+ const parts = [Number(match[1]), Number(match[2]), Number(match[3])] as [number, number, number];
30
+ return parts.every(Number.isSafeInteger) ? parts : null;
31
+ }
32
+
33
+ /** Numeric comparison, so 0.10.0 is newer than 0.9.9 rather than lexicographically smaller. */
34
+ export function compareRunnerVersions(left: string, right: string): number | null {
35
+ const a = versionParts(left);
36
+ const b = versionParts(right);
37
+ if (!a || !b) return null;
38
+ for (let index = 0; index < a.length; index += 1) {
39
+ if (a[index]! > b[index]!) return 1;
40
+ if (a[index]! < b[index]!) return -1;
41
+ }
42
+ return 0;
43
+ }
44
+
45
+ /** Parses only a coherent policy. A bad control-plane response never becomes an install command. */
46
+ export function runnerVersionPolicyFrom(value: unknown): RunnerVersionPolicy | null {
47
+ if (!value || typeof value !== "object") return null;
48
+ const policy = value as { minimum?: unknown; recommended?: unknown };
49
+ if (typeof policy.minimum !== "string" || typeof policy.recommended !== "string") return null;
50
+ const order = compareRunnerVersions(policy.recommended, policy.minimum);
51
+ if (order === null || order < 0) return null;
52
+ return { minimum: policy.minimum, recommended: policy.recommended };
53
+ }
54
+
55
+ export interface RunnerUpdate {
56
+ target: string;
57
+ /** Required means the installed release cannot claim work if updating fails. */
58
+ required: boolean;
59
+ }
60
+
61
+ /** What this installed runner should do with one valid server policy. Never chooses a downgrade. */
62
+ export function runnerUpdateFor(
63
+ policy: RunnerVersionPolicy,
64
+ current: string = RUNNER_VERSION,
65
+ ): RunnerUpdate | null {
66
+ const recommendedOrder = compareRunnerVersions(policy.recommended, current);
67
+ const minimumOrder = compareRunnerVersions(policy.minimum, current);
68
+ if (recommendedOrder === null || minimumOrder === null) return null;
69
+ if (recommendedOrder <= 0) return null;
70
+ return { target: policy.recommended, required: minimumOrder > 0 };
71
+ }