@camstack/types 1.1.21 → 1.1.22

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,7 +1,7 @@
1
+ import type { ZodType } from 'zod';
1
2
  import type { AddonContext, AddonInitResult, CapabilitiesAccess, ProviderRegistration } from '../interfaces/addon.js';
2
- import type { ConfigUISchema, ConfigUISchemaWithValues, ConfigField, ConfigSection } from '../interfaces/config-ui.js';
3
+ import type { ConfigField, ConfigSection, ConfigUISchema, ConfigUISchemaWithValues } from '../interfaces/config-ui.js';
3
4
  import { type DurableState } from './durable-state.js';
4
- import type { ZodType } from 'zod';
5
5
  export type { CapabilitiesAccess };
6
6
  /**
7
7
  * Utility type that constrains a ConfigField's `key` to only accept
@@ -182,8 +182,29 @@ export declare abstract class BaseAddon<TConfig extends object = Record<string,
182
182
  protected globalSettingsSchema(_cap?: string): ConfigUISchema | null;
183
183
  /** Override to provide device-level settings UI schema. */
184
184
  protected deviceSettingsSchema(): ConfigUISchema | null;
185
- getGlobalSettings(overlay?: Record<string, unknown>, cap?: string, _nodeId?: string): Promise<ConfigUISchemaWithValues | null>;
186
- updateGlobalSettings(patch: Partial<TConfig>, _nodeId?: string): Promise<void>;
185
+ getGlobalSettings(overlay?: Record<string, unknown>, cap?: string, nodeId?: string): Promise<ConfigUISchemaWithValues | null>;
186
+ /**
187
+ * The raw addon store PROJECTED onto the target node's bare per-node keys:
188
+ * every `perNode: true` field carries THAT node's scoped value on its bare
189
+ * key (absent scoped key ⇒ key absent, so the schema `default` wins — no
190
+ * bare fallback), all `@`-scoped and stray bare per-node keys are dropped.
191
+ * A no-op passthrough when the schema declares no `perNode` field.
192
+ *
193
+ * This is the sanctioned way for a `getGlobalSettings` OVERRIDE that needs
194
+ * the store for custom option logic (option narrowing, value snapping) to
195
+ * read it per-node — never `ctx.settings.readAddonStore()` directly.
196
+ * `nodeId` omitted ⇒ the local node (node-blind injection from ctx).
197
+ */
198
+ protected resolveGlobalStore(nodeId?: string, cap?: string): Promise<Record<string, unknown>>;
199
+ updateGlobalSettings(patch: Partial<TConfig>, nodeId?: string): Promise<void>;
200
+ /**
201
+ * The set of field keys the global settings schema declares `perNode: true`
202
+ * — derived once per `cap` argument and memoized (schemas are static
203
+ * declarations). Empty set ⇒ every per-node code path is bypassed and the
204
+ * settings API behaves exactly like the legacy node-agnostic one.
205
+ */
206
+ private readonly _perNodeKeysCache;
207
+ private perNodeKeys;
187
208
  /**
188
209
  * If any field in `patch` is marked `requiresRestart` in `schema`,
189
210
  * schedule an addon restart for the next tick. Deferred via
@@ -255,6 +276,11 @@ export declare abstract class BaseAddon<TConfig extends object = Record<string,
255
276
  * The merge is shallow: each key in `defaults` is checked against the store.
256
277
  * Only keys present in defaults are read — the store can contain extra keys
257
278
  * (e.g. from older versions) without polluting the typed config.
279
+ *
280
+ * Keys the global settings schema declares `perNode: true` resolve from
281
+ * THIS node's scoped key (`<key>@<localNode>`) via `readNodeValue` — never
282
+ * from the bare key — so a per-node field resolves to this node's own
283
+ * selection at boot (absent scoped key ⇒ the constructor default wins).
258
284
  */
259
285
  protected resolveConfig(): Promise<void>;
260
286
  /**
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Per-node scoping for the shared addon-settings blob.
3
+ *
4
+ * An addon's settings store is hub-central (the `addon-settings` cap is
5
+ * hub-routed — the hub instance answers for every node), so fields whose
6
+ * value is a NODE fact (decoder backend, engine pick, probed hardware
7
+ * capabilities) persist under the node-scoped key `<key>@<nodeId>` inside
8
+ * the single shared blob. The SCHEMA field key stays bare: the write path
9
+ * ({@link scopePatch}) maps the bare field onto the target node's scoped
10
+ * key; the read/hydrate path ({@link projectStore}) maps THIS node's value
11
+ * back, so UI forms and `resolveConfig` only ever see the bare key.
12
+ *
13
+ * Fields opt in via the `perNode: true` schema marker on `ConfigFieldBase`
14
+ * (`interfaces/config-ui.ts`); `BaseAddon` derives the key set from the
15
+ * schema and routes reads/writes through these helpers.
16
+ *
17
+ * ## No bare-key fallback — deliberate
18
+ *
19
+ * {@link readNodeValue} reads the node-scoped key ONLY. A node with no
20
+ * scoped key resolves to `undefined` so the field's schema `default` wins —
21
+ * NEVER `store[base]` and never another node's value. A bare legacy key in
22
+ * the store is invisible to every node, hub included, so one node's
23
+ * selection can never leak onto another. (This generalizes the
24
+ * `decoder-backend-keys.ts` semantics — the no-fallback variant — over an
25
+ * arbitrary set of per-node field keys.)
26
+ *
27
+ * Pure functions only — no I/O, no imports beyond the language. This is a
28
+ * LEAF module: import it via its deep path, never from the root barrel.
29
+ */
30
+ /**
31
+ * Normalize a raw kernel node id to the bare node id used for scoping.
32
+ * `localNodeId` can carry a `<node>/<addon>` suffix on forked child
33
+ * processes; per-node settings are per-NODE, so strip the addon segment.
34
+ * `undefined` / `null` / empty falls back to `'hub'`.
35
+ */
36
+ export declare function normalizeNodeId(raw: string | undefined | null): string;
37
+ /** The node-scoped store key for a per-node field: `<base>@<nodeId>`. */
38
+ export declare function nodeScopedKey(base: string, nodeId: string): string;
39
+ /**
40
+ * Read a node's value for a per-node field from the raw shared store:
41
+ * the node-scoped key when present, otherwise `undefined`.
42
+ * Deliberately NO bare-key fallback (see module doc) — the caller lets the
43
+ * schema `default` win on `undefined`.
44
+ */
45
+ export declare function readNodeValue(store: Readonly<Record<string, unknown>>, base: string, nodeId: string): unknown;
46
+ /**
47
+ * Re-map a UI/settings patch so every bare perNode field persists under the
48
+ * TARGET node's scoped key; all other keys pass through unchanged. Used on
49
+ * the write path so a save for one node never clobbers another node's value
50
+ * (and the bare key is never written). Returns a new object — the input
51
+ * patch is not mutated.
52
+ */
53
+ export declare function scopePatch(patch: Readonly<Record<string, unknown>>, perNodeKeys: ReadonlySet<string>, nodeId: string): Record<string, unknown>;
54
+ /**
55
+ * Project the raw shared store onto the bare schema keys for ONE node so a
56
+ * UI schema (whose field keys are bare) hydrates from that node's own
57
+ * values:
58
+ *
59
+ * - EVERY `@`-scoped key (any node's) is dropped from the pass-through.
60
+ * - Every bare perNode key is dropped from the pass-through (a stray bare
61
+ * legacy key must never hydrate any node — no bare fallback).
62
+ * - THIS node's effective value ({@link readNodeValue}) is then laid onto
63
+ * each bare perNode key; when the node has no scoped key the bare key is
64
+ * left ABSENT so the field's schema `default` wins.
65
+ *
66
+ * Returns a new object — the input store is not mutated.
67
+ */
68
+ export declare function projectStore(store: Readonly<Record<string, unknown>>, perNodeKeys: ReadonlySet<string>, nodeId: string): Record<string, unknown>;
package/dist/addon.js CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_sleep = require("./sleep-DaQgDq90.js");
2
+ const require_sleep = require("./sleep-B8cp-HUn.js");
3
3
  const require_err_msg = require("./err-msg-COpsHMw2.js");
4
4
  exports.BaseAddon = require_sleep.BaseAddon;
5
5
  exports.DATAPLANE_SECRET_HEADER = require_sleep.DATAPLANE_SECRET_HEADER;
package/dist/addon.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { A as ReadinessRegistry, C as asJsonObject, O as parseJsonUnknown, P as scopeKey, T as asString, a as adminUiCapability, b as DeviceType, gt as DisposerChain, ht as EventCategory, i as deviceOpsCapability, j as ReadinessTimeoutError, k as DATAPLANE_SECRET_HEADER, o as createDeviceProxy, ot as BaseAddon, p as expandCapMethods, st as normalizeAddonInitResult, t as sleep, ut as emitReadiness } from "./sleep-BO1nweKv.mjs";
1
+ import { A as ReadinessRegistry, C as asJsonObject, O as parseJsonUnknown, P as scopeKey, T as asString, a as adminUiCapability, b as DeviceType, gt as DisposerChain, ht as EventCategory, i as deviceOpsCapability, j as ReadinessTimeoutError, k as DATAPLANE_SECRET_HEADER, o as createDeviceProxy, ot as BaseAddon, p as expandCapMethods, st as normalizeAddonInitResult, t as sleep, ut as emitReadiness } from "./sleep-BiDFW0E7.mjs";
2
2
  import { t as errMsg } from "./err-msg-IQTHeDzc.mjs";
3
3
  export { BaseAddon, DATAPLANE_SECRET_HEADER, DeviceType, DisposerChain, EventCategory, ReadinessRegistry, ReadinessTimeoutError, adminUiCapability, asJsonObject, asString, createDeviceProxy, deviceOpsCapability, emitReadiness, errMsg, expandCapMethods, normalizeAddonInitResult, parseJsonUnknown, scopeKey, sleep };
@@ -116,8 +116,8 @@ export declare const cameraStreamsCapability: {
116
116
  sourceCamStreamId: z.ZodNullable<z.ZodString>;
117
117
  status: z.ZodEnum<{
118
118
  error: "error";
119
- idle: "idle";
120
119
  unassigned: "unassigned";
120
+ idle: "idle";
121
121
  connecting: "connecting";
122
122
  streaming: "streaming";
123
123
  }>;
@@ -280,8 +280,8 @@ export declare const cameraStreamsCapability: {
280
280
  sourceCamStreamId: z.ZodNullable<z.ZodString>;
281
281
  status: z.ZodEnum<{
282
282
  error: "error";
283
- idle: "idle";
284
283
  unassigned: "unassigned";
284
+ idle: "idle";
285
285
  connecting: "connecting";
286
286
  streaming: "streaming";
287
287
  }>;
@@ -323,22 +323,22 @@ export declare const cameraStreamsCapability: {
323
323
  slotStatuses: z.ZodObject<{
324
324
  high: z.ZodOptional<z.ZodEnum<{
325
325
  error: "error";
326
- idle: "idle";
327
326
  unassigned: "unassigned";
327
+ idle: "idle";
328
328
  connecting: "connecting";
329
329
  streaming: "streaming";
330
330
  }>>;
331
331
  mid: z.ZodOptional<z.ZodEnum<{
332
332
  error: "error";
333
- idle: "idle";
334
333
  unassigned: "unassigned";
334
+ idle: "idle";
335
335
  connecting: "connecting";
336
336
  streaming: "streaming";
337
337
  }>>;
338
338
  low: z.ZodOptional<z.ZodEnum<{
339
339
  error: "error";
340
- idle: "idle";
341
340
  unassigned: "unassigned";
341
+ idle: "idle";
342
342
  connecting: "connecting";
343
343
  streaming: "streaming";
344
344
  }>>;
@@ -109,6 +109,7 @@ export declare const decoderCapability: {
109
109
  readonly pullFrames: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
110
110
  sessionId: z.ZodString;
111
111
  maxCount: z.ZodDefault<z.ZodNumber>;
112
+ waitMs: z.ZodOptional<z.ZodNumber>;
112
113
  }, z.core.$strip>, z.ZodArray<z.ZodObject<{
113
114
  data: z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>;
114
115
  width: z.ZodNumber;
@@ -125,6 +126,7 @@ export declare const decoderCapability: {
125
126
  readonly pullHandles: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
126
127
  sessionId: z.ZodString;
127
128
  maxCount: z.ZodDefault<z.ZodNumber>;
129
+ waitMs: z.ZodOptional<z.ZodNumber>;
128
130
  }, z.core.$strip>, z.ZodArray<z.ZodObject<{
129
131
  shmId: z.ZodString;
130
132
  slot: z.ZodNumber;
@@ -177,6 +177,7 @@ export { type ITemperatureSensorProvider, type TemperatureSensorStatus, Temperat
177
177
  export { type IToastProvider, ToastSchema, toastCapability } from './toast.cap.js';
178
178
  export { type IUpdateProvider, type UpdateStatus, UpdateStatusSchema, updateCapability, } from './update.cap.js';
179
179
  export { ApiKeySummarySchema, CreateApiKeyInputSchema, CreateApiKeyResultSchema, CreateScopedTokenInputSchema, CreateScopedTokenResultSchema, CreateUserInputSchema, type IUserManagementProvider, ScopedTokenSummarySchema, UpdateUserInputSchema, UserSummarySchema, userManagementCapability, } from './user-management.cap.js';
180
+ export { type IPetFeederProvider, PET_FEEDER_MANUAL_FEED_MAX, PET_FEEDER_MANUAL_FEED_MIN, type PetFeederStatus, PetFeederStatusSchema, petFeederCapability, } from './pet-feeder.cap.js';
180
181
  export { type IVacuumControlProvider, type TankStatus, TankStatusSchema, type VacuumControlStatus, VacuumControlStatusSchema, type VacuumState, VacuumStateSchema, vacuumControlCapability, } from './vacuum-control.cap.js';
181
182
  export { type IValveProvider, type ValveState, ValveStateSchema, type ValveStatus, ValveStatusSchema, valveCapability, } from './valve.cap.js';
182
183
  export { type IVibrationProvider, type VibrationStatus, VibrationStatusSchema, vibrationCapability, } from './vibration.cap.js';
@@ -213,6 +214,7 @@ import type { cameraPipelineConfigCapability } from './camera-pipeline-config.ca
213
214
  import type { cameraStreamsCapability } from './camera-streams.cap.js';
214
215
  import type { carbonMonoxideCapability } from './carbon-monoxide.cap.js';
215
216
  import type { climateControlCapability } from './climate-control.cap.js';
217
+ import type { petFeederCapability } from './pet-feeder.cap.js';
216
218
  import type { colorCapability } from './color.cap.js';
217
219
  import type { connectivityCapability } from './connectivity.cap.js';
218
220
  import type { consumablesCapability } from './consumables.cap.js';
@@ -306,6 +308,6 @@ import type { webrtcSessionCapability } from './webrtc-session.cap.js';
306
308
  import type { zoneAnalyticsCapability } from './zone-analytics.cap.js';
307
309
  import type { zoneRulesCapability } from './zone-rules.cap.js';
308
310
  import type { zonesCapability } from './zones.cap.js';
309
- type AnyCapability = typeof addonSettingsCapability | typeof alertsCapability | typeof storageCapability | typeof storageProviderCapability | typeof storageEvictableCapability | typeof filesystemBrowseCapability | typeof backupCapability | typeof settingsStoreCapability | typeof logDestinationCapability | typeof adminUiCapability | typeof ssoBridgeCapability | typeof userPasskeysCapability | typeof smtpProviderCapability | typeof mqttBrokerCapability | typeof brokerCapability | typeof deviceAdoptionCapability | typeof deviceExportCapability | typeof addonPagesCapability | typeof addonPagesSourceCapability | typeof addonWidgetsCapability | typeof addonWidgetsSourceCapability | typeof customModelRegistryCapability | typeof modelDistributorCapability | typeof modelConvertCapability | typeof addonRoutesCapability | typeof streamBrokerCapability | typeof decoderCapability | typeof restreamerCapability | typeof webrtcCapability | typeof webrtcSessionCapability | typeof cameraStreamsCapability | typeof streamingEngineCapability | typeof motionDetectionCapability | typeof pipelineExecutorCapability | typeof detectionPipelineCapability | typeof cameraPipelineConfigCapability | typeof pipelineRunnerCapability | typeof pipelineOrchestratorCapability | typeof audioAnalyzerCapability | typeof audioAnalysisCapability | typeof audioCodecCapability | typeof embeddingEncoderCapability | typeof deviceProviderCapability | typeof deviceManagerCapability | typeof deviceStateCapability | typeof authProviderCapability | typeof networkAccessCapability | typeof turnProviderCapability | typeof snapshotCapability | typeof snapshotProviderCapability | typeof notificationOutputCapability | typeof advancedNotifierCapability | typeof pipelineAnalyticsCapability | typeof metricsProviderCapability | typeof ptzCapability | typeof ptzAutotrackCapability | typeof consumablesCapability | typeof rebootCapability | typeof deviceDiscoveryCapability | typeof brightnessCapability | typeof colorCapability | typeof climateControlCapability | typeof coverCapability | typeof valveCapability | typeof humidifierCapability | typeof waterHeaterCapability | typeof weatherCapability | typeof imageCapability | typeof lockControlCapability | typeof vacuumControlCapability | typeof lawnMowerControlCapability | typeof fanControlCapability | typeof controlCapability | typeof notifierCapability | typeof mediaPlayerCapability | typeof alarmPanelCapability | typeof presenceCapability | typeof scriptRunnerCapability | typeof automationControlCapability | typeof motionTriggerCapability | typeof eventsCapability | typeof zonesCapability | typeof zoneRulesCapability | typeof zoneAnalyticsCapability | typeof audioMetricsCapability | typeof motionCapability | typeof contactCapability | typeof floodCapability | typeof smokeCapability | typeof carbonMonoxideCapability | typeof gasCapability | typeof tamperCapability | typeof vibrationCapability | typeof connectivityCapability | typeof binaryCapability | typeof temperatureSensorCapability | typeof humiditySensorCapability | typeof ambientLightSensorCapability | typeof pressureSensorCapability | typeof powerMeterCapability | typeof airQualitySensorCapability | typeof numericSensorCapability | typeof enumSensorCapability | typeof recordingCapability | typeof deviceOpsCapability | typeof platformProbeCapability | typeof localNetworkCapability | typeof meshNetworkCapability | typeof userManagementCapability | typeof systemCapability | typeof networkQualityCapability | typeof toastCapability | typeof nodesCapability | typeof integrationsCapability | typeof addonsCapability | typeof oauthIntegrationCapability | typeof streamParamsCapability | typeof streamCatalogCapability | typeof motionZonesCapability | typeof privacyMaskCapability;
311
+ type AnyCapability = typeof addonSettingsCapability | typeof alertsCapability | typeof storageCapability | typeof storageProviderCapability | typeof storageEvictableCapability | typeof filesystemBrowseCapability | typeof backupCapability | typeof settingsStoreCapability | typeof logDestinationCapability | typeof adminUiCapability | typeof ssoBridgeCapability | typeof userPasskeysCapability | typeof smtpProviderCapability | typeof mqttBrokerCapability | typeof brokerCapability | typeof deviceAdoptionCapability | typeof deviceExportCapability | typeof addonPagesCapability | typeof addonPagesSourceCapability | typeof addonWidgetsCapability | typeof addonWidgetsSourceCapability | typeof customModelRegistryCapability | typeof modelDistributorCapability | typeof modelConvertCapability | typeof addonRoutesCapability | typeof streamBrokerCapability | typeof decoderCapability | typeof restreamerCapability | typeof webrtcCapability | typeof webrtcSessionCapability | typeof cameraStreamsCapability | typeof streamingEngineCapability | typeof motionDetectionCapability | typeof pipelineExecutorCapability | typeof detectionPipelineCapability | typeof cameraPipelineConfigCapability | typeof pipelineRunnerCapability | typeof pipelineOrchestratorCapability | typeof audioAnalyzerCapability | typeof audioAnalysisCapability | typeof audioCodecCapability | typeof embeddingEncoderCapability | typeof deviceProviderCapability | typeof deviceManagerCapability | typeof deviceStateCapability | typeof authProviderCapability | typeof networkAccessCapability | typeof turnProviderCapability | typeof snapshotCapability | typeof snapshotProviderCapability | typeof notificationOutputCapability | typeof advancedNotifierCapability | typeof pipelineAnalyticsCapability | typeof metricsProviderCapability | typeof ptzCapability | typeof ptzAutotrackCapability | typeof consumablesCapability | typeof rebootCapability | typeof deviceDiscoveryCapability | typeof brightnessCapability | typeof colorCapability | typeof climateControlCapability | typeof coverCapability | typeof valveCapability | typeof humidifierCapability | typeof waterHeaterCapability | typeof weatherCapability | typeof imageCapability | typeof lockControlCapability | typeof vacuumControlCapability | typeof petFeederCapability | typeof lawnMowerControlCapability | typeof fanControlCapability | typeof controlCapability | typeof notifierCapability | typeof mediaPlayerCapability | typeof alarmPanelCapability | typeof presenceCapability | typeof scriptRunnerCapability | typeof automationControlCapability | typeof motionTriggerCapability | typeof eventsCapability | typeof zonesCapability | typeof zoneRulesCapability | typeof zoneAnalyticsCapability | typeof audioMetricsCapability | typeof motionCapability | typeof contactCapability | typeof floodCapability | typeof smokeCapability | typeof carbonMonoxideCapability | typeof gasCapability | typeof tamperCapability | typeof vibrationCapability | typeof connectivityCapability | typeof binaryCapability | typeof temperatureSensorCapability | typeof humiditySensorCapability | typeof ambientLightSensorCapability | typeof pressureSensorCapability | typeof powerMeterCapability | typeof airQualitySensorCapability | typeof numericSensorCapability | typeof enumSensorCapability | typeof recordingCapability | typeof deviceOpsCapability | typeof platformProbeCapability | typeof localNetworkCapability | typeof meshNetworkCapability | typeof userManagementCapability | typeof systemCapability | typeof networkQualityCapability | typeof toastCapability | typeof nodesCapability | typeof integrationsCapability | typeof addonsCapability | typeof oauthIntegrationCapability | typeof streamParamsCapability | typeof streamCatalogCapability | typeof motionZonesCapability | typeof privacyMaskCapability;
310
312
  export type CapabilityName = AnyCapability['name'];
311
313
  export type ITypedReadinessRegistry = IReadinessRegistry<CapabilityName>;
@@ -170,8 +170,8 @@ declare const AddonInstanceSchema: z.ZodObject<{
170
170
  pid: z.ZodNumber;
171
171
  state: z.ZodEnum<{
172
172
  running: "running";
173
- starting: "starting";
174
173
  stopped: "stopped";
174
+ starting: "starting";
175
175
  stopping: "stopping";
176
176
  crashed: "crashed";
177
177
  }>;
@@ -466,8 +466,8 @@ export declare const metricsProviderCapability: {
466
466
  pid: z.ZodNumber;
467
467
  state: z.ZodEnum<{
468
468
  running: "running";
469
- starting: "starting";
470
469
  stopped: "stopped";
470
+ starting: "starting";
471
471
  stopping: "stopping";
472
472
  crashed: "crashed";
473
473
  }>;
@@ -47,7 +47,7 @@ export declare const motionDetectionCapability: {
47
47
  readonly methods: {
48
48
  readonly analyze: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
49
49
  deviceId: z.ZodNumber;
50
- frame: z.ZodObject<{
50
+ frame: z.ZodOptional<z.ZodObject<{
51
51
  data: z.ZodCustom<Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>>;
52
52
  format: z.ZodEnum<{
53
53
  jpeg: "jpeg";
@@ -59,7 +59,25 @@ export declare const motionDetectionCapability: {
59
59
  width: z.ZodNumber;
60
60
  height: z.ZodNumber;
61
61
  timestamp: z.ZodNumber;
62
- }, z.core.$strip>;
62
+ }, z.core.$strip>>;
63
+ frameHandle: z.ZodOptional<z.ZodObject<{
64
+ shmId: z.ZodString;
65
+ slot: z.ZodNumber;
66
+ seq: z.ZodNumber;
67
+ width: z.ZodNumber;
68
+ height: z.ZodNumber;
69
+ format: z.ZodEnum<{
70
+ jpeg: "jpeg";
71
+ rgb: "rgb";
72
+ bgr: "bgr";
73
+ yuv420: "yuv420";
74
+ gray: "gray";
75
+ }>;
76
+ pts: z.ZodNumber;
77
+ byteLength: z.ZodNumber;
78
+ nodeId: z.ZodString;
79
+ slotCount: z.ZodNumber;
80
+ }, z.core.$strip>>;
63
81
  }, z.core.$strip>, z.ZodObject<{
64
82
  detected: z.ZodBoolean;
65
83
  regionCount: z.ZodNumber;
@@ -0,0 +1,185 @@
1
+ import { z } from 'zod';
2
+ import { type InferProvider } from './capability-definition.js';
3
+ import { DeviceType } from '../device/device-type.js';
4
+ /**
5
+ * PetKit pet-feeder cap. Models the control + telemetry surface of a
6
+ * cloud-connected smart feeder (Fresh Element / Mini / D3 / D4 / D4S
7
+ * Gemini / D4H / D4SH) as a single coherent slice — bowl food level,
8
+ * battery, desiccant life, feeding state + the four persisted settings
9
+ * (child-lock / indicator-light / feed-sound / volume).
10
+ *
11
+ * Sources: native PetKit (`nodepetkit` `FeederDevice`). Reusable by any
12
+ * feeder integration that speaks the same food/desiccant/hopper surface.
13
+ *
14
+ * `kind: 'poll'` — PetKit exposes only a cloud REST API (no push
15
+ * channel), so the provider refreshes the slice on a poll interval and
16
+ * eagerly after every command.
17
+ *
18
+ * Dual-hopper feeders (D4S/D4SH) split the bowl into two independent
19
+ * hoppers. `isDualHopper` gates the two-hopper UI; `food1`/`food2` carry
20
+ * the per-hopper levels (both `null` on single-hopper models, where
21
+ * `foodLevel` is the single reading). The manual-feed portion honours the
22
+ * PetKit hardware range 4–200 g in 1 g steps.
23
+ *
24
+ * Device status is exposed both raw and decoded, mirroring PetKit's HA
25
+ * integration (RobertD502/py-petkit-api). `status` is the connectivity /
26
+ * power enum (`normal` / `offline` / `on_batteries`); `error` is the
27
+ * decoded human-readable fault message (null / `no_error` = healthy);
28
+ * `errorCode` keeps the raw device integer (0 / null = no error) so a
29
+ * provider that only has the numeric code stays lossless. A provider maps
30
+ * the library's fields onto these; any it cannot determine stays `null`.
31
+ */
32
+ /** PetKit manual-feed portion bounds (grams). Mirrors the HA `manual_feed`
33
+ * number entity (min 4, max 200, step 1, device_class weight). */
34
+ export declare const PET_FEEDER_MANUAL_FEED_MIN = 4;
35
+ export declare const PET_FEEDER_MANUAL_FEED_MAX = 200;
36
+ /**
37
+ * Feeder connectivity / power status — mirrors the HA petkit device-status
38
+ * enum: `normal` (online, mains), `offline` (not reaching PetKit cloud),
39
+ * `on_batteries` (running on battery backup). `null` until first reported.
40
+ */
41
+ export declare const PetFeederDeviceStatusSchema: z.ZodEnum<{
42
+ offline: "offline";
43
+ normal: "normal";
44
+ on_batteries: "on_batteries";
45
+ }>;
46
+ export type PetFeederDeviceStatus = z.infer<typeof PetFeederDeviceStatusSchema>;
47
+ export declare const PetFeederStatusSchema: z.ZodObject<{
48
+ foodLevel: z.ZodNullable<z.ZodNumber>;
49
+ food1: z.ZodNullable<z.ZodNumber>;
50
+ food2: z.ZodNullable<z.ZodNumber>;
51
+ lowFood: z.ZodBoolean;
52
+ batteryPower: z.ZodNullable<z.ZodNumber>;
53
+ desiccantLeftDays: z.ZodNullable<z.ZodNumber>;
54
+ feeding: z.ZodBoolean;
55
+ status: z.ZodNullable<z.ZodEnum<{
56
+ offline: "offline";
57
+ normal: "normal";
58
+ on_batteries: "on_batteries";
59
+ }>>;
60
+ error: z.ZodNullable<z.ZodString>;
61
+ errorCode: z.ZodNullable<z.ZodNumber>;
62
+ isDualHopper: z.ZodBoolean;
63
+ childLock: z.ZodBoolean;
64
+ indicatorLight: z.ZodBoolean;
65
+ feedSound: z.ZodBoolean;
66
+ volume: z.ZodNumber;
67
+ lastFetchedAt: z.ZodNumber;
68
+ }, z.core.$strip>;
69
+ export type PetFeederStatus = z.infer<typeof PetFeederStatusSchema>;
70
+ export declare const petFeederCapability: {
71
+ readonly name: "pet-feeder";
72
+ readonly scope: "device";
73
+ readonly deviceNative: true;
74
+ readonly mode: "singleton";
75
+ readonly deviceTypes: readonly [DeviceType.PetFeeder];
76
+ readonly methods: {
77
+ /**
78
+ * Dispense food now. Single-hopper feeders take `grams`; dual-hopper
79
+ * feeders (D4S/D4SH) accept `hopper1`/`hopper2` to target one or both
80
+ * hoppers. All portions honour the 4–200 g hardware range. At least
81
+ * one of the three must be present — the provider rejects an empty
82
+ * request.
83
+ */
84
+ readonly feed: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
85
+ deviceId: z.ZodNumber;
86
+ grams: z.ZodOptional<z.ZodNumber>;
87
+ hopper1: z.ZodOptional<z.ZodNumber>;
88
+ hopper2: z.ZodOptional<z.ZodNumber>;
89
+ }, z.core.$strip>, z.ZodVoid, "mutation">;
90
+ /** Cancel an in-progress manual feed. */
91
+ readonly cancelFeed: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
92
+ deviceId: z.ZodNumber;
93
+ }, z.core.$strip>, z.ZodVoid, "mutation">;
94
+ /** Reset the desiccant "days remaining" counter after replacing it. */
95
+ readonly resetDesiccant: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
96
+ deviceId: z.ZodNumber;
97
+ }, z.core.$strip>, z.ZodVoid, "mutation">;
98
+ /** Mark a hopper as refilled (D4H/D4S/D4SH). */
99
+ readonly markFoodReplenished: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
100
+ deviceId: z.ZodNumber;
101
+ }, z.core.$strip>, z.ZodVoid, "mutation">;
102
+ /** Call the pet with the recorded prompt (D3). */
103
+ readonly callPet: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
104
+ deviceId: z.ZodNumber;
105
+ }, z.core.$strip>, z.ZodVoid, "mutation">;
106
+ /** Play a stored sound by id (D3 / D4H / D4SH). */
107
+ readonly playSound: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
108
+ deviceId: z.ZodNumber;
109
+ soundId: z.ZodNumber;
110
+ }, z.core.$strip>, z.ZodVoid, "mutation">;
111
+ /** Toggle the child-lock (manual-lock) setting. */
112
+ readonly setChildLock: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
113
+ deviceId: z.ZodNumber;
114
+ on: z.ZodBoolean;
115
+ }, z.core.$strip>, z.ZodVoid, "mutation">;
116
+ /** Toggle the front indicator light. */
117
+ readonly setIndicatorLight: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
118
+ deviceId: z.ZodNumber;
119
+ on: z.ZodBoolean;
120
+ }, z.core.$strip>, z.ZodVoid, "mutation">;
121
+ /** Toggle the dispense chime. */
122
+ readonly setFeedSound: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
123
+ deviceId: z.ZodNumber;
124
+ on: z.ZodBoolean;
125
+ }, z.core.$strip>, z.ZodVoid, "mutation">;
126
+ /** Set the speaker / prompt volume level. */
127
+ readonly setVolume: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
128
+ deviceId: z.ZodNumber;
129
+ level: z.ZodNumber;
130
+ }, z.core.$strip>, z.ZodVoid, "mutation">;
131
+ };
132
+ readonly status: {
133
+ readonly schema: z.ZodObject<{
134
+ foodLevel: z.ZodNullable<z.ZodNumber>;
135
+ food1: z.ZodNullable<z.ZodNumber>;
136
+ food2: z.ZodNullable<z.ZodNumber>;
137
+ lowFood: z.ZodBoolean;
138
+ batteryPower: z.ZodNullable<z.ZodNumber>;
139
+ desiccantLeftDays: z.ZodNullable<z.ZodNumber>;
140
+ feeding: z.ZodBoolean;
141
+ status: z.ZodNullable<z.ZodEnum<{
142
+ offline: "offline";
143
+ normal: "normal";
144
+ on_batteries: "on_batteries";
145
+ }>>;
146
+ error: z.ZodNullable<z.ZodString>;
147
+ errorCode: z.ZodNullable<z.ZodNumber>;
148
+ isDualHopper: z.ZodBoolean;
149
+ childLock: z.ZodBoolean;
150
+ indicatorLight: z.ZodBoolean;
151
+ feedSound: z.ZodBoolean;
152
+ volume: z.ZodNumber;
153
+ lastFetchedAt: z.ZodNumber;
154
+ }, z.core.$strip>;
155
+ readonly kind: "poll";
156
+ };
157
+ /**
158
+ * Runtime-state slice — mirrored by the kernel. UI feeder cards read
159
+ * the full slice via `device.state.petFeeder.value` and refresh on
160
+ * every poll without re-querying the provider.
161
+ */
162
+ readonly runtimeState: z.ZodObject<{
163
+ foodLevel: z.ZodNullable<z.ZodNumber>;
164
+ food1: z.ZodNullable<z.ZodNumber>;
165
+ food2: z.ZodNullable<z.ZodNumber>;
166
+ lowFood: z.ZodBoolean;
167
+ batteryPower: z.ZodNullable<z.ZodNumber>;
168
+ desiccantLeftDays: z.ZodNullable<z.ZodNumber>;
169
+ feeding: z.ZodBoolean;
170
+ status: z.ZodNullable<z.ZodEnum<{
171
+ offline: "offline";
172
+ normal: "normal";
173
+ on_batteries: "on_batteries";
174
+ }>>;
175
+ error: z.ZodNullable<z.ZodString>;
176
+ errorCode: z.ZodNullable<z.ZodNumber>;
177
+ isDualHopper: z.ZodBoolean;
178
+ childLock: z.ZodBoolean;
179
+ indicatorLight: z.ZodBoolean;
180
+ feedSound: z.ZodBoolean;
181
+ volume: z.ZodNumber;
182
+ lastFetchedAt: z.ZodNumber;
183
+ }, z.core.$strip>;
184
+ };
185
+ export type IPetFeederProvider = InferProvider<typeof petFeederCapability>;
@@ -710,11 +710,20 @@ export declare const pipelineExecutorCapability: {
710
710
  * legacy call shape used by existing benchmark code; once all
711
711
  * callers pass it explicitly we make it required.
712
712
  *
713
- * Exactly one of `frame`, `imageBase64`, `referenceImage` must be
714
- * provided:
713
+ * Exactly one of `frame`, `frameHandle`, `imageBase64`,
714
+ * `referenceImage` must be provided:
715
715
  * - `frame`: runtime dispatch path (runner → decoded broker frame).
716
716
  * Carries the raw buffer, dimensions, and format; the executor
717
717
  * uses it directly without base64 round-tripping.
718
+ * - `frameHandle` (CB5): a zero-pixel shm `FrameHandle` for the SAME
719
+ * decoded frame. Both runner and executor are hub-local processes
720
+ * sharing `/dev/shm`, so the executor maps the named segment and
721
+ * reads the pixels back zero-copy — eliminating the ~1.2MB
722
+ * re-serialisation over UDS/MsgPack the `frame` path pays per call.
723
+ * High-risk: the FrameRing is a latest-wins seqlock with no
724
+ * refcount, so a recycled slot yields a null read; the executor
725
+ * then degrades to an empty result and the runner ships pixels via
726
+ * `frame` as the fallback (queue-depth gated on the runner side).
718
727
  * - `imageBase64`: one-shot test path (benchmark ImageTab).
719
728
  * - `referenceImage`: named file from the reference-image store.
720
729
  */
@@ -748,6 +757,24 @@ export declare const pipelineExecutorCapability: {
748
757
  height: z.ZodNumber;
749
758
  timestamp: z.ZodNumber;
750
759
  }, z.core.$strip>>;
760
+ frameHandle: z.ZodOptional<z.ZodObject<{
761
+ shmId: z.ZodString;
762
+ slot: z.ZodNumber;
763
+ seq: z.ZodNumber;
764
+ width: z.ZodNumber;
765
+ height: z.ZodNumber;
766
+ format: z.ZodEnum<{
767
+ jpeg: "jpeg";
768
+ rgb: "rgb";
769
+ bgr: "bgr";
770
+ yuv420: "yuv420";
771
+ gray: "gray";
772
+ }>;
773
+ pts: z.ZodNumber;
774
+ byteLength: z.ZodNumber;
775
+ nodeId: z.ZodString;
776
+ slotCount: z.ZodNumber;
777
+ }, z.core.$strip>>;
751
778
  imageBase64: z.ZodOptional<z.ZodString>;
752
779
  image: z.ZodOptional<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>;
753
780
  referenceImage: z.ZodOptional<z.ZodString>;
@@ -264,9 +264,9 @@ export declare const platformProbeCapability: {
264
264
  directml: "directml";
265
265
  webgpu: "webgpu";
266
266
  }>>>;
267
- nodeId: z.ZodOptional<z.ZodString>;
268
267
  }, z.core.$strip>, z.ZodObject<{
269
268
  preferred: z.ZodReadonly<z.ZodArray<z.ZodString>>;
269
+ rationale: z.ZodString;
270
270
  }, z.core.$strip>, import("./capability-definition.js").CapabilityMethodKind>;
271
271
  /**
272
272
  * Hardware-encoder probe — see Task #185. Cached after first call.
@@ -49,8 +49,8 @@ export declare const CameraStreamSchema: z.ZodObject<{
49
49
  export type CameraStream = z.infer<typeof CameraStreamSchema>;
50
50
  export declare const ProfileSlotStatusSchema: z.ZodEnum<{
51
51
  error: "error";
52
- idle: "idle";
53
52
  unassigned: "unassigned";
53
+ idle: "idle";
54
54
  connecting: "connecting";
55
55
  streaming: "streaming";
56
56
  }>;
@@ -66,8 +66,8 @@ export declare const ProfileSlotSchema: z.ZodObject<{
66
66
  sourceCamStreamId: z.ZodNullable<z.ZodString>;
67
67
  status: z.ZodEnum<{
68
68
  error: "error";
69
- idle: "idle";
70
69
  unassigned: "unassigned";
70
+ idle: "idle";
71
71
  connecting: "connecting";
72
72
  streaming: "streaming";
73
73
  }>;
@@ -413,8 +413,8 @@ export declare const streamBrokerCapability: {
413
413
  sourceCamStreamId: z.ZodNullable<z.ZodString>;
414
414
  status: z.ZodEnum<{
415
415
  error: "error";
416
- idle: "idle";
417
416
  unassigned: "unassigned";
417
+ idle: "idle";
418
418
  connecting: "connecting";
419
419
  streaming: "streaming";
420
420
  }>;
@@ -81,7 +81,14 @@ export declare enum DeviceType {
81
81
  Container = "container",
82
82
  /** Single still-image entity (HA `image.*`). Read-only display of an
83
83
  * `entity_picture` signed URL the browser loads directly. `image` cap. */
84
- Image = "image"
84
+ Image = "image",
85
+ /** Smart pet feeder — cloud-connected food dispenser with a bowl food
86
+ * level, battery, desiccant life, feeding state and manual-feed /
87
+ * call-pet / maintenance actions. Installed with the `pet-feeder` cap;
88
+ * dual-hopper models (D4S/D4SH) expose per-hopper portions. Sources:
89
+ * native PetKit (`nodepetkit` `FeederDevice`), reusable by other feeder
90
+ * integrations sharing the same food/desiccant/hopper surface. */
91
+ PetFeeder = "pet-feeder"
85
92
  }
86
93
  export declare enum DeviceFeature {
87
94
  BatteryOperated = "battery-operated",