@north-light/api 0.3.514 → 0.3.518

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.
@@ -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.23";
2
+ export declare const CONTRACT_LEVEL = "1.24";
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`. */
@@ -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.23';
15
+ export const CONTRACT_LEVEL = '1.24';
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`. */
@@ -15,7 +15,8 @@ const PROVIDER_ID = /^[A-Za-z0-9_-]{1,64}$/;
15
15
  const PROVIDER_KEYS = new Set(['id', 'major', 'groups']);
16
16
  const PROVIDER_GROUP_KEYS = new Set(['group', 'consent_line', 'rate', 'who', 'allowlist']);
17
17
  const PROVIDER_WHO = new Set(['own', 'user', 'allowlist', 'any']);
18
- const BUNDLE_KEYS = new Set(['bundleVersion', 'kinds', 'page_components', 'memory_extensions', 'version', 'transport', 'provider', 'object_kinds', 'scopes']);
18
+ // `groups` is a provider archive's tool-group declaration (consent lines, `who`); only the directory reads it, so an install accepts the key and ignores it.
19
+ const BUNDLE_KEYS = new Set(['bundleVersion', 'kinds', 'page_components', 'memory_extensions', 'version', 'transport', 'provider', 'object_kinds', 'scopes', 'groups']);
19
20
  function issue(code, message, received, expected, next, path) {
20
21
  return { code, message, received, expected, next, ...(path !== undefined ? { path } : {}) };
21
22
  }
@@ -276,7 +277,7 @@ function parseBundleMetadata(bytes) {
276
277
  const unknownKeys = Object.keys(record).filter((key) => !BUNDLE_KEYS.has(key));
277
278
  if (record['bundleVersion'] !== 1 || unknownKeys.length > 0) {
278
279
  return {
279
- issue: bundleInvalid('bundle.json must contain bundleVersion 1 and at most version, transport, provider, kinds, page_components, memory_extensions, object_kinds, and scopes', JSON.stringify(raw), 'an object with bundleVersion set to 1 and optional version, transport, provider, kinds, page_components, memory_extensions, object_kinds, and scopes', 'Set bundle.json to {"bundleVersion":1} plus optional contribution blocks.', 'bundle.json'),
280
+ issue: bundleInvalid('bundle.json must contain bundleVersion 1 and at most version, transport, provider, kinds, page_components, memory_extensions, object_kinds, scopes, and groups', JSON.stringify(raw), 'an object with bundleVersion set to 1 and optional version, transport, provider, kinds, page_components, memory_extensions, object_kinds, scopes, and groups', 'Set bundle.json to {"bundleVersion":1} plus optional contribution blocks.', 'bundle.json'),
280
281
  };
281
282
  }
282
283
  // Install-time strictness: a bad block fails the install loudly here, because
@@ -1,4 +1,7 @@
1
1
  export declare function isReservedEnvName(name: string): boolean;
2
+ /** The app env store's reservation: `isReservedEnvName` minus the admitted
3
+ * deployment names. Both its write and read paths use this one rule. */
4
+ export declare function isReservedAppEnvName(name: string): boolean;
2
5
  /** Every stored variable NAME for a profile, sorted. Never returns values. */
3
6
  export declare function listProfileEnvNames(profileId: string): string[];
4
7
  /** Set one variable, replacing any prior value under the same name. Holds the
@@ -24,12 +24,25 @@ import { notFound, usage } from '../errors.js';
24
24
  * read (`readStoreUnlocked`, which every reader — list/set/remove/inject —
25
25
  * goes through), so even a reserved name that reached disk some other way
26
26
  * (hand-edited file, a pre-reservation write) is uniformly invisible rather
27
- * than trusted. */
27
+ * than trusted.
28
+ *
29
+ * Exception, app env store only (`isReservedAppEnvName`): the two names in
30
+ * `APP_ENV_ADMITTED_CRTR_NAMES`. They are crtr-owned deployment settings (where
31
+ * `crtr sys feedback` posts, and its bearer token) that must reach every node
32
+ * of the app, and neither can redirect a broker's home, canvas or identity.
33
+ * They are app-wide deployment config, so the per-profile store still refuses
34
+ * them. */
28
35
  const RESERVED_ENV_PREFIX = 'CRTR_';
29
36
  const RESERVED_ENV_EXACT_NAMES = new Set(['HOME']);
37
+ const APP_ENV_ADMITTED_CRTR_NAMES = new Set(['CRTR_FEEDBACK_ENDPOINT', 'CRTR_FEEDBACK_TOKEN']);
30
38
  export function isReservedEnvName(name) {
31
39
  return name.startsWith(RESERVED_ENV_PREFIX) || RESERVED_ENV_EXACT_NAMES.has(name);
32
40
  }
41
+ /** The app env store's reservation: `isReservedEnvName` minus the admitted
42
+ * deployment names. Both its write and read paths use this one rule. */
43
+ export function isReservedAppEnvName(name) {
44
+ return isReservedEnvName(name) && !APP_ENV_ADMITTED_CRTR_NAMES.has(name);
45
+ }
33
46
  /** NUL is the one byte no OS accepts in an env value — Node's own `spawn`
34
47
  * rejects it synchronously and echoes the full value in the thrown error, so
35
48
  * it must never reach storage or a spawn call. */
@@ -85,6 +85,11 @@ export declare function envPiBinaryOverride(): string | undefined;
85
85
  /** Whether implicit daemon autostart is suppressed for this invocation
86
86
  * (`CRTR_NO_DAEMON_AUTOSTART=1`). */
87
87
  export declare function envNoDaemonAutostart(): boolean;
88
+ /** Port override for crtrd's localhost document listener (`CRTR_DOCUMENT_PORT`),
89
+ * ahead of the `document_port` user setting. The test lanes set `0` so a daemon
90
+ * under test binds an OS-picked port and never holds the real daemon's port.
91
+ * Undefined when unset or not an integer from 0 to 65535. */
92
+ export declare function envDocumentPort(): number | undefined;
88
93
  /** The `--tcp` fallback for crtrd's opt-in TCP listener (`CRTRD_TCP`), raw
89
94
  * (`host:port` or undefined — absent means unix socket only). */
90
95
  export declare function envCrtrdTcp(): string | undefined;
@@ -221,6 +221,17 @@ export function envPiBinaryOverride() {
221
221
  export function envNoDaemonAutostart() {
222
222
  return process.env['CRTR_NO_DAEMON_AUTOSTART'] === '1';
223
223
  }
224
+ /** Port override for crtrd's localhost document listener (`CRTR_DOCUMENT_PORT`),
225
+ * ahead of the `document_port` user setting. The test lanes set `0` so a daemon
226
+ * under test binds an OS-picked port and never holds the real daemon's port.
227
+ * Undefined when unset or not an integer from 0 to 65535. */
228
+ export function envDocumentPort() {
229
+ const raw = process.env['CRTR_DOCUMENT_PORT'];
230
+ if (raw === undefined || !/^\d+$/.test(raw))
231
+ return undefined;
232
+ const port = Number(raw);
233
+ return port <= 65535 ? port : undefined;
234
+ }
224
235
  /** The `--tcp` fallback for crtrd's opt-in TCP listener (`CRTRD_TCP`), raw
225
236
  * (`host:port` or undefined — absent means unix socket only). */
226
237
  export function envCrtrdTcp() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/api",
3
- "version": "0.3.514",
3
+ "version": "0.3.518",
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",