@camstack/system 1.2.114 → 1.2.116

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.
Files changed (69) hide show
  1. package/dist/addon-runner.js +1 -1
  2. package/dist/addon-runner.mjs +1 -1
  3. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  4. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  5. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  6. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  7. package/dist/builtins/alerts/alerts.addon.d.ts +1 -1
  8. package/dist/builtins/alerts/alerts.addon.js +6 -1
  9. package/dist/builtins/alerts/alerts.addon.mjs +6 -1
  10. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
  11. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
  12. package/dist/builtins/console-logging/index.js +1 -1
  13. package/dist/builtins/console-logging/index.mjs +1 -1
  14. package/dist/builtins/core-blocks/core-blocks.addon.js +1 -1
  15. package/dist/builtins/core-blocks/core-blocks.addon.mjs +1 -1
  16. package/dist/builtins/device-manager/device-manager.addon.js +2 -2
  17. package/dist/builtins/device-manager/device-manager.addon.mjs +2 -2
  18. package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
  19. package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
  20. package/dist/builtins/hub-forwarder/index.js +1 -1
  21. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  22. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  23. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  24. package/dist/builtins/local-auth/local-auth.addon.js +1 -1
  25. package/dist/builtins/local-auth/local-auth.addon.mjs +3 -3
  26. package/dist/builtins/local-network/local-hostname.d.ts +15 -0
  27. package/dist/builtins/local-network/local-network.addon.d.ts +31 -7
  28. package/dist/builtins/local-network/local-network.addon.js +177 -28
  29. package/dist/builtins/local-network/local-network.addon.mjs +177 -28
  30. package/dist/builtins/loki-logging/index.js +1 -1
  31. package/dist/builtins/loki-logging/index.mjs +1 -1
  32. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  33. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  34. package/dist/builtins/platform-probe/index.js +1 -1
  35. package/dist/builtins/platform-probe/index.mjs +1 -1
  36. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  37. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  38. package/dist/builtins/snapshot/index.js +1 -1
  39. package/dist/builtins/snapshot/index.mjs +1 -1
  40. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  41. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  42. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +2 -2
  43. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +2 -2
  44. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  45. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  46. package/dist/builtins/system-config/system-config.addon.js +1 -1
  47. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  48. package/dist/builtins/winston-logging/index.js +1 -1
  49. package/dist/builtins/winston-logging/index.mjs +1 -1
  50. package/dist/{dist-CJ8RRSvQ.mjs → dist-BpzbLPel.mjs} +149 -6
  51. package/dist/{dist-C1Aea3c6.js → dist-Cri60Jd0.js} +149 -6
  52. package/dist/http/lan-http-bind.d.ts +19 -0
  53. package/dist/index.d.ts +1 -0
  54. package/dist/index.js +30 -82
  55. package/dist/index.mjs +11 -83
  56. package/dist/lan-http-bind-BDJm4d-K.mjs +716 -0
  57. package/dist/lan-http-bind-CZ4EBeD_.js +848 -0
  58. package/dist/{retired-settings-keys-B52KsNz8.js → retired-settings-keys-BVAxT5XL.js} +1 -1
  59. package/dist/{retired-settings-keys-C1efPfyW.mjs → retired-settings-keys-SrxMH3OT.mjs} +1 -1
  60. package/dist/tls/cert-evaluation.d.ts +41 -0
  61. package/dist/tls/cert-identity.d.ts +37 -0
  62. package/dist/tls/cert-manager.d.ts +71 -6
  63. package/dist/tls/cert-openssl.d.ts +23 -0
  64. package/dist/tls/index.d.ts +5 -1
  65. package/dist/tls/tls-status.d.ts +16 -0
  66. package/dist/tls/uploaded-cert.d.ts +14 -0
  67. package/package.json +1 -1
  68. package/dist/{manifest-python-deps-MA_BZGBz.js → manifest-python-deps-CwBbX4Ut.js} +1 -1
  69. package/dist/{manifest-python-deps-Cb1ANt3i.mjs → manifest-python-deps-SGdbr9D5.mjs} +1 -1
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-C1Aea3c6.js");
1
+ const require_dist = require("./dist-Cri60Jd0.js");
2
2
  //#region src/builtins/sqlite-storage/retired-settings-keys.ts
3
3
  /**
4
4
  * Is THIS node the one whose settings store is the cluster's authority?
@@ -1,4 +1,4 @@
1
- import { kt as asJsonObject } from "./dist-CJ8RRSvQ.mjs";
1
+ import { kt as asJsonObject } from "./dist-BpzbLPel.mjs";
2
2
  //#region src/builtins/sqlite-storage/retired-settings-keys.ts
3
3
  /**
4
4
  * Is THIS node the one whose settings store is the cluster's authority?
@@ -0,0 +1,41 @@
1
+ import { CertIdentity } from './cert-identity.js';
2
+ /** OID `id-kp-serverAuth`. Apple's trustd requires it on the leaf. */
3
+ export declare const SERVER_AUTH_OID = "1.3.6.1.5.5.7.3.1";
4
+ /**
5
+ * Apple's `SecPolicyCheckOtherTrustValidityPeriod` ceiling is 825 days;
6
+ * the CA/Browser Forum's recommended maximum is 397. We sit at 397.
7
+ */
8
+ export declare const MAX_LEAF_VALIDITY_DAYS = 397;
9
+ /** Reissue this long before the leaf dies, so nobody serves an expired one. */
10
+ export declare const LEAF_RENEWAL_WINDOW_DAYS = 30;
11
+ /** A local root outlives many leaves — it is the anchor an operator trusts. */
12
+ export declare const CA_VALIDITY_DAYS = 3650;
13
+ /**
14
+ * The CA must outlive any leaf it signs by a margin, or a leaf issued
15
+ * today expires after its own issuer.
16
+ */
17
+ export declare const CA_RENEWAL_WINDOW_DAYS: number;
18
+ /**
19
+ * Why a reissue is happening. Reported on `EnsureTlsResult` and logged
20
+ * verbatim — an operator who trusted the old certificate by hand learns
21
+ * from this string, not from a browser error.
22
+ */
23
+ export type CertRegenerationReason = 'missing' | 'unreadable' | 'no-local-ca' | 'ca-expiring' | 'key-mismatch' | 'expiring' | 'missing-server-auth-eku' | 'not-issued-by-local-ca' | 'validity-too-long' | 'san-coverage-gap';
24
+ export interface CertEvaluationInput {
25
+ /** Contents of `camstack.crt` — leaf first, then the issuing CA. */
26
+ readonly chainPem: string;
27
+ /** Contents of `camstack.key` — the leaf's private key. */
28
+ readonly keyPem: string;
29
+ /** Contents of `camstack-ca.crt` — the local root. */
30
+ readonly caPem: string;
31
+ readonly identity: CertIdentity;
32
+ readonly now: Date;
33
+ }
34
+ export declare function reasonRequiresNewCa(reason: CertRegenerationReason): boolean;
35
+ /**
36
+ * `null` when the material on disk is fit to keep serving.
37
+ *
38
+ * Order matters only for the quality of the reported reason; any
39
+ * non-null answer produces the same action.
40
+ */
41
+ export declare function evaluateExistingCert(input: CertEvaluationInput): CertRegenerationReason | null;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Names/addresses that go INTO the certificate, and the subset whose
3
+ * absence forces a reissue.
4
+ *
5
+ * The two are deliberately different sizes. Everything plausible is
6
+ * certified — costs nothing. Only a **stable** identity gates
7
+ * regeneration, because a gate that fires on a rotating address rewrites
8
+ * the certificate on every boot, which is a worse bug than the one the
9
+ * gate exists to fix.
10
+ */
11
+ export interface CertIdentity {
12
+ readonly dnsNames: readonly string[];
13
+ readonly ipAddresses: readonly string[];
14
+ readonly requiredDnsNames: readonly string[];
15
+ readonly requiredIpAddresses: readonly string[];
16
+ }
17
+ export interface CertIdentityOptions {
18
+ readonly commonName: string;
19
+ readonly extraSans: readonly string[];
20
+ }
21
+ export declare function isIpv4(value: string): boolean;
22
+ export declare function isIpv6(value: string): boolean;
23
+ /**
24
+ * `fe80::/10` and `169.254.0.0/16`. An IPv6 link-local address needs a
25
+ * zone index to be usable and a SAN cannot carry one, so such an entry
26
+ * can never match anything — it is noise that makes the certificate look
27
+ * broader than it is.
28
+ */
29
+ export declare function isLinkLocal(value: string): boolean;
30
+ /** `fc00::/7` — the IPv6 range that behaves like RFC 1918 does for v4. */
31
+ export declare function isUniqueLocalIpv6(value: string): boolean;
32
+ /**
33
+ * Snapshot the machine's identity. Called once per `ensureTlsCert`; the
34
+ * result is both the SAN list for a new leaf and the yardstick the
35
+ * existing leaf is measured against.
36
+ */
37
+ export declare function collectCertIdentity(options: CertIdentityOptions): CertIdentity;
@@ -1,26 +1,91 @@
1
+ import { CertRegenerationReason, evaluateExistingCert, MAX_LEAF_VALIDITY_DAYS } from './cert-evaluation.js';
2
+ import { CertIdentity, collectCertIdentity } from './cert-identity.js';
1
3
  export interface TlsCertPair {
2
4
  readonly cert: Buffer;
3
5
  readonly key: Buffer;
4
6
  }
5
7
  export interface EnsureTlsResult {
8
+ /** Full chain — leaf then CA. This is what the listener serves. */
6
9
  readonly certPath: string;
10
+ /** The leaf's private key. */
7
11
  readonly keyPath: string;
12
+ /** The local root. **This** is the file an operator installs as trusted. */
13
+ readonly caCertPath: string;
14
+ readonly caKeyPath: string;
8
15
  readonly generated: boolean;
16
+ /** Why it was reissued — `null` when the existing material was kept. */
17
+ readonly reason: CertRegenerationReason | null;
18
+ /** True when the ROOT rotated, i.e. trust granted by hand is now void. */
19
+ readonly caRotated: boolean;
20
+ readonly fingerprintSha256: string;
21
+ readonly caFingerprintSha256: string;
22
+ /** Fingerprint of the leaf this one replaced — `null` on a fresh install. */
23
+ readonly previousFingerprintSha256: string | null;
24
+ /** ISO timestamp at which the leaf stops being valid. */
25
+ readonly validTo: string;
26
+ readonly sans: readonly string[];
27
+ /**
28
+ * Set when a reissue was needed and FAILED, and the previous material is
29
+ * still being served. Never null-and-degraded silently: this is the line
30
+ * that says the certificate is not what the rule wants it to be.
31
+ */
32
+ readonly reissueError: string | null;
9
33
  }
10
34
  export interface CertOptions {
11
- /** Common Name for the cert (default: 'camstack.local') */
35
+ /** Common Name for the leaf (default: 'camstack.local') */
12
36
  readonly commonName?: string;
13
- /** Validity in days (default: 825 max for browsers) */
37
+ /** Leaf validity in days. Clamped to `MAX_LEAF_VALIDITY_DAYS`. */
14
38
  readonly validDays?: number;
15
- /** Additional SANs (DNS names or IPs) */
39
+ /** Additional SANs (DNS names or IPs). Required coverage by definition. */
16
40
  readonly extraSans?: readonly string[];
17
41
  }
18
42
  /**
19
- * Ensure a self-signed TLS certificate exists in the given directory.
20
- * Generates one if missing. Returns paths to cert and key files.
43
+ * Ensure the hub has a usable TLS identity under `<dataDir>/tls`, made of
44
+ * a long-lived local **root** (`camstack-ca.crt`) and a short **leaf**
45
+ * chained to it (`camstack.crt` = leaf + root, `camstack.key`).
46
+ *
47
+ * ## The regeneration rule (D227)
48
+ *
49
+ * Reissue happens when, and only when, the material on disk **cannot do
50
+ * its job**:
51
+ *
52
+ * - it is absent, unreadable, or the key does not match the certificate;
53
+ * - the root is absent (every pre-2026-08 install: one self-signed
54
+ * `CA:TRUE` leaf and no root) or is inside its renewal window;
55
+ * - the leaf is inside its 30-day renewal window;
56
+ * - the leaf lacks `extendedKeyUsage = serverAuth` — Apple's trustd
57
+ * rejects an app-supplied anchor without it;
58
+ * - the leaf is not actually issued by the root on disk;
59
+ * - the leaf's validity span exceeds {@link MAX_LEAF_VALIDITY_DAYS};
60
+ * - **a name or address the hub must answer for is missing from the SAN
61
+ * list** — a DHCP move, a new interface or a new hostname.
62
+ *
63
+ * And explicitly NOT when: the certificate names an address the machine
64
+ * no longer has (a superset still works — the check is one-directional),
65
+ * a volatile interface (docker/VPN/mesh) or a global-scope IPv6 address
66
+ * changed (SLAAC privacy addresses rotate daily), or a new build shipped.
67
+ *
68
+ * Every trigger is derived from the files plus the machine, so once a
69
+ * reissue clears them it clears them for good: the next boot returns
70
+ * `generated: false`. A certificate that moved on every boot would
71
+ * invalidate every trust an operator granted by hand — worse than the
72
+ * bugs this rule fixes.
73
+ *
74
+ * **The root is rotated only for root-level reasons.** SAN drift rotates
75
+ * the leaf alone, so trust granted to `camstack-ca.crt` survives every
76
+ * address change the hub will ever see.
21
77
  */
22
78
  export declare function ensureTlsCert(dataDir: string, options?: CertOptions): Promise<EnsureTlsResult>;
23
79
  /**
24
- * Load TLS cert+key from files. Returns Buffers suitable for Node.js TLS options.
80
+ * Operator "Regenerate": issue a new leaf under the existing local CA.
81
+ * Never rotates the root — trust granted to `camstack-ca.crt` survives.
82
+ */
83
+ export declare function reissueTlsLeaf(dataDir: string, options?: CertOptions): Promise<EnsureTlsResult>;
84
+ /**
85
+ * Load TLS cert+key from files. Returns Buffers suitable for Node.js TLS
86
+ * options. `certPath` is a full chain, so the listener presents the local
87
+ * root alongside the leaf.
25
88
  */
26
89
  export declare function loadTlsCert(certPath: string, keyPath: string): TlsCertPair;
90
+ export type { CertIdentity, CertRegenerationReason };
91
+ export { collectCertIdentity, evaluateExistingCert, MAX_LEAF_VALIDITY_DAYS };
@@ -0,0 +1,23 @@
1
+ import { CertIdentity } from './cert-identity.js';
2
+ /** Subject of the local root. Distinct from the leaf's CN by construction. */
3
+ export declare const CA_COMMON_NAME = "CamStack Local CA";
4
+ export interface CaMaterialPaths {
5
+ readonly caCertPath: string;
6
+ readonly caKeyPath: string;
7
+ }
8
+ export interface LeafMaterialPaths {
9
+ readonly certPath: string;
10
+ readonly keyPath: string;
11
+ }
12
+ /**
13
+ * A local root: 10 years, `pathlen:0` so it can sign leaves and nothing
14
+ * else, and **no EKU** — Apple rejects an anchor asserting
15
+ * `anyExtendedKeyUsage`, and a root with no EKU constrains nothing.
16
+ */
17
+ export declare function generateCa(tmpDir: string): Promise<CaMaterialPaths>;
18
+ /**
19
+ * A server leaf signed by the local root: `CA:FALSE`, and
20
+ * `extendedKeyUsage=serverAuth` — not `anyExtendedKeyUsage`, which
21
+ * Apple's `testAppTrustRoot_AnyEKU_AfterJul2019` asserts must fail.
22
+ */
23
+ export declare function issueLeaf(tmpDir: string, ca: CaMaterialPaths, identity: CertIdentity, commonName: string, validDays: number): Promise<LeafMaterialPaths>;
@@ -1 +1,5 @@
1
- export { ensureTlsCert, loadTlsCert, type TlsCertPair, type EnsureTlsResult, type CertOptions, } from './cert-manager.js';
1
+ export { CA_VALIDITY_DAYS, type CertEvaluationInput, LEAF_RENEWAL_WINDOW_DAYS, SERVER_AUTH_OID, } from './cert-evaluation.js';
2
+ export { type CertIdentity, type CertOptions, type CertRegenerationReason, collectCertIdentity, type EnsureTlsResult, ensureTlsCert, reissueTlsLeaf, evaluateExistingCert, loadTlsCert, MAX_LEAF_VALIDITY_DAYS, type TlsCertPair, } from './cert-manager.js';
3
+ export { CA_COMMON_NAME } from './cert-openssl.js';
4
+ export { validateUploadedTls, type UploadedTlsValidation } from './uploaded-cert.js';
5
+ export { type TlsAccessStatus, readTlsAccessStatus, writeTlsMode, readTlsMode, readExtraSans, writeExtraSans, } from './tls-status.js';
@@ -0,0 +1,16 @@
1
+ export type TlsMode = 'generated' | 'uploaded' | 'disabled';
2
+ export interface TlsAccessStatus {
3
+ readonly mode: TlsMode;
4
+ readonly leafFingerprintSha256: string | null;
5
+ readonly caFingerprintSha256: string | null;
6
+ readonly validTo: string | null;
7
+ readonly sans: readonly string[];
8
+ readonly caCertPem: string | null;
9
+ readonly reissueError: string | null;
10
+ readonly restartRequired: boolean;
11
+ }
12
+ export declare function readTlsMode(dataDir: string): TlsMode;
13
+ export declare function writeTlsMode(dataDir: string, mode: TlsMode): void;
14
+ export declare function readExtraSans(dataDir: string): readonly string[];
15
+ export declare function writeExtraSans(dataDir: string, sans: readonly string[]): void;
16
+ export declare function readTlsAccessStatus(dataDir: string, restartRequired?: boolean): TlsAccessStatus;
@@ -0,0 +1,14 @@
1
+ export type UploadedTlsValidation = {
2
+ readonly ok: true;
3
+ readonly fingerprintSha256: string;
4
+ readonly validTo: string;
5
+ } | {
6
+ readonly ok: false;
7
+ readonly error: string;
8
+ };
9
+ /**
10
+ * Operator-supplied material must parse, match its key, and carry
11
+ * `extendedKeyUsage = serverAuth` — the same leaf defects D227 refused
12
+ * to keep generating.
13
+ */
14
+ export declare function validateUploadedTls(certPem: string, keyPem: string): UploadedTlsValidation;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/system",
3
- "version": "1.2.114",
3
+ "version": "1.2.116",
4
4
  "description": "Core addon for CamStack — builtins, pipeline, process management, auth, logging, events",
5
5
  "keywords": [
6
6
  "camstack",
@@ -17,8 +17,8 @@ node_v8 = require_chunk.__toESM(node_v8);
17
17
  let node_vm = require("node:vm");
18
18
  node_vm = require_chunk.__toESM(node_vm);
19
19
  let _camstack_types_addon = require("@camstack/types/addon");
20
- let _trpc_client = require("@trpc/client");
21
20
  let node_net = require("node:net");
21
+ let _trpc_client = require("@trpc/client");
22
22
  //#region src/kernel/heap-watch.ts
23
23
  /**
24
24
  * heap-watch — hub-main's own memory, on the record, and returned to the OS.
@@ -13,8 +13,8 @@ import { createServer } from "node:http";
13
13
  import * as v8 from "node:v8";
14
14
  import * as vm from "node:vm";
15
15
  import { BOOT_RECOVERY_BACKOFF_MS, DATAPLANE_SECRET_HEADER, DeviceType, DisposerChain, EventCategory, ReadinessRegistry, asJsonObject, asString, createDeviceProxy, deviceOpsCapability, emitReadiness, errMsg, expandCapMethods, readNodePin, scopeKey, sleep, withCapInputDefaults } from "@camstack/types/addon";
16
- import { TRPCClientError, createTRPCClient } from "@trpc/client";
17
16
  import { connect, createServer as createServer$1 } from "node:net";
17
+ import { TRPCClientError, createTRPCClient } from "@trpc/client";
18
18
  //#region src/kernel/heap-watch.ts
19
19
  /**
20
20
  * heap-watch — hub-main's own memory, on the record, and returned to the OS.