@camstack/sdk 0.1.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1087 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+
4
+ // src/backend-client.ts
5
+ import { createTRPCClient, createWSClient, wsLink, httpLink } from "@trpc/client";
6
+ import superjson from "superjson";
7
+ var BackendClient = class {
8
+ static {
9
+ __name(this, "BackendClient");
10
+ }
11
+ /** Raw tRPC client — for advanced usage / direct path access */
12
+ trpc;
13
+ serverUrl;
14
+ token;
15
+ wsClient = null;
16
+ constructor(config) {
17
+ this.serverUrl = config.serverUrl.replace(/\/+$/, "");
18
+ this.token = config.token;
19
+ const isBrowser = typeof window !== "undefined";
20
+ const useWs = config.useWebSocket ?? isBrowser;
21
+ const headers = /* @__PURE__ */ __name(() => {
22
+ const h = {};
23
+ if (this.token) {
24
+ h["Authorization"] = `Bearer ${this.token}`;
25
+ }
26
+ return h;
27
+ }, "headers");
28
+ if (useWs) {
29
+ const wsUrl = this.serverUrl.replace(/^http/, "ws") + "/trpc";
30
+ this.wsClient = createWSClient({
31
+ url: wsUrl,
32
+ connectionParams: /* @__PURE__ */ __name(() => ({
33
+ token: this.token
34
+ }), "connectionParams"),
35
+ retryDelayMs: /* @__PURE__ */ __name(() => 2e3, "retryDelayMs")
36
+ });
37
+ this.trpc = createTRPCClient({
38
+ links: [
39
+ wsLink({
40
+ client: this.wsClient,
41
+ transformer: superjson
42
+ })
43
+ ]
44
+ });
45
+ } else {
46
+ this.trpc = createTRPCClient({
47
+ links: [
48
+ httpLink({
49
+ url: `${this.serverUrl}/trpc`,
50
+ headers,
51
+ transformer: superjson
52
+ })
53
+ ]
54
+ });
55
+ }
56
+ }
57
+ /** Update the auth token (e.g. after login) */
58
+ setToken(token) {
59
+ this.token = token;
60
+ }
61
+ /** Close the WebSocket connection (if using WS transport) */
62
+ close() {
63
+ this.wsClient?.close();
64
+ }
65
+ // ─── Auth ──────────────────────────────────────────────────────────
66
+ async login(username, password) {
67
+ return this.trpc.auth.login.mutate({
68
+ username,
69
+ password
70
+ });
71
+ }
72
+ async getMe() {
73
+ return this.trpc.auth.me.query();
74
+ }
75
+ async logout() {
76
+ return this.trpc.auth.logout.mutate();
77
+ }
78
+ // ─── System ────────────────────────────────────────────────────────
79
+ async getSystemInfo() {
80
+ return this.trpc.system.info.query();
81
+ }
82
+ async getFeatureFlags() {
83
+ return this.trpc.system.featureFlags.query();
84
+ }
85
+ // ─── Providers ─────────────────────────────────────────────────────
86
+ async listProviders() {
87
+ return this.trpc.providers.list.query();
88
+ }
89
+ async getProvider(providerId) {
90
+ return this.trpc.providers.get.query({
91
+ id: providerId
92
+ });
93
+ }
94
+ async startProvider(providerId) {
95
+ return this.trpc.providers.start.mutate({
96
+ id: providerId
97
+ });
98
+ }
99
+ async stopProvider(providerId) {
100
+ return this.trpc.providers.stop.mutate({
101
+ id: providerId
102
+ });
103
+ }
104
+ async listProviderTypes() {
105
+ return this.trpc.providerConfig.getAvailableTypes.query();
106
+ }
107
+ // ─── Devices ───────────────────────────────────────────────────────
108
+ async listDevices() {
109
+ return this.trpc.devices.list.query();
110
+ }
111
+ async getDevice(deviceId) {
112
+ return this.trpc.devices.get.query({
113
+ id: deviceId
114
+ });
115
+ }
116
+ async discoverDevices(providerId) {
117
+ return this.trpc.devices.discoverDevices.query({
118
+ providerId
119
+ });
120
+ }
121
+ async adoptDevice(providerId, externalId) {
122
+ return this.trpc.devices.adoptDevice.mutate({
123
+ providerId,
124
+ externalId
125
+ });
126
+ }
127
+ async createDevice(providerId, config) {
128
+ return this.trpc.devices.createDevice.mutate({
129
+ providerId,
130
+ config
131
+ });
132
+ }
133
+ /** Returns the URL path for a static asset served by an addon. */
134
+ getAddonAssetUrl(addonId, assetPath) {
135
+ return `/api/addon-assets/${addonId}/${assetPath}`;
136
+ }
137
+ // ─── Addons ────────────────────────────────────────────────────────
138
+ async listAddons() {
139
+ return this.trpc.addons.list.query();
140
+ }
141
+ async getAddonConfigSchema(addonId) {
142
+ return this.trpc.addons.getConfigSchema.query({
143
+ addonId
144
+ });
145
+ }
146
+ async getAddonConfig(addonId) {
147
+ return this.trpc.addons.getConfig.query({
148
+ addonId
149
+ });
150
+ }
151
+ async updateAddonConfig(addonId, config) {
152
+ return this.trpc.addons.updateConfig.mutate({
153
+ addonId,
154
+ config
155
+ });
156
+ }
157
+ async getAddonLogs(addonId, options) {
158
+ return this.trpc.addons.getLogs.query({
159
+ addonId,
160
+ ...options
161
+ });
162
+ }
163
+ // ─── Known Faces ───────────────────────────────────────────────────
164
+ async listKnownFaces() {
165
+ return this.trpc.knownFaces.list.query();
166
+ }
167
+ async registerFace(label, cropBase64, group) {
168
+ return this.trpc.knownFaces.register.mutate({
169
+ label,
170
+ cropBase64,
171
+ group
172
+ });
173
+ }
174
+ // ─── Pipeline ──────────────────────────────────────────────────────
175
+ async listPipelines() {
176
+ return this.trpc.bridgePipeline.listAddons.query();
177
+ }
178
+ async getPipelineStatus(deviceId) {
179
+ return this.trpc.bridgePipeline.getPipeline.query({
180
+ deviceId
181
+ });
182
+ }
183
+ // ─── Agents ────────────────────────────────────────────────────────
184
+ async listAgents() {
185
+ return this.trpc.agents.listAgents.query();
186
+ }
187
+ async dispatchTask(agentId, task) {
188
+ return this.trpc.agents.dispatchTask.mutate({
189
+ capability: agentId,
190
+ input: task
191
+ });
192
+ }
193
+ async getProcessTree() {
194
+ return this.trpc.agent.processTree.query();
195
+ }
196
+ // ─── Bridge Pipeline ───────────────────────────────────────────────
197
+ async bridgeListAddons() {
198
+ return this.trpc.bridgePipeline.listAddons.query();
199
+ }
200
+ async bridgeGetPipeline(deviceId) {
201
+ return this.trpc.bridgePipeline.getPipeline.query({
202
+ deviceId
203
+ });
204
+ }
205
+ async bridgeSetPipeline(deviceId, config) {
206
+ return this.trpc.bridgePipeline.setPipeline.mutate({
207
+ deviceId,
208
+ config
209
+ });
210
+ }
211
+ async bridgeValidatePipeline(config) {
212
+ return this.trpc.bridgePipeline.validatePipeline.query(config);
213
+ }
214
+ async bridgeGetAddonConfig(addonId) {
215
+ return this.trpc.bridgePipeline.getAddonConfig.query({
216
+ addonId
217
+ });
218
+ }
219
+ async bridgeSetAddonConfig(addonId, config) {
220
+ return this.trpc.bridgePipeline.setAddonConfig.mutate({
221
+ addonId,
222
+ config
223
+ });
224
+ }
225
+ // ─── Bridge Addons ─────────────────────────────────────────────────
226
+ async bridgeListPackages() {
227
+ return this.trpc.bridgeAddons.listPackages.query();
228
+ }
229
+ async bridgeListAddonsPackages() {
230
+ return this.trpc.bridgeAddons.listAddons.query();
231
+ }
232
+ async bridgeInstallPackage(packageName, version) {
233
+ return this.trpc.bridgeAddons.installPackage.mutate({
234
+ packageName,
235
+ version
236
+ });
237
+ }
238
+ async bridgeUninstallPackage(packageName) {
239
+ return this.trpc.bridgeAddons.uninstallPackage.mutate({
240
+ packageName
241
+ });
242
+ }
243
+ // ─── Recording ─────────────────────────────────────────────────────
244
+ async getRecordingConfig(deviceId) {
245
+ return this.trpc.recording.getConfig.query({
246
+ deviceId
247
+ });
248
+ }
249
+ async getRecordingPolicy(deviceId) {
250
+ return this.trpc.recording.getPolicy.query({
251
+ deviceId
252
+ });
253
+ }
254
+ async getRecordingPolicyStatus(deviceId) {
255
+ return this.trpc.recording.getPolicyStatus.query({
256
+ deviceId
257
+ });
258
+ }
259
+ async getRecordingSegments(deviceId, streamId, startTime, endTime) {
260
+ return this.trpc.recording.getSegments.query({
261
+ deviceId,
262
+ streamId,
263
+ startTime,
264
+ endTime
265
+ });
266
+ }
267
+ // ─── Events ────────────────────────────────────────────────────────
268
+ async getEvents(deviceId, options) {
269
+ return this.trpc.events.query.query({
270
+ deviceId,
271
+ ...options
272
+ });
273
+ }
274
+ // ─── Logs ──────────────────────────────────────────────────────────
275
+ async getLogs(options) {
276
+ return this.trpc.logs.query.query(options ?? {});
277
+ }
278
+ // ─── REPL ──────────────────────────────────────────────────────────
279
+ async replEval(code, scope) {
280
+ return this.trpc.repl.execute.mutate({
281
+ code,
282
+ scope: scope ?? {
283
+ type: "system"
284
+ }
285
+ });
286
+ }
287
+ // ─── Users ─────────────────────────────────────────────────────────
288
+ async listUsers() {
289
+ return this.trpc.users.list.query();
290
+ }
291
+ async createUser(username, password, role) {
292
+ return this.trpc.users.create.mutate({
293
+ username,
294
+ password,
295
+ role
296
+ });
297
+ }
298
+ // ─── Session Tracker ───────────────────────────────────────────────
299
+ async getTrackingSessions(deviceId) {
300
+ return this.trpc.session.getActiveTracks.query({
301
+ deviceId
302
+ });
303
+ }
304
+ // ─── Processes ─────────────────────────────────────────────────────
305
+ async listProcesses() {
306
+ return this.trpc.processes.listProcesses.query();
307
+ }
308
+ async enableProvider(providerId) {
309
+ return this.trpc.processes.enableProvider.mutate({
310
+ id: providerId
311
+ });
312
+ }
313
+ async disableProvider(providerId) {
314
+ return this.trpc.processes.disableProvider.mutate({
315
+ id: providerId
316
+ });
317
+ }
318
+ // ─── Settings ──────────────────────────────────────────────────────
319
+ /** Fetch the UI schema for a single section, or all sections if omitted. */
320
+ async getSettingsSchema(section) {
321
+ return this.trpc.settings.getSchema.query({
322
+ section
323
+ });
324
+ }
325
+ async getSettings(section) {
326
+ return this.trpc.settings.get.query({
327
+ section
328
+ });
329
+ }
330
+ async updateSettings(section, data) {
331
+ return this.trpc.settings.update.mutate({
332
+ section,
333
+ data
334
+ });
335
+ }
336
+ };
337
+ function createBackendClient(config) {
338
+ return new BackendClient(config);
339
+ }
340
+ __name(createBackendClient, "createBackendClient");
341
+
342
+ // src/detection.ts
343
+ var DetectionClass = /* @__PURE__ */ (function(DetectionClass2) {
344
+ DetectionClass2["Motion"] = "motion";
345
+ DetectionClass2["Person"] = "person";
346
+ DetectionClass2["Vehicle"] = "vehicle";
347
+ DetectionClass2["Animal"] = "animal";
348
+ DetectionClass2["Audio"] = "audio";
349
+ DetectionClass2["Face"] = "face";
350
+ DetectionClass2["Plate"] = "plate";
351
+ DetectionClass2["Package"] = "package";
352
+ DetectionClass2["Doorbell"] = "doorbell";
353
+ DetectionClass2["Sensor"] = "sensor";
354
+ return DetectionClass2;
355
+ })({});
356
+ var animalClasses = [
357
+ "animal",
358
+ "dog_cat",
359
+ "dog",
360
+ "cat",
361
+ "horse",
362
+ "sheep",
363
+ "cow",
364
+ "elephant",
365
+ "bear",
366
+ "zebra",
367
+ "giraffe",
368
+ "mouse",
369
+ "rabbit",
370
+ "deer",
371
+ "lion",
372
+ "tiger",
373
+ "bird",
374
+ "eagle",
375
+ "owl",
376
+ "pigeon",
377
+ "fish",
378
+ "whale",
379
+ "dolphin",
380
+ "snake",
381
+ "turtle",
382
+ "lizard"
383
+ ];
384
+ var personClasses = [
385
+ "person",
386
+ "people",
387
+ "pedestrian",
388
+ "rider",
389
+ "driver",
390
+ "cyclist",
391
+ "skier",
392
+ "skateboarder",
393
+ "face",
394
+ "hand",
395
+ "head",
396
+ "body"
397
+ ];
398
+ var vehicleClasses = [
399
+ "vehicle",
400
+ "car",
401
+ "truck",
402
+ "bus",
403
+ "motorcycle",
404
+ "bicycle",
405
+ "van",
406
+ "ambulance",
407
+ "police_car",
408
+ "fire_truck",
409
+ "train",
410
+ "subway",
411
+ "tram",
412
+ "airplane",
413
+ "boat",
414
+ "ship",
415
+ "helicopter"
416
+ ];
417
+ var faceClasses = [
418
+ "face",
419
+ "eyes",
420
+ "nose",
421
+ "mouth",
422
+ "ears",
423
+ "eyebrows",
424
+ "left_eye",
425
+ "right_eye",
426
+ "pupil",
427
+ "iris",
428
+ "eyelid",
429
+ "eye_corner",
430
+ "upper_lip",
431
+ "lower_lip",
432
+ "teeth",
433
+ "chin",
434
+ "cheek",
435
+ "forehead",
436
+ "jaw",
437
+ "glasses",
438
+ "sunglasses",
439
+ "facial_hair",
440
+ "beard",
441
+ "mustache",
442
+ "facial_landmark",
443
+ "facial_keypoint"
444
+ ];
445
+ var licensePlateClasses = [
446
+ "plate",
447
+ "license_plate",
448
+ "front_plate",
449
+ "rear_plate",
450
+ "motorcycle_plate",
451
+ "temporary_plate",
452
+ "dealer_plate",
453
+ "licensePlate",
454
+ "plate_number",
455
+ "plate_character",
456
+ "plate_digit",
457
+ "plate_letter",
458
+ "plate_symbol",
459
+ "plate_region",
460
+ "plate_country_identifier",
461
+ "plate_frame",
462
+ "plate_bolt",
463
+ "plate_sticker",
464
+ "plate_validation_tag",
465
+ "damaged_plate",
466
+ "obscured_plate",
467
+ "dirty_plate"
468
+ ];
469
+ var motionClasses = [
470
+ "motion",
471
+ "movement",
472
+ "other"
473
+ ];
474
+ var packageClasses = [
475
+ "package",
476
+ "packet"
477
+ ];
478
+ var audioClasses = [
479
+ "audio"
480
+ ];
481
+ var audioLabelClasses = [
482
+ "speech",
483
+ "scream",
484
+ "babbling",
485
+ "yell",
486
+ "bellow",
487
+ "whoop",
488
+ "whispering",
489
+ "laughter",
490
+ "snicker",
491
+ "crying",
492
+ "cry",
493
+ "sigh",
494
+ "singing",
495
+ "choir",
496
+ "chant",
497
+ "mantra",
498
+ "child_singing",
499
+ "rapping",
500
+ "humming",
501
+ "groan",
502
+ "grunt",
503
+ "whistling",
504
+ "breathing",
505
+ "wheeze",
506
+ "snoring",
507
+ "gasp",
508
+ "pant",
509
+ "snort",
510
+ "cough",
511
+ "throat_clearing",
512
+ "sneeze",
513
+ "sniff",
514
+ "cheering",
515
+ "applause",
516
+ "chatter",
517
+ "crowd",
518
+ "children_playing",
519
+ "bark",
520
+ "yip",
521
+ "howl",
522
+ "bow-wow",
523
+ "growling",
524
+ "whimper_dog",
525
+ "purr",
526
+ "meow",
527
+ "hiss",
528
+ "caterwaul",
529
+ "pets",
530
+ "livestock",
531
+ "doorbell",
532
+ "ding-dong",
533
+ "door",
534
+ "slam",
535
+ "knock",
536
+ "alarm",
537
+ "telephone",
538
+ "music",
539
+ "dog",
540
+ "dogs"
541
+ ];
542
+ var doorbellClasses = [
543
+ "doorbell",
544
+ "ring"
545
+ ];
546
+ var sensorLabelClasses = [
547
+ "lock",
548
+ "binary",
549
+ "flood",
550
+ "entry",
551
+ "door",
552
+ "leak",
553
+ "door_open",
554
+ "flooded",
555
+ "entry_open"
556
+ ];
557
+ var detectionClassesDefaultMap = {
558
+ ...animalClasses.reduce((tot, curr) => ({
559
+ ...tot,
560
+ [curr]: "animal"
561
+ }), {}),
562
+ ...personClasses.reduce((tot, curr) => ({
563
+ ...tot,
564
+ [curr]: "person"
565
+ }), {}),
566
+ ...vehicleClasses.reduce((tot, curr) => ({
567
+ ...tot,
568
+ [curr]: "vehicle"
569
+ }), {}),
570
+ ...motionClasses.reduce((tot, curr) => ({
571
+ ...tot,
572
+ [curr]: "motion"
573
+ }), {}),
574
+ ...packageClasses.reduce((tot, curr) => ({
575
+ ...tot,
576
+ [curr]: "package"
577
+ }), {}),
578
+ ...faceClasses.reduce((tot, curr) => ({
579
+ ...tot,
580
+ [curr]: "face"
581
+ }), {}),
582
+ ...licensePlateClasses.reduce((tot, curr) => ({
583
+ ...tot,
584
+ [curr]: "plate"
585
+ }), {}),
586
+ ...audioClasses.reduce((tot, curr) => ({
587
+ ...tot,
588
+ [curr]: "audio"
589
+ }), {}),
590
+ ...audioLabelClasses.reduce((tot, curr) => ({
591
+ ...tot,
592
+ [curr]: "audio"
593
+ }), {}),
594
+ ...doorbellClasses.reduce((tot, curr) => ({
595
+ ...tot,
596
+ [curr]: "doorbell"
597
+ }), {}),
598
+ ...sensorLabelClasses.reduce((tot, curr) => ({
599
+ ...tot,
600
+ [curr]: "sensor"
601
+ }), {})
602
+ };
603
+ var isFaceClassname = /* @__PURE__ */ __name((c) => faceClasses.includes(c), "isFaceClassname");
604
+ var isPlateClassname = /* @__PURE__ */ __name((c) => licensePlateClasses.includes(c), "isPlateClassname");
605
+ var isAnimalClassname = /* @__PURE__ */ __name((c) => animalClasses.includes(c), "isAnimalClassname");
606
+ var isPersonClassname = /* @__PURE__ */ __name((c) => personClasses.includes(c), "isPersonClassname");
607
+ var isVehicleClassname = /* @__PURE__ */ __name((c) => vehicleClasses.includes(c), "isVehicleClassname");
608
+ var isMotionClassname = /* @__PURE__ */ __name((c) => motionClasses.includes(c), "isMotionClassname");
609
+ var isDoorbellClassname = /* @__PURE__ */ __name((c) => doorbellClasses.includes(c), "isDoorbellClassname");
610
+ var isPackageClassname = /* @__PURE__ */ __name((c) => packageClasses.includes(c), "isPackageClassname");
611
+ var isAudioClassname = /* @__PURE__ */ __name((c) => audioClasses.includes(c) || audioLabelClasses.includes(c), "isAudioClassname");
612
+ var isSensorLabelClassname = /* @__PURE__ */ __name((c) => sensorLabelClasses.includes(c), "isSensorLabelClassname");
613
+ var isLabelDetection = /* @__PURE__ */ __name((c) => isFaceClassname(c) || isPlateClassname(c), "isLabelDetection");
614
+ var getParentClass = /* @__PURE__ */ __name((className) => detectionClassesDefaultMap[className], "getParentClass");
615
+ var getParentDetectionClass = /* @__PURE__ */ __name((det) => {
616
+ const { className } = det;
617
+ const baseMap = {
618
+ ["face"]: "person",
619
+ ["plate"]: "vehicle"
620
+ };
621
+ const parentGroup = detectionClassesDefaultMap[className];
622
+ if (parentGroup && parentGroup !== className) return parentGroup;
623
+ return baseMap[className];
624
+ }, "getParentDetectionClass");
625
+ var defaultDetectionClasses = Object.values(DetectionClass);
626
+ var DEFAULT_ENABLED_CLASSES = defaultDetectionClasses.filter((c) => c !== "motion");
627
+ var TIMELINE_PRESET_CRITICAL = [
628
+ "person",
629
+ "doorbell",
630
+ "package"
631
+ ];
632
+ var TIMELINE_PRESET_IMPORTANT = [
633
+ ...TIMELINE_PRESET_CRITICAL,
634
+ "vehicle",
635
+ "animal",
636
+ "audio",
637
+ "face",
638
+ "plate"
639
+ ];
640
+ var TIMELINE_PRESET_ALL = [
641
+ ...DEFAULT_ENABLED_CLASSES
642
+ ];
643
+ function getClassesForTimelinePreset(preset, customClasses) {
644
+ switch (preset) {
645
+ case "critical":
646
+ return TIMELINE_PRESET_CRITICAL;
647
+ case "important":
648
+ return TIMELINE_PRESET_IMPORTANT;
649
+ case "all":
650
+ return TIMELINE_PRESET_ALL;
651
+ case "custom":
652
+ return customClasses?.length ? customClasses : DEFAULT_ENABLED_CLASSES;
653
+ default:
654
+ return DEFAULT_ENABLED_CLASSES;
655
+ }
656
+ }
657
+ __name(getClassesForTimelinePreset, "getClassesForTimelinePreset");
658
+
659
+ // src/devices.ts
660
+ var RAW_TO_CANONICAL = {
661
+ // Scrypted PascalCase
662
+ Light: "light",
663
+ Switch: "switch",
664
+ WindowCovering: "cover",
665
+ Lock: "lock",
666
+ SecuritySystem: "alarm",
667
+ Buttons: "button",
668
+ Select: "select",
669
+ Siren: "siren",
670
+ Sensor: "sensor",
671
+ Entry: "entry",
672
+ Program: "script",
673
+ MediaPlayer: "media_player",
674
+ Outlet: "switch",
675
+ // Home Assistant lowercase domains
676
+ light: "light",
677
+ switch: "switch",
678
+ input_boolean: "switch",
679
+ cover: "cover",
680
+ lock: "lock",
681
+ alarm_control_panel: "alarm",
682
+ input_button: "button",
683
+ button: "button",
684
+ input_select: "select",
685
+ select: "select",
686
+ siren: "siren",
687
+ sensor: "sensor",
688
+ media_player: "media_player",
689
+ script: "script"
690
+ };
691
+ var HA_DOMAIN_TYPE_MAP = {
692
+ light: "light",
693
+ switch: "switch",
694
+ input_boolean: "switch",
695
+ cover: "cover",
696
+ lock: "lock",
697
+ alarm_control_panel: "alarm",
698
+ input_button: "button",
699
+ button: "button",
700
+ input_select: "select",
701
+ select: "select",
702
+ siren: "siren",
703
+ sensor: "sensor",
704
+ binary_sensor: "sensor",
705
+ media_player: "media_player",
706
+ script: "script",
707
+ climate: "climate",
708
+ camera: "camera",
709
+ fan: "fan",
710
+ vacuum: "vacuum",
711
+ automation: "automation",
712
+ scene: "scene",
713
+ input_number: "sensor",
714
+ person: "person",
715
+ device_tracker: "tracker",
716
+ weather: "weather",
717
+ water_heater: "climate"
718
+ };
719
+ var SCRYPTED_TYPE_TO_CANONICAL = {
720
+ Light: "light",
721
+ Switch: "switch",
722
+ WindowCovering: "cover",
723
+ Lock: "lock",
724
+ SecuritySystem: "alarm",
725
+ Buttons: "button",
726
+ Select: "select",
727
+ Siren: "siren",
728
+ Sensor: "sensor",
729
+ Entry: "entry",
730
+ Program: "script",
731
+ MediaPlayer: "media_player",
732
+ Camera: "camera",
733
+ Doorbell: "doorbell",
734
+ Fan: "fan",
735
+ Outlet: "switch"
736
+ };
737
+ function getCanonicalDeviceType(rawType) {
738
+ const canonical = RAW_TO_CANONICAL[rawType];
739
+ if (canonical) return canonical;
740
+ const lower = rawType.toLowerCase();
741
+ return RAW_TO_CANONICAL[lower] ?? null;
742
+ }
743
+ __name(getCanonicalDeviceType, "getCanonicalDeviceType");
744
+ var ELIGIBLE_SCRYPTED_DEVICE_TYPES = [
745
+ "Entry",
746
+ "Light",
747
+ "Switch",
748
+ "Lock",
749
+ "SecuritySystem",
750
+ "Buttons",
751
+ "WindowCovering",
752
+ "Siren",
753
+ "Sensor",
754
+ "Select",
755
+ "Program"
756
+ ];
757
+ var ELIGIBLE_SCRYPTED_DEVICE_TYPES_SET = new Set(ELIGIBLE_SCRYPTED_DEVICE_TYPES);
758
+ var ELIGIBLE_HA_DOMAINS = [
759
+ "light",
760
+ "switch",
761
+ "input_boolean",
762
+ "cover",
763
+ "lock",
764
+ "alarm_control_panel",
765
+ "input_button",
766
+ "button",
767
+ "input_select",
768
+ "select",
769
+ "siren",
770
+ "media_player",
771
+ "script"
772
+ ];
773
+ var ELIGIBLE_HA_DOMAINS_SET = new Set(ELIGIBLE_HA_DOMAINS);
774
+
775
+ // src/features.ts
776
+ var FEATURE_MATRIX = [
777
+ {
778
+ id: "liveStream",
779
+ label: "Live Stream",
780
+ sources: {
781
+ frigate: true,
782
+ scrypted: true,
783
+ rtsp: true
784
+ },
785
+ adapterMethod: "getLiveStream"
786
+ },
787
+ {
788
+ id: "multiResolution",
789
+ label: "Multi-Resolution",
790
+ sources: {
791
+ frigate: true,
792
+ scrypted: true,
793
+ rtsp: false
794
+ },
795
+ adapterMethod: "getResolutions"
796
+ },
797
+ {
798
+ id: "motion",
799
+ label: "Motion Detection",
800
+ sources: {
801
+ frigate: false,
802
+ scrypted: true,
803
+ rtsp: false
804
+ },
805
+ adapterMethod: "getMotion"
806
+ },
807
+ {
808
+ id: "objectDetection",
809
+ label: "Object Detection",
810
+ sources: {
811
+ frigate: false,
812
+ scrypted: true,
813
+ rtsp: false
814
+ },
815
+ adapterMethod: "getObjectDetections"
816
+ },
817
+ {
818
+ id: "audioVolume",
819
+ label: "Audio Level",
820
+ sources: {
821
+ frigate: false,
822
+ scrypted: true,
823
+ rtsp: false
824
+ },
825
+ adapterMethod: "getAudioVolume"
826
+ },
827
+ {
828
+ id: "audioVolumes",
829
+ label: "Audio Volumes (dBFS)",
830
+ sources: {
831
+ frigate: false,
832
+ scrypted: true,
833
+ rtsp: false
834
+ },
835
+ adapterMethod: "getAudioVolumes"
836
+ },
837
+ {
838
+ id: "ptz",
839
+ label: "PTZ Control",
840
+ sources: {
841
+ frigate: false,
842
+ scrypted: true,
843
+ rtsp: false
844
+ },
845
+ adapterMethod: "getPTZ"
846
+ },
847
+ {
848
+ id: "intercom",
849
+ label: "Intercom (Mic)",
850
+ sources: {
851
+ frigate: false,
852
+ scrypted: true,
853
+ rtsp: false
854
+ },
855
+ adapterMethod: "getIntercomSupport"
856
+ },
857
+ {
858
+ id: "deviceStatus",
859
+ label: "Device Status",
860
+ sources: {
861
+ frigate: false,
862
+ scrypted: true,
863
+ rtsp: false
864
+ },
865
+ adapterMethod: "getStatus"
866
+ },
867
+ {
868
+ id: "timeline",
869
+ label: "Detection Timeline",
870
+ sources: {
871
+ frigate: true,
872
+ scrypted: true,
873
+ rtsp: false
874
+ },
875
+ adapterMethod: "getCameraDayData"
876
+ },
877
+ {
878
+ id: "clusteredTimeline",
879
+ label: "Clustered Timeline",
880
+ sources: {
881
+ frigate: true,
882
+ scrypted: true,
883
+ rtsp: false
884
+ },
885
+ requiresBackend: true,
886
+ adapterMethod: "getClusteredDayData"
887
+ },
888
+ {
889
+ id: "detectionClasses",
890
+ label: "Detection Classes",
891
+ sources: {
892
+ frigate: true,
893
+ scrypted: true,
894
+ rtsp: false
895
+ },
896
+ adapterMethod: "getDetectionClasses"
897
+ },
898
+ {
899
+ id: "videoClips",
900
+ label: "Video Clips",
901
+ sources: {
902
+ frigate: true,
903
+ scrypted: true,
904
+ rtsp: false
905
+ },
906
+ adapterMethod: "getVideoClips"
907
+ },
908
+ {
909
+ id: "nvrPlayback",
910
+ label: "NVR Playback",
911
+ sources: {
912
+ frigate: true,
913
+ scrypted: true,
914
+ rtsp: false
915
+ },
916
+ adapterMethod: "getNvrPlaybackSupported"
917
+ },
918
+ {
919
+ id: "nvrScrub",
920
+ label: "NVR Scrub/Seek",
921
+ sources: {
922
+ frigate: false,
923
+ scrypted: true,
924
+ rtsp: false
925
+ },
926
+ adapterMethod: "seekRecordingStream"
927
+ },
928
+ {
929
+ id: "recordingThumbnail",
930
+ label: "Recording Thumbnails",
931
+ sources: {
932
+ frigate: true,
933
+ scrypted: true,
934
+ rtsp: false
935
+ },
936
+ adapterMethod: "getRecordingStreamThumbnail"
937
+ },
938
+ {
939
+ id: "nvrSeekToLive",
940
+ label: "Seek to Live",
941
+ sources: {
942
+ frigate: false,
943
+ scrypted: true,
944
+ rtsp: false
945
+ },
946
+ adapterMethod: "seekNvrToLive"
947
+ }
948
+ ];
949
+ function isFeatureAvailable(featureId, source, platform) {
950
+ const entry = FEATURE_MATRIX.find((f) => f.id === featureId);
951
+ if (!entry) return false;
952
+ if (!entry.sources[source]) return false;
953
+ if (entry.platforms && entry.platforms[platform] === false) return false;
954
+ return true;
955
+ }
956
+ __name(isFeatureAvailable, "isFeatureAvailable");
957
+ function getSourceFeatures(source) {
958
+ return FEATURE_MATRIX.filter((f) => f.sources[source]);
959
+ }
960
+ __name(getSourceFeatures, "getSourceFeatures");
961
+ function getBackendRequiredFeatures() {
962
+ return FEATURE_MATRIX.filter((f) => f.requiresBackend);
963
+ }
964
+ __name(getBackendRequiredFeatures, "getBackendRequiredFeatures");
965
+
966
+ // src/adaptive-stream.ts
967
+ function selectOptimalStream(streams, constraints, defaultTransport) {
968
+ if (streams.length === 0) return null;
969
+ const viewportPixels = constraints.viewportWidth * constraints.viewportHeight * (constraints.pixelRatio ?? 1);
970
+ const bw = constraints.bandwidthMbps ?? 100;
971
+ const loss = constraints.packetLoss ?? 0;
972
+ const rtt = constraints.rttMs ?? 50;
973
+ let targetTier = "high";
974
+ if (constraints.maxResolution === "low" || constraints.isCellular || bw < 1 || loss > 0.05) {
975
+ targetTier = "low";
976
+ } else if (constraints.maxResolution === "medium" || bw < 5 || viewportPixels < 5e5 || rtt > 200) {
977
+ targetTier = "medium";
978
+ } else if (constraints.maxResolution === "high" || viewportPixels > 2e6) {
979
+ targetTier = "high";
980
+ }
981
+ const PROFILE_TIER = {
982
+ main: "high",
983
+ sub: "medium",
984
+ ext: "low"
985
+ };
986
+ const preferTransport = defaultTransport ?? "native";
987
+ const scored = streams.map((s) => {
988
+ let score = 0;
989
+ const streamTier = PROFILE_TIER[s.profile] ?? "medium";
990
+ if (streamTier === targetTier) score += 100;
991
+ else if (targetTier === "high" && streamTier === "medium" || targetTier === "medium" && streamTier === "high" || targetTier === "medium" && streamTier === "low" || targetTier === "low" && streamTier === "medium") score += 50;
992
+ if (s.transport === preferTransport) score += 30;
993
+ else if (s.transport === "native") score += 20;
994
+ else if (s.transport === "rtsp") score += 15;
995
+ else if (s.transport === "rtmp") score += 10;
996
+ if (s.metadata?.width && s.metadata?.height) {
997
+ const streamPixels = s.metadata.width * s.metadata.height;
998
+ const ratio = streamPixels / Math.max(viewportPixels, 1);
999
+ if (ratio >= 0.8 && ratio <= 2) score += 25;
1000
+ else if (ratio >= 0.5 && ratio <= 3) score += 15;
1001
+ if (ratio > 4 && bw < 10) score -= 20;
1002
+ }
1003
+ if (s.metadata?.codec) {
1004
+ if (bw < 5 && s.metadata.codec.includes("265")) score += 10;
1005
+ if (bw >= 10 && s.metadata.codec.includes("264")) score += 5;
1006
+ }
1007
+ return {
1008
+ ...s,
1009
+ score,
1010
+ targetTier
1011
+ };
1012
+ });
1013
+ scored.sort((a, b) => b.score - a.score);
1014
+ const best = scored[0];
1015
+ const tierNames = {
1016
+ high: "main",
1017
+ medium: "sub",
1018
+ low: "ext"
1019
+ };
1020
+ return {
1021
+ streamName: best.streamName,
1022
+ profile: best.profile,
1023
+ transport: best.transport,
1024
+ label: best.label,
1025
+ metadata: best.metadata,
1026
+ reason: `${best.targetTier} quality \u2192 ${best.profile}/${best.transport} (score: ${best.score})`
1027
+ };
1028
+ }
1029
+ __name(selectOptimalStream, "selectOptimalStream");
1030
+ function getNextEvalInterval(constraints, wasSwitch) {
1031
+ if (wasSwitch) return 10;
1032
+ if (constraints.isCellular) return 15;
1033
+ if ((constraints.packetLoss ?? 0) > 0.02) return 15;
1034
+ return 30;
1035
+ }
1036
+ __name(getNextEvalInterval, "getNextEvalInterval");
1037
+ export {
1038
+ BackendClient,
1039
+ DEFAULT_ENABLED_CLASSES,
1040
+ DetectionClass,
1041
+ ELIGIBLE_HA_DOMAINS,
1042
+ ELIGIBLE_HA_DOMAINS_SET,
1043
+ ELIGIBLE_SCRYPTED_DEVICE_TYPES,
1044
+ ELIGIBLE_SCRYPTED_DEVICE_TYPES_SET,
1045
+ FEATURE_MATRIX,
1046
+ HA_DOMAIN_TYPE_MAP,
1047
+ RAW_TO_CANONICAL,
1048
+ SCRYPTED_TYPE_TO_CANONICAL,
1049
+ TIMELINE_PRESET_ALL,
1050
+ TIMELINE_PRESET_CRITICAL,
1051
+ TIMELINE_PRESET_IMPORTANT,
1052
+ animalClasses,
1053
+ audioClasses,
1054
+ audioLabelClasses,
1055
+ createBackendClient,
1056
+ defaultDetectionClasses,
1057
+ detectionClassesDefaultMap,
1058
+ doorbellClasses,
1059
+ faceClasses,
1060
+ getBackendRequiredFeatures,
1061
+ getCanonicalDeviceType,
1062
+ getClassesForTimelinePreset,
1063
+ getNextEvalInterval,
1064
+ getParentClass,
1065
+ getParentDetectionClass,
1066
+ getSourceFeatures,
1067
+ isAnimalClassname,
1068
+ isAudioClassname,
1069
+ isDoorbellClassname,
1070
+ isFaceClassname,
1071
+ isFeatureAvailable,
1072
+ isLabelDetection,
1073
+ isMotionClassname,
1074
+ isPackageClassname,
1075
+ isPersonClassname,
1076
+ isPlateClassname,
1077
+ isSensorLabelClassname,
1078
+ isVehicleClassname,
1079
+ licensePlateClasses,
1080
+ motionClasses,
1081
+ packageClasses,
1082
+ personClasses,
1083
+ selectOptimalStream,
1084
+ sensorLabelClasses,
1085
+ vehicleClasses
1086
+ };
1087
+ //# sourceMappingURL=index.js.map