@camstack/types 1.2.364 → 1.2.366

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.
Files changed (93) hide show
  1. package/dist/addon.js +3 -2
  2. package/dist/addon.mjs +3 -2
  3. package/dist/auth/device-certificate.d.ts +372 -0
  4. package/dist/auth/request-origin.d.ts +43 -0
  5. package/dist/capabilities/air-quality-sensor.cap.d.ts +32 -0
  6. package/dist/capabilities/alarm-panel.cap.d.ts +4 -0
  7. package/dist/capabilities/ambient-light-sensor.cap.d.ts +13 -0
  8. package/dist/capabilities/audio-metrics.cap.d.ts +4 -0
  9. package/dist/capabilities/automation-control.cap.d.ts +4 -0
  10. package/dist/capabilities/battery.cap.d.ts +11 -0
  11. package/dist/capabilities/binary.cap.d.ts +10 -0
  12. package/dist/capabilities/brightness.cap.d.ts +12 -0
  13. package/dist/capabilities/camera-streams.cap.d.ts +4 -0
  14. package/dist/capabilities/capability-definition.d.ts +70 -0
  15. package/dist/capabilities/carbon-monoxide.cap.d.ts +10 -0
  16. package/dist/capabilities/climate-control.cap.d.ts +32 -0
  17. package/dist/capabilities/color.cap.d.ts +4 -0
  18. package/dist/capabilities/connectivity.cap.d.ts +4 -0
  19. package/dist/capabilities/consumables.cap.d.ts +4 -0
  20. package/dist/capabilities/contact.cap.d.ts +10 -0
  21. package/dist/capabilities/control.cap.d.ts +4 -0
  22. package/dist/capabilities/cover.cap.d.ts +12 -0
  23. package/dist/capabilities/day-night.cap.d.ts +4 -0
  24. package/dist/capabilities/device-credentials.cap.d.ts +174 -0
  25. package/dist/capabilities/device-discovery.cap.d.ts +4 -0
  26. package/dist/capabilities/device-status.cap.d.ts +10 -0
  27. package/dist/capabilities/doorbell.cap.d.ts +4 -0
  28. package/dist/capabilities/enum-sensor.cap.d.ts +4 -0
  29. package/dist/capabilities/event-emitter.cap.d.ts +4 -0
  30. package/dist/capabilities/fan-control.cap.d.ts +15 -0
  31. package/dist/capabilities/feature-probe.cap.d.ts +4 -0
  32. package/dist/capabilities/flood.cap.d.ts +10 -0
  33. package/dist/capabilities/gas.cap.d.ts +10 -0
  34. package/dist/capabilities/humidifier.cap.d.ts +15 -0
  35. package/dist/capabilities/humidity-sensor.cap.d.ts +12 -0
  36. package/dist/capabilities/image-settings.cap.d.ts +4 -0
  37. package/dist/capabilities/image.cap.d.ts +4 -0
  38. package/dist/capabilities/index.d.ts +7 -3
  39. package/dist/capabilities/intercom.cap.d.ts +4 -0
  40. package/dist/capabilities/lawn-mower-control.cap.d.ts +12 -0
  41. package/dist/capabilities/lock-control.cap.d.ts +4 -0
  42. package/dist/capabilities/media-player.cap.d.ts +4 -0
  43. package/dist/capabilities/motion-trigger.cap.d.ts +4 -0
  44. package/dist/capabilities/motion-zones.cap.d.ts +4 -0
  45. package/dist/capabilities/motion.cap.d.ts +11 -0
  46. package/dist/capabilities/native-object-detection.cap.d.ts +4 -0
  47. package/dist/capabilities/navigation.cap.d.ts +4 -0
  48. package/dist/capabilities/network-link.cap.d.ts +19 -0
  49. package/dist/capabilities/node-certificates.cap.d.ts +128 -0
  50. package/dist/capabilities/notifier.cap.d.ts +4 -0
  51. package/dist/capabilities/numeric-sensor.cap.d.ts +12 -0
  52. package/dist/capabilities/pet-feeder.cap.d.ts +25 -0
  53. package/dist/capabilities/power-meter.cap.d.ts +43 -0
  54. package/dist/capabilities/presence.cap.d.ts +12 -0
  55. package/dist/capabilities/pressure-sensor.cap.d.ts +12 -0
  56. package/dist/capabilities/privacy-mask.cap.d.ts +4 -0
  57. package/dist/capabilities/ptz-autotrack.cap.d.ts +4 -0
  58. package/dist/capabilities/recording-onboard.cap.d.ts +4 -0
  59. package/dist/capabilities/recording-signal.cap.d.ts +4 -0
  60. package/dist/capabilities/scene-monitor.cap.d.ts +4 -0
  61. package/dist/capabilities/script-runner.cap.d.ts +4 -0
  62. package/dist/capabilities/smoke.cap.d.ts +10 -0
  63. package/dist/capabilities/stream-catalog.cap.d.ts +4 -0
  64. package/dist/capabilities/stream-params.cap.d.ts +4 -0
  65. package/dist/capabilities/stream-signals.cap.d.ts +4 -0
  66. package/dist/capabilities/switch.cap.d.ts +10 -0
  67. package/dist/capabilities/tamper.cap.d.ts +10 -0
  68. package/dist/capabilities/temperature-sensor.cap.d.ts +12 -0
  69. package/dist/capabilities/update.cap.d.ts +4 -0
  70. package/dist/capabilities/vacuum-control.cap.d.ts +32 -0
  71. package/dist/capabilities/valve.cap.d.ts +12 -0
  72. package/dist/capabilities/vibration.cap.d.ts +10 -0
  73. package/dist/capabilities/water-heater.cap.d.ts +17 -0
  74. package/dist/capabilities/weather.cap.d.ts +27 -0
  75. package/dist/capabilities/zone-analytics.cap.d.ts +4 -0
  76. package/dist/capabilities/zone-rules.cap.d.ts +4 -0
  77. package/dist/capabilities/zones.cap.d.ts +4 -0
  78. package/dist/client.d.ts +1 -1
  79. package/dist/client.js +255 -0
  80. package/dist/client.mjs +245 -1
  81. package/dist/generated/addon-api.d.ts +797 -4
  82. package/dist/generated/cap-input-defaults.d.ts +1 -1
  83. package/dist/generated/capability-router-map.d.ts +8 -2
  84. package/dist/generated/history-catalog.d.ts +11 -0
  85. package/dist/generated/method-access-map.d.ts +1 -1
  86. package/dist/generated/system-proxy.d.ts +2 -0
  87. package/dist/index.d.ts +3 -0
  88. package/dist/index.js +1574 -34
  89. package/dist/index.mjs +1522 -35
  90. package/dist/interfaces/auth.d.ts +6 -0
  91. package/dist/{sleep-BBF1iXUi.mjs → sleep-DxJdzHni.mjs} +26 -1
  92. package/dist/{sleep-BBXNq778.js → sleep-NZlEFYGX.js} +37 -0
  93. package/package.json +1 -1
@@ -35,6 +35,16 @@ export declare const tamperCapability: {
35
35
  * `scripts/check-runtime-state-durability.ts`.
36
36
  */
37
37
  readonly durability: 'restored';
38
+ /**
39
+ * History (D850): recorded series.
40
+ */
41
+ readonly history: {
42
+ readonly fields: {
43
+ readonly tampered: {
44
+ readonly kind: 'boolean';
45
+ };
46
+ };
47
+ };
38
48
  /** Clock fields: written, but excluded from the compare that decides
39
49
  * whether persisting is worth a SQLite commit. */
40
50
  readonly volatileStateFields: readonly ["lastChangedAt"];
@@ -53,6 +53,18 @@ export declare const temperatureSensorCapability: {
53
53
  * `scripts/check-runtime-state-durability.ts`.
54
54
  */
55
55
  readonly durability: 'restored';
56
+ /**
57
+ * History (D850): recorded series.
58
+ */
59
+ readonly history: {
60
+ readonly fields: {
61
+ readonly celsius: {
62
+ readonly kind: 'gauge';
63
+ readonly unit: '°C';
64
+ readonly deadband: 0.1;
65
+ };
66
+ };
67
+ };
56
68
  /** Clock fields: written, but excluded from the compare that decides
57
69
  * whether persisting is worth a SQLite commit. */
58
70
  readonly volatileStateFields: readonly ["lastFetchedAt"];
@@ -51,5 +51,9 @@ export declare const updateCapability: {
51
51
  * `scripts/check-runtime-state-durability.ts`.
52
52
  */
53
53
  readonly durability: 'session';
54
+ /**
55
+ * History (D850): none — text and state.
56
+ */
57
+ readonly history: 'none';
54
58
  };
55
59
  export type IUpdateProvider = InferProvider<typeof updateCapability>;
@@ -244,5 +244,37 @@ export declare const vacuumControlCapability: {
244
244
  * `scripts/check-runtime-state-durability.ts`.
245
245
  */
246
246
  readonly durability: 'session';
247
+ /**
248
+ * History (D850): recorded series. Tank levels are fixed-object paths (`cleanWater.level`, ...).
249
+ */
250
+ readonly history: {
251
+ readonly fields: {
252
+ readonly batteryLevel: {
253
+ readonly kind: 'gauge';
254
+ readonly unit: '%';
255
+ readonly deadband: 2;
256
+ };
257
+ readonly 'cleanWater.level': {
258
+ readonly kind: 'gauge';
259
+ readonly unit: '%';
260
+ readonly deadband: 2;
261
+ };
262
+ readonly 'dirtyWater.level': {
263
+ readonly kind: 'gauge';
264
+ readonly unit: '%';
265
+ readonly deadband: 2;
266
+ };
267
+ readonly 'detergent.level': {
268
+ readonly kind: 'gauge';
269
+ readonly unit: '%';
270
+ readonly deadband: 2;
271
+ };
272
+ readonly 'dustBin.level': {
273
+ readonly kind: 'gauge';
274
+ readonly unit: '%';
275
+ readonly deadband: 2;
276
+ };
277
+ };
278
+ };
247
279
  };
248
280
  export type IVacuumControlProvider = InferProvider<typeof vacuumControlCapability>;
@@ -95,5 +95,17 @@ export declare const valveCapability: {
95
95
  * `scripts/check-runtime-state-durability.ts`.
96
96
  */
97
97
  readonly durability: 'session';
98
+ /**
99
+ * History (D850): recorded series. Actuator tier: position keeps every change.
100
+ */
101
+ readonly history: {
102
+ readonly fields: {
103
+ readonly position: {
104
+ readonly kind: 'gauge';
105
+ readonly unit: '%';
106
+ readonly minIntervalMs: 0;
107
+ };
108
+ };
109
+ };
98
110
  };
99
111
  export type IValveProvider = InferProvider<typeof valveCapability>;
@@ -35,6 +35,16 @@ export declare const vibrationCapability: {
35
35
  * `scripts/check-runtime-state-durability.ts`.
36
36
  */
37
37
  readonly durability: 'restored';
38
+ /**
39
+ * History (D850): recorded series.
40
+ */
41
+ readonly history: {
42
+ readonly fields: {
43
+ readonly detected: {
44
+ readonly kind: 'boolean';
45
+ };
46
+ };
47
+ };
38
48
  /** Clock fields: written, but excluded from the compare that decides
39
49
  * whether persisting is worth a SQLite commit. */
40
50
  readonly volatileStateFields: readonly ["lastChangedAt"];
@@ -80,5 +80,22 @@ export declare const waterHeaterCapability: {
80
80
  * `scripts/check-runtime-state-durability.ts`.
81
81
  */
82
82
  readonly durability: 'session';
83
+ /**
84
+ * History (D850): recorded series. The schema carries no unit; providers publish Celsius. Setpoint keeps every change.
85
+ */
86
+ readonly history: {
87
+ readonly fields: {
88
+ readonly currentTemp: {
89
+ readonly kind: 'gauge';
90
+ readonly unit: '°C';
91
+ readonly deadband: 0.5;
92
+ };
93
+ readonly targetTemp: {
94
+ readonly kind: 'gauge';
95
+ readonly unit: '°C';
96
+ readonly minIntervalMs: 0;
97
+ };
98
+ };
99
+ };
83
100
  };
84
101
  export type IWaterHeaterProvider = InferProvider<typeof waterHeaterCapability>;
@@ -78,5 +78,32 @@ export declare const weatherCapability: {
78
78
  * `scripts/check-runtime-state-durability.ts`.
79
79
  */
80
80
  readonly durability: 'session';
81
+ /**
82
+ * History (D850): recorded series. Units follow the sibling `*Unit` fields.
83
+ */
84
+ readonly history: {
85
+ readonly fields: {
86
+ readonly temperature: {
87
+ readonly kind: 'gauge';
88
+ readonly unitFrom: 'temperatureUnit';
89
+ readonly deadband: 0.2;
90
+ };
91
+ readonly humidity: {
92
+ readonly kind: 'gauge';
93
+ readonly unit: '%';
94
+ readonly deadband: 1;
95
+ };
96
+ readonly pressure: {
97
+ readonly kind: 'gauge';
98
+ readonly unitFrom: 'pressureUnit';
99
+ readonly deadband: 0.5;
100
+ };
101
+ readonly windSpeed: {
102
+ readonly kind: 'gauge';
103
+ readonly unitFrom: 'windSpeedUnit';
104
+ readonly deadband: 0.5;
105
+ };
106
+ };
107
+ };
81
108
  };
82
109
  export type IWeatherProvider = InferProvider<typeof weatherCapability>;
@@ -462,6 +462,10 @@ export declare const zoneAnalyticsCapability: {
462
462
  * `scripts/check-runtime-state-durability.ts`.
463
463
  */
464
464
  readonly durability: 'session';
465
+ /**
466
+ * History (D850): none — occupancy is the addon series `pipeline-analytics/occupancy`; the rest is per-zone arrays keyed by runtime ids.
467
+ */
468
+ readonly history: 'none';
465
469
  };
466
470
  export type IZoneAnalyticsProvider = InferProvider<typeof zoneAnalyticsCapability>;
467
471
  export { CameraOccupancySnapshotSchema as _CameraOccupancySnapshotSchema, HistoryPointSchema, HistoryRangeSchema, HistoryResolutionEnum, PerScopeBreakdownSchema, StationaryObjectSchema, ZoneScopeBreakdownSchema, };
@@ -156,5 +156,9 @@ export declare const zoneRulesCapability: {
156
156
  * `scripts/check-runtime-state-durability.ts`.
157
157
  */
158
158
  readonly durability: 'restored';
159
+ /**
160
+ * History (D850): none — configuration arrays.
161
+ */
162
+ readonly history: 'none';
159
163
  };
160
164
  export type IZoneRulesProvider = InferProvider<typeof zoneRulesCapability>;
@@ -153,5 +153,9 @@ export declare const zonesCapability: {
153
153
  * `scripts/check-runtime-state-durability.ts`.
154
154
  */
155
155
  readonly durability: 'restored';
156
+ /**
157
+ * History (D850): none — configuration arrays.
158
+ */
159
+ readonly history: 'none';
156
160
  };
157
161
  export type IZonesProvider = InferProvider<typeof zonesCapability>;
package/dist/client.d.ts CHANGED
@@ -14,4 +14,4 @@
14
14
  * value this entry does not export — a missing name here is `undefined` at
15
15
  * runtime, not a build error.
16
16
  */
17
- export { APPLE_SA_TO_MACRO, AUDIO_MACRO_LABELS, AlarmArmModeSchema, CLIP_BROKER_PACED_RATES, COCO_TO_MACRO, CamProfileSchema, ICON_CATEGORIES, ICON_ENTRIES, ICON_KEYS, ICON_VIEWER_MODULES, IconKeySchema, LOCATION_ICON_FALLBACK, DEFAULT_TIMELAPSE_PREVIEW_TEXT, DeviceType, EVENTFUL_CAP_NAMES, EVENT_KIND_BY_CAP, EVENT_TAXONOMY, MACRO_LABELS, NC_ALARM_DELAY_MAX_SEC, NC_ALARM_SENSORS_MAX, NC_ALARM_SYSTEM_EVENT_KINDS, NC_ALARM_TRIGGERED_MAX_SEC, NC_BATTERY_CONSUMABLE_SYSTEM_EVENT_KINDS, NC_CAMERA_SCOPE_CAP_NAME, NC_CONSUMABLE_LOW_PERCENT_DEFAULT, NC_CONSUMABLE_LOW_PERCENT_MAX, NC_GROUPING_DEFAULT_SEC, NC_GROUPING_MAX_SEC, NC_GROUPING_MIN_SEC, NC_RULE_EDITOR_SECTION_ORDER, NC_RULE_KIND_SPECS, NC_SENSOR_TRANSITION_UNSUPPORTED_REASON, NC_SYSTEM_EVENT_FAMILY_FILTERS, NC_SYSTEM_EVENT_KIND_GROUP_SPECS, NC_SYSTEM_EVENT_SUMMARY_FAMILIES, NC_TEMPLATE_HELD_BACK_SYSTEM_EVENT_KINDS, NC_TEMPLATE_VARS, NcAlarmConfigSchema, NcAlarmSensorsSchema, NcAlarmSettingsPatchSchema, NcHistoryEntrySchema, NcRuleLastRunsSchema, NodeDirectorySchema, RECORDING_EXPORT_MAX_READ_BYTES, RETRAIN_REVIEW_ADJUSTED_IOU, RETRAIN_REVIEW_MATCH_IOU, RETRAIN_REVIEW_STATUSES, RETRAIN_REVISION_CONFLICT, SystemMirror, TIMELAPSE_DENSE_FLOOR_SEC, TimelapseRuleSchema, YAMNET_TO_MACRO, alarmDeviceBlocksArming, alarmDeviceSecureOnArm, alarmPatchLanded, canonicalIconKey, classifyRetrainReview, conditionVisibleForKind, createSystemProxy, droppedConditionsForKind, iconCategoryLabel, iconEntry, iconsInCategory, isIconKey, isHeldBackTemplateVar, isSystemRuleKind, kindsForDiscriminator, locationIconKey, knownValues, nodePickerItems, packagePickerItems, pickerForCondition, pickerForRuleClasses, parseRetrainRevisionConflict, resolveIconKey, resolveModeDelays, retrainBoxIou, retrainRevisionConflictMessage, ruleDeviceCompatCapNames, ruleEditorSectionsForKind, ruleGroupingApplies, ruleKindOf, ruleKindSpec, ruleSeedForSection, searchIcons, sensorTransitionNeverFires, sensorTransitionOffered, stateLabel, summarizeReview, systemEventDeliveryProblems, systemEventFilterAppliesToAnyKind, systemEventKindsOfFamily, systemFamilyOfKind, templateCarriesSummary, templateVarDeliveryApplies, templateVarKindApplies, templateVarSystemEventApplies, } from './index.js';
17
+ export { APPLE_SA_TO_MACRO, AUDIO_MACRO_LABELS, AlarmArmModeSchema, CLIP_BROKER_PACED_RATES, COCO_TO_MACRO, CamProfileSchema, ICON_CATEGORIES, ICON_ENTRIES, ICON_KEYS, ICON_VIEWER_MODULES, IconKeySchema, LOCATION_ICON_FALLBACK, DEFINITIVE_DEVICE_REFUSALS, DEVICE_CERT_RENEW_WINDOW_DAYS, DEVICE_DEFINITIVE_REFUSALS_BEFORE_DELETE, DEVICE_REFRESH_REFUSAL_PREFIX, DEVICE_CERT_SIGNATURE, DEVICE_SIGNATURE_MESSAGE_VERSION, DEFAULT_TIMELAPSE_PREVIEW_TEXT, DeviceType, EVENTFUL_CAP_NAMES, EVENT_KIND_BY_CAP, EVENT_TAXONOMY, MACRO_LABELS, NC_ALARM_DELAY_MAX_SEC, NC_ALARM_SENSORS_MAX, NC_ALARM_SYSTEM_EVENT_KINDS, NC_ALARM_TRIGGERED_MAX_SEC, NC_BATTERY_CONSUMABLE_SYSTEM_EVENT_KINDS, NC_CAMERA_SCOPE_CAP_NAME, NC_CONSUMABLE_LOW_PERCENT_DEFAULT, NC_CONSUMABLE_LOW_PERCENT_MAX, NC_GROUPING_DEFAULT_SEC, NC_GROUPING_MAX_SEC, NC_GROUPING_MIN_SEC, NC_RULE_EDITOR_SECTION_ORDER, NC_RULE_KIND_SPECS, NC_SENSOR_TRANSITION_UNSUPPORTED_REASON, NC_SYSTEM_EVENT_FAMILY_FILTERS, NC_SYSTEM_EVENT_KIND_GROUP_SPECS, NC_SYSTEM_EVENT_SUMMARY_FAMILIES, NC_TEMPLATE_HELD_BACK_SYSTEM_EVENT_KINDS, NC_TEMPLATE_VARS, NcAlarmConfigSchema, NcAlarmSensorsSchema, NcAlarmSettingsPatchSchema, NcHistoryEntrySchema, NcRuleLastRunsSchema, NodeDirectorySchema, RECORDING_EXPORT_MAX_READ_BYTES, RETRAIN_REVIEW_ADJUSTED_IOU, RETRAIN_REVIEW_MATCH_IOU, RETRAIN_REVIEW_STATUSES, RETRAIN_REVISION_CONFLICT, SystemMirror, TIMELAPSE_DENSE_FLOOR_SEC, TimelapseRuleSchema, YAMNET_TO_MACRO, alarmDeviceBlocksArming, alarmDeviceSecureOnArm, alarmPatchLanded, canonicalIconKey, buildDeviceEnrollmentLink, buildDeviceSignatureMessage, deviceRefusalFromMessage, isDefinitiveDeviceRefusal, classifyRetrainReview, conditionVisibleForKind, createSystemProxy, droppedConditionsForKind, iconCategoryLabel, iconEntry, iconsInCategory, isIconKey, isHeldBackTemplateVar, isSystemRuleKind, kindsForDiscriminator, locationIconKey, knownValues, nodePickerItems, parseDeviceEnrollmentLink, packagePickerItems, pickerForCondition, pickerForRuleClasses, parseRetrainRevisionConflict, resolveIconKey, resolveModeDelays, retrainBoxIou, retrainRevisionConflictMessage, ruleDeviceCompatCapNames, ruleEditorSectionsForKind, ruleGroupingApplies, ruleKindOf, ruleKindSpec, ruleSeedForSection, searchIcons, sensorTransitionNeverFires, sensorTransitionOffered, stateLabel, summarizeReview, systemEventDeliveryProblems, systemEventFilterAppliesToAnyKind, systemEventKindsOfFamily, systemFamilyOfKind, templateCarriesSummary, templateVarDeliveryApplies, templateVarKindApplies, templateVarSystemEventApplies, } from './index.js';
package/dist/client.js CHANGED
@@ -559,6 +559,240 @@ zod.z.object({
559
559
  resolution: CamStreamResolutionSchema.optional()
560
560
  });
561
561
  //#endregion
562
+ //#region src/auth/device-certificate.ts
563
+ /**
564
+ * Device certificates (D855) — the wire contract shared by the hub, the admin
565
+ * UI and the native viewer.
566
+ *
567
+ * A device (a phone) generates its OWN P-256 key pair in hardware (Secure
568
+ * Enclave / Android Keystore / a non-extractable WebCrypto key). The private
569
+ * key never travels. The hub signs the PUBLIC key into an X.509 leaf under a
570
+ * dedicated device CA; the device later proves possession of the key by
571
+ * signing a hub-issued nonce, and the hub answers with the same session a
572
+ * password login opens.
573
+ *
574
+ * Everything on the wire is a small string (a PEM, a base64url signature):
575
+ * D613 is about bulk bytes, and a certificate is ~600 bytes.
576
+ */
577
+ /** Signature algorithm of every device credential: ECDSA, curve P-256, SHA-256. */
578
+ var DEVICE_CERT_SIGNATURE = "ecdsa-p256-sha256";
579
+ /** First line of every signed message; a change of format bumps the version. */
580
+ var DEVICE_SIGNATURE_MESSAGE_VERSION = "camstack-device-cert-v1";
581
+ zod.z.enum([
582
+ "login",
583
+ "renew",
584
+ "revoke"
585
+ ]);
586
+ var DEVICE_CERT_RENEW_WINDOW_DAYS = 30;
587
+ /**
588
+ * The exact bytes a device signs (UTF-8, `\n` separators, no trailing newline):
589
+ *
590
+ * camstack-device-cert-v1
591
+ * <login|renew>
592
+ * <origin> the hub origin returned by `getDeviceChallenge`
593
+ * <nonce>
594
+ *
595
+ * The origin is part of the message so a signature collected by a look-alike
596
+ * hub is worthless on the real one; the hub additionally binds the nonce to
597
+ * the origin it issued it for and refuses any other.
598
+ */
599
+ function buildDeviceSignatureMessage(input) {
600
+ return [
601
+ DEVICE_SIGNATURE_MESSAGE_VERSION,
602
+ input.purpose,
603
+ input.origin,
604
+ input.nonce
605
+ ].join("\n");
606
+ }
607
+ /** The deep link a QR carries: `camstack://enroll?hub=<origin>&code=<code>`. */
608
+ function buildDeviceEnrollmentLink(input) {
609
+ const query = new URLSearchParams();
610
+ if (input.hub !== void 0) query.set("hub", input.hub);
611
+ query.set("code", input.code);
612
+ return `${input.scheme ?? "camstack"}://enroll?${query.toString()}`;
613
+ }
614
+ /** Parse an enrollment deep link; `null` when it is not one. `hub` is absent when the link names none. */
615
+ function parseDeviceEnrollmentLink(raw) {
616
+ let url;
617
+ try {
618
+ url = new URL(raw);
619
+ } catch {
620
+ return null;
621
+ }
622
+ if (url.protocol !== "camstack:" && url.protocol !== "camstack.dev:") return null;
623
+ if (url.hostname !== "enroll") return null;
624
+ const code = url.searchParams.get("code");
625
+ if (code === null || code === "") return null;
626
+ const hub = url.searchParams.get("hub");
627
+ return {
628
+ hub: hub === null || hub === "" ? null : hub,
629
+ code
630
+ };
631
+ }
632
+ var DevicePlatformSchema = zod.z.enum([
633
+ "ios",
634
+ "android",
635
+ "web",
636
+ "other"
637
+ ]);
638
+ var Base64UrlSchema = zod.z.string().min(1).max(4096).regex(/^[A-Za-z0-9_-]+$/);
639
+ var PemSchema = zod.z.string().min(1).max(16384);
640
+ /**
641
+ * Why a device-certificate endpoint said no. Distinct from a transport / 5xx
642
+ * failure: those carry no reason and mean "try again", never "the credential is
643
+ * dead". The viewer switches on this exhaustively.
644
+ */
645
+ var DeviceRefusalReasonSchema = zod.z.enum([
646
+ "revoked",
647
+ "unknown-credential",
648
+ "expired",
649
+ "bad-signature",
650
+ "nonce-invalid",
651
+ "rate-limited",
652
+ "invalid-certificate",
653
+ "superseded",
654
+ "user-gone",
655
+ "unavailable",
656
+ "code-invalid",
657
+ "self-enrollment-disabled",
658
+ "step-up-required",
659
+ "bad-public-key"
660
+ ]);
661
+ /** The only answers after which the app may count towards deleting its credential. */
662
+ var DEFINITIVE_DEVICE_REFUSALS = [
663
+ "revoked",
664
+ "unknown-credential",
665
+ "user-gone"
666
+ ];
667
+ /** Consecutive DEFINITIVE answers before the app deletes its key and certificate. */
668
+ var DEVICE_DEFINITIVE_REFUSALS_BEFORE_DELETE = 3;
669
+ function isDefinitiveDeviceRefusal(reason) {
670
+ return DEFINITIVE_DEVICE_REFUSALS.includes(reason);
671
+ }
672
+ var DeviceRefusalSchema = zod.z.object({
673
+ ok: zod.z.literal(false),
674
+ reason: DeviceRefusalReasonSchema,
675
+ definitive: zod.z.boolean(),
676
+ retryAfterSeconds: zod.z.number().optional()
677
+ });
678
+ /**
679
+ * A credential-bound session that can no longer refresh answers
680
+ * `auth.refreshSession` with UNAUTHORIZED whose message is this prefix + the
681
+ * reason; {@link deviceRefusalFromMessage} reads it back.
682
+ */
683
+ var DEVICE_REFRESH_REFUSAL_PREFIX = "device-credential:";
684
+ function deviceRefusalFromMessage(message) {
685
+ if (!message.startsWith("device-credential:")) return null;
686
+ const parsed = DeviceRefusalReasonSchema.safeParse(message.slice(18));
687
+ return parsed.success ? parsed.data : null;
688
+ }
689
+ zod.z.object({
690
+ code: zod.z.string().min(1).max(256),
691
+ /** SubjectPublicKeyInfo DER of the device's P-256 public key, base64url. */
692
+ publicKeySpki: Base64UrlSchema,
693
+ deviceName: zod.z.string().min(1).max(80).optional(),
694
+ platform: DevicePlatformSchema
695
+ });
696
+ var CompleteEnrollmentOutputSchema = zod.z.object({
697
+ credentialId: zod.z.string(),
698
+ certPem: PemSchema,
699
+ /** The device CA certificate the leaf chains to. */
700
+ chainPem: PemSchema,
701
+ notAfter: zod.z.number(),
702
+ user: zod.z.object({
703
+ id: zod.z.string(),
704
+ username: zod.z.string()
705
+ })
706
+ });
707
+ zod.z.discriminatedUnion("ok", [CompleteEnrollmentOutputSchema.extend({ ok: zod.z.literal(true) }), DeviceRefusalSchema]);
708
+ zod.z.object({
709
+ /** The single-use step-up proof (`auth.deviceEnrollProofFrom…`). */
710
+ proof: zod.z.string().min(1).max(512),
711
+ publicKeySpki: Base64UrlSchema,
712
+ deviceName: zod.z.string().min(1).max(80),
713
+ platform: DevicePlatformSchema
714
+ });
715
+ zod.z.object({
716
+ proof: zod.z.string(),
717
+ expiresAt: zod.z.number()
718
+ });
719
+ var DeviceChallengeSchema = zod.z.object({
720
+ nonce: zod.z.string(),
721
+ /** The origin to put in the signed message. The app compares it to the hub it dialled. */
722
+ origin: zod.z.string(),
723
+ expiresAt: zod.z.number(),
724
+ signature: zod.z.literal(DEVICE_CERT_SIGNATURE)
725
+ });
726
+ zod.z.discriminatedUnion("ok", [DeviceChallengeSchema.extend({ ok: zod.z.literal(true) }), DeviceRefusalSchema]);
727
+ zod.z.object({
728
+ certPem: PemSchema,
729
+ nonce: zod.z.string().min(1).max(256),
730
+ /** ECDSA P-256 SHA-256 over {@link buildDeviceSignatureMessage}; raw r||s or DER, base64url. */
731
+ signature: Base64UrlSchema
732
+ });
733
+ var RenewDeviceCertificateOutputSchema = zod.z.object({
734
+ credentialId: zod.z.string(),
735
+ certPem: PemSchema,
736
+ chainPem: PemSchema,
737
+ notAfter: zod.z.number()
738
+ });
739
+ zod.z.discriminatedUnion("ok", [RenewDeviceCertificateOutputSchema.extend({ ok: zod.z.literal(true) }), DeviceRefusalSchema]);
740
+ zod.z.discriminatedUnion("ok", [zod.z.object({
741
+ ok: zod.z.literal(true),
742
+ credentialId: zod.z.string(),
743
+ sessionsEnded: zod.z.number().int()
744
+ }), DeviceRefusalSchema]);
745
+ var DeviceCredentialStatusSchema = zod.z.enum([
746
+ "active",
747
+ "expired",
748
+ "revoked"
749
+ ]);
750
+ zod.z.object({
751
+ id: zod.z.string(),
752
+ userId: zod.z.string(),
753
+ username: zod.z.string().nullable(),
754
+ deviceName: zod.z.string(),
755
+ platform: DevicePlatformSchema,
756
+ enrolledVia: zod.z.enum(["qr", "self"]),
757
+ /** SHA-256 of the leaf certificate DER, colon-hex. */
758
+ fingerprint: zod.z.string(),
759
+ issuedAt: zod.z.number(),
760
+ expiresAt: zod.z.number(),
761
+ lastUsedAt: zod.z.number().nullable(),
762
+ lastUsedFrom: zod.z.string().nullable(),
763
+ revokedAt: zod.z.number().nullable(),
764
+ /** `admin:<userId>` | `user:<userId>` | `device` | `user-deleted`. */
765
+ revokedBy: zod.z.string().nullable(),
766
+ status: DeviceCredentialStatusSchema
767
+ });
768
+ zod.z.object({
769
+ /** Shown once; only its hash is kept. */
770
+ code: zod.z.string(),
771
+ expiresAt: zod.z.number(),
772
+ /** `camstack://enroll?hub=…&code=…` — what the QR encodes. */
773
+ enrollUrl: zod.z.string(),
774
+ /** The hub origin in the link, or `null` when the hub could not name one (the link then has no `hub`). */
775
+ hubOrigin: zod.z.string().nullable(),
776
+ /** Every origin the apps may try (role `appConnections`). */
777
+ hubOrigins: zod.z.array(zod.z.string())
778
+ });
779
+ zod.z.object({
780
+ kind: zod.z.literal("device-certificate"),
781
+ id: zod.z.literal("device-certificate"),
782
+ label: zod.z.string(),
783
+ stage: zod.z.literal("primary"),
784
+ /** tRPC paths under the hub's `auth` router, so a client names no literal. */
785
+ challengePath: zod.z.literal("auth.getDeviceChallenge"),
786
+ revokePath: zod.z.literal("auth.revokeOwnDeviceCertificate"),
787
+ enrollSelfPath: zod.z.literal("auth.enrollSelf"),
788
+ loginPath: zod.z.literal("auth.loginWithDeviceCertificate"),
789
+ renewPath: zod.z.literal("auth.renewDeviceCertificate"),
790
+ signature: zod.z.literal(DEVICE_CERT_SIGNATURE),
791
+ messageVersion: zod.z.literal(DEVICE_SIGNATURE_MESSAGE_VERSION),
792
+ /** Which clients can execute it: a native app silently, a browser with a non-extractable WebCrypto key. */
793
+ clients: zod.z.array(zod.z.enum(["native", "web"]))
794
+ });
795
+ //#endregion
562
796
  //#region src/catalogs/sensor-active-state.ts
563
797
  /**
564
798
  * THE table "which boolean of this device type counts as HIGH", and the
@@ -27412,6 +27646,16 @@ function createSystemProxy(api) {
27412
27646
  release: (input) => dispatch("deviceAdoption", "release", "mutation", input),
27413
27647
  resync: (input) => dispatch("deviceAdoption", "resync", "mutation", input)
27414
27648
  },
27649
+ deviceCredentials: {
27650
+ listDeviceCredentials: (input) => dispatch("deviceCredentials", "listDeviceCredentials", "query", input),
27651
+ startEnrollment: (input) => dispatch("deviceCredentials", "startEnrollment", "mutation", input),
27652
+ revokeDeviceCredential: (input) => dispatch("deviceCredentials", "revokeDeviceCredential", "mutation", input),
27653
+ getDeviceCertificateSettings: (input) => dispatch("deviceCredentials", "getDeviceCertificateSettings", "query", input),
27654
+ setDeviceCertificateSettings: (input) => dispatch("deviceCredentials", "setDeviceCertificateSettings", "mutation", input),
27655
+ deleteDeviceCredential: (input) => dispatch("deviceCredentials", "deleteDeviceCredential", "mutation", input),
27656
+ getDeviceCaStatus: (input) => dispatch("deviceCredentials", "getDeviceCaStatus", "query", input),
27657
+ renameDeviceCredential: (input) => dispatch("deviceCredentials", "renameDeviceCredential", "mutation", input)
27658
+ },
27415
27659
  deviceExport: {
27416
27660
  getStatus: (input) => dispatch("deviceExport", "getStatus", "query", input),
27417
27661
  listSupportedDeviceKinds: (input) => dispatch("deviceExport", "listSupportedDeviceKinds", "query", input),
@@ -30881,6 +31125,12 @@ exports.CLIP_BROKER_PACED_RATES = CLIP_BROKER_PACED_RATES;
30881
31125
  exports.COCO_TO_MACRO = COCO_TO_MACRO;
30882
31126
  exports.CamProfileSchema = CamProfileSchema;
30883
31127
  exports.DEFAULT_TIMELAPSE_PREVIEW_TEXT = DEFAULT_TIMELAPSE_PREVIEW_TEXT;
31128
+ exports.DEFINITIVE_DEVICE_REFUSALS = DEFINITIVE_DEVICE_REFUSALS;
31129
+ exports.DEVICE_CERT_RENEW_WINDOW_DAYS = DEVICE_CERT_RENEW_WINDOW_DAYS;
31130
+ exports.DEVICE_CERT_SIGNATURE = DEVICE_CERT_SIGNATURE;
31131
+ exports.DEVICE_DEFINITIVE_REFUSALS_BEFORE_DELETE = DEVICE_DEFINITIVE_REFUSALS_BEFORE_DELETE;
31132
+ exports.DEVICE_REFRESH_REFUSAL_PREFIX = DEVICE_REFRESH_REFUSAL_PREFIX;
31133
+ exports.DEVICE_SIGNATURE_MESSAGE_VERSION = DEVICE_SIGNATURE_MESSAGE_VERSION;
30884
31134
  exports.DeviceType = DeviceType;
30885
31135
  exports.EVENTFUL_CAP_NAMES = EVENTFUL_CAP_NAMES;
30886
31136
  exports.EVENT_KIND_BY_CAP = EVENT_KIND_BY_CAP;
@@ -30929,14 +31179,18 @@ exports.YAMNET_TO_MACRO = YAMNET_TO_MACRO;
30929
31179
  exports.alarmDeviceBlocksArming = alarmDeviceBlocksArming;
30930
31180
  exports.alarmDeviceSecureOnArm = alarmDeviceSecureOnArm;
30931
31181
  exports.alarmPatchLanded = alarmPatchLanded;
31182
+ exports.buildDeviceEnrollmentLink = buildDeviceEnrollmentLink;
31183
+ exports.buildDeviceSignatureMessage = buildDeviceSignatureMessage;
30932
31184
  exports.canonicalIconKey = canonicalIconKey;
30933
31185
  exports.classifyRetrainReview = classifyRetrainReview;
30934
31186
  exports.conditionVisibleForKind = conditionVisibleForKind;
30935
31187
  exports.createSystemProxy = createSystemProxy;
31188
+ exports.deviceRefusalFromMessage = deviceRefusalFromMessage;
30936
31189
  exports.droppedConditionsForKind = droppedConditionsForKind;
30937
31190
  exports.iconCategoryLabel = iconCategoryLabel;
30938
31191
  exports.iconEntry = iconEntry;
30939
31192
  exports.iconsInCategory = iconsInCategory;
31193
+ exports.isDefinitiveDeviceRefusal = isDefinitiveDeviceRefusal;
30940
31194
  exports.isHeldBackTemplateVar = isHeldBackTemplateVar;
30941
31195
  exports.isIconKey = isIconKey;
30942
31196
  exports.isSystemRuleKind = isSystemRuleKind;
@@ -30945,6 +31199,7 @@ exports.knownValues = knownValues;
30945
31199
  exports.locationIconKey = locationIconKey;
30946
31200
  exports.nodePickerItems = nodePickerItems;
30947
31201
  exports.packagePickerItems = packagePickerItems;
31202
+ exports.parseDeviceEnrollmentLink = parseDeviceEnrollmentLink;
30948
31203
  exports.parseRetrainRevisionConflict = parseRetrainRevisionConflict;
30949
31204
  exports.pickerForCondition = pickerForCondition;
30950
31205
  exports.pickerForRuleClasses = pickerForRuleClasses;