@camstack/system 1.2.440 → 1.2.442
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/addon-runner.js +72 -2
- package/dist/addon-runner.mjs +72 -2
- package/dist/auth/totp-manager.d.ts +46 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
- package/dist/builtins/alerts/alerts.addon.d.ts +41 -1
- package/dist/builtins/alerts/alerts.addon.js +638 -26
- package/dist/builtins/alerts/alerts.addon.mjs +638 -26
- package/dist/builtins/alerts/critical-push.d.ts +86 -0
- package/dist/builtins/alerts/runner-alert.d.ts +71 -0
- package/dist/builtins/autotrack/index.js +1 -1
- package/dist/builtins/autotrack/index.mjs +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +2 -2
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +2 -2
- package/dist/builtins/calendars/calendars.addon.js +1 -1
- package/dist/builtins/calendars/calendars.addon.mjs +1 -1
- package/dist/builtins/camera-grid/index.js +1 -1
- package/dist/builtins/camera-grid/index.mjs +1 -1
- package/dist/builtins/composer/composer.addon.js +2 -2
- package/dist/builtins/composer/composer.addon.mjs +2 -2
- package/dist/builtins/console-logging/index.js +1 -1
- package/dist/builtins/console-logging/index.mjs +1 -1
- package/dist/builtins/core-blocks/core-blocks.addon.js +2 -2
- package/dist/builtins/core-blocks/core-blocks.addon.mjs +2 -2
- package/dist/builtins/device-manager/device-manager.addon.js +1 -1
- package/dist/builtins/device-manager/device-manager.addon.mjs +1 -1
- package/dist/builtins/hub-forwarder/index.js +1 -1
- package/dist/builtins/hub-forwarder/index.mjs +1 -1
- package/dist/builtins/keychain/index.js +3 -3
- package/dist/builtins/keychain/index.mjs +3 -3
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
- package/dist/builtins/local-auth/auth-schema.d.ts +1 -1
- package/dist/builtins/local-auth/local-auth.addon.js +226 -17
- package/dist/builtins/local-auth/local-auth.addon.mjs +226 -17
- package/dist/builtins/local-network/local-network.addon.js +2 -2
- package/dist/builtins/local-network/local-network.addon.mjs +2 -2
- package/dist/builtins/loki-logging/index.js +1 -1
- package/dist/builtins/loki-logging/index.mjs +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
- package/dist/builtins/platform-probe/index.js +1 -1
- package/dist/builtins/platform-probe/index.mjs +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
- package/dist/builtins/snapshot/index.js +1 -1
- package/dist/builtins/snapshot/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
- package/dist/builtins/sqlite-storage/index.js +1 -1
- package/dist/builtins/sqlite-storage/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +2 -2
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +2 -2
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
- package/dist/builtins/system-config/system-config.addon.js +2 -2
- package/dist/builtins/system-config/system-config.addon.mjs +283 -283
- package/dist/builtins/winston-logging/index.js +1 -1
- package/dist/builtins/winston-logging/index.mjs +1 -1
- package/dist/{composition-sources-CS0D7imL.mjs → composition-sources-CftPpY4O.mjs} +1 -1
- package/dist/{composition-sources-cBG8fBTu.js → composition-sources-DmSEMtUD.js} +1 -1
- package/dist/{constants-CIzPjw7L.mjs → constants-2iWQ-Nx-.mjs} +1 -1
- package/dist/{constants-CRI3QzT4.js → constants-b7kpjuO4.js} +1 -1
- package/dist/{device-ca-DLKXYseS.mjs → device-ca-BJpYTAPg.mjs} +1 -1
- package/dist/{device-ca-DNHjts4_.js → device-ca-tKY_ZS9H.js} +1 -1
- package/dist/{dist-BKhlcYz6.js → dist-CyIHDLCg.js} +169 -10
- package/dist/{dist-9fcsrFU3.mjs → dist-DsrQYcLm.mjs} +164 -11
- package/dist/file-host-worker.js +1 -1
- package/dist/file-host-worker.mjs +1 -1
- package/dist/{hub-mdns-ciao-Dy2YjRqC.mjs → hub-mdns-ciao-BS2akjWx.mjs} +1 -1
- package/dist/{hub-mdns-ciao-3Zc9G9MS.js → hub-mdns-ciao-Da-0NEyr.js} +1 -1
- package/dist/index.js +142 -13
- package/dist/index.mjs +137 -14
- package/dist/kernel/addon-refused-error.d.ts +30 -0
- package/dist/kernel/index.d.ts +3 -0
- package/dist/kernel/legacy-blob-guard.d.ts +6 -1
- package/dist/kernel/moleculer/process-service.d.ts +16 -1
- package/dist/kernel/moleculer/runner-refusal.d.ts +27 -0
- package/dist/{restore-archive-49aZwkp8.js → restore-archive-Cdf09dHm.js} +1 -1
- package/dist/{restore-archive-DgvDecXM.mjs → restore-archive-RaA3uZ7H.mjs} +82 -82
- package/dist/{wal-maintenance-C041zn6V.js → wal-maintenance-C-bmkDhm.js} +0 -0
- package/dist/{wal-maintenance-BZGmF-3U.mjs → wal-maintenance-DE8QrreK.mjs} +0 -0
- package/package.json +1 -1
package/dist/addon-runner.js
CHANGED
|
@@ -44,6 +44,65 @@ let node_events = require("node:events");
|
|
|
44
44
|
let _camstack_types_node = require("@camstack/types/node");
|
|
45
45
|
let node_module = require("node:module");
|
|
46
46
|
let node_url = require("node:url");
|
|
47
|
+
//#region src/kernel/addon-refused-error.ts
|
|
48
|
+
/**
|
|
49
|
+
* A deterministic Init refusal (D877): an addon that says, in a typed way,
|
|
50
|
+
* "I will not start, and here is why" - as opposed to a crash.
|
|
51
|
+
*
|
|
52
|
+
* The difference matters to the supervisor. A crash may be transient (a camera
|
|
53
|
+
* dropping mid-handshake) and is bounded by the D6 circuit-breaker; a refusal
|
|
54
|
+
* repeats identically until somebody changes the world (runs a migration,
|
|
55
|
+
* fixes a setting), so counting it toward the breaker only turns "waiting for
|
|
56
|
+
* the operator" into a terminal `failed` with a stack trace nobody needed.
|
|
57
|
+
* On 2026-10-17 twenty-eight addons refused on an unmigrated store, exited five
|
|
58
|
+
* times in ten seconds and were marked `failed` as if they had crashed.
|
|
59
|
+
*
|
|
60
|
+
* The runner reports a refusal to its parent (see `runner-refusal.ts`); the
|
|
61
|
+
* process service parks the runner in `refused` with the reason and retries it
|
|
62
|
+
* only when an operator acts.
|
|
63
|
+
*/
|
|
64
|
+
var AddonRefusedError = class extends Error {
|
|
65
|
+
/** Stable, greppable cause, e.g. `unmigrated-settings`. */
|
|
66
|
+
code;
|
|
67
|
+
/** What the operator does about it. */
|
|
68
|
+
remedy;
|
|
69
|
+
constructor(code, message, remedy, options) {
|
|
70
|
+
super(message, options);
|
|
71
|
+
this.name = "AddonRefusedError";
|
|
72
|
+
this.code = code;
|
|
73
|
+
this.remedy = remedy;
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* The refusal in `err`'s cause chain, if any. An addon that wraps the error it
|
|
78
|
+
* got from the kernel (`new Error('init failed', { cause })`) is still refusing.
|
|
79
|
+
*/
|
|
80
|
+
function findAddonRefusal(err) {
|
|
81
|
+
const seen = /* @__PURE__ */ new Set();
|
|
82
|
+
let current = err;
|
|
83
|
+
while (current !== null && current !== void 0 && !seen.has(current)) {
|
|
84
|
+
if (current instanceof AddonRefusedError) return current;
|
|
85
|
+
seen.add(current);
|
|
86
|
+
current = current instanceof Error ? current.cause : void 0;
|
|
87
|
+
}
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
//#endregion
|
|
91
|
+
//#region src/kernel/moleculer/runner-refusal.ts
|
|
92
|
+
var REFUSED_PREFIX = "REFUSED:";
|
|
93
|
+
/** The stdout line for a refusal. Always one line: JSON has no raw newline. */
|
|
94
|
+
function formatRunnerRefusalLine(nodeId, report) {
|
|
95
|
+
return `${REFUSED_PREFIX}${nodeId}:${JSON.stringify(report)}\n`;
|
|
96
|
+
}
|
|
97
|
+
function refusalReportOf(addonId, err) {
|
|
98
|
+
return {
|
|
99
|
+
addonId,
|
|
100
|
+
code: err.code,
|
|
101
|
+
reason: err.message,
|
|
102
|
+
remedy: err.remedy
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
//#endregion
|
|
47
106
|
//#region src/kernel/addon-class-resolver.ts
|
|
48
107
|
function isRecord$5(value) {
|
|
49
108
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -9917,9 +9976,13 @@ function isRetiredRootKey(addonId, key) {
|
|
|
9917
9976
|
if (OWN_RETIRED_ROOT_KEYS.has(key)) return true;
|
|
9918
9977
|
return RETIRED_SETTINGS_KEYS.some((spec) => spec.namespace === addonId && (spec.keys.includes(key) || spec.perNodeKeys.some((k) => key === k || key.startsWith(`${k}@`))));
|
|
9919
9978
|
}
|
|
9920
|
-
|
|
9979
|
+
/** Stable `code` of the D870 refusal. */
|
|
9980
|
+
var UNMIGRATED_SETTINGS_CODE = "unmigrated-settings";
|
|
9981
|
+
/** The remedy the refusal (and the update pre-flight) names. */
|
|
9982
|
+
var UNMIGRATED_SETTINGS_REMEDY = "Run scripts/hub/migrate-device-store.ts --copy --apply (D870), then restart the addon.";
|
|
9983
|
+
var UnmigratedSettingsError = class extends AddonRefusedError {
|
|
9921
9984
|
constructor(addonId, what) {
|
|
9922
|
-
super(`addon "${addonId}" refuses to start: ${what} - the settings it had are still in the per-addon tables and the standard store holds none. Run scripts/hub/migrate-device-store.ts --copy --apply (D870) before starting it
|
|
9985
|
+
super(UNMIGRATED_SETTINGS_CODE, `addon "${addonId}" refuses to start: ${what} - the settings it had are still in the per-addon tables and the standard store holds none. Run scripts/hub/migrate-device-store.ts --copy --apply (D870) before starting it.`, UNMIGRATED_SETTINGS_REMEDY);
|
|
9923
9986
|
this.name = "UnmigratedSettingsError";
|
|
9924
9987
|
}
|
|
9925
9988
|
};
|
|
@@ -11300,6 +11363,13 @@ async function main() {
|
|
|
11300
11363
|
});
|
|
11301
11364
|
} catch (err) {
|
|
11302
11365
|
console.error(`[addon-runner] Init failed for "${spec.addonId}": ${(0, _camstack_types_addon.errMsg)(err)}`);
|
|
11366
|
+
const refusal = findAddonRefusal(err);
|
|
11367
|
+
if (refusal !== null) {
|
|
11368
|
+
try {
|
|
11369
|
+
node_fs.writeSync(1, formatRunnerRefusalLine(nodeId, refusalReportOf(spec.addonId, refusal)));
|
|
11370
|
+
} catch {}
|
|
11371
|
+
process.exit(78);
|
|
11372
|
+
}
|
|
11303
11373
|
process.exit(1);
|
|
11304
11374
|
}
|
|
11305
11375
|
if (deviceRestorePromises.length > 0 && !shuttingDown) await Promise.allSettled(deviceRestorePromises);
|
package/dist/addon-runner.mjs
CHANGED
|
@@ -20,6 +20,65 @@ import { createServer as createServer$1, request } from "node:http";
|
|
|
20
20
|
import { once } from "node:events";
|
|
21
21
|
import { ensureBinary, ensureFfmpeg, ensurePython, installPythonPackages, installPythonRequirements } from "@camstack/types/node";
|
|
22
22
|
import { pathToFileURL } from "node:url";
|
|
23
|
+
//#region src/kernel/addon-refused-error.ts
|
|
24
|
+
/**
|
|
25
|
+
* A deterministic Init refusal (D877): an addon that says, in a typed way,
|
|
26
|
+
* "I will not start, and here is why" - as opposed to a crash.
|
|
27
|
+
*
|
|
28
|
+
* The difference matters to the supervisor. A crash may be transient (a camera
|
|
29
|
+
* dropping mid-handshake) and is bounded by the D6 circuit-breaker; a refusal
|
|
30
|
+
* repeats identically until somebody changes the world (runs a migration,
|
|
31
|
+
* fixes a setting), so counting it toward the breaker only turns "waiting for
|
|
32
|
+
* the operator" into a terminal `failed` with a stack trace nobody needed.
|
|
33
|
+
* On 2026-10-17 twenty-eight addons refused on an unmigrated store, exited five
|
|
34
|
+
* times in ten seconds and were marked `failed` as if they had crashed.
|
|
35
|
+
*
|
|
36
|
+
* The runner reports a refusal to its parent (see `runner-refusal.ts`); the
|
|
37
|
+
* process service parks the runner in `refused` with the reason and retries it
|
|
38
|
+
* only when an operator acts.
|
|
39
|
+
*/
|
|
40
|
+
var AddonRefusedError = class extends Error {
|
|
41
|
+
/** Stable, greppable cause, e.g. `unmigrated-settings`. */
|
|
42
|
+
code;
|
|
43
|
+
/** What the operator does about it. */
|
|
44
|
+
remedy;
|
|
45
|
+
constructor(code, message, remedy, options) {
|
|
46
|
+
super(message, options);
|
|
47
|
+
this.name = "AddonRefusedError";
|
|
48
|
+
this.code = code;
|
|
49
|
+
this.remedy = remedy;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* The refusal in `err`'s cause chain, if any. An addon that wraps the error it
|
|
54
|
+
* got from the kernel (`new Error('init failed', { cause })`) is still refusing.
|
|
55
|
+
*/
|
|
56
|
+
function findAddonRefusal(err) {
|
|
57
|
+
const seen = /* @__PURE__ */ new Set();
|
|
58
|
+
let current = err;
|
|
59
|
+
while (current !== null && current !== void 0 && !seen.has(current)) {
|
|
60
|
+
if (current instanceof AddonRefusedError) return current;
|
|
61
|
+
seen.add(current);
|
|
62
|
+
current = current instanceof Error ? current.cause : void 0;
|
|
63
|
+
}
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
//#endregion
|
|
67
|
+
//#region src/kernel/moleculer/runner-refusal.ts
|
|
68
|
+
var REFUSED_PREFIX = "REFUSED:";
|
|
69
|
+
/** The stdout line for a refusal. Always one line: JSON has no raw newline. */
|
|
70
|
+
function formatRunnerRefusalLine(nodeId, report) {
|
|
71
|
+
return `${REFUSED_PREFIX}${nodeId}:${JSON.stringify(report)}\n`;
|
|
72
|
+
}
|
|
73
|
+
function refusalReportOf(addonId, err) {
|
|
74
|
+
return {
|
|
75
|
+
addonId,
|
|
76
|
+
code: err.code,
|
|
77
|
+
reason: err.message,
|
|
78
|
+
remedy: err.remedy
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
//#endregion
|
|
23
82
|
//#region src/kernel/addon-class-resolver.ts
|
|
24
83
|
function isRecord$5(value) {
|
|
25
84
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -9893,9 +9952,13 @@ function isRetiredRootKey(addonId, key) {
|
|
|
9893
9952
|
if (OWN_RETIRED_ROOT_KEYS.has(key)) return true;
|
|
9894
9953
|
return RETIRED_SETTINGS_KEYS.some((spec) => spec.namespace === addonId && (spec.keys.includes(key) || spec.perNodeKeys.some((k) => key === k || key.startsWith(`${k}@`))));
|
|
9895
9954
|
}
|
|
9896
|
-
|
|
9955
|
+
/** Stable `code` of the D870 refusal. */
|
|
9956
|
+
var UNMIGRATED_SETTINGS_CODE = "unmigrated-settings";
|
|
9957
|
+
/** The remedy the refusal (and the update pre-flight) names. */
|
|
9958
|
+
var UNMIGRATED_SETTINGS_REMEDY = "Run scripts/hub/migrate-device-store.ts --copy --apply (D870), then restart the addon.";
|
|
9959
|
+
var UnmigratedSettingsError = class extends AddonRefusedError {
|
|
9897
9960
|
constructor(addonId, what) {
|
|
9898
|
-
super(`addon "${addonId}" refuses to start: ${what} - the settings it had are still in the per-addon tables and the standard store holds none. Run scripts/hub/migrate-device-store.ts --copy --apply (D870) before starting it
|
|
9961
|
+
super(UNMIGRATED_SETTINGS_CODE, `addon "${addonId}" refuses to start: ${what} - the settings it had are still in the per-addon tables and the standard store holds none. Run scripts/hub/migrate-device-store.ts --copy --apply (D870) before starting it.`, UNMIGRATED_SETTINGS_REMEDY);
|
|
9899
9962
|
this.name = "UnmigratedSettingsError";
|
|
9900
9963
|
}
|
|
9901
9964
|
};
|
|
@@ -11276,6 +11339,13 @@ async function main() {
|
|
|
11276
11339
|
});
|
|
11277
11340
|
} catch (err) {
|
|
11278
11341
|
console.error(`[addon-runner] Init failed for "${spec.addonId}": ${errMsg(err)}`);
|
|
11342
|
+
const refusal = findAddonRefusal(err);
|
|
11343
|
+
if (refusal !== null) {
|
|
11344
|
+
try {
|
|
11345
|
+
fs.writeSync(1, formatRunnerRefusalLine(nodeId, refusalReportOf(spec.addonId, refusal)));
|
|
11346
|
+
} catch {}
|
|
11347
|
+
process.exit(78);
|
|
11348
|
+
}
|
|
11279
11349
|
process.exit(1);
|
|
11280
11350
|
}
|
|
11281
11351
|
if (deviceRestorePromises.length > 0 && !shuttingDown) await Promise.allSettled(deviceRestorePromises);
|
|
@@ -1,4 +1,16 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type RawSecretMigrationReport, type IScopedLogger, type SecretsAccess, type SettingsStoreClient } from "@camstack/types";
|
|
2
|
+
/**
|
|
3
|
+
* The seed cannot be used right now. The message is what a not-yet-logged-in
|
|
4
|
+
* caller sees, so it is generic; `reason` (keychain detail) is for the server log only.
|
|
5
|
+
*/
|
|
6
|
+
export declare class TotpSecretUnavailableError extends Error {
|
|
7
|
+
readonly reason: string;
|
|
8
|
+
constructor(reason: string);
|
|
9
|
+
}
|
|
10
|
+
/** A seed cannot be stored: setup is refused, never written as plaintext. */
|
|
11
|
+
export declare class TotpSecretStorageUnavailableError extends Error {
|
|
12
|
+
constructor(reason: string);
|
|
13
|
+
}
|
|
2
14
|
export interface TotpSetupResult {
|
|
3
15
|
readonly secret: string;
|
|
4
16
|
readonly otpauthUrl: string;
|
|
@@ -12,9 +24,17 @@ export declare class TotpManager {
|
|
|
12
24
|
/** ±N steps of clock-skew tolerance, expressed in seconds for otplib v13's
|
|
13
25
|
* per-call `epochTolerance`. Default window 1 = ±30 s. */
|
|
14
26
|
private readonly epochTolerance;
|
|
27
|
+
private readonly secrets;
|
|
28
|
+
private readonly logger;
|
|
29
|
+
/** Per-user queue: setup / confirm / disable / migration never interleave on one user. */
|
|
30
|
+
private readonly chains;
|
|
15
31
|
constructor(store: SettingsStoreClient, opts?: {
|
|
16
32
|
/** ±N 30-second windows tolerated. Default 1 = ±30 s clock skew. */
|
|
17
33
|
readonly window?: number;
|
|
34
|
+
/** Keychain handle for owner `system`; `null` = no keychain door (setup refuses). */
|
|
35
|
+
readonly secrets?: SecretsAccess | null;
|
|
36
|
+
/** Server-side log for the keychain detail of a refused read. */
|
|
37
|
+
readonly logger?: IScopedLogger;
|
|
18
38
|
});
|
|
19
39
|
/**
|
|
20
40
|
* Begin enrollment. Always generates a fresh secret — calling `setup`
|
|
@@ -26,6 +46,7 @@ export declare class TotpManager {
|
|
|
26
46
|
* recognition. `ISSUER` is the CamStack brand.
|
|
27
47
|
*/
|
|
28
48
|
setup(userId: string, username: string): Promise<TotpSetupResult>;
|
|
49
|
+
private setupLocked;
|
|
29
50
|
/**
|
|
30
51
|
* Confirm enrollment by checking a code from the authenticator
|
|
31
52
|
* against the pending secret. On success, flips `confirmedAt` so
|
|
@@ -34,10 +55,12 @@ export declare class TotpManager {
|
|
|
34
55
|
* change.
|
|
35
56
|
*/
|
|
36
57
|
confirm(userId: string, code: string): Promise<boolean>;
|
|
58
|
+
private confirmLocked;
|
|
37
59
|
/**
|
|
38
60
|
* Remove enrollment. Idempotent — no error if the user had no row.
|
|
39
61
|
*/
|
|
40
62
|
disable(userId: string): Promise<void>;
|
|
63
|
+
private serialize;
|
|
41
64
|
/**
|
|
42
65
|
* Verify a code against the confirmed secret. Returns `false` when:
|
|
43
66
|
* - The user has no row (not set up).
|
|
@@ -50,5 +73,27 @@ export declare class TotpManager {
|
|
|
50
73
|
* reported as `enabled: false` — only a confirmed row counts.
|
|
51
74
|
*/
|
|
52
75
|
getStatus(userId: string): Promise<TotpStatus>;
|
|
76
|
+
private refFor;
|
|
77
|
+
/** A refused read: generic to the caller, the keychain detail to the server log. */
|
|
78
|
+
private unavailable;
|
|
79
|
+
/** The seed in clear: from the keychain for a marker row, inline for a pre-D878 row. Throws when unreadable. */
|
|
80
|
+
private seedOf;
|
|
81
|
+
/** Remove a user's seed from the keychain; a miss leaves an orphan the Secrets page shows. */
|
|
82
|
+
private dropSeed;
|
|
83
|
+
/**
|
|
84
|
+
* D878: move every inline seed into the keychain. Dry run unless `apply`.
|
|
85
|
+
* Per row: put -> read back and compare -> only then rewrite the row with the
|
|
86
|
+
* marker, so the inline seed is cleared by the verified move and nowhere
|
|
87
|
+
* else. Counts only; idempotent.
|
|
88
|
+
*/
|
|
89
|
+
migrateRawSecrets(apply: boolean): Promise<RawSecretMigrationReport>;
|
|
90
|
+
/**
|
|
91
|
+
* Compare-and-set under the user's queue: the row is re-read and moved only if
|
|
92
|
+
* it still holds the very inline seed we planned to move, so a concurrent
|
|
93
|
+
* `setup` (its seed and marker) is never overwritten. The ref is always the
|
|
94
|
+
* user's own, never taken from the row.
|
|
95
|
+
*/
|
|
96
|
+
private moveRow;
|
|
97
|
+
private readAll;
|
|
53
98
|
private find;
|
|
54
99
|
}
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-CyIHDLCg.js");
|
|
7
7
|
const require_settle_sources = require("../../settle-sources-Bhsy57y-.js");
|
|
8
8
|
let node_crypto = require("node:crypto");
|
|
9
9
|
let node_path = require("node:path");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Ar as errMsg,
|
|
1
|
+
import { Ar as errMsg, Ci as EventCategory, it as addonPagesCapability, jr as BaseAddon } from "../../dist-DsrQYcLm.mjs";
|
|
2
2
|
import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
|
|
3
3
|
import { createHash, randomUUID } from "node:crypto";
|
|
4
4
|
import * as path$1 from "node:path";
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-CyIHDLCg.js");
|
|
7
7
|
const require_settle_sources = require("../../settle-sources-Bhsy57y-.js");
|
|
8
8
|
let node_crypto = require("node:crypto");
|
|
9
9
|
let node_path = require("node:path");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Ar as errMsg,
|
|
1
|
+
import { Ar as errMsg, Ci as EventCategory, jr as BaseAddon, ot as addonWidgetsCapability } from "../../dist-DsrQYcLm.mjs";
|
|
2
2
|
import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
|
|
3
3
|
import { createHash, randomUUID } from "node:crypto";
|
|
4
4
|
import * as path$1 from "node:path";
|
|
@@ -3,10 +3,18 @@ import { BaseAddon, type ProviderRegistration } from "@camstack/types";
|
|
|
3
3
|
interface AlertCenterConfig {
|
|
4
4
|
readonly maxAlerts: number;
|
|
5
5
|
readonly retentionDays: number;
|
|
6
|
+
/** Push critical system alerts (runner failed/refused, runners degraded) straight to the notifiers (D877). */
|
|
7
|
+
readonly criticalPushEnabled: boolean;
|
|
8
|
+
/** Comma-separated notifier target ids for that push; empty = every enabled operator-level target. */
|
|
9
|
+
readonly criticalPushTargetIds: string;
|
|
6
10
|
}
|
|
7
11
|
export declare class AlertCenterAddon extends BaseAddon<AlertCenterConfig> {
|
|
8
12
|
private unsubscribers;
|
|
9
|
-
|
|
13
|
+
/** How long a burst of critical findings is gathered into one digest push. */
|
|
14
|
+
private readonly pushCoalesceMs;
|
|
15
|
+
constructor(options?: {
|
|
16
|
+
readonly pushCoalesceMs?: number;
|
|
17
|
+
});
|
|
10
18
|
/**
|
|
11
19
|
* Per `(category, source.id)` counter used to rate-limit chatty
|
|
12
20
|
* events. Entries are pruned lazily when they age out of
|
|
@@ -25,6 +33,38 @@ export declare class AlertCenterAddon extends BaseAddon<AlertCenterConfig> {
|
|
|
25
33
|
markAllRead(): Promise<void>;
|
|
26
34
|
dismiss(alertId: string): Promise<void>;
|
|
27
35
|
private handleEvent;
|
|
36
|
+
private readRunnerRecord;
|
|
37
|
+
private handleRunnerEvent;
|
|
38
|
+
/**
|
|
39
|
+
* A runner reached `running`: its episode is over. Close the runner alert so a
|
|
40
|
+
* later failure opens a NEW episode (new push key), instead of folding into a
|
|
41
|
+
* stale `refused` record that would never push again.
|
|
42
|
+
*/
|
|
43
|
+
private handleRunnerStateChanged;
|
|
44
|
+
/** The node's one-shot runner boot check: one alert, dismissed when the node is clean. */
|
|
45
|
+
private handleRunnerCheck;
|
|
46
|
+
private readAlertRaw;
|
|
47
|
+
/** Pushes run one at a time so a burst can never send the same state twice. */
|
|
48
|
+
private pushChain;
|
|
49
|
+
/** Findings waiting for the next digest, by alert id. */
|
|
50
|
+
private readonly pushQueue;
|
|
51
|
+
private pushTimer;
|
|
52
|
+
private pushPolicy;
|
|
53
|
+
private pushPorts;
|
|
54
|
+
/**
|
|
55
|
+
* Queue a critical finding for the next digest. A burst (every runner of a boot)
|
|
56
|
+
* arrives within the coalesce window and leaves as ONE message per target.
|
|
57
|
+
*/
|
|
58
|
+
private queuePush;
|
|
59
|
+
/** Send the queued findings now (also the reconcile path). */
|
|
60
|
+
private flushPushes;
|
|
61
|
+
private storePushState;
|
|
62
|
+
/**
|
|
63
|
+
* Retry every critical alert whose push is still pending - at boot and when
|
|
64
|
+
* the notifiers or notification-center start. An alert whose state was already
|
|
65
|
+
* delivered is skipped by its key, so reconciling never sends twice.
|
|
66
|
+
*/
|
|
67
|
+
private reconcilePendingPushes;
|
|
28
68
|
private handleModelDownload;
|
|
29
69
|
/**
|
|
30
70
|
* `[ALERT-CENTER-EVENTS]` — rate limit a `(category, source.id)`
|