@north-light/crouter-api 0.3.233 → 0.3.234
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/dist/api/client.js +16 -15
- package/dist/shared/env.d.ts +68 -0
- package/dist/shared/env.js +171 -0
- package/package.json +1 -1
package/dist/api/client.js
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
//
|
|
10
10
|
// TRANSPORT (spec O-1): `node:http`/`node:https` `request()` — NO `undici`.
|
|
11
11
|
// unix socket via `{ socketPath }`; TCP/remote via a parsed `baseUrl`.
|
|
12
|
+
import { envHomeOverride } from '../shared/env.js';
|
|
12
13
|
import { request as httpRequest } from 'node:http';
|
|
13
14
|
import { request as httpsRequest } from 'node:https';
|
|
14
15
|
import { homedir } from 'node:os';
|
|
@@ -27,7 +28,7 @@ const SOCKET_BASENAME = 'crtrd.sock';
|
|
|
27
28
|
/** Resolve crtrd's default unix socket path the same way `apiSocketPath()` does,
|
|
28
29
|
* via Node built-ins only (no `core/canvas/paths.ts` import). */
|
|
29
30
|
function defaultSocketPath() {
|
|
30
|
-
const override =
|
|
31
|
+
const override = envHomeOverride();
|
|
31
32
|
const home = override !== undefined && override !== ''
|
|
32
33
|
? override
|
|
33
34
|
: join(homedir(), CRTR_DIR_NAME, 'canvas');
|
|
@@ -74,7 +75,7 @@ export class CrtrClient {
|
|
|
74
75
|
static forLocalSocket(opts) {
|
|
75
76
|
return new CrtrClient({ socketPath: defaultSocketPath(), autostart: true, ...opts });
|
|
76
77
|
}
|
|
77
|
-
//
|
|
78
|
+
// Health / status
|
|
78
79
|
healthz() {
|
|
79
80
|
return this.request('GET', routes.healthz());
|
|
80
81
|
}
|
|
@@ -88,7 +89,7 @@ export class CrtrClient {
|
|
|
88
89
|
restartDaemon() {
|
|
89
90
|
return this.request('POST', routes.daemonRestart());
|
|
90
91
|
}
|
|
91
|
-
//
|
|
92
|
+
// Nodes
|
|
92
93
|
createNode(req) {
|
|
93
94
|
return this.request('POST', routes.nodes(), req);
|
|
94
95
|
}
|
|
@@ -178,7 +179,7 @@ export class CrtrClient {
|
|
|
178
179
|
subscribe(id, req) {
|
|
179
180
|
return this.request('POST', routes.nodeSubscriptions(this.nodePath(id)), req);
|
|
180
181
|
}
|
|
181
|
-
//
|
|
182
|
+
// Focuses (viewer registry)
|
|
182
183
|
// The tmux verbs that open/move/close a viewer pane run LOCALLY in the
|
|
183
184
|
// caller's session (placement-tmux); only the canvas.db focus rows route here.
|
|
184
185
|
// Reads GC lazily server-side, so a returned row is always live; a `null` body
|
|
@@ -245,7 +246,7 @@ export class CrtrClient {
|
|
|
245
246
|
ensureAttach(id, req) {
|
|
246
247
|
return this.request('POST', routes.nodeAttach(this.nodePath(id)), req ?? {});
|
|
247
248
|
}
|
|
248
|
-
//
|
|
249
|
+
// Reads / feed
|
|
249
250
|
getReports(id, q) {
|
|
250
251
|
return this.request('GET', withQuery(routes.nodeReports(this.nodePath(id)), q));
|
|
251
252
|
}
|
|
@@ -283,20 +284,20 @@ export class CrtrClient {
|
|
|
283
284
|
getContext(id) {
|
|
284
285
|
return this.request('GET', routes.nodeContext(this.nodePath(id)));
|
|
285
286
|
}
|
|
286
|
-
//
|
|
287
|
+
// Host file read
|
|
287
288
|
/** Read an absolute host path as UTF-8 (capped, `truncated` when clipped) for
|
|
288
289
|
* the browser file-peek panel. */
|
|
289
290
|
peekFile(path) {
|
|
290
291
|
return this.request('GET', withQuery(routes.filePeek(), { path }));
|
|
291
292
|
}
|
|
292
|
-
//
|
|
293
|
+
// Memory documents
|
|
293
294
|
/** Resolve an exact canonical `[[name]]` memory-document link to the winning
|
|
294
295
|
* document's physical origin for the given node — the node's own precedence
|
|
295
296
|
* chain, not this process's. Pair with `peekFile` to render the document. */
|
|
296
297
|
resolveMemoryDoc(name, nodeId) {
|
|
297
298
|
return this.request('GET', withQuery(routes.memoryResolve(), { name, node: nodeId }));
|
|
298
299
|
}
|
|
299
|
-
//
|
|
300
|
+
// Profiles
|
|
300
301
|
/** Create-or-return by name. Supplied `projects` are shape-checked even when
|
|
301
302
|
* the profile already exists; their directories are only required to exist
|
|
302
303
|
* when this call creates the profile. */
|
|
@@ -317,7 +318,7 @@ export class CrtrClient {
|
|
|
317
318
|
deleteProfile(name, req) {
|
|
318
319
|
return this.request('DELETE', routes.profile(name), req);
|
|
319
320
|
}
|
|
320
|
-
//
|
|
321
|
+
// Model auth
|
|
321
322
|
listModelAuth() {
|
|
322
323
|
return this.request('GET', routes.modelAuths());
|
|
323
324
|
}
|
|
@@ -327,7 +328,7 @@ export class CrtrClient {
|
|
|
327
328
|
removeCredential(provider) {
|
|
328
329
|
return this.request('DELETE', routes.modelAuth(provider));
|
|
329
330
|
}
|
|
330
|
-
//
|
|
331
|
+
// Human bridge + completion-handler forwarding (spec §6.5)
|
|
331
332
|
/** Create a terminal `kind:'human'` bridge node with NO broker engine
|
|
332
333
|
* (`spawnNode` server-side). Distinct from `createNode` (which launches a
|
|
333
334
|
* broker) precisely because a human bridge must never have one. */
|
|
@@ -344,7 +345,7 @@ export class CrtrClient {
|
|
|
344
345
|
cancelHumanTicket(ticketId, body) {
|
|
345
346
|
return this.request('POST', routes.humanTicketCancel(this.interactionPath(ticketId)), body);
|
|
346
347
|
}
|
|
347
|
-
//
|
|
348
|
+
// Daemon-owned document reviews and comments
|
|
348
349
|
createReview(req) {
|
|
349
350
|
return this.request('POST', routes.humanReviews(), req);
|
|
350
351
|
}
|
|
@@ -433,7 +434,7 @@ export class CrtrClient {
|
|
|
433
434
|
cancelHumanInboxTicket(ticketId, request) {
|
|
434
435
|
return this.request('POST', routes.humanInboxCancel(this.ticketId(ticketId)), request ?? {});
|
|
435
436
|
}
|
|
436
|
-
//
|
|
437
|
+
// Durable programmatic human requests
|
|
437
438
|
/** Create one durable human request. Its `request_id` is the same opaque id
|
|
438
439
|
* the inbox routes address, so the request and the inbox ticket are one
|
|
439
440
|
* record. An unresolvable `action.name` is rejected before the page is
|
|
@@ -474,7 +475,7 @@ export class CrtrClient {
|
|
|
474
475
|
}
|
|
475
476
|
return this.request('POST', routes.humanInboxFeedbackResolve(this.ticketId(ticketId), commentId), { node_id: nodeId });
|
|
476
477
|
}
|
|
477
|
-
//
|
|
478
|
+
// Canvas reads / maintenance
|
|
478
479
|
/** Composed client-side from `GET /v1/nodes` + `GET /v1/status` (spec §6.3 —
|
|
479
480
|
* the dashboard is absorbed into those two reads; there is no single route).
|
|
480
481
|
* `generated_at` is the client-side capture instant of the composition. */
|
|
@@ -527,7 +528,7 @@ export class CrtrClient {
|
|
|
527
528
|
rebuildIndex() {
|
|
528
529
|
return this.request('POST', routes.canvasRebuildIndex(), {});
|
|
529
530
|
}
|
|
530
|
-
//
|
|
531
|
+
// Escape hatch
|
|
531
532
|
/** Raw request for routes not yet method-wrapped. Applies the same
|
|
532
533
|
* autostart + error-mapping semantics. */
|
|
533
534
|
async request(method, path, body) {
|
|
@@ -549,7 +550,7 @@ export class CrtrClient {
|
|
|
549
550
|
throw toTransportApiError(err);
|
|
550
551
|
}
|
|
551
552
|
}
|
|
552
|
-
//
|
|
553
|
+
// internals
|
|
553
554
|
nodePath(id) {
|
|
554
555
|
if (!isSafeNodeId(id)) {
|
|
555
556
|
throw new ApiError(400, 'invalid_node_id', `invalid node id: ${JSON.stringify(id)}`);
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/** The current node's id (`CRTR_NODE_ID`), or undefined outside a node. */
|
|
2
|
+
export declare function envNodeId(): string | undefined;
|
|
3
|
+
/** The current node's target profile id (`CRTR_PROFILE_ID`), or undefined. */
|
|
4
|
+
export declare function envProfileId(): string | undefined;
|
|
5
|
+
/** The current node's working directory (`CRTR_NODE_CWD`), or undefined. */
|
|
6
|
+
export declare function envNodeCwd(): string | undefined;
|
|
7
|
+
/** An explicit model-routing override for this turn (`CRTR_MODEL_INTENT`), or
|
|
8
|
+
* undefined. Cleared (not read) via `delete process.env['CRTR_MODEL_INTENT']`
|
|
9
|
+
* in `runtime/broker.ts` — a mutation, not a read, so it stays there. */
|
|
10
|
+
export declare function envModelIntent(): string | undefined;
|
|
11
|
+
/** The raw `CRTR_HOME` override, unresolved. Use `crtrHome()`
|
|
12
|
+
* (`core/canvas/paths.ts`) to get the resolved canvas-home path; use this
|
|
13
|
+
* only when a caller needs the override itself — to check whether one is
|
|
14
|
+
* set, or to propagate it verbatim into a child process's env. */
|
|
15
|
+
export declare function envHomeOverride(): string | undefined;
|
|
16
|
+
/** Dead-provider watchdog timeout (`CRTR_STREAM_WATCHDOG_MS`), 5 minutes by
|
|
17
|
+
* default. See `runtime/stream-watchdog.ts` for what it guards. */
|
|
18
|
+
export declare function envStreamWatchdogMs(): number;
|
|
19
|
+
/** The canvas inbox watcher's poll tick (`CRTR_WATCHER_TICK_MS`). */
|
|
20
|
+
export declare function envWatcherTickMs(): number;
|
|
21
|
+
/** The canvas inbox watcher's debounce window (`CRTR_WATCHER_DEBOUNCE_MS`). */
|
|
22
|
+
export declare function envWatcherDebounceMs(): number;
|
|
23
|
+
/** No-new-message window before a recap is shown (`CRTR_RECAP_IDLE_MS`), 60s
|
|
24
|
+
* by default. */
|
|
25
|
+
export declare function envRecapIdleMs(): number;
|
|
26
|
+
/** Explicit recap-model override (`CRTR_RECAP_MODEL`), trimmed; undefined if
|
|
27
|
+
* unset or blank. */
|
|
28
|
+
export declare function envRecapModelOverride(): string | undefined;
|
|
29
|
+
/** The bash safety-valve deadline (`CRTR_BASH_VALVE_MS`), 5 minutes by
|
|
30
|
+
* default; undocumented test-only override so the E2E valve check doesn't
|
|
31
|
+
* sleep 5 minutes. */
|
|
32
|
+
export declare function envBashValveMs(): number;
|
|
33
|
+
/** Explicit pidfile path override (`CRTR_PIDFILE`, tests only); undefined if
|
|
34
|
+
* unset or blank. */
|
|
35
|
+
export declare function envPidfileOverride(): string | undefined;
|
|
36
|
+
/** The broker engine module spec (`CRTR_BROKER_ENGINE`, the T11 test seam),
|
|
37
|
+
* defaulting to the real SDK. `runtime/host.ts` layers `inv.env` ahead of
|
|
38
|
+
* this (a launch-time override mirrored into the child's env, since
|
|
39
|
+
* spawn-env.ts's default-deny allowlist strips `CRTR_*` from ambient env). */
|
|
40
|
+
export declare function envBrokerEngine(): string;
|
|
41
|
+
/** Test-only pi-binary substitution (`CRTR_PI_BINARY`) so the integration
|
|
42
|
+
* harness can point a real `crtr node new` at a deterministic fake-pi
|
|
43
|
+
* vehicle. Undefined in production. */
|
|
44
|
+
export declare function envPiBinaryOverride(): string | undefined;
|
|
45
|
+
/** Whether implicit daemon autostart is suppressed for this invocation
|
|
46
|
+
* (`CRTR_NO_DAEMON_AUTOSTART=1`). */
|
|
47
|
+
export declare function envNoDaemonAutostart(): boolean;
|
|
48
|
+
/** The `--tcp` fallback for crtrd's opt-in TCP listener (`CRTRD_TCP`), raw
|
|
49
|
+
* (`host:port` or undefined — absent means unix socket only). */
|
|
50
|
+
export declare function envCrtrdTcp(): string | undefined;
|
|
51
|
+
/** Kill switch for the host-exports writer/pruner (`CRTR_NO_EXPORTS=1`). */
|
|
52
|
+
export declare function envNoExports(): boolean;
|
|
53
|
+
/** Verbose-diagnostics gate for otherwise-silent best-effort catches
|
|
54
|
+
* (`CRTR_DEBUG=1`). Distinct from `CRTR_DEBUG_PID_LIVENESS`
|
|
55
|
+
* (`core/canvas/pid.ts`), a different, unrelated var. */
|
|
56
|
+
export declare function envDebug(): boolean;
|
|
57
|
+
/** Live-broker automatic-revive cap override (`CRTR_MAX_LIVE_BROKERS`); wins
|
|
58
|
+
* over `readConfig('user').brokerThresholds.automaticReviveCap` when set. */
|
|
59
|
+
export declare function envMaxLiveBrokers(): number | undefined;
|
|
60
|
+
/** Live-broker warning threshold override (`CRTR_WARN_LIVE_BROKERS`); wins
|
|
61
|
+
* over `readConfig('user').brokerThresholds.warning` when set. */
|
|
62
|
+
export declare function envWarnLiveBrokers(): number | undefined;
|
|
63
|
+
/** Test-only unattended-park interval override (`CRTR_TEST_UNATTENDED_PARK_MS`),
|
|
64
|
+
* gated by `envNoDaemonAutostart()` at the call site; no production default. */
|
|
65
|
+
export declare function envTestUnattendedParkMs(): number | undefined;
|
|
66
|
+
/** Test-only park-summary grace-period override
|
|
67
|
+
* (`CRTR_TEST_PARK_SUMMARY_GRACE_MS`); no production default. */
|
|
68
|
+
export declare function envTestParkSummaryGraceMs(): number | undefined;
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
// The reader-side surface for every environment variable crouter reads back
|
|
2
|
+
// out of `process.env`, outside `core/runtime/spawn-env.ts`'s writer
|
|
3
|
+
// allowlist. That module documents what a broker child is ADMITTED to see;
|
|
4
|
+
// this one documents what crouter itself reads. Two families:
|
|
5
|
+
//
|
|
6
|
+
// - Identity: raw passthrough (`string | undefined`, exactly what
|
|
7
|
+
// `process.env[name]` returns). Every existing call site keeps its own
|
|
8
|
+
// established fallback (`?? ''`, `|| null`, `?? cfg.cwd`, a presence
|
|
9
|
+
// check, ...) — the fallback has always been call-site-owned, not
|
|
10
|
+
// var-owned, so centralizing it here would be a behavior change, not a
|
|
11
|
+
// dedup. `CRTR_HOME` also has a resolved-path accessor, `crtrHome()` in
|
|
12
|
+
// `core/canvas/paths.ts`; that stays the canonical way to get the
|
|
13
|
+
// resolved canvas home; `envHomeOverride()` here is for the handful of
|
|
14
|
+
// sites that want the raw override value itself (to check presence or
|
|
15
|
+
// propagate it verbatim to a child env).
|
|
16
|
+
//
|
|
17
|
+
// - Tuning: parsed, with the default baked into the accessor. Each of
|
|
18
|
+
// these had exactly one parse site before this module existed; the
|
|
19
|
+
// parse logic moved here unchanged so a second site, if one appears,
|
|
20
|
+
// reads the single implementation instead of re-deriving it.
|
|
21
|
+
//
|
|
22
|
+
// `CRTR_DIR_NAME` is NOT here — it is a plain exported string constant
|
|
23
|
+
// (`types.ts`), never read off `process.env`.
|
|
24
|
+
// Identity
|
|
25
|
+
/** The current node's id (`CRTR_NODE_ID`), or undefined outside a node. */
|
|
26
|
+
export function envNodeId() {
|
|
27
|
+
return process.env['CRTR_NODE_ID'];
|
|
28
|
+
}
|
|
29
|
+
/** The current node's target profile id (`CRTR_PROFILE_ID`), or undefined. */
|
|
30
|
+
export function envProfileId() {
|
|
31
|
+
return process.env['CRTR_PROFILE_ID'];
|
|
32
|
+
}
|
|
33
|
+
/** The current node's working directory (`CRTR_NODE_CWD`), or undefined. */
|
|
34
|
+
export function envNodeCwd() {
|
|
35
|
+
return process.env['CRTR_NODE_CWD'];
|
|
36
|
+
}
|
|
37
|
+
/** An explicit model-routing override for this turn (`CRTR_MODEL_INTENT`), or
|
|
38
|
+
* undefined. Cleared (not read) via `delete process.env['CRTR_MODEL_INTENT']`
|
|
39
|
+
* in `runtime/broker.ts` — a mutation, not a read, so it stays there. */
|
|
40
|
+
export function envModelIntent() {
|
|
41
|
+
return process.env['CRTR_MODEL_INTENT'];
|
|
42
|
+
}
|
|
43
|
+
/** The raw `CRTR_HOME` override, unresolved. Use `crtrHome()`
|
|
44
|
+
* (`core/canvas/paths.ts`) to get the resolved canvas-home path; use this
|
|
45
|
+
* only when a caller needs the override itself — to check whether one is
|
|
46
|
+
* set, or to propagate it verbatim into a child process's env. */
|
|
47
|
+
export function envHomeOverride() {
|
|
48
|
+
return process.env['CRTR_HOME'];
|
|
49
|
+
}
|
|
50
|
+
// Tuning
|
|
51
|
+
/** Generic `Number(raw)` parse with a positive-finite guard, shared by every
|
|
52
|
+
* millisecond tuning var below (each previously reimplemented this locally,
|
|
53
|
+
* identically). */
|
|
54
|
+
function parsePositiveMs(raw, fallback) {
|
|
55
|
+
if (raw === undefined)
|
|
56
|
+
return fallback;
|
|
57
|
+
const n = Number(raw);
|
|
58
|
+
return Number.isFinite(n) && n > 0 ? n : fallback;
|
|
59
|
+
}
|
|
60
|
+
const DEFAULT_STREAM_WATCHDOG_MS = 5 * 60_000; // 5 minutes.
|
|
61
|
+
/** Dead-provider watchdog timeout (`CRTR_STREAM_WATCHDOG_MS`), 5 minutes by
|
|
62
|
+
* default. See `runtime/stream-watchdog.ts` for what it guards. */
|
|
63
|
+
export function envStreamWatchdogMs() {
|
|
64
|
+
return parsePositiveMs(process.env['CRTR_STREAM_WATCHDOG_MS'], DEFAULT_STREAM_WATCHDOG_MS);
|
|
65
|
+
}
|
|
66
|
+
const DEFAULT_WATCHER_TICK_MS = 800;
|
|
67
|
+
/** The canvas inbox watcher's poll tick (`CRTR_WATCHER_TICK_MS`). */
|
|
68
|
+
export function envWatcherTickMs() {
|
|
69
|
+
return parsePositiveMs(process.env['CRTR_WATCHER_TICK_MS'], DEFAULT_WATCHER_TICK_MS);
|
|
70
|
+
}
|
|
71
|
+
const DEFAULT_WATCHER_DEBOUNCE_MS = 1000;
|
|
72
|
+
/** The canvas inbox watcher's debounce window (`CRTR_WATCHER_DEBOUNCE_MS`). */
|
|
73
|
+
export function envWatcherDebounceMs() {
|
|
74
|
+
return parsePositiveMs(process.env['CRTR_WATCHER_DEBOUNCE_MS'], DEFAULT_WATCHER_DEBOUNCE_MS);
|
|
75
|
+
}
|
|
76
|
+
const DEFAULT_RECAP_IDLE_MS = 60_000;
|
|
77
|
+
/** No-new-message window before a recap is shown (`CRTR_RECAP_IDLE_MS`), 60s
|
|
78
|
+
* by default. */
|
|
79
|
+
export function envRecapIdleMs() {
|
|
80
|
+
return parsePositiveMs(process.env['CRTR_RECAP_IDLE_MS'], DEFAULT_RECAP_IDLE_MS);
|
|
81
|
+
}
|
|
82
|
+
/** Explicit recap-model override (`CRTR_RECAP_MODEL`), trimmed; undefined if
|
|
83
|
+
* unset or blank. */
|
|
84
|
+
export function envRecapModelOverride() {
|
|
85
|
+
const raw = process.env['CRTR_RECAP_MODEL'];
|
|
86
|
+
return raw !== undefined && raw.trim() !== '' ? raw.trim() : undefined;
|
|
87
|
+
}
|
|
88
|
+
const DEFAULT_BASH_VALVE_MS = 5 * 60 * 1000;
|
|
89
|
+
/** The bash safety-valve deadline (`CRTR_BASH_VALVE_MS`), 5 minutes by
|
|
90
|
+
* default; undocumented test-only override so the E2E valve check doesn't
|
|
91
|
+
* sleep 5 minutes. */
|
|
92
|
+
export function envBashValveMs() {
|
|
93
|
+
return parsePositiveMs(process.env['CRTR_BASH_VALVE_MS'], DEFAULT_BASH_VALVE_MS);
|
|
94
|
+
}
|
|
95
|
+
/** Explicit pidfile path override (`CRTR_PIDFILE`, tests only); undefined if
|
|
96
|
+
* unset or blank. */
|
|
97
|
+
export function envPidfileOverride() {
|
|
98
|
+
const raw = process.env['CRTR_PIDFILE'];
|
|
99
|
+
return raw !== undefined && raw !== '' ? raw : undefined;
|
|
100
|
+
}
|
|
101
|
+
const DEFAULT_BROKER_ENGINE = '@earendil-works/pi-coding-agent';
|
|
102
|
+
/** The broker engine module spec (`CRTR_BROKER_ENGINE`, the T11 test seam),
|
|
103
|
+
* defaulting to the real SDK. `runtime/host.ts` layers `inv.env` ahead of
|
|
104
|
+
* this (a launch-time override mirrored into the child's env, since
|
|
105
|
+
* spawn-env.ts's default-deny allowlist strips `CRTR_*` from ambient env). */
|
|
106
|
+
export function envBrokerEngine() {
|
|
107
|
+
return process.env['CRTR_BROKER_ENGINE'] ?? DEFAULT_BROKER_ENGINE;
|
|
108
|
+
}
|
|
109
|
+
/** Test-only pi-binary substitution (`CRTR_PI_BINARY`) so the integration
|
|
110
|
+
* harness can point a real `crtr node new` at a deterministic fake-pi
|
|
111
|
+
* vehicle. Undefined in production. */
|
|
112
|
+
export function envPiBinaryOverride() {
|
|
113
|
+
return process.env['CRTR_PI_BINARY'];
|
|
114
|
+
}
|
|
115
|
+
/** Whether implicit daemon autostart is suppressed for this invocation
|
|
116
|
+
* (`CRTR_NO_DAEMON_AUTOSTART=1`). */
|
|
117
|
+
export function envNoDaemonAutostart() {
|
|
118
|
+
return process.env['CRTR_NO_DAEMON_AUTOSTART'] === '1';
|
|
119
|
+
}
|
|
120
|
+
/** The `--tcp` fallback for crtrd's opt-in TCP listener (`CRTRD_TCP`), raw
|
|
121
|
+
* (`host:port` or undefined — absent means unix socket only). */
|
|
122
|
+
export function envCrtrdTcp() {
|
|
123
|
+
return process.env['CRTRD_TCP'];
|
|
124
|
+
}
|
|
125
|
+
/** Kill switch for the host-exports writer/pruner (`CRTR_NO_EXPORTS=1`). */
|
|
126
|
+
export function envNoExports() {
|
|
127
|
+
return process.env['CRTR_NO_EXPORTS'] === '1';
|
|
128
|
+
}
|
|
129
|
+
/** Verbose-diagnostics gate for otherwise-silent best-effort catches
|
|
130
|
+
* (`CRTR_DEBUG=1`). Distinct from `CRTR_DEBUG_PID_LIVENESS`
|
|
131
|
+
* (`core/canvas/pid.ts`), a different, unrelated var. */
|
|
132
|
+
export function envDebug() {
|
|
133
|
+
return process.env['CRTR_DEBUG'] === '1';
|
|
134
|
+
}
|
|
135
|
+
// Precedence — broker-supervision.ts's threshold/interval overrides. Each
|
|
136
|
+
// returns the raw parsed value with NO default: the caller (config for the
|
|
137
|
+
// thresholds, a hardcoded production constant for the intervals) supplies
|
|
138
|
+
// the default, and env wins over it when set. Undefined, unparseable, or
|
|
139
|
+
// non-positive all mean "no override" — the caller's own default applies.
|
|
140
|
+
function parsePositiveInteger(raw) {
|
|
141
|
+
if (raw === undefined || raw === '')
|
|
142
|
+
return undefined;
|
|
143
|
+
const n = Number(raw);
|
|
144
|
+
return Number.isSafeInteger(n) && n >= 1 ? n : undefined;
|
|
145
|
+
}
|
|
146
|
+
/** Live-broker automatic-revive cap override (`CRTR_MAX_LIVE_BROKERS`); wins
|
|
147
|
+
* over `readConfig('user').brokerThresholds.automaticReviveCap` when set. */
|
|
148
|
+
export function envMaxLiveBrokers() {
|
|
149
|
+
return parsePositiveInteger(process.env['CRTR_MAX_LIVE_BROKERS']);
|
|
150
|
+
}
|
|
151
|
+
/** Live-broker warning threshold override (`CRTR_WARN_LIVE_BROKERS`); wins
|
|
152
|
+
* over `readConfig('user').brokerThresholds.warning` when set. */
|
|
153
|
+
export function envWarnLiveBrokers() {
|
|
154
|
+
return parsePositiveInteger(process.env['CRTR_WARN_LIVE_BROKERS']);
|
|
155
|
+
}
|
|
156
|
+
function parsePositiveMsNoDefault(raw) {
|
|
157
|
+
if (raw === undefined)
|
|
158
|
+
return undefined;
|
|
159
|
+
const n = Number(raw);
|
|
160
|
+
return Number.isFinite(n) && n > 0 ? n : undefined;
|
|
161
|
+
}
|
|
162
|
+
/** Test-only unattended-park interval override (`CRTR_TEST_UNATTENDED_PARK_MS`),
|
|
163
|
+
* gated by `envNoDaemonAutostart()` at the call site; no production default. */
|
|
164
|
+
export function envTestUnattendedParkMs() {
|
|
165
|
+
return parsePositiveMsNoDefault(process.env['CRTR_TEST_UNATTENDED_PARK_MS']);
|
|
166
|
+
}
|
|
167
|
+
/** Test-only park-summary grace-period override
|
|
168
|
+
* (`CRTR_TEST_PARK_SUMMARY_GRACE_MS`); no production default. */
|
|
169
|
+
export function envTestParkSummaryGraceMs() {
|
|
170
|
+
return parsePositiveMsNoDefault(process.env['CRTR_TEST_PARK_SUMMARY_GRACE_MS']);
|
|
171
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@north-light/crouter-api",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.234",
|
|
4
4
|
"description": "Typed crtrd /v1 API contract — DTOs, route builders, the error contract, and the CrtrClient. Zero runtime dependencies.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/api/index.js",
|