@camstack/system 1.2.57 → 1.2.59
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 +1 -1
- package/dist/addon-runner.mjs +1 -1
- package/dist/addon-utils.js +1 -1
- package/dist/addon-utils.mjs +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +2 -2
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +2 -2
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +2 -2
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +2 -2
- package/dist/builtins/alerts/alerts.addon.js +1 -1
- package/dist/builtins/alerts/alerts.addon.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/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 +2 -2
- package/dist/builtins/device-manager/device-manager.addon.mjs +2 -2
- package/dist/builtins/doorbell/binding-mirror.d.ts +65 -0
- package/dist/builtins/doorbell/virtual-doorbell.addon.d.ts +56 -11
- package/dist/builtins/doorbell/virtual-doorbell.addon.js +248 -26
- package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +248 -26
- package/dist/builtins/hub-forwarder/index.js +1 -1
- package/dist/builtins/hub-forwarder/index.mjs +1 -1
- 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/local-auth.addon.js +1 -1
- package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
- package/dist/builtins/local-network/local-network.addon.js +1 -1
- package/dist/builtins/local-network/local-network.addon.mjs +1 -1
- 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 +2 -2
- package/dist/builtins/snapshot/index.mjs +2 -2
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +2 -2
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +2 -2
- package/dist/builtins/sqlite-storage/index.d.ts +3 -0
- package/dist/builtins/sqlite-storage/index.js +8 -0
- package/dist/builtins/sqlite-storage/index.mjs +2 -2
- package/dist/builtins/sqlite-storage/retired-settings-keys.d.ts +94 -0
- package/dist/builtins/sqlite-storage/sqlite-pragmas.d.ts +85 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.d.ts +1 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +445 -2
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +438 -3
- package/dist/builtins/sqlite-storage/wal-maintenance.d.ts +113 -0
- 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 +1 -1
- package/dist/builtins/system-config/system-config.addon.mjs +1 -1
- package/dist/builtins/winston-logging/index.js +1 -1
- package/dist/builtins/winston-logging/index.mjs +1 -1
- package/dist/{dist-DhL_zGRT.mjs → dist-BqJJWCS8.mjs} +994 -34
- package/dist/{dist-BupxnZOi.js → dist-CV6XTApk.js} +1005 -33
- package/dist/index.js +190 -42
- package/dist/index.mjs +191 -43
- package/dist/kernel/addon-installer.d.ts +55 -7
- package/dist/kernel/addon-manifest.d.ts +36 -16
- package/dist/kernel/transport/frame-codec.d.ts +43 -2
- package/dist/{manifest-python-deps-Ck4-9K9m.mjs → manifest-python-deps-CX5tGRqf.mjs} +95 -10
- package/dist/{manifest-python-deps-BqE5j0-O.js → manifest-python-deps-d4acYXVV.js} +95 -10
- package/package.json +1 -1
- package/dist/{model-download-service-hf0ookyy.js → model-download-service-Cpc6SWzV.js} +1 -1
- package/dist/{model-download-service-Cp9f4dk6.mjs → model-download-service-D8B-4ktF.mjs} +1 -1
package/dist/addon-runner.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_chunk = require("./chunk-Cek0wNdY.js");
|
|
2
|
-
const require_manifest_python_deps = require("./manifest-python-deps-
|
|
2
|
+
const require_manifest_python_deps = require("./manifest-python-deps-d4acYXVV.js");
|
|
3
3
|
const require_custom_action_registry = require("./custom-action-registry-jY0NOZK8.js");
|
|
4
4
|
let node_v8 = require("node:v8");
|
|
5
5
|
node_v8 = require_chunk.__toESM(node_v8);
|
package/dist/addon-runner.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Ct as resolveAddonClass, I as createUdsLoggerWithControl, L as LocalChildClient, at as setWorkerNativeCapsChangeListener, bt as installManifestNativeDeps, i as createUdsAddonContext, nt as getWorkerNativeCapProvider, rt as getWorkerNativeCapSnapshot, st as validateProviderRegistrations, t as installManifestPythonDeps } from "./manifest-python-deps-
|
|
1
|
+
import { Ct as resolveAddonClass, I as createUdsLoggerWithControl, L as LocalChildClient, at as setWorkerNativeCapsChangeListener, bt as installManifestNativeDeps, i as createUdsAddonContext, nt as getWorkerNativeCapProvider, rt as getWorkerNativeCapSnapshot, st as validateProviderRegistrations, t as installManifestPythonDeps } from "./manifest-python-deps-CX5tGRqf.mjs";
|
|
2
2
|
import { t as CustomActionRegistry } from "./custom-action-registry-F__gp_VX.mjs";
|
|
3
3
|
import { register } from "node:module";
|
|
4
4
|
import * as v8 from "node:v8";
|
package/dist/addon-utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
require("./chunk-Cek0wNdY.js");
|
|
3
|
-
const require_model_download_service = require("./model-download-service-
|
|
3
|
+
const require_model_download_service = require("./model-download-service-Cpc6SWzV.js");
|
|
4
4
|
const require_custom_action_registry = require("./custom-action-registry-jY0NOZK8.js");
|
|
5
5
|
exports.CustomActionRegistry = require_custom_action_registry.CustomActionRegistry;
|
|
6
6
|
exports.ModelDownloadService = require_model_download_service.ModelDownloadService;
|
package/dist/addon-utils.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { c as getModelFilePath, d as contentTypeFor, i as downloadFile, l as isModelDownloaded, n as collectModelFiles, o as ensureModel, p as parseRangeHeader, r as deleteModelFromDisk, t as ModelDownloadService, u as createFileDataPlaneHandler } from "./model-download-service-
|
|
1
|
+
import { c as getModelFilePath, d as contentTypeFor, i as downloadFile, l as isModelDownloaded, n as collectModelFiles, o as ensureModel, p as parseRangeHeader, r as deleteModelFromDisk, t as ModelDownloadService, u as createFileDataPlaneHandler } from "./model-download-service-D8B-4ktF.mjs";
|
|
2
2
|
import { t as CustomActionRegistry } from "./custom-action-registry-F__gp_VX.mjs";
|
|
3
3
|
export { CustomActionRegistry, ModelDownloadService, collectModelFiles, contentTypeFor, createFileDataPlaneHandler, deleteModelFromDisk, downloadFile, ensureModel, getModelFilePath, isModelDownloaded, parseRangeHeader };
|
|
@@ -3,13 +3,13 @@ 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-CV6XTApk.js");
|
|
7
7
|
const require_settle_sources = require("../../settle-sources-Bhsy57y-.js");
|
|
8
|
+
let node_crypto = require("node:crypto");
|
|
8
9
|
let node_fs = require("node:fs");
|
|
9
10
|
node_fs = require_chunk.__toESM(node_fs);
|
|
10
11
|
let node_path = require("node:path");
|
|
11
12
|
node_path = require_chunk.__toESM(node_path);
|
|
12
|
-
let node_crypto = require("node:crypto");
|
|
13
13
|
//#region src/builtins/addon-pages-aggregator/dedupe-pages.ts
|
|
14
14
|
/** Stable identity for an addon page, independent of which node reported it. */
|
|
15
15
|
function pageKey(info) {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ft as errMsg, m as addonPagesCapability, pt as BaseAddon, zt as EventCategory } from "../../dist-BqJJWCS8.mjs";
|
|
2
2
|
import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
|
|
3
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
3
4
|
import * as fs from "node:fs";
|
|
4
5
|
import * as path$1 from "node:path";
|
|
5
|
-
import { createHash, randomUUID } from "node:crypto";
|
|
6
6
|
//#region src/builtins/addon-pages-aggregator/dedupe-pages.ts
|
|
7
7
|
/** Stable identity for an addon page, independent of which node reported it. */
|
|
8
8
|
function pageKey(info) {
|
|
@@ -3,13 +3,13 @@ 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-CV6XTApk.js");
|
|
7
7
|
const require_settle_sources = require("../../settle-sources-Bhsy57y-.js");
|
|
8
|
+
let node_crypto = require("node:crypto");
|
|
8
9
|
let node_fs = require("node:fs");
|
|
9
10
|
node_fs = require_chunk.__toESM(node_fs);
|
|
10
11
|
let node_path = require("node:path");
|
|
11
12
|
node_path = require_chunk.__toESM(node_path);
|
|
12
|
-
let node_crypto = require("node:crypto");
|
|
13
13
|
//#region src/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.ts
|
|
14
14
|
/**
|
|
15
15
|
* Addon Widgets Aggregator — hub-local builtin that owns the singleton
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ft as errMsg, g as addonWidgetsCapability, pt as BaseAddon, zt as EventCategory } from "../../dist-BqJJWCS8.mjs";
|
|
2
2
|
import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
|
|
3
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
3
4
|
import * as fs from "node:fs";
|
|
4
5
|
import * as path$1 from "node:path";
|
|
5
|
-
import { createHash, randomUUID } from "node:crypto";
|
|
6
6
|
//#region src/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.ts
|
|
7
7
|
/**
|
|
8
8
|
* Addon Widgets Aggregator — hub-local builtin that owns the singleton
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-CV6XTApk.js");
|
|
7
7
|
//#region src/builtins/alerts/prune-policy.ts
|
|
8
8
|
/**
|
|
9
9
|
* Ids older than `cutoffMs`, oldest first.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Et as createEvent, _ as alertsCapability, ft as errMsg, n as AlertSchema, pt as BaseAddon, zt as EventCategory } from "../../dist-BqJJWCS8.mjs";
|
|
2
2
|
//#region src/builtins/alerts/prune-policy.ts
|
|
3
3
|
/**
|
|
4
4
|
* Ids older than `cutoffMs`, oldest first.
|
|
@@ -3,14 +3,14 @@ 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-CV6XTApk.js");
|
|
7
|
+
let node_crypto = require("node:crypto");
|
|
7
8
|
let node_fs = require("node:fs");
|
|
8
9
|
let node_fs$1 = require_chunk.__toESM(node_fs, 1);
|
|
9
10
|
node_fs = require_chunk.__toESM(node_fs);
|
|
10
11
|
let node_path = require("node:path");
|
|
11
12
|
let node_path$1 = require_chunk.__toESM(node_path, 1);
|
|
12
13
|
node_path = require_chunk.__toESM(node_path);
|
|
13
|
-
let node_crypto = require("node:crypto");
|
|
14
14
|
let node_fs_promises = require("node:fs/promises");
|
|
15
15
|
let node_fs_promises$1 = require_chunk.__toESM(node_fs_promises, 1);
|
|
16
16
|
node_fs_promises = require_chunk.__toESM(node_fs_promises);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { b as backupCapability, pt as BaseAddon, zt as EventCategory } from "../../dist-BqJJWCS8.mjs";
|
|
2
|
+
import { randomBytes, randomUUID } from "node:crypto";
|
|
2
3
|
import * as fs from "node:fs";
|
|
3
4
|
import Kt from "node:fs";
|
|
4
5
|
import * as path$1 from "node:path";
|
|
5
6
|
import path, { basename, join, posix, win32 } from "node:path";
|
|
6
|
-
import { randomBytes, randomUUID } from "node:crypto";
|
|
7
7
|
import * as fsp from "node:fs/promises";
|
|
8
8
|
import jn from "node:fs/promises";
|
|
9
9
|
import { Buffer as Buffer$1 } from "buffer";
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-CV6XTApk.js");
|
|
7
7
|
const require_formatter = require("../../formatter-DqAKDlvN.js");
|
|
8
8
|
//#region src/builtins/console-logging/console-destination.ts
|
|
9
9
|
var LEVEL_RANK = {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { G as logDestinationCapability, pt as BaseAddon } from "../../dist-BqJJWCS8.mjs";
|
|
2
2
|
import { t as formatLogLine } from "../../formatter-B7qW8bPJ.mjs";
|
|
3
3
|
//#region src/builtins/console-logging/console-destination.ts
|
|
4
4
|
var LEVEL_RANK = {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
3
|
-
const require_dist = require("../../dist-
|
|
3
|
+
const require_dist = require("../../dist-CV6XTApk.js");
|
|
4
|
+
let node_crypto = require("node:crypto");
|
|
4
5
|
let node_path = require("node:path");
|
|
5
6
|
node_path = require_chunk.__toESM(node_path);
|
|
6
|
-
let node_crypto = require("node:crypto");
|
|
7
7
|
let node_fs_promises = require("node:fs/promises");
|
|
8
8
|
node_fs_promises = require_chunk.__toESM(node_fs_promises);
|
|
9
9
|
//#region src/builtins/core-blocks/block-package.ts
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { o as __toESM } from "../../chunk-CNf5ZN-e.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import * as path$1 from "node:path";
|
|
2
|
+
import { C as coreBlocksCapability, o as CoreBlockSchema, pt as BaseAddon } from "../../dist-BqJJWCS8.mjs";
|
|
4
3
|
import { randomUUID } from "node:crypto";
|
|
4
|
+
import * as path$1 from "node:path";
|
|
5
5
|
import * as fs from "node:fs/promises";
|
|
6
6
|
//#region src/builtins/core-blocks/block-package.ts
|
|
7
7
|
/**
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-CV6XTApk.js");
|
|
7
7
|
let _camstack_types_node = require("@camstack/types/node");
|
|
8
8
|
let zod = require("zod");
|
|
9
9
|
let node_crypto = require("node:crypto");
|
|
@@ -1644,7 +1644,7 @@ async function getBindings(deps, input) {
|
|
|
1644
1644
|
entries.push({
|
|
1645
1645
|
capName,
|
|
1646
1646
|
kind: "linked",
|
|
1647
|
-
providerAddonId: deps.ctx.id,
|
|
1647
|
+
providerAddonId: require_dist.bareAddonId(deps.ctx.id),
|
|
1648
1648
|
providerNodeId: deps.ctx.kernel.localNodeId ?? "hub",
|
|
1649
1649
|
nativeAddonId: ""
|
|
1650
1650
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { D as deviceStateCapability, E as deviceManagerCapability, I as getByPath, M as enumerateSchemaFields, N as evaluateLinkExpression, O as deviceStatusCapability, Rt as sleep, S as buildStreamParamsConfigSchema, St as WELL_KNOWN_TAB_MAP, Y as normalizeUnit, Z as parseStreamParamsFormPatch, _t as DeviceFeature, a as CAP_NAMES_WITH_STATUS, ft as errMsg, j as enumerateItemArrayFields, jt as isDeviceConfigCap, lt as validateExpressionSource, pt as BaseAddon, s as DeviceStatusSchema, st as toExpressionValue, t as ALL_CAPABILITY_DEFINITIONS, tt as setByPath, u as STREAM_PROFILE_META, v as applyTransform, vt as DeviceRole, x as bareAddonId, yt as DeviceType, zt as EventCategory } from "../../dist-BqJJWCS8.mjs";
|
|
2
2
|
import { canonicalDeviceFingerprint } from "@camstack/types/node";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
@@ -1639,7 +1639,7 @@ async function getBindings(deps, input) {
|
|
|
1639
1639
|
entries.push({
|
|
1640
1640
|
capName,
|
|
1641
1641
|
kind: "linked",
|
|
1642
|
-
providerAddonId: deps.ctx.id,
|
|
1642
|
+
providerAddonId: bareAddonId(deps.ctx.id),
|
|
1643
1643
|
providerNodeId: deps.ctx.kernel.localNodeId ?? "hub",
|
|
1644
1644
|
nativeAddonId: ""
|
|
1645
1645
|
});
|
|
@@ -31,6 +31,31 @@
|
|
|
31
31
|
* evidence the wrapper was bound. The cost of erring open is a spurious
|
|
32
32
|
* ring on a camera the operator unbound but left configured, for at most
|
|
33
33
|
* two reload cycles. The cost of erring closed is the press.
|
|
34
|
+
*
|
|
35
|
+
* ─────────────────────────────────────────────────────────────────────
|
|
36
|
+
* 2026-08-07 (D72). The corroboration above was DEFEATED, and the reason
|
|
37
|
+
* matters more than the fix. `refreshBindingMirror` matched the binding with
|
|
38
|
+
* `entry.providerAddonId === this.ctx.id`. The two addon-context factories do
|
|
39
|
+
* not spell `ctx.id` the same way: a forked addon gets `virtual-doorbell`, a
|
|
40
|
+
* hub-main BUILTIN gets `addon:virtual-doorbell`. Every entry on the wire
|
|
41
|
+
* carries the bare form. So for this builtin the comparison was false for
|
|
42
|
+
* every entry, forever — not a blip. Corroboration only defends against a
|
|
43
|
+
* TRANSIENT bad read; two systematically-wrong reads agree with each other,
|
|
44
|
+
* and the mirror latched `unbound` with no way back except an operator
|
|
45
|
+
* opening the settings page. A real press on camera 615 was dropped.
|
|
46
|
+
*
|
|
47
|
+
* Two things follow, and both are now load-bearing here:
|
|
48
|
+
*
|
|
49
|
+
* 1. The comparison goes through `isSameAddonId` ({@link entriesBindWrapper}),
|
|
50
|
+
* never a raw `===`.
|
|
51
|
+
* 2. The DERIVED view (`deviceManager.getBindings`) is no longer the sole
|
|
52
|
+
* input. Before a negative is believed — and again on the ring path
|
|
53
|
+
* before a press is destroyed — the DURABLE authority is consulted
|
|
54
|
+
* directly ({@link readDurableWrapperBinding} over the `device-manager`
|
|
55
|
+
* addon store's `deviceBindings` map). That read carries a discriminator
|
|
56
|
+
* the derived view genuinely cannot offer: a store answering from an
|
|
57
|
+
* empty snapshot (D44) has no `deviceBindings` key at all, while a
|
|
58
|
+
* genuine unbind leaves the key present and merely omits the row.
|
|
34
59
|
*/
|
|
35
60
|
/**
|
|
36
61
|
* `bound` — a read saw the wrapper's activation.
|
|
@@ -48,3 +73,43 @@ export declare function nextBindingState(previous: DoorbellBindingState | undefi
|
|
|
48
73
|
export declare function allowsRing(state: DoorbellBindingState | undefined): boolean;
|
|
49
74
|
/** True only when a read has positively confirmed the binding. */
|
|
50
75
|
export declare function hasConfirmedBinding(state: DoorbellBindingState | undefined): boolean;
|
|
76
|
+
/** The fields of a `DeviceBindingEntry` this module reasons about. */
|
|
77
|
+
export interface BindingEntryView {
|
|
78
|
+
readonly capName: string;
|
|
79
|
+
readonly kind: string;
|
|
80
|
+
readonly providerAddonId: string;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Does this list of binding entries name `ownAddonId` as the ACTIVE WRAPPER
|
|
84
|
+
* of `capName`?
|
|
85
|
+
*
|
|
86
|
+
* `isSameAddonId` is the whole point: `ownAddonId` is an `AddonContext.id`,
|
|
87
|
+
* which is prefixed (`addon:…`) in hub-main and bare in a forked runner,
|
|
88
|
+
* while `providerAddonId` is always bare. A raw `===` here is the D72 bug.
|
|
89
|
+
*/
|
|
90
|
+
export declare function entriesBindWrapper(entries: ReadonlyArray<BindingEntryView>, capName: string, ownAddonId: string): boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Render binding entries for a log line. A systematic wrong answer and a
|
|
93
|
+
* one-off blip produce the same VERDICT; only the entries themselves tell
|
|
94
|
+
* them apart, so a negative read never gets to report just its conclusion.
|
|
95
|
+
*/
|
|
96
|
+
export declare function summariseEntries(entries: ReadonlyArray<BindingEntryView>): string[];
|
|
97
|
+
/**
|
|
98
|
+
* `bound` / `unbound` — the durable store answered, and this is its answer.
|
|
99
|
+
* `unreadable` — the store could not be read, or answered from an empty
|
|
100
|
+
* snapshot (D44). It carries NO information and must never destroy work.
|
|
101
|
+
*/
|
|
102
|
+
export type DurableBindingVerdict = 'bound' | 'unbound' | 'unreadable';
|
|
103
|
+
/**
|
|
104
|
+
* Read the DURABLE authority — the `device-manager` addon store's
|
|
105
|
+
* `deviceBindings` map — for "is `ownAddonId` the active wrapper of
|
|
106
|
+
* `capName` on `deviceId`".
|
|
107
|
+
*
|
|
108
|
+
* This is the input the derived `getBindings` view is not: it is the row the
|
|
109
|
+
* operator's toggle actually writes, with no registry resolution, no
|
|
110
|
+
* `defaultActive` auto-binding and no cross-node cap folding in between. It
|
|
111
|
+
* also grades its own trustworthiness, which `getBindings` cannot: the
|
|
112
|
+
* absence of the `deviceBindings` KEY is the signature of a store answering
|
|
113
|
+
* from an empty snapshot, whereas a genuine unbind leaves the key present.
|
|
114
|
+
*/
|
|
115
|
+
export declare function readDurableWrapperBinding(record: unknown, deviceId: number, capName: string, ownAddonId: string): DurableBindingVerdict;
|
|
@@ -67,23 +67,68 @@ export declare class VirtualDoorbellAddon extends BaseAddon<VirtualDoorbellAddon
|
|
|
67
67
|
* byte-shaped like a native firmware ring so every downstream consumer
|
|
68
68
|
* (UI toast, notifier rules, exporters) is agnostic to the origin.
|
|
69
69
|
*
|
|
70
|
-
* The binding gate here is a pure in-memory read
|
|
71
|
-
*
|
|
72
|
-
*
|
|
70
|
+
* The binding gate here is a pure in-memory read on the path that RINGS:
|
|
71
|
+
* an open mirror performs NO I/O and cannot fail. The mirror can only
|
|
72
|
+
* DESTROY a press through the one branch below, and that branch is not
|
|
73
|
+
* allowed to be the last word — see `ringsDespiteUnboundMirror`.
|
|
73
74
|
*/
|
|
74
75
|
private fireDoorbell;
|
|
75
76
|
/**
|
|
76
|
-
*
|
|
77
|
-
* assignment-reload cadence, never while firing.
|
|
77
|
+
* The addon id as the REGISTRY and the bindings store spell it.
|
|
78
78
|
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
|
|
84
|
-
|
|
79
|
+
* `ctx.id` does NOT: hub-main prefixes it (`addon:virtual-doorbell`) while
|
|
80
|
+
* a forked runner does not, and this builtin runs in hub-main. Comparing
|
|
81
|
+
* the raw `ctx.id` to a `providerAddonId` was false for every entry for
|
|
82
|
+
* twelve hours on 2026-08-07 (D72).
|
|
83
|
+
*/
|
|
84
|
+
private get ownAddonId();
|
|
85
|
+
/**
|
|
86
|
+
* One read of the DERIVED binding view. `null` when the read could not be
|
|
87
|
+
* answered at all — which carries no information and must leave the mirror
|
|
88
|
+
* untouched.
|
|
89
|
+
*/
|
|
90
|
+
private readDerivedBinding;
|
|
91
|
+
/**
|
|
92
|
+
* One read of the DURABLE authority: the `device-manager` addon store's
|
|
93
|
+
* `deviceBindings` map, straight from the settings DB.
|
|
94
|
+
*
|
|
95
|
+
* This is deliberately NOT `getBindings`. The derived view folds the store
|
|
96
|
+
* together with the capability registry, `defaultActive` auto-binding and
|
|
97
|
+
* the cluster native-cap feeds — any of which can make it disagree with
|
|
98
|
+
* what the operator actually persisted, and one of which (an addon-id
|
|
99
|
+
* spelling mismatch) made it disagree *systematically* while looking
|
|
100
|
+
* exactly like a genuine unbind. The raw row cannot: it is what the
|
|
101
|
+
* bindings toggle wrote, and it grades its own trustworthiness (D44).
|
|
102
|
+
*/
|
|
103
|
+
private readDurableAuthority;
|
|
104
|
+
/**
|
|
105
|
+
* Reconcile `cameraId`'s mirror against the authority. Runs on the
|
|
106
|
+
* assignment-reload cadence, never while firing — and it runs on EVERY
|
|
107
|
+
* cycle regardless of the current verdict, so a camera sitting in
|
|
108
|
+
* `unbound` returns to `bound` on its own the moment the authority says
|
|
109
|
+
* so. There is no latch here that an operator has to clear.
|
|
110
|
+
*
|
|
111
|
+
* A positive derived read is believed immediately. A NEGATIVE one never
|
|
112
|
+
* is: the durable authority is asked, and it outranks the derived view in
|
|
113
|
+
* the direction that destroys work. Only when the authority agrees does
|
|
114
|
+
* the negative get folded, and even then `nextBindingState` still wants a
|
|
115
|
+
* second consecutive one (D49).
|
|
85
116
|
*/
|
|
86
117
|
private refreshBindingMirror;
|
|
118
|
+
/**
|
|
119
|
+
* The mirror says `unbound` and a real press just arrived. Decide, with
|
|
120
|
+
* ONE read of the durable authority, whether to destroy it.
|
|
121
|
+
*
|
|
122
|
+
* D49 forbade I/O on the ring path because the read it would have made was
|
|
123
|
+
* the same fallible derived read that caused the problem. This read is
|
|
124
|
+
* different in both directions: it is the authority rather than a view of
|
|
125
|
+
* it, and it is paid ONLY on the branch that would otherwise drop a press —
|
|
126
|
+
* a ring is rare, one query is cheap, and a dropped ring has no retry, no
|
|
127
|
+
* reconcile and nothing downstream that notices.
|
|
128
|
+
*
|
|
129
|
+
* Returns `true` when the ring must proceed.
|
|
130
|
+
*/
|
|
131
|
+
private ringsDespiteUnboundMirror;
|
|
87
132
|
/**
|
|
88
133
|
* Record a binding we observed FIRST-HAND. Both callers are cap methods
|
|
89
134
|
* the router only reaches by resolving this wrapper for this device —
|