@north-light/api 0.3.566 → 0.3.567
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/contract.d.ts +1 -1
- package/dist/api/contract.js +1 -1
- package/dist/core/config.js +8 -12
- package/dist/core/ledger/rates.d.ts +24 -0
- package/dist/core/ledger/rates.js +64 -0
- package/dist/core/user-settings.d.ts +0 -4
- package/dist/core/user-settings.js +0 -1
- package/dist/types.d.ts +0 -16
- package/package.json +1 -1
package/dist/api/contract.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** The contract level this build serves and requires. Written by `scripts/contract.mjs release`; never edit by hand. */
|
|
2
|
-
export declare const CONTRACT_LEVEL = "1.
|
|
2
|
+
export declare const CONTRACT_LEVEL = "1.36";
|
|
3
3
|
/** Request header naming the one contract level the caller needs, e.g. `1.3`. Optional: absent means no check. */
|
|
4
4
|
export declare const REQUIRED_CONTRACT_HEADER = "Crouter-Required-Contract";
|
|
5
5
|
/** Response header listing the contract levels the server serves, comma-separated, one per major, e.g. `1.3`. */
|
package/dist/api/contract.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
//
|
|
13
13
|
// PURITY (spec §3.1): Node built-ins + `src/api/*` only.
|
|
14
14
|
/** The contract level this build serves and requires. Written by `scripts/contract.mjs release`; never edit by hand. */
|
|
15
|
-
export const CONTRACT_LEVEL = '1.
|
|
15
|
+
export const CONTRACT_LEVEL = '1.36';
|
|
16
16
|
/** Request header naming the one contract level the caller needs, e.g. `1.3`. Optional: absent means no check. */
|
|
17
17
|
export const REQUIRED_CONTRACT_HEADER = 'Crouter-Required-Contract';
|
|
18
18
|
/** Response header listing the contract levels the server serves, comma-separated, one per major, e.g. `1.3`. */
|
package/dist/core/config.js
CHANGED
|
@@ -6,6 +6,7 @@ import { CONFIG_FILE, STATE_FILE, CONDENSED_HISTORY_MODES, MOUSE_MODE_DEFAULTS,
|
|
|
6
6
|
import { BINDING_CATALOG, BINDING_IDS, isAttachPaneBinding } from './keybindings/catalog.js';
|
|
7
7
|
import { notFound } from './errors.js';
|
|
8
8
|
import { emitEvent } from './events/emit.js';
|
|
9
|
+
import { LEDGER_ENV } from './ledger/rates.js';
|
|
9
10
|
import { atomicWriteJson, readJsonIfExists, ensureDir } from './fs-utils.js';
|
|
10
11
|
import { scopeRoot, requireScopeRoot, findProjectScopeRoots, userScopeRoot } from './scope.js';
|
|
11
12
|
import { listInstalledPluginsInRoot } from './installed-plugins.js';
|
|
@@ -805,7 +806,13 @@ function mergeApi(raw, defaults) {
|
|
|
805
806
|
const tcp = raw.tcp;
|
|
806
807
|
return { tcp: typeof tcp === 'string' ? tcp : defaults.tcp };
|
|
807
808
|
}
|
|
809
|
+
let ledgerKeyWarned = false;
|
|
808
810
|
function mergeConfig(partial) {
|
|
811
|
+
// The ledger's rates and switches moved from a stored `ledger` key to the deployment's `CRTR_LEDGER_*` variables; the stored key is no longer read.
|
|
812
|
+
if (!ledgerKeyWarned && partial['ledger'] !== undefined) {
|
|
813
|
+
ledgerKeyWarned = true;
|
|
814
|
+
emitEvent({ level: 'warn', event: 'config.ledger.ignored', fields: { variables: Object.values(LEDGER_ENV) } });
|
|
815
|
+
}
|
|
809
816
|
const defaults = defaultScopeConfig();
|
|
810
817
|
const schema_version = defaults.schema_version;
|
|
811
818
|
const marketplaces = partial.marketplaces === undefined ? {} : partial.marketplaces;
|
|
@@ -866,17 +873,6 @@ function mergeConfig(partial) {
|
|
|
866
873
|
if (paths?.user_files !== undefined && (typeof paths.user_files !== 'string' || !paths.user_files.startsWith('/'))) {
|
|
867
874
|
throw new Error('paths.user_files must be an absolute path');
|
|
868
875
|
}
|
|
869
|
-
const ledger = partial.ledger;
|
|
870
|
-
if (ledger?.take_pct !== undefined && (typeof ledger.take_pct !== 'number' || !Number.isFinite(ledger.take_pct) || ledger.take_pct < 0 || ledger.take_pct > 100)) {
|
|
871
|
-
throw new Error('ledger.take_pct must be a number from 0 to 100');
|
|
872
|
-
}
|
|
873
|
-
for (const key of ['sandbox_usd_per_gb_hour', 'sandbox_standby_s', 'storage_usd_per_gb_month', 'sandbox_disk_usd_per_gb_month', 'infra_free_usd_per_month']) {
|
|
874
|
-
const value = ledger?.[key];
|
|
875
|
-
if (value !== undefined && (typeof value !== 'number' || !Number.isFinite(value) || value < 0))
|
|
876
|
-
throw new Error(`ledger.${key} must be a number of at least 0`);
|
|
877
|
-
}
|
|
878
|
-
if (ledger?.r2_move !== undefined && typeof ledger.r2_move !== 'boolean')
|
|
879
|
-
throw new Error('ledger.r2_move must be true or false');
|
|
880
876
|
const store = partial.store;
|
|
881
877
|
const runtime = partial.runtime;
|
|
882
878
|
if (runtime?.person_uids !== undefined && (!Array.isArray(runtime.person_uids)
|
|
@@ -886,7 +882,7 @@ function mergeConfig(partial) {
|
|
|
886
882
|
const spawnEnv = mergeSpawnEnv(partial.spawnEnv, defaults.spawnEnv?.allow);
|
|
887
883
|
const bin = normalizeBin(partial.bin);
|
|
888
884
|
const humanActions = normalizeHumanActions(partial.humanActions);
|
|
889
|
-
return { bin, humanActions, schema_version, marketplaces, plugins, auto_update, max_panes_per_window, auto_open_child_viewers, brokerThresholds, lifecycle, completion_bell, working_gerunds, whip_mode, page_components, page_surface, whip_messages, whip_message_mode, mouse_mode_default, live_cycles, condensed_history, bash_tool_purpose, fold_finished_tools, summarize_tool_calls, detailed_tool_recaps, document_port, consolidate_replies, keybindings, tmux_passthrough, modelLadders, providerOptions, ...(Object.keys(modelRoutes).length > 0 ? { modelRoutes } : {}), ...(Object.keys(routes.legacy).length > 0 ? { legacyModelRoutes: routes.legacy } : {}), ...(modelRouting !== undefined ? { modelRouting } : {}), kinds, remoteCanvas, api, ...(paths ? { paths } : {}), ...(
|
|
885
|
+
return { bin, humanActions, schema_version, marketplaces, plugins, auto_update, max_panes_per_window, auto_open_child_viewers, brokerThresholds, lifecycle, completion_bell, working_gerunds, whip_mode, page_components, page_surface, whip_messages, whip_message_mode, mouse_mode_default, live_cycles, condensed_history, bash_tool_purpose, fold_finished_tools, summarize_tool_calls, detailed_tool_recaps, document_port, consolidate_replies, keybindings, tmux_passthrough, modelLadders, providerOptions, ...(Object.keys(modelRoutes).length > 0 ? { modelRoutes } : {}), ...(Object.keys(routes.legacy).length > 0 ? { legacyModelRoutes: routes.legacy } : {}), ...(modelRouting !== undefined ? { modelRouting } : {}), kinds, remoteCanvas, api, ...(paths ? { paths } : {}), ...(store ? { store } : {}), ...(runtime ? { runtime } : {}), spawnEnv };
|
|
890
886
|
}
|
|
891
887
|
/** Raw (un-defaulted) partial config for one scope, or null if the scope has
|
|
892
888
|
* no root or no config.json. Used by `readMergedLaunchConfig` to layer
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export declare const LEDGER_ENV: {
|
|
2
|
+
readonly sandboxUsdPerGbHour: "CRTR_LEDGER_SANDBOX_USD_PER_GB_HOUR";
|
|
3
|
+
readonly sandboxStandbyS: "CRTR_LEDGER_SANDBOX_STANDBY_S";
|
|
4
|
+
readonly storageUsdPerGbMonth: "CRTR_LEDGER_STORAGE_USD_PER_GB_MONTH";
|
|
5
|
+
readonly sandboxDiskUsdPerGbMonth: "CRTR_LEDGER_SANDBOX_DISK_USD_PER_GB_MONTH";
|
|
6
|
+
readonly infraFreeUsdPerMonth: "CRTR_LEDGER_INFRA_FREE_USD_PER_MONTH";
|
|
7
|
+
readonly takePct: "CRTR_LEDGER_TAKE_PCT";
|
|
8
|
+
readonly r2Move: "CRTR_LEDGER_R2_MOVE";
|
|
9
|
+
};
|
|
10
|
+
export declare const DEFAULT_STANDBY_S = 30;
|
|
11
|
+
export declare const DEFAULT_INFRA_FREE_USD = 50;
|
|
12
|
+
export declare const sandboxUsdPerGbHour: () => number | null;
|
|
13
|
+
export declare const sandboxStandbyS: () => number;
|
|
14
|
+
export declare const storageUsdPerGbMonth: () => number | null;
|
|
15
|
+
export declare const sandboxDiskUsdPerGbMonth: () => number | null;
|
|
16
|
+
export declare const infraFreeUsdPerMonth: () => number;
|
|
17
|
+
/** Northlight's take on each priced model or tool charge, in percent; 0 (the default) writes no take rows. */
|
|
18
|
+
export declare const takePercent: () => number;
|
|
19
|
+
/** The `ledger-r2` lane moves closed months into the blob store only while this is true (off by default until 5b is accepted). */
|
|
20
|
+
export declare const r2MoveEnabled: () => boolean;
|
|
21
|
+
/** Throws on the first malformed ledger variable. Called once at daemon boot. */
|
|
22
|
+
export declare function assertLedgerEnv(): void;
|
|
23
|
+
/** Say once per process that a lane writes nothing because its rate is unset. */
|
|
24
|
+
export declare function warnRateUnset(lane: string, ...names: string[]): void;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// The ledger's platform prices and switches (design-fleet D56), read from the deployment's environment on every role (a Mac, the api
|
|
2
|
+
// role, the reconcile role) the way the other deployment settings are (`CRTR_R2_BUCKET`, `BLAXEL_REGION`). They are Northlight's
|
|
3
|
+
// list prices, not one person's setting. A rate that is unset is `null`: its lane writes nothing and says so once. A set but
|
|
4
|
+
// malformed value throws, and `assertLedgerEnv()` runs at daemon boot so the daemon refuses to start on it.
|
|
5
|
+
import { emitEvent } from '../events/emit.js';
|
|
6
|
+
export const LEDGER_ENV = {
|
|
7
|
+
sandboxUsdPerGbHour: 'CRTR_LEDGER_SANDBOX_USD_PER_GB_HOUR',
|
|
8
|
+
sandboxStandbyS: 'CRTR_LEDGER_SANDBOX_STANDBY_S',
|
|
9
|
+
storageUsdPerGbMonth: 'CRTR_LEDGER_STORAGE_USD_PER_GB_MONTH',
|
|
10
|
+
sandboxDiskUsdPerGbMonth: 'CRTR_LEDGER_SANDBOX_DISK_USD_PER_GB_MONTH',
|
|
11
|
+
infraFreeUsdPerMonth: 'CRTR_LEDGER_INFRA_FREE_USD_PER_MONTH',
|
|
12
|
+
takePct: 'CRTR_LEDGER_TAKE_PCT',
|
|
13
|
+
r2Move: 'CRTR_LEDGER_R2_MOVE',
|
|
14
|
+
};
|
|
15
|
+
export const DEFAULT_STANDBY_S = 30;
|
|
16
|
+
export const DEFAULT_INFRA_FREE_USD = 50;
|
|
17
|
+
function number(name, max = Infinity) {
|
|
18
|
+
const raw = process.env[name];
|
|
19
|
+
if (raw === undefined || raw === '')
|
|
20
|
+
return null;
|
|
21
|
+
// Only a plain decimal: `Number()` would take whitespace as 0 and hex, binary, exponent or `Infinity` spellings as numbers.
|
|
22
|
+
const value = /^\d+(\.\d+)?$/.test(raw) ? Number(raw) : NaN;
|
|
23
|
+
if (!Number.isFinite(value) || value > max)
|
|
24
|
+
throw new Error(`${name} must be a number from 0${max === Infinity ? ' up' : ` to ${max}`}, got ${JSON.stringify(raw)}`);
|
|
25
|
+
return value;
|
|
26
|
+
}
|
|
27
|
+
function flag(name) {
|
|
28
|
+
const raw = process.env[name];
|
|
29
|
+
if (raw === undefined || raw === '')
|
|
30
|
+
return false;
|
|
31
|
+
if (raw === 'true' || raw === '1')
|
|
32
|
+
return true;
|
|
33
|
+
if (raw === 'false' || raw === '0')
|
|
34
|
+
return false;
|
|
35
|
+
throw new Error(`${name} must be true, false, 1 or 0, got ${JSON.stringify(raw)}`);
|
|
36
|
+
}
|
|
37
|
+
export const sandboxUsdPerGbHour = () => number(LEDGER_ENV.sandboxUsdPerGbHour);
|
|
38
|
+
export const sandboxStandbyS = () => number(LEDGER_ENV.sandboxStandbyS) ?? DEFAULT_STANDBY_S;
|
|
39
|
+
export const storageUsdPerGbMonth = () => number(LEDGER_ENV.storageUsdPerGbMonth);
|
|
40
|
+
export const sandboxDiskUsdPerGbMonth = () => number(LEDGER_ENV.sandboxDiskUsdPerGbMonth);
|
|
41
|
+
export const infraFreeUsdPerMonth = () => number(LEDGER_ENV.infraFreeUsdPerMonth) ?? DEFAULT_INFRA_FREE_USD;
|
|
42
|
+
/** Northlight's take on each priced model or tool charge, in percent; 0 (the default) writes no take rows. */
|
|
43
|
+
export const takePercent = () => number(LEDGER_ENV.takePct, 100) ?? 0;
|
|
44
|
+
/** The `ledger-r2` lane moves closed months into the blob store only while this is true (off by default until 5b is accepted). */
|
|
45
|
+
export const r2MoveEnabled = () => flag(LEDGER_ENV.r2Move);
|
|
46
|
+
/** Throws on the first malformed ledger variable. Called once at daemon boot. */
|
|
47
|
+
export function assertLedgerEnv() {
|
|
48
|
+
sandboxUsdPerGbHour();
|
|
49
|
+
sandboxStandbyS();
|
|
50
|
+
storageUsdPerGbMonth();
|
|
51
|
+
sandboxDiskUsdPerGbMonth();
|
|
52
|
+
infraFreeUsdPerMonth();
|
|
53
|
+
takePercent();
|
|
54
|
+
r2MoveEnabled();
|
|
55
|
+
}
|
|
56
|
+
const warned = new Set();
|
|
57
|
+
/** Say once per process that a lane writes nothing because its rate is unset. */
|
|
58
|
+
export function warnRateUnset(lane, ...names) {
|
|
59
|
+
const key = `${lane}:${names.join(',')}`;
|
|
60
|
+
if (warned.has(key))
|
|
61
|
+
return;
|
|
62
|
+
warned.add(key);
|
|
63
|
+
emitEvent({ level: 'warn', event: 'ledger.rate_unset', fields: { lane, unset: names } });
|
|
64
|
+
}
|
|
@@ -469,7 +469,6 @@ export const CONFIG_SETTINGS_COVERAGE = {
|
|
|
469
469
|
remoteCanvas: { surface: 'specialized', owner: 'canvas config commands' },
|
|
470
470
|
api: { surface: 'specialized', owner: 'sys connect' },
|
|
471
471
|
paths: { surface: 'specialized', owner: 'runtime layout' },
|
|
472
|
-
ledger: { surface: 'specialized', owner: 'money ledger (take_pct, sandbox rates)' },
|
|
473
472
|
store: { surface: 'specialized', owner: 'daemon conversation store' },
|
|
474
473
|
runtime: { surface: 'specialized', owner: 'app-facing listener' },
|
|
475
474
|
spawnEnv: { surface: 'specialized', owner: 'spawn environment allow-list' },
|
package/dist/types.d.ts
CHANGED
|
@@ -402,22 +402,6 @@ export interface ScopeConfig {
|
|
|
402
402
|
paths?: {
|
|
403
403
|
user_files?: string;
|
|
404
404
|
};
|
|
405
|
-
/** The money ledger. `take_pct` (0-100, default 0) is Northlight's take on each priced model or tool charge; at 0 no take rows are written. */
|
|
406
|
-
ledger?: {
|
|
407
|
-
take_pct?: number;
|
|
408
|
-
/** USD per GB-hour of Blaxel sandbox awake time; the `ledger-sandbox` lane writes no rows while it is unset. */
|
|
409
|
-
sandbox_usd_per_gb_hour?: number;
|
|
410
|
-
/** Seconds a sandbox stays awake after its broker goes idle or exits (default 30). */
|
|
411
|
-
sandbox_standby_s?: number;
|
|
412
|
-
/** USD per GB-month of R2 storage; the `ledger-storage` lane writes no `r2` rows while it is unset. */
|
|
413
|
-
storage_usd_per_gb_month?: number;
|
|
414
|
-
/** USD per GB-month of Blaxel sandbox disk; the `ledger-storage` lane writes no `blaxel` rows while it is unset. */
|
|
415
|
-
sandbox_disk_usd_per_gb_month?: number;
|
|
416
|
-
/** USD of sandbox and storage a billing account uses free each UTC month (default 50); `billed_usd` on those rows is the part above it. */
|
|
417
|
-
infra_free_usd_per_month?: number;
|
|
418
|
-
/** The `ledger-r2` lane moves closed months into the blob store only while this is true (off until 5b is accepted). */
|
|
419
|
-
r2_move?: boolean;
|
|
420
|
-
};
|
|
421
405
|
/** Conversation store configuration for the daemon. */
|
|
422
406
|
store?: {
|
|
423
407
|
root?: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@north-light/api",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.567",
|
|
4
4
|
"description": "Typed crtrd /v1 API contract — DTOs, route builders, the error contract, the CrtrClient, and the command-plugin manifest format. Zero runtime dependencies.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/api/index.js",
|