@camstack/types 1.2.242 → 1.2.244

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.js CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_sleep = require("./sleep-vrBqRLsb.js");
2
+ const require_sleep = require("./sleep-Da9UCU5_.js");
3
3
  const require_event_category = require("./event-category-BVfsrBYA.js");
4
4
  const require_err_msg = require("./err-msg-COpsHMw2.js");
5
5
  //#region src/generated/cap-input-defaults.ts
package/dist/addon.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { A as DeviceType, Dt as DisposerChain, G as readNodePin, J as ReadinessTimeoutError, L as expandCapMethods, Mt as emitReadiness, Ot as BaseAddon, S as DEVICE_CHILDREN_BATCH_MAX, T as describeCustomActions, Tt as DATAPLANE_SECRET_HEADER, W as nodePin, Z as scopeKey, a as asJsonObject, b as deviceOpsCapability, d as BOOT_RECOVERY_BACKOFF_MS, f as DEVICE_SCOPED_CAPS, h as createEventBusSliceSource, j as adminUiCapability, kt as normalizeAddonInitResult, m as createDeviceProxy, p as isDeviceScopedCap, q as ReadinessRegistry, s as asString, t as sleep, u as parseJsonUnknown, x as viewerUiCapability } from "./sleep-CUmLTud7.mjs";
1
+ import { A as DeviceType, Dt as DisposerChain, G as readNodePin, J as ReadinessTimeoutError, L as expandCapMethods, Mt as emitReadiness, Ot as BaseAddon, S as DEVICE_CHILDREN_BATCH_MAX, T as describeCustomActions, Tt as DATAPLANE_SECRET_HEADER, W as nodePin, Z as scopeKey, a as asJsonObject, b as deviceOpsCapability, d as BOOT_RECOVERY_BACKOFF_MS, f as DEVICE_SCOPED_CAPS, h as createEventBusSliceSource, j as adminUiCapability, kt as normalizeAddonInitResult, m as createDeviceProxy, p as isDeviceScopedCap, q as ReadinessRegistry, s as asString, t as sleep, u as parseJsonUnknown, x as viewerUiCapability } from "./sleep-i3eUVc-d.mjs";
2
2
  import { t as EventCategory } from "./event-category-BVDXG4tB.mjs";
3
3
  import { t as errMsg } from "./err-msg-IQTHeDzc.mjs";
4
4
  //#region src/generated/cap-input-defaults.ts
@@ -0,0 +1,87 @@
1
+ /**
2
+ * The ONE place a device-admin-link URL is built.
3
+ *
4
+ * Every provider of `device-admin-link` calls {@link buildDeviceAdminUrl}. No
5
+ * provider concatenates a URL itself, and `scripts/check-admin-link-builder-
6
+ * is-the-only-url-source.ts` is what makes that true rather than hoped for.
7
+ *
8
+ * ## Why a builder at all, for a string that looks like `http://` + host
9
+ *
10
+ * Because the one thing that must never happen to this string is easy to do by
11
+ * accident. Every provider that knows a device's host knows its PASSWORD too —
12
+ * they sit next to each other in the same device config (`{ host, port,
13
+ * username, password }` on Hikvision, Reolink, Amcrest, ONVIF alike). A
14
+ * convenience that "pre-fills the login" is one template literal away, and
15
+ * `http://admin:hunter2@192.168.50.139/` is a working URL that browsers accept,
16
+ * that lands in the DOM, in a right-click → copy, in a screenshot, and in any
17
+ * log line that prints what was opened. `scripts/check-no-credential-urls-in-
18
+ * fixtures.ts` already exists because this repo shipped exactly that leak on
19
+ * the RTSP surfaces.
20
+ *
21
+ * So the builder takes host/port/scheme/path as SEPARATE arguments — there is
22
+ * no parameter a credential could be passed in — and then re-checks the result
23
+ * it produced. A camera's admin page asks for its own login; that is correct,
24
+ * and pre-filling it is not ours to do.
25
+ */
26
+ /** Scheme of a device admin page. Only these two; nothing else is a web page. */
27
+ export type DeviceAdminScheme = 'http' | 'https';
28
+ /** Everything needed to address a management page, with no room for a secret. */
29
+ export interface DeviceAdminUrlParts {
30
+ /** Hostname or IP. Never a URL, never `user@host`. */
31
+ readonly host: string;
32
+ /**
33
+ * TCP port of the WEB interface. `null` means "the scheme default" and the
34
+ * port is omitted from the URL.
35
+ *
36
+ * Not the vendor's control port. Reolink's device config carries `port: 9000`
37
+ * — the Baichuan media port — and `http://<reolink>:9000/` answers nothing
38
+ * (verified against 192.168.50.226 on 2026-09-22: `:9000` refuses the
39
+ * connection, `:80` returns 200 text/html). A provider that reads a port
40
+ * field without knowing what that port IS produces a button that opens a
41
+ * browser error.
42
+ */
43
+ readonly port: number | null;
44
+ readonly scheme: DeviceAdminScheme;
45
+ /** Absolute path, starting with `/`. `'/'` for the site root. */
46
+ readonly path: string;
47
+ /**
48
+ * Query parameters, already decided by the caller. Values are encoded here.
49
+ * A key named like a credential is REFUSED — see {@link CREDENTIAL_QUERY_KEYS}.
50
+ */
51
+ readonly query?: Readonly<Record<string, string>>;
52
+ }
53
+ /** Why a link could not be built. Named, because a silent `null` is a defect. */
54
+ export type DeviceAdminUrlRefusal = 'empty-host' | 'host-not-plain' | 'host-carries-userinfo' | 'port-out-of-range' | 'path-not-absolute' | 'credential-query-key' | 'userinfo-in-result';
55
+ /** Discriminated result — a refusal always carries its reason. */
56
+ export type DeviceAdminUrlResult = {
57
+ readonly ok: true;
58
+ readonly url: string;
59
+ } | {
60
+ readonly ok: false;
61
+ readonly reason: DeviceAdminUrlRefusal;
62
+ };
63
+ /**
64
+ * Build the admin-page URL, or refuse by name.
65
+ *
66
+ * The refusal is never thrown: a provider answering "no page for this device"
67
+ * is an ordinary answer (`getAdminLink` → `null`), and a throw here would turn
68
+ * a missing host on one device into a failed query for the whole surface.
69
+ */
70
+ export declare function buildDeviceAdminUrl(parts: DeviceAdminUrlParts): DeviceAdminUrlResult;
71
+ /** Host/port/scheme recovered from an operator-configured base URL. */
72
+ export interface DeviceAdminBase {
73
+ readonly ok: true;
74
+ readonly host: string;
75
+ readonly port: number | null;
76
+ readonly scheme: DeviceAdminScheme;
77
+ /** Path prefix the base URL carried (`''` when it was just an origin). */
78
+ readonly basePath: string;
79
+ }
80
+ /** Refusal shape for {@link parseAdminBase}. */
81
+ export type DeviceAdminBaseResult = DeviceAdminBase | {
82
+ readonly ok: false;
83
+ readonly reason: DeviceAdminBaseRefusal;
84
+ };
85
+ /** Why a configured base URL cannot be used to build a link. */
86
+ export type DeviceAdminBaseRefusal = 'empty' | 'unparseable' | 'scheme-not-http' | 'base-carries-userinfo';
87
+ export declare function parseAdminBase(baseUrl: string): DeviceAdminBaseResult;
@@ -0,0 +1,118 @@
1
+ /**
2
+ * device-admin-link — "this device has a management page of its own, and here
3
+ * is its address".
4
+ *
5
+ * ## Why this is not a `deviceConfig` cap
6
+ *
7
+ * There is nothing to edit. A `deviceConfig` cap (D14) exists so the framework
8
+ * can DERIVE a settings form from `getOptions` + `getStatus` and route a flat
9
+ * patch back through a setter; it costs a `builderId` reducer in
10
+ * `device-config-contribution.ts` and a `*-config-schema.ts` beside it, and it
11
+ * renders a form section. This cap answers ONE question with ONE read and
12
+ * renders a button. Nothing about it is a form, so it carries no `deviceConfig`
13
+ * block, no `settings`, no `runtimeState` and no reducer — exactly like
14
+ * `reboot`, the other pure-RPC device-native cap.
15
+ *
16
+ * ## Absent, and the difference between "no page" and "we cannot say"
17
+ *
18
+ * The two are answered at DIFFERENT layers, on purpose:
19
+ *
20
+ * - **"We cannot say"** → the provider never registers the cap for that
21
+ * device. A VeSync humidifier, a Petkit feeder, a Dreame vacuum and a Dreo
22
+ * fan are reached only through a vendor cloud; there is no address to hand
23
+ * out and no page to open. A Tuya plug, a Wyze camera and a Gree air
24
+ * conditioner DO have a LAN IP, and still have no HTTP management page
25
+ * behind it. None of them register, so `deviceManager.getBindings` never
26
+ * lists the cap and no surface asks.
27
+ * - **"This device has no page, and I know that"** → the provider registers
28
+ * and `getAdminLink` returns `null`. This is the answer for a device whose
29
+ * sibling DOES have a page: a Reolink battery camera reached over UDP by
30
+ * `uid` with a blank `host`, an Ecowitt gateway configured in `listener`
31
+ * transport, a Home Assistant broker authenticated by supervisor token
32
+ * (which carries no `baseUrl` at all).
33
+ *
34
+ * Both draw NOTHING. A button that opens a browser error is worse than no
35
+ * button, and D62 is the same rule from the other side: an off switch is
36
+ * reported off, never made to look broken. There is no third state where the
37
+ * UI renders a disabled button "because the device might have a page".
38
+ *
39
+ * ## The URL never carries credentials
40
+ *
41
+ * Not in userinfo, not in a query string. Every provider builds through
42
+ * `buildDeviceAdminUrl` (`device-admin-link-url.ts`), which takes host, port,
43
+ * scheme and path as separate arguments — there is no parameter a secret could
44
+ * arrive in — and re-checks its own output for the `scheme://user:pass@` shape
45
+ * that `scripts/check-no-credential-urls-in-fixtures.ts` bans from recorded
46
+ * output. `scripts/check-admin-link-builder-is-the-only-url-source.ts` is what
47
+ * keeps providers from hand-rolling one anyway.
48
+ *
49
+ * This matters here more than anywhere else in the repo, because every provider
50
+ * that knows a device's host knows its PASSWORD too: `{ host, port, username,
51
+ * password }` sit in one object on Hikvision, Amcrest, Reolink and ONVIF alike,
52
+ * and `http://admin:hunter2@192.168.50.139/` is a URL a browser accepts. The
53
+ * camera's own page will ask for its own login. That is correct, and pre-
54
+ * filling it is the operator's business, not ours.
55
+ *
56
+ * ## It is a LAN fact
57
+ *
58
+ * The URL addresses the device where the NODE can see it. It is not proxied,
59
+ * not made reachable from outside, and not sent anywhere. A surface renders it
60
+ * as a link the operator's own browser follows, on the operator's own network,
61
+ * or renders nothing.
62
+ */
63
+ import { z } from 'zod';
64
+ import { type InferProvider } from './capability-definition.js';
65
+ /**
66
+ * Whose page is it. The distinction is for the OPERATOR, who needs to know
67
+ * before clicking whether he is about to land on a camera's own web server or
68
+ * inside Home Assistant.
69
+ */
70
+ export declare const AdminLinkTargetEnum: z.ZodEnum<{
71
+ device: "device";
72
+ integration: "integration";
73
+ }>;
74
+ export type AdminLinkTarget = z.infer<typeof AdminLinkTargetEnum>;
75
+ export declare const DeviceAdminLinkSchema: z.ZodObject<{
76
+ url: z.ZodString;
77
+ label: z.ZodString;
78
+ target: z.ZodEnum<{
79
+ device: "device";
80
+ integration: "integration";
81
+ }>;
82
+ host: z.ZodString;
83
+ }, z.core.$strip>;
84
+ export type DeviceAdminLink = z.infer<typeof DeviceAdminLinkSchema>;
85
+ export declare const deviceAdminLinkCapability: {
86
+ readonly name: "device-admin-link";
87
+ readonly scope: "device";
88
+ readonly deviceNative: true;
89
+ readonly mode: "singleton";
90
+ readonly methods: {
91
+ /**
92
+ * The device's management page, or `null` when this device has none.
93
+ *
94
+ * `auth: 'admin'` deliberately. This is administration, not actuation —
95
+ * the same bucket as `reboot` and `camera-credentials`, and explicitly NOT
96
+ * the actuation set `scripts/check-actuation-not-admin.ts` protects (D403).
97
+ * The URL is also a statement about the LAN, which a household member with
98
+ * a `view` grant on a light has no reason to be handed.
99
+ *
100
+ * The surfaces gate on the QUERY, never on a role they guessed: a caller
101
+ * without the right loses the query and draws nothing, which is the same
102
+ * thing a device with no page draws. There is no path on which a button
103
+ * appears and then fails — the D403 failure mode, from the other end.
104
+ */
105
+ readonly getAdminLink: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
106
+ deviceId: z.ZodNumber;
107
+ }, z.core.$strip>, z.ZodNullable<z.ZodObject<{
108
+ url: z.ZodString;
109
+ label: z.ZodString;
110
+ target: z.ZodEnum<{
111
+ device: "device";
112
+ integration: "integration";
113
+ }>;
114
+ host: z.ZodString;
115
+ }, z.core.$strip>>, import("./capability-definition.js").CapabilityMethodKind>;
116
+ };
117
+ };
118
+ export type IDeviceAdminLinkProvider = InferProvider<typeof deviceAdminLinkCapability>;
@@ -48,6 +48,8 @@ export type { DecoderHwAccelConfig, HwAccelChoice, IDecoderCapProvider, ShmRingS
48
48
  export { DEFAULT_DECODER_HWACCEL_CONFIG, DecoderSessionConfigSchema, decoderCapability, HWACCEL_OPTIONS, ShmRingStatsSchema, } from './decoder.cap.js';
49
49
  export { detectionPipelineCapability, type IDetectionPipelineProvider, } from './detection-pipeline.cap.js';
50
50
  export { AdoptInputSchema as AdoptionAdoptInputSchema, type AdoptionFilter, AdoptionFilterSchema, type AdoptionStatus, AdoptionStatusSchema, AdoptResultSchema as AdoptionAdoptResultSchema, CandidateQueryFilterSchema, deviceAdoptionCapability, GetCandidateInputSchema as AdoptionGetCandidateInputSchema, type IDeviceAdoptionProvider, ListCandidatesInputSchema as AdoptionListCandidatesInputSchema, ListCandidatesOutputSchema as AdoptionListCandidatesOutputSchema, ReleaseInputSchema as AdoptionReleaseInputSchema, } from './device-adoption.cap.js';
51
+ export { type AdminLinkTarget, AdminLinkTargetEnum, type DeviceAdminLink, DeviceAdminLinkSchema, deviceAdminLinkCapability, type IDeviceAdminLinkProvider, } from './device-admin-link.cap.js';
52
+ export { buildDeviceAdminUrl, type DeviceAdminBase, type DeviceAdminBaseRefusal, type DeviceAdminBaseResult, type DeviceAdminScheme, type DeviceAdminUrlParts, type DeviceAdminUrlRefusal, type DeviceAdminUrlResult, parseAdminBase, } from './device-admin-link-url.js';
51
53
  export type { IDeviceExportProvider } from './device-export.cap.js';
52
54
  export { DeviceExportStatusSchema, deviceExportCapability, ExportSetupFieldSchema, ExportSetupSchema, ExposedDeviceSchema, ExposeInputSchema as DeviceExportExposeInputSchema, UnexposeInputSchema as DeviceExportUnexposeInputSchema, } from './device-export.cap.js';
53
55
  export type { DeviceInfo, DeviceManagerApplyInitialMetaInput } from './device-manager.cap.js';
@@ -116,8 +118,8 @@ export type { IUserPasskeysProvider, PasskeySummary } from './user-passkeys.cap.
116
118
  export { PasskeySummarySchema, userPasskeysCapability } from './user-passkeys.cap.js';
117
119
  export type { IVectorStoreProvider } from './vector-store.cap.js';
118
120
  export { VectorDeclareIndexInputSchema, VectorDeleteByFilterInputSchema, VectorDeleteInputSchema, VectorDeleteResultSchema, type VectorFilter, VectorFilterSchema, VectorGetInputSchema, VectorGetResultSchema, type VectorItem, VectorItemSchema, type VectorMatch, VectorMatchSchema, type VectorMetadata, VectorMetadataSchema, type VectorMetric, VectorMetricSchema, VectorQueryInputSchema, VectorQueryResultSchema, VectorStatsInputSchema, VectorStatsResultSchema, VectorUpsertInputSchema, VectorUpsertResultSchema, vectorStoreCapability, } from './vector-store.cap.js';
119
- export type { Clip, ClipBytes, ClipPlayback, ClipSource, ClipSourceAvailability, ClipStillDisposition, ClipStillRefusalCode, ClipWake, IVideoclipsProvider, } from './videoclips.cap.js';
120
- export { CLIP_STILL_DISPOSITION_HEADER, CLIP_STILL_REASON_CODE_HEADER, CLIP_STILL_REASON_HEADER, ClipBytesSchema, ClipPlaybackSchema, ClipSchema, ClipSourceAvailabilitySchema, ClipSourceSchema, ClipStillDispositionSchema, ClipStillRefusalCodeSchema, ClipWakeSchema, MAX_CLIP_EVENT_IDS, MAX_CLIP_LABELS, VIDEOCLIPS_MAX_READ_BYTES, videoclipsCapability, } from './videoclips.cap.js';
121
+ export type { Clip, ClipBytes, ClipPlayback, ClipSource, ClipSourceAvailability, ClipStillDisposition, ClipStillRefusalCode, ClipStreamAudio, ClipStreamAudioReason, ClipStreamDial, ClipWake, IVideoclipsProvider, } from './videoclips.cap.js';
122
+ export { CLIP_STILL_DISPOSITION_HEADER, CLIP_STILL_REASON_CODE_HEADER, CLIP_STILL_REASON_HEADER, CLIP_STREAM_TRANSPORT_HEADER, ClipBytesSchema, ClipPlaybackSchema, ClipSchema, ClipSourceAvailabilitySchema, ClipSourceSchema, ClipStillDispositionSchema, ClipStillRefusalCodeSchema, ClipStreamAudioReasonSchema, ClipStreamAudioSchema, ClipStreamDialSchema, ClipWakeSchema, MAX_CLIP_EVENT_IDS, MAX_CLIP_LABELS, VIDEOCLIPS_MAX_READ_BYTES, videoclipsCapability, } from './videoclips.cap.js';
121
123
  export type { IViewerUiProvider } from './viewer-ui.cap.js';
122
124
  export { viewerUiCapability } from './viewer-ui.cap.js';
123
125
  export { type IWebrtcSessionProvider, type WebrtcClientHints, type WebrtcLadderDecision, WebrtcLadderDecisionSchema, type WebrtcSessionDebug, WebrtcSessionDebugSchema, type WebrtcStreamChoice, WebrtcStreamChoiceSchema, type WebrtcStreamTarget, WebrtcStreamTargetSchema, type WebrtcTierFailure, WebrtcTierFailureSchema, webrtcClientHintsSchema, webrtcSessionCapability, } from './webrtc-session.cap.js';
@@ -143,6 +145,8 @@ export { type ContactStatus, ContactStatusSchema, contactCapability, type IConta
143
145
  export { type ControlKind, ControlKindSchema, type ControlSetValueInput, type ControlStatus, ControlStatusSchema, controlCapability, type IControlProvider, } from './control.cap.js';
144
146
  export { type CoverState, CoverStateSchema, type CoverStatus, CoverStatusSchema, coverCapability, type ICoverProvider, } from './cover.cap.js';
145
147
  export { type DayNightMode, DayNightModeSchema, type DayNightOptions, DayNightOptionsSchema, type DayNightSettingsPatch, DayNightSettingsPatchSchema, type DayNightStatus, DayNightStatusSchema, dayNightCapability, type IDayNightProvider, } from './day-night.cap.js';
148
+ export { type OnboardAllowedValues, type OnboardFieldSupport, OnboardFieldSupportSchema, type OnboardRecordTrack, OnboardRecordTrackSchema, type OnboardScheduleSupport, OnboardScheduleSupportSchema, type OnboardStorage, OnboardStorageSchema, type OnboardStorageVolume, OnboardStorageVolumeSchema, type IRecordingOnboardProvider, type RecordTrigger, RecordTriggerSchema, type RecordWindow, RecordWindowSchema, type RecordingOnboardOptions, RecordingOnboardOptionsSchema, type RecordingOnboardPatch, RecordingOnboardPatchSchema, type RecordingOnboardStatus, RecordingOnboardStatusSchema, recordingOnboardCapability, } from './recording-onboard.cap.js';
149
+ export { DAYS_PER_WEEK, DAY_NAMES, HOURS_PER_DAY, MINUTES_PER_DAY, WEEKLY_MASK_LENGTH, dayOfWeekToIndex, describeOnboardClamp, describeOnboardRefusal, formatMinutes, minutesToTimeOfDay, timeOfDayToMinutes, weeklyMaskIndex, weeklyMaskIsUniform, weeklyMaskToWindows, windowsToWeeklyMask, } from './recording-onboard-rules.js';
146
150
  export { type DeviceDiscoveryStatus, DeviceDiscoveryStatusSchema, type DiscoveredChildDevice, DiscoveredChildDeviceSchema, type DiscoveredChildStatus, DiscoveredChildStatusSchema, deviceDiscoveryCapability, type IDeviceDiscoveryNativeProvider, type IDeviceDiscoveryProvider, } from './device-discovery.cap.js';
147
151
  export { deviceOpsCapability, type IDeviceOpsProvider, type RawStateResult, RawStateResultSchema, } from './device-ops.cap.js';
148
152
  export { type DeviceStatus, DeviceStatusSchema, deviceStatusCapability, type IDeviceStatusProvider, } from './device-status.cap.js';
@@ -258,9 +262,11 @@ import type { coverCapability } from './cover.cap.js';
258
262
  import type { customModelRegistryCapability } from './custom-model-registry.cap.js';
259
263
  import type { dataStoreProviderCapability } from './data-store-provider.cap.js';
260
264
  import type { dayNightCapability } from './day-night.cap.js';
265
+ import type { recordingOnboardCapability } from './recording-onboard.cap.js';
261
266
  import type { decoderCapability } from './decoder.cap.js';
262
267
  import type { detectionPipelineCapability } from './detection-pipeline.cap.js';
263
268
  import type { deviceAdoptionCapability } from './device-adoption.cap.js';
269
+ import type { deviceAdminLinkCapability } from './device-admin-link.cap.js';
264
270
  import type { deviceDiscoveryCapability } from './device-discovery.cap.js';
265
271
  import type { deviceExportCapability } from './device-export.cap.js';
266
272
  import type { deviceManagerCapability } from './device-manager.cap.js';
@@ -374,6 +380,6 @@ import type { webrtcSessionCapability } from './webrtc-session.cap.js';
374
380
  import type { zoneAnalyticsCapability } from './zone-analytics.cap.js';
375
381
  import type { zoneRulesCapability } from './zone-rules.cap.js';
376
382
  import type { zonesCapability } from './zones.cap.js';
377
- type AnyCapability = typeof streamSignalsCapability | typeof addonSettingsCapability | typeof alertsCapability | typeof storageCapability | typeof storageMigrationCapability | typeof storageProviderCapability | typeof storageEvictableCapability | typeof storageOccupancyCapability | typeof filesystemBrowseCapability | typeof backupCapability | typeof terminalSessionCapability | typeof settingsStoreCapability | typeof dataStoreProviderCapability | typeof logChannelsCapability | typeof logDestinationCapability | typeof loadContributionCapability | typeof failureContributionCapability | typeof adminUiCapability | typeof viewerUiCapability | 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 webrtcSessionCapability | typeof cameraStreamsCapability | typeof motionDetectionCapability | typeof pipelineExecutorCapability | typeof detectionPipelineCapability | typeof cameraPipelineConfigCapability | typeof pipelineRunnerCapability | typeof pipelineOrchestratorCapability | typeof audioAnalyzerCapability | typeof audioAnalysisCapability | typeof audioCodecCapability | typeof embeddingEncoderCapability | typeof vectorStoreCapability | typeof deviceProviderCapability | typeof deviceManagerCapability | typeof deviceStateCapability | typeof authProviderCapability | typeof loginMethodCapability | typeof networkAccessCapability | typeof turnProviderCapability | typeof snapshotCapability | typeof llmCapability | typeof llmRuntimeCapability | typeof notificationOutputCapability | typeof coreBlocksCapability | typeof notificationRulesCapability | typeof pipelineAnalyticsCapability | typeof metricsProviderCapability | typeof ptzCapability | typeof ptzAutotrackCapability | typeof navigationCapability | typeof consumablesCapability | typeof connectionTestCapability | 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 recordingExportCapability | typeof recordingSignalCapability | typeof deviceOpsCapability | typeof platformProbeCapability | typeof localNetworkCapability | typeof meshNetworkCapability | typeof userManagementCapability | typeof systemCapability | typeof networkQualityCapability | typeof toastCapability | typeof nodesCapability | typeof serverManagementCapability | typeof integrationsCapability | typeof addonsCapability | typeof oauthIntegrationCapability | typeof streamParamsCapability | typeof streamCatalogCapability | typeof motionZonesCapability | typeof cameraGridLayoutCapability | typeof sceneMonitorCapability | typeof privacyMaskCapability | typeof dayNightCapability | typeof imageSettingsCapability | typeof osdCapability | typeof osdManagerCapability | typeof accessoriesCapability | typeof batteryCapability | typeof networkLinkCapability | typeof buttonCapability | typeof cameraCredentialsCapability | typeof deviceStatusCapability | typeof doorbellCapability | typeof eventEmitterCapability | typeof faceGalleryCapability | typeof featureProbeCapability | typeof intercomCapability | typeof nativeObjectDetectionCapability | typeof plateGalleryCapability | typeof switchCapability | typeof updateCapability | typeof videoclipsCapability;
383
+ type AnyCapability = typeof streamSignalsCapability | typeof addonSettingsCapability | typeof alertsCapability | typeof storageCapability | typeof storageMigrationCapability | typeof storageProviderCapability | typeof storageEvictableCapability | typeof storageOccupancyCapability | typeof filesystemBrowseCapability | typeof backupCapability | typeof terminalSessionCapability | typeof settingsStoreCapability | typeof dataStoreProviderCapability | typeof logChannelsCapability | typeof logDestinationCapability | typeof loadContributionCapability | typeof failureContributionCapability | typeof adminUiCapability | typeof viewerUiCapability | typeof ssoBridgeCapability | typeof userPasskeysCapability | typeof smtpProviderCapability | typeof mqttBrokerCapability | typeof brokerCapability | typeof deviceAdoptionCapability | typeof deviceAdminLinkCapability | typeof deviceExportCapability | typeof addonPagesCapability | typeof addonPagesSourceCapability | typeof addonWidgetsCapability | typeof addonWidgetsSourceCapability | typeof customModelRegistryCapability | typeof modelDistributorCapability | typeof modelConvertCapability | typeof addonRoutesCapability | typeof streamBrokerCapability | typeof decoderCapability | typeof webrtcSessionCapability | typeof cameraStreamsCapability | typeof motionDetectionCapability | typeof pipelineExecutorCapability | typeof detectionPipelineCapability | typeof cameraPipelineConfigCapability | typeof pipelineRunnerCapability | typeof pipelineOrchestratorCapability | typeof audioAnalyzerCapability | typeof audioAnalysisCapability | typeof audioCodecCapability | typeof embeddingEncoderCapability | typeof vectorStoreCapability | typeof deviceProviderCapability | typeof deviceManagerCapability | typeof deviceStateCapability | typeof authProviderCapability | typeof loginMethodCapability | typeof networkAccessCapability | typeof turnProviderCapability | typeof snapshotCapability | typeof llmCapability | typeof llmRuntimeCapability | typeof notificationOutputCapability | typeof coreBlocksCapability | typeof notificationRulesCapability | typeof pipelineAnalyticsCapability | typeof metricsProviderCapability | typeof ptzCapability | typeof ptzAutotrackCapability | typeof navigationCapability | typeof consumablesCapability | typeof connectionTestCapability | 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 recordingExportCapability | typeof recordingSignalCapability | typeof deviceOpsCapability | typeof platformProbeCapability | typeof localNetworkCapability | typeof meshNetworkCapability | typeof userManagementCapability | typeof systemCapability | typeof networkQualityCapability | typeof toastCapability | typeof nodesCapability | typeof serverManagementCapability | typeof integrationsCapability | typeof addonsCapability | typeof oauthIntegrationCapability | typeof streamParamsCapability | typeof streamCatalogCapability | typeof motionZonesCapability | typeof cameraGridLayoutCapability | typeof sceneMonitorCapability | typeof privacyMaskCapability | typeof dayNightCapability | typeof recordingOnboardCapability | typeof imageSettingsCapability | typeof osdCapability | typeof osdManagerCapability | typeof accessoriesCapability | typeof batteryCapability | typeof networkLinkCapability | typeof buttonCapability | typeof cameraCredentialsCapability | typeof deviceStatusCapability | typeof doorbellCapability | typeof eventEmitterCapability | typeof faceGalleryCapability | typeof featureProbeCapability | typeof intercomCapability | typeof nativeObjectDetectionCapability | typeof plateGalleryCapability | typeof switchCapability | typeof updateCapability | typeof videoclipsCapability;
378
384
  export type CapabilityName = AnyCapability['name'];
379
385
  export type ITypedReadinessRegistry = IReadinessRegistry<CapabilityName>;
@@ -1273,9 +1273,11 @@ export declare const pipelineOrchestratorCapability: {
1273
1273
  unavailableReason: z.ZodOptional<z.ZodEnum<{
1274
1274
  "no-provider": "no-provider";
1275
1275
  "source-unreachable": "source-unreachable";
1276
- "not-configured": "not-configured";
1277
1276
  "device-disabled": "device-disabled";
1278
1277
  }>>;
1278
+ warning: z.ZodOptional<z.ZodEnum<{
1279
+ "no-privacy-zones": "no-privacy-zones";
1280
+ }>>;
1279
1281
  enabled: z.ZodBoolean;
1280
1282
  authority: z.ZodDiscriminatedUnion<[z.ZodObject<{
1281
1283
  kind: z.ZodLiteral<"device-disabled">;
@@ -1349,9 +1351,11 @@ export declare const pipelineOrchestratorCapability: {
1349
1351
  unavailableReason: z.ZodOptional<z.ZodEnum<{
1350
1352
  "no-provider": "no-provider";
1351
1353
  "source-unreachable": "source-unreachable";
1352
- "not-configured": "not-configured";
1353
1354
  "device-disabled": "device-disabled";
1354
1355
  }>>;
1356
+ warning: z.ZodOptional<z.ZodEnum<{
1357
+ "no-privacy-zones": "no-privacy-zones";
1358
+ }>>;
1355
1359
  enabled: z.ZodBoolean;
1356
1360
  authority: z.ZodDiscriminatedUnion<[z.ZodObject<{
1357
1361
  kind: z.ZodLiteral<"device-disabled">;
@@ -0,0 +1,135 @@
1
+ /**
2
+ * `recording-onboard` — the vendor-neutral rules both providers share.
3
+ *
4
+ * Three things live here rather than in each addon, because two
5
+ * hand-written copies of them would be two different opinions about the
6
+ * same question:
7
+ *
8
+ * 1. {@link describeOnboardRefusal} — THE refusal vocabulary. A write
9
+ * a camera cannot honour is refused with one sentence an operator
10
+ * can read, and the sentence is the same whoever refuses it.
11
+ * 2. {@link weeklyMaskToWindows} / {@link windowsToWeeklyMask} —
12
+ * Reolink's 7×24 hour mask ↔ the cap's {@link RecordWindow} list.
13
+ * 3. {@link timeOfDayToMinutes} / {@link minutesToTimeOfDay} —
14
+ * Hikvision's `TimeOfDay` strings ↔ minutes since midnight.
15
+ *
16
+ * Pure. No I/O, no clock, no logger.
17
+ */
18
+ import type { RecordTrigger, RecordWindow, RecordingOnboardOptions, RecordingOnboardPatch } from './recording-onboard.cap.js';
19
+ /** Minutes in a day. `endMinute === 1440` means "to end of day". */
20
+ export declare const MINUTES_PER_DAY = 1440;
21
+ /** Days in the cap's week, 0 = Monday. */
22
+ export declare const DAYS_PER_WEEK = 7;
23
+ /** Hours per day — the resolution of Reolink's mask. */
24
+ export declare const HOURS_PER_DAY = 24;
25
+ /** Length of a Reolink weekly `valueTable`: 7 days × 24 hours. */
26
+ export declare const WEEKLY_MASK_LENGTH: number;
27
+ /**
28
+ * Day-of-week names in the cap's index order (0 = Monday), for messages
29
+ * an operator reads and for Hikvision's `<DayOfWeek>` element.
30
+ */
31
+ export declare const DAY_NAMES: readonly string[];
32
+ /**
33
+ * Does `patch` ask this camera for something it cannot do?
34
+ *
35
+ * Returns the operator-readable reason, or `null` when every field in
36
+ * the patch is within what `options` says this camera accepts. A
37
+ * provider calls this BEFORE touching the camera and throws the string:
38
+ * refusing is the point, and refusing identically on both vendors is why
39
+ * this is one function.
40
+ *
41
+ * The order of checks is the order an operator would read them: the
42
+ * scalar knobs first, then the schedule, because a schedule complaint is
43
+ * longer and a scalar one is usually the real problem.
44
+ */
45
+ export declare function describeOnboardRefusal(options: RecordingOnboardOptions, patch: RecordingOnboardPatch): string | null;
46
+ /** `510` → `08:30`. For messages, not for the wire. */
47
+ export declare function formatMinutes(minute: number): string;
48
+ /**
49
+ * Index of the mask character covering `day` at `hour`.
50
+ *
51
+ * **Layout: day-major, Monday first** — `day * 24 + hour`.
52
+ *
53
+ * This is an ASSUMPTION, and it is recorded as one because the fleet
54
+ * cannot currently confirm it: every `valueTable` on every Reolink
55
+ * measured on 2026-09-22 is uniform (all `1` or all `0`), and a uniform
56
+ * mask reads identically under either layout. To settle it, set a single
57
+ * hour on one day from the Reolink app and re-read `getRecordSchedule`.
58
+ * Until then, a NON-uniform mask is reported as windows under this
59
+ * layout and the day labels may be transposed; a uniform one is exact.
60
+ */
61
+ export declare function weeklyMaskIndex(day: number, hour: number): number;
62
+ /**
63
+ * True when every slot of the mask carries the same value — the case in
64
+ * which {@link weeklyMaskIndex}'s layout assumption cannot be wrong.
65
+ */
66
+ export declare function weeklyMaskIsUniform(mask: string): boolean;
67
+ /**
68
+ * Expand one trigger's weekly hour mask into windows, merging adjacent
69
+ * set hours into one window per run so a full day is ONE window rather
70
+ * than twenty-four.
71
+ *
72
+ * A mask of the wrong length yields no windows: a truncated table is not
73
+ * a schedule of fewer days, it is an answer we did not understand.
74
+ */
75
+ export declare function weeklyMaskToWindows(mask: string, trigger: RecordTrigger): RecordWindow[];
76
+ /**
77
+ * Collapse this trigger's windows back into a weekly hour mask.
78
+ *
79
+ * Windows for other triggers are ignored — the mask is per trigger. A
80
+ * window that is not hour-aligned is REFUSED upstream by
81
+ * {@link describeOnboardRefusal}; this function rounds nothing, it
82
+ * simply sets every hour the window fully or partly covers, so a caller
83
+ * that skipped the refusal cannot silently lose coverage.
84
+ */
85
+ export declare function windowsToWeeklyMask(windows: readonly RecordWindow[], trigger: RecordTrigger): string;
86
+ /**
87
+ * Parse a Hikvision `<TimeOfDay>` into minutes since midnight.
88
+ *
89
+ * The firmware is not self-consistent and both spellings are real, on
90
+ * the same camera in the same block: a start time reads `00:00:00` and
91
+ * the matching end time reads `24:00`. Seconds are accepted and
92
+ * discarded — the cap's resolution is minutes — and `24:00` maps to
93
+ * {@link MINUTES_PER_DAY}, not to 0.
94
+ *
95
+ * Returns null for anything else, which a caller reports as a window it
96
+ * could not read rather than as midnight.
97
+ */
98
+ export declare function timeOfDayToMinutes(value: string): number | null;
99
+ /**
100
+ * Render minutes back as a Hikvision `TimeOfDay`.
101
+ *
102
+ * Emits the camera's own two spellings: `24:00` for end-of-day, because
103
+ * that is what the firmware writes and `24:00:00` is not observed, and
104
+ * `HH:MM:SS` otherwise.
105
+ */
106
+ export declare function minutesToTimeOfDay(minute: number): string;
107
+ /** `'Monday'` → 0. Case-insensitive. Null for anything unrecognised. */
108
+ export declare function dayOfWeekToIndex(value: string): number | null;
109
+ /** One field a camera stored differently from what it was asked. */
110
+ export interface OnboardClamp {
111
+ readonly field: string;
112
+ readonly asked: number | boolean | string;
113
+ /** What the camera holds now. `null` when the read-back could not say. */
114
+ readonly stored: number | boolean | string | null;
115
+ }
116
+ /**
117
+ * Which fields of a patch the camera did NOT take verbatim.
118
+ *
119
+ * Measured on a Hikvision I91DN (1436, 2026-09-22): a `PUT` of
120
+ * `PreRecordTimeSeconds: 8` answered `200`, `statusCode 1`, `OK` — and stored
121
+ * **5**. Neither the asked value nor the previous one. The camera declares no
122
+ * allowed set for that field, so there is nothing to refuse against before the
123
+ * wire: `/capabilities` returns a plain value where a constrained field would
124
+ * carry an `opt=` list.
125
+ *
126
+ * So the only honest moment is after the read-back, and re-reading alone is
127
+ * not enough — it makes the difference VISIBLE while leaving it unexplained.
128
+ * A write that reports success for a value the camera never took is the same
129
+ * silent substitution D599 removed from the clip path, wearing a different hat.
130
+ *
131
+ * Compares only the fields the patch actually named: a field nobody asked
132
+ * about cannot have been clamped, and a read-back that could not answer it is
133
+ * `stored: null` rather than a claim.
134
+ */
135
+ export declare function describeOnboardClamp(patch: Readonly<Record<string, unknown>>, landed: Readonly<Record<string, unknown>> | null): readonly OnboardClamp[];