@camstack/system 1.1.21 → 1.1.23
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/builtins/device-manager/device-aggregation.d.ts +8 -1
- package/dist/builtins/device-manager/device-bindings-store.d.ts +3 -0
- package/dist/builtins/device-manager/device-link-cycle.d.ts +18 -0
- package/dist/builtins/device-manager/device-link-resolver.d.ts +20 -2
- package/dist/builtins/device-manager/device-manager.addon.d.ts +9 -2
- package/dist/builtins/device-manager/device-manager.addon.js +353 -52
- package/dist/builtins/device-manager/device-manager.addon.mjs +354 -53
- package/dist/builtins/device-manager/device-meta-store.d.ts +6 -0
- package/dist/builtins/device-manager/device-provider-context.d.ts +4 -0
- package/dist/builtins/device-manager/device-state-mirror.d.ts +13 -5
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/kernel/transport/cap-route-resolver.d.ts +10 -1
- package/dist/kernel/transport/cap-route.d.ts +20 -0
- package/dist/{manifest-python-deps-Di_9ayDE.js → manifest-python-deps-D7iR07uA.js} +12 -2
- package/dist/{manifest-python-deps-Bp7nvTNF.mjs → manifest-python-deps-hDWMDe_b.mjs} +12 -2
- package/package.json +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-D7iR07uA.js");
|
|
3
3
|
const require_custom_action_registry = require("./custom-action-registry-vLYEFTtv.js");
|
|
4
4
|
let node_fs = require("node:fs");
|
|
5
5
|
node_fs = require_chunk.__toESM(node_fs);
|
package/dist/addon-runner.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { I as createUdsLoggerWithControl, L as LocalChildClient, at as setWorkerNativeCapsChangeListener, bt as resolveAddonClass, i as createUdsAddonContext, nt as getWorkerNativeCapProvider, rt as getWorkerNativeCapSnapshot, st as validateProviderRegistrations, t as installManifestPythonDeps, yt as installManifestNativeDeps } from "./manifest-python-deps-
|
|
1
|
+
import { I as createUdsLoggerWithControl, L as LocalChildClient, at as setWorkerNativeCapsChangeListener, bt as resolveAddonClass, i as createUdsAddonContext, nt as getWorkerNativeCapProvider, rt as getWorkerNativeCapSnapshot, st as validateProviderRegistrations, t as installManifestPythonDeps, yt as installManifestNativeDeps } from "./manifest-python-deps-hDWMDe_b.mjs";
|
|
2
2
|
import { t as CustomActionRegistry } from "./custom-action-registry-BEXwC-oo.mjs";
|
|
3
3
|
import { register } from "node:module";
|
|
4
4
|
import * as fs from "node:fs";
|
|
@@ -214,7 +214,14 @@ export declare function setWrapperActive(deps: AggregationDeps, input: {
|
|
|
214
214
|
* bound caps expose, for the operator's cross-device wiring UI. Binding-driven:
|
|
215
215
|
* walks `getBindings(deviceId)`, skips wrapper caps (their status schemas are
|
|
216
216
|
* internal book-keeping, not wireable domain data), and enumerates each cap's
|
|
217
|
-
* status schema leaf fields
|
|
217
|
+
* status schema leaf fields (per-item fields included for item-array caps).
|
|
218
|
+
*
|
|
219
|
+
* `includeSynthesizable: true` (TARGET pickers only) additionally unions in
|
|
220
|
+
* UNBOUND device-scoped caps that declare `status.empty` (the synthesize-target
|
|
221
|
+
* marker) and whose `deviceTypes` admit this device's persisted type — so the
|
|
222
|
+
* FIRST link to a synthesize-only cap (consumables on an HA vacuum) can be
|
|
223
|
+
* authored before any binding exists. Default (absent/false) behavior is
|
|
224
|
+
* byte-identical to the binding-driven catalog.
|
|
218
225
|
*/
|
|
219
226
|
export declare function getWireableFields(deps: AggregationDeps, input: Parameters<IDeviceManagerProvider['getWireableFields']>[0]): ReturnType<IDeviceManagerProvider['getWireableFields']>;
|
|
220
227
|
export {};
|
|
@@ -14,6 +14,9 @@ export interface BindingsDeps {
|
|
|
14
14
|
readonly ctx: AddonContext;
|
|
15
15
|
readonly capabilityRegistry: ICapabilityRegistry | undefined;
|
|
16
16
|
readonly remoteNativeCaps: RemoteNativeCaps;
|
|
17
|
+
/** O(1) gate over devices that have `deviceLinks` (the addon's live set).
|
|
18
|
+
* Optional: when absent, getBindings adds no virtual `linked` entries. */
|
|
19
|
+
readonly devicesWithLinks?: ReadonlySet<number>;
|
|
17
20
|
}
|
|
18
21
|
/**
|
|
19
22
|
* Wire the push-fed cross-process native-cap cache (`remoteNativeCaps`).
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { DeviceLink } from '@camstack/types';
|
|
2
|
+
/** The slice of a persisted meta row cycle detection needs. Structural subset
|
|
3
|
+
* of `PersistedDeviceMeta` so tests (and future callers) can pass plain rows. */
|
|
4
|
+
export interface LinkCycleMetaRow {
|
|
5
|
+
readonly id: number;
|
|
6
|
+
readonly stableId: string;
|
|
7
|
+
readonly parentDeviceId: number | null;
|
|
8
|
+
readonly deviceLinks?: readonly DeviceLink[];
|
|
9
|
+
}
|
|
10
|
+
/** Node key of the dependency graph: `${deviceId}:${cap}`. */
|
|
11
|
+
type NodeKey = string;
|
|
12
|
+
/**
|
|
13
|
+
* Detect whether replacing `editedDeviceId`'s links with `editedLinks` closes
|
|
14
|
+
* a dependency cycle. Returns the cycle as an ordered list of node keys
|
|
15
|
+
* (first node repeated at the end) or null when the set is safe.
|
|
16
|
+
*/
|
|
17
|
+
export declare function findDeviceLinkCycle(allMeta: Record<string, LinkCycleMetaRow>, editedDeviceId: number, editedLinks: readonly DeviceLink[]): readonly NodeKey[] | null;
|
|
18
|
+
export {};
|
|
@@ -1,15 +1,33 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { DeviceLink } from '@camstack/types';
|
|
2
|
+
import { CapabilityStatusItemArray, DeviceLink } from '@camstack/types';
|
|
3
3
|
/** One resolved source reading paired with the link that produced it. The
|
|
4
4
|
* `sourceValue` is already transformed; `undefined` skips the overlay. */
|
|
5
5
|
export interface ResolvedLinkValue {
|
|
6
6
|
readonly link: DeviceLink;
|
|
7
7
|
readonly sourceValue: unknown;
|
|
8
8
|
}
|
|
9
|
+
/**
|
|
10
|
+
* Resolve one link's transformed value. Field sources read via `readField`
|
|
11
|
+
* (the caller supplies the sibling lookup — sync, e.g. the in-hub state
|
|
12
|
+
* mirror); literal sources use their per-device constant and never consult
|
|
13
|
+
* the reader. Returns `undefined` to skip the overlay (unreadable field).
|
|
14
|
+
* Pure. Async source reads (`resolveLinkedStatus`'s provider `getStatus`
|
|
15
|
+
* path) cannot use this helper for field sources — they branch on
|
|
16
|
+
* `source.kind` directly.
|
|
17
|
+
*/
|
|
18
|
+
export declare function resolveLinkValue(link: DeviceLink, readField: (cap: string, fieldPath: string) => unknown): unknown;
|
|
9
19
|
/**
|
|
10
20
|
* Overlay transformed source values onto `base` by dot-path, then validate the
|
|
11
21
|
* result against the target cap's `statusSchema`. On validation failure the
|
|
12
22
|
* overlay is discarded and `base` is returned unchanged (a misconfigured link
|
|
13
23
|
* must never corrupt a cap response). Pure — all I/O happens in the caller.
|
|
24
|
+
*
|
|
25
|
+
* Item-array grouping (P2b): when the cap declares `status.itemArray`, links
|
|
26
|
+
* carrying a `target.itemKey` are grouped per key and upserted as items into
|
|
27
|
+
* the array (see `upsertItemArrayLinks`); their `fieldPath` is relative to
|
|
28
|
+
* ONE item ('level', 'status', 'label'). Links WITHOUT an itemKey keep the
|
|
29
|
+
* scalar dot-path behavior unchanged. A link with an itemKey on a cap that
|
|
30
|
+
* declares NO `itemArray` is dropped (its item-relative path must never be
|
|
31
|
+
* scalar-applied to the status root).
|
|
14
32
|
*/
|
|
15
|
-
export declare function mergeLinkedStatus(base: Record<string, unknown>, resolved: readonly ResolvedLinkValue[], statusSchema?: z.ZodType): Record<string, unknown>;
|
|
33
|
+
export declare function mergeLinkedStatus(base: Record<string, unknown>, resolved: readonly ResolvedLinkValue[], statusSchema?: z.ZodType, itemArray?: CapabilityStatusItemArray): Record<string, unknown>;
|
|
@@ -59,10 +59,15 @@ export declare class DeviceManagerAddon extends BaseAddon {
|
|
|
59
59
|
private linkTargets;
|
|
60
60
|
/** `${sourceDeviceId}:${sourceCap}` → targets to recompute when that source changes. */
|
|
61
61
|
private linkDependents;
|
|
62
|
-
/** Expected source `stableId`s (`${container}-${sourceKey}`
|
|
62
|
+
/** Expected source `stableId`s (`${container}-${sourceKey}` for sibling
|
|
63
|
+
* sources, the full `sourceStableId` for global sources) across all links,
|
|
63
64
|
* resolved or not — gates the `registerDevice` rebuild so only a registering
|
|
64
65
|
* device that IS a link source triggers a reindex (not every boot restore). */
|
|
65
66
|
private expectedSourceStableIds;
|
|
67
|
+
/** In-flight `${deviceId}:${cap}` pairs of `resolveLinkedStatus` — the P2e
|
|
68
|
+
* defensive re-entrancy guard bounding link cycles at resolve time. Mutated
|
|
69
|
+
* in place (never reassigned), so the host exposes a direct reference. */
|
|
70
|
+
private readonly linkResolveInFlight;
|
|
66
71
|
/** Test/diagnostic accessors. */
|
|
67
72
|
linkTargetKeys(): string[];
|
|
68
73
|
linkDependentsKeys(): string[];
|
|
@@ -104,7 +109,9 @@ export declare class DeviceManagerAddon extends BaseAddon {
|
|
|
104
109
|
private discoveryProviderLabel;
|
|
105
110
|
/** Provider ids that report `supportsDiscovery() === true` (probed in parallel). */
|
|
106
111
|
private listDiscoveryCapableProviderIds;
|
|
107
|
-
/** Build the dependency context the extracted binding resolvers consume.
|
|
112
|
+
/** Build the dependency context the extracted binding resolvers consume.
|
|
113
|
+
* `devicesWithLinks` is mutated in place (never reassigned) so the direct
|
|
114
|
+
* reference stays live — it gates the virtual `linked` binding step. */
|
|
108
115
|
private get bindingsDeps();
|
|
109
116
|
getBindings(input: {
|
|
110
117
|
deviceId: number;
|