@camstack/types 1.2.147 → 1.2.149

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.
@@ -11,6 +11,7 @@ import { DeviceType } from '../device/device-type.js';
11
11
  export declare const BatteryStatusSchema: z.ZodObject<{
12
12
  percentage: z.ZodNullable<z.ZodNumber>;
13
13
  charging: z.ZodEnum<{
14
+ unknown: "unknown";
14
15
  none: "none";
15
16
  dc: "dc";
16
17
  solar: "solar";
@@ -65,6 +66,7 @@ export declare const batteryCapability: {
65
66
  status: z.ZodObject<{
66
67
  percentage: z.ZodNullable<z.ZodNumber>;
67
68
  charging: z.ZodEnum<{
69
+ unknown: "unknown";
68
70
  none: "none";
69
71
  dc: "dc";
70
72
  solar: "solar";
@@ -81,6 +83,7 @@ export declare const batteryCapability: {
81
83
  readonly schema: z.ZodObject<{
82
84
  percentage: z.ZodNullable<z.ZodNumber>;
83
85
  charging: z.ZodEnum<{
86
+ unknown: "unknown";
84
87
  none: "none";
85
88
  dc: "dc";
86
89
  solar: "solar";
@@ -93,7 +96,7 @@ export declare const batteryCapability: {
93
96
  readonly kind: "push";
94
97
  readonly empty: {
95
98
  readonly percentage: 0;
96
- readonly charging: "none";
99
+ readonly charging: "unknown";
97
100
  readonly sleeping: false;
98
101
  readonly lastUpdated: 0;
99
102
  };
@@ -110,6 +113,7 @@ export declare const batteryCapability: {
110
113
  readonly runtimeState: z.ZodObject<{
111
114
  percentage: z.ZodNullable<z.ZodNumber>;
112
115
  charging: z.ZodEnum<{
116
+ unknown: "unknown";
113
117
  none: "none";
114
118
  dc: "dc";
115
119
  solar: "solar";
@@ -107,8 +107,12 @@ export declare const ConfigEntrySchema: z.ZodObject<{
107
107
  value: z.ZodUnknown;
108
108
  description: z.ZodOptional<z.ZodString>;
109
109
  }, z.core.$strip>;
110
+ /**
111
+ * Only `manual` since D356: the operator picks, nothing links itself. The
112
+ * field survives on the wire because a viewer already OTA'd parses it —
113
+ * drop it once no shipped client reads `mode`.
114
+ */
110
115
  export declare const LinkedDevicesModeSchema: z.ZodEnum<{
111
- auto: "auto";
112
116
  manual: "manual";
113
117
  }>;
114
118
  export type LinkedDevicesMode = z.infer<typeof LinkedDevicesModeSchema>;
@@ -127,7 +131,6 @@ export type LinkedDevice = z.infer<typeof LinkedDeviceSchema>;
127
131
  export declare const LinkedDevicesForDeviceSchema: z.ZodObject<{
128
132
  deviceId: z.ZodNumber;
129
133
  mode: z.ZodEnum<{
130
- auto: "auto";
131
134
  manual: "manual";
132
135
  }>;
133
136
  devices: z.ZodArray<z.ZodObject<{
@@ -926,7 +929,6 @@ export declare const deviceManagerCapability: {
926
929
  deviceId: z.ZodNumber;
927
930
  }, z.core.$strip>, z.ZodObject<{
928
931
  mode: z.ZodEnum<{
929
- auto: "auto";
930
932
  manual: "manual";
931
933
  }>;
932
934
  devices: z.ZodArray<z.ZodObject<{
@@ -958,7 +960,6 @@ export declare const deviceManagerCapability: {
958
960
  }, z.core.$strip>, z.ZodArray<z.ZodObject<{
959
961
  deviceId: z.ZodNumber;
960
962
  mode: z.ZodEnum<{
961
- auto: "auto";
962
963
  manual: "manual";
963
964
  }>;
964
965
  devices: z.ZodArray<z.ZodObject<{
@@ -1250,6 +1250,7 @@ export declare const pipelineOrchestratorCapability: {
1250
1250
  "no-provider": "no-provider";
1251
1251
  "source-unreachable": "source-unreachable";
1252
1252
  "not-configured": "not-configured";
1253
+ "device-disabled": "device-disabled";
1253
1254
  }>>;
1254
1255
  enabled: z.ZodBoolean;
1255
1256
  authority: z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -1323,6 +1324,7 @@ export declare const pipelineOrchestratorCapability: {
1323
1324
  "no-provider": "no-provider";
1324
1325
  "source-unreachable": "source-unreachable";
1325
1326
  "not-configured": "not-configured";
1327
+ "device-disabled": "device-disabled";
1326
1328
  }>>;
1327
1329
  enabled: z.ZodBoolean;
1328
1330
  authority: z.ZodDiscriminatedUnion<[z.ZodObject<{
package/dist/index.js CHANGED
@@ -887,7 +887,8 @@ var CameraSwitchAuthoritySchema = zod.z.discriminatedUnion("kind", [
887
887
  var CameraSwitchUnavailableReasonSchema = zod.z.enum([
888
888
  "no-provider",
889
889
  "source-unreachable",
890
- "not-configured"
890
+ "not-configured",
891
+ "device-disabled"
891
892
  ]);
892
893
  /**
893
894
  * One switch, resolved for one camera.
@@ -1057,7 +1058,7 @@ function resolveState(descriptor, input) {
1057
1058
  if (audio === null) return {
1058
1059
  available: false,
1059
1060
  enabled: true,
1060
- unavailableReason: "source-unreachable"
1061
+ unavailableReason: input.deviceDisabled ? "device-disabled" : "source-unreachable"
1061
1062
  };
1062
1063
  if (!audio.supported) return {
1063
1064
  available: false,
@@ -1079,7 +1080,7 @@ function resolveState(descriptor, input) {
1079
1080
  if (mask === null) return {
1080
1081
  available: false,
1081
1082
  enabled: false,
1082
- unavailableReason: "source-unreachable"
1083
+ unavailableReason: input.deviceDisabled ? "device-disabled" : "source-unreachable"
1083
1084
  };
1084
1085
  if (!mask.supported) return {
1085
1086
  available: false,
@@ -10350,7 +10351,12 @@ var ConfigEntrySchema = zod.z.object({
10350
10351
  value: zod.z.unknown(),
10351
10352
  description: zod.z.string().optional()
10352
10353
  });
10353
- var LinkedDevicesModeSchema = zod.z.enum(["auto", "manual"]);
10354
+ /**
10355
+ * Only `manual` since D356: the operator picks, nothing links itself. The
10356
+ * field survives on the wire because a viewer already OTA'd parses it —
10357
+ * drop it once no shipped client reads `mode`.
10358
+ */
10359
+ var LinkedDevicesModeSchema = zod.z.enum(["manual"]);
10354
10360
  /** One resolved linked device — the compact projection consumers need. */
10355
10361
  var LinkedDeviceSchema = zod.z.object({
10356
10362
  deviceId: zod.z.number(),
@@ -25377,12 +25383,20 @@ var BatteryStatusSchema = zod.z.object({
25377
25383
  * Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
25378
25384
  * Reolink-specific for the Solar Panel 2 accessory (will become
25379
25385
  * common on other battery cams). `'none'` means running on battery
25380
- * alone.
25386
+ * alone — a NEGATIVE the firmware actually reported.
25387
+ *
25388
+ * `'unknown'` is the absence of an answer: the provider has not read the
25389
+ * power fields yet, or the firmware reported neither. Before it existed,
25390
+ * two unreadable fields produced `'none'`, and a camera nobody had reached
25391
+ * was drawn "on battery alone" — the same D315 defect `percentage` closed
25392
+ * by going nullable. Consumers SKIP it (no charger state published, no
25393
+ * glyph, no HomeKit ChargingState) rather than coerce it either way.
25381
25394
  */
25382
25395
  charging: zod.z.enum([
25383
25396
  "dc",
25384
25397
  "solar",
25385
- "none"
25398
+ "none",
25399
+ "unknown"
25386
25400
  ]),
25387
25401
  /**
25388
25402
  * True when the camera firmware has gone into low-power mode. Battery
@@ -25472,7 +25486,7 @@ onStatusChanged: { data: zod.z.object({
25472
25486
  kind: "push",
25473
25487
  empty: {
25474
25488
  percentage: 0,
25475
- charging: "none",
25489
+ charging: "unknown",
25476
25490
  sleeping: false,
25477
25491
  lastUpdated: 0
25478
25492
  }
@@ -37005,8 +37019,17 @@ var BaseDeviceProvider = class extends require_sleep.BaseAddon {
37005
37019
  async onRestoreDevices(savedDevices) {
37006
37020
  const restored = /* @__PURE__ */ new Set();
37007
37021
  const failures = [];
37022
+ const liveStableIds = new Set((await this.ctx.kernel.devices.getAll()).map((device) => device.stableId));
37008
37023
  const attemptRestore = async (saved) => {
37009
37024
  if (restored.has(saved.id)) return;
37025
+ if (liveStableIds.has(saved.stableId)) {
37026
+ this.ctx.logger.debug("Restore row already live — not dialled again", { tags: {
37027
+ deviceId: saved.id,
37028
+ stableId: saved.stableId
37029
+ } });
37030
+ restored.add(saved.id);
37031
+ return;
37032
+ }
37010
37033
  const Class = this.deviceClasses[saved.type];
37011
37034
  if (!Class) throw new Error(`no device class registered for type "${saved.type}"`);
37012
37035
  if (saved.parentDeviceId !== null && !restored.has(saved.parentDeviceId)) throw new Error(`parent device ${saved.parentDeviceId} not restored`);
package/dist/index.mjs CHANGED
@@ -886,7 +886,8 @@ var CameraSwitchAuthoritySchema = z.discriminatedUnion("kind", [
886
886
  var CameraSwitchUnavailableReasonSchema = z.enum([
887
887
  "no-provider",
888
888
  "source-unreachable",
889
- "not-configured"
889
+ "not-configured",
890
+ "device-disabled"
890
891
  ]);
891
892
  /**
892
893
  * One switch, resolved for one camera.
@@ -1056,7 +1057,7 @@ function resolveState(descriptor, input) {
1056
1057
  if (audio === null) return {
1057
1058
  available: false,
1058
1059
  enabled: true,
1059
- unavailableReason: "source-unreachable"
1060
+ unavailableReason: input.deviceDisabled ? "device-disabled" : "source-unreachable"
1060
1061
  };
1061
1062
  if (!audio.supported) return {
1062
1063
  available: false,
@@ -1078,7 +1079,7 @@ function resolveState(descriptor, input) {
1078
1079
  if (mask === null) return {
1079
1080
  available: false,
1080
1081
  enabled: false,
1081
- unavailableReason: "source-unreachable"
1082
+ unavailableReason: input.deviceDisabled ? "device-disabled" : "source-unreachable"
1082
1083
  };
1083
1084
  if (!mask.supported) return {
1084
1085
  available: false,
@@ -10349,7 +10350,12 @@ var ConfigEntrySchema = z.object({
10349
10350
  value: z.unknown(),
10350
10351
  description: z.string().optional()
10351
10352
  });
10352
- var LinkedDevicesModeSchema = z.enum(["auto", "manual"]);
10353
+ /**
10354
+ * Only `manual` since D356: the operator picks, nothing links itself. The
10355
+ * field survives on the wire because a viewer already OTA'd parses it —
10356
+ * drop it once no shipped client reads `mode`.
10357
+ */
10358
+ var LinkedDevicesModeSchema = z.enum(["manual"]);
10353
10359
  /** One resolved linked device — the compact projection consumers need. */
10354
10360
  var LinkedDeviceSchema = z.object({
10355
10361
  deviceId: z.number(),
@@ -25376,12 +25382,20 @@ var BatteryStatusSchema = z.object({
25376
25382
  * Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
25377
25383
  * Reolink-specific for the Solar Panel 2 accessory (will become
25378
25384
  * common on other battery cams). `'none'` means running on battery
25379
- * alone.
25385
+ * alone — a NEGATIVE the firmware actually reported.
25386
+ *
25387
+ * `'unknown'` is the absence of an answer: the provider has not read the
25388
+ * power fields yet, or the firmware reported neither. Before it existed,
25389
+ * two unreadable fields produced `'none'`, and a camera nobody had reached
25390
+ * was drawn "on battery alone" — the same D315 defect `percentage` closed
25391
+ * by going nullable. Consumers SKIP it (no charger state published, no
25392
+ * glyph, no HomeKit ChargingState) rather than coerce it either way.
25380
25393
  */
25381
25394
  charging: z.enum([
25382
25395
  "dc",
25383
25396
  "solar",
25384
- "none"
25397
+ "none",
25398
+ "unknown"
25385
25399
  ]),
25386
25400
  /**
25387
25401
  * True when the camera firmware has gone into low-power mode. Battery
@@ -25471,7 +25485,7 @@ onStatusChanged: { data: z.object({
25471
25485
  kind: "push",
25472
25486
  empty: {
25473
25487
  percentage: 0,
25474
- charging: "none",
25488
+ charging: "unknown",
25475
25489
  sleeping: false,
25476
25490
  lastUpdated: 0
25477
25491
  }
@@ -36997,8 +37011,17 @@ var BaseDeviceProvider = class extends BaseAddon {
36997
37011
  async onRestoreDevices(savedDevices) {
36998
37012
  const restored = /* @__PURE__ */ new Set();
36999
37013
  const failures = [];
37014
+ const liveStableIds = new Set((await this.ctx.kernel.devices.getAll()).map((device) => device.stableId));
37000
37015
  const attemptRestore = async (saved) => {
37001
37016
  if (restored.has(saved.id)) return;
37017
+ if (liveStableIds.has(saved.stableId)) {
37018
+ this.ctx.logger.debug("Restore row already live — not dialled again", { tags: {
37019
+ deviceId: saved.id,
37020
+ stableId: saved.stableId
37021
+ } });
37022
+ restored.add(saved.id);
37023
+ return;
37024
+ }
37002
37025
  const Class = this.deviceClasses[saved.type];
37003
37026
  if (!Class) throw new Error(`no device class registered for type "${saved.type}"`);
37004
37027
  if (saved.parentDeviceId !== null && !restored.has(saved.parentDeviceId)) throw new Error(`parent device ${saved.parentDeviceId} not restored`);
@@ -173,6 +173,7 @@ export declare const CameraSwitchUnavailableReasonSchema: z.ZodEnum<{
173
173
  "no-provider": "no-provider";
174
174
  "source-unreachable": "source-unreachable";
175
175
  "not-configured": "not-configured";
176
+ "device-disabled": "device-disabled";
176
177
  }>;
177
178
  export type CameraSwitchUnavailableReason = z.infer<typeof CameraSwitchUnavailableReasonSchema>;
178
179
  /**
@@ -201,6 +202,7 @@ export declare const CameraSwitchSchema: z.ZodObject<{
201
202
  "no-provider": "no-provider";
202
203
  "source-unreachable": "source-unreachable";
203
204
  "not-configured": "not-configured";
205
+ "device-disabled": "device-disabled";
204
206
  }>>;
205
207
  enabled: z.ZodBoolean;
206
208
  authority: z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -244,6 +246,7 @@ export declare const CameraSwitchGroupSchema: z.ZodObject<{
244
246
  "no-provider": "no-provider";
245
247
  "source-unreachable": "source-unreachable";
246
248
  "not-configured": "not-configured";
249
+ "device-disabled": "device-disabled";
247
250
  }>>;
248
251
  enabled: z.ZodBoolean;
249
252
  authority: z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -392,6 +392,9 @@ export interface DeviceSelectFilter {
392
392
  readonly types?: readonly string[];
393
393
  /** Always drop this device id from the options (e.g. the host device). */
394
394
  readonly excludeDeviceId?: number;
395
+ /** Always drop devices of these `DeviceType`s — a container is never a
396
+ * legitimate pick, its children are. Applied before every positive clause. */
397
+ readonly excludeTypes?: readonly string[];
395
398
  }
396
399
  /**
397
400
  * Pick a SINGLE device from the live device catalogue. Options are the
@@ -411,6 +414,14 @@ export interface ConfigDeviceMultiSelectField extends ConfigFieldBase {
411
414
  type: 'device-multiselect';
412
415
  deviceFilter?: DeviceSelectFilter;
413
416
  maxItems?: number;
417
+ /**
418
+ * Devices sharing this location are listed FIRST, under a "Suggested"
419
+ * heading, and the location / type facet chips are shown — the shape the
420
+ * linked-devices picker needs (D356): a catalogue of hundreds narrowed by
421
+ * where and what before the free-text search, and the room's own devices
422
+ * offered without being linked on anybody's behalf. `null` = no suggestion.
423
+ */
424
+ suggestLocation?: string | null;
414
425
  }
415
426
  export interface ConfigPasswordField extends ConfigFieldBase {
416
427
  type: 'password';
@@ -1095,7 +1095,8 @@ export interface EventCatalog {
1095
1095
  readonly status: {
1096
1096
  /** `null` = NOT YET KNOWN. See `BatteryStatusSchema.percentage`. */
1097
1097
  readonly percentage: number | null;
1098
- readonly charging: 'dc' | 'solar' | 'none';
1098
+ /** `'unknown'` = the power source was never read. See `BatteryStatusSchema.charging`. */
1099
+ readonly charging: 'dc' | 'solar' | 'none' | 'unknown';
1099
1100
  readonly sleeping: boolean;
1100
1101
  readonly lastUpdated: number;
1101
1102
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/types",
3
- "version": "1.2.147",
3
+ "version": "1.2.149",
4
4
  "description": "Shared types, interfaces, and model catalogs for the CamStack detection ecosystem",
5
5
  "keywords": [
6
6
  "camstack",