@camstack/types 1.2.100 → 1.2.102

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.
@@ -2709,6 +2709,83 @@ function createLazyTrpcSource(api) {
2709
2709
  };
2710
2710
  }
2711
2711
  /**
2712
+ * Addon-process slice source — the one that actually reaches a forked child.
2713
+ *
2714
+ * Identical cache/refresh/write to {@link createLazyTrpcSource}. The push
2715
+ * channel is `eventBus.subscribe({ category: 'device.state-changed' })`
2716
+ * instead of `api.live.onEvent`. On a UDS child that subscribe is what
2717
+ * populates `RegisterMessage.eventPatterns`, which is what the parent's
2718
+ * `broadcastEventToChildren` filters on. Without it the child never
2719
+ * declares interest and the 30 s `refresh()` timer was the only path a
2720
+ * zone edit took to analytics (live, device 617, 2026-07-16).
2721
+ */
2722
+ function createEventBusSliceSource(deps) {
2723
+ const { eventBus, api } = deps;
2724
+ const cache = /* @__PURE__ */ new Map();
2725
+ const listeners = /* @__PURE__ */ new Map();
2726
+ let offBus = null;
2727
+ const keyOf = (deviceId, capName) => `${deviceId}:${capName}`;
2728
+ const fanOut = (deviceId, capName, slice) => {
2729
+ const k = keyOf(deviceId, capName);
2730
+ cache.set(k, slice);
2731
+ const set = listeners.get(k);
2732
+ if (!set) return;
2733
+ for (const cb of set) try {
2734
+ cb(slice);
2735
+ } catch {}
2736
+ };
2737
+ const ensureBridge = () => {
2738
+ if (offBus) return;
2739
+ offBus = eventBus.subscribe({ category: DEVICE_STATE_EVENT_CATEGORY }, (event) => {
2740
+ const data = event.data;
2741
+ if (typeof data !== "object" || data === null) return;
2742
+ const deviceId = Reflect.get(data, "deviceId");
2743
+ const capName = Reflect.get(data, "capName");
2744
+ if (typeof deviceId !== "number" || typeof capName !== "string") return;
2745
+ fanOut(deviceId, capName, Reflect.get(data, "slice"));
2746
+ });
2747
+ };
2748
+ const closeBridgeIfIdle = () => {
2749
+ if (offBus === null) return;
2750
+ if (listeners.size > 0) return;
2751
+ offBus();
2752
+ offBus = null;
2753
+ };
2754
+ return {
2755
+ read(deviceId, capName) {
2756
+ return cache.get(keyOf(deviceId, capName));
2757
+ },
2758
+ async refresh(deviceId, capName) {
2759
+ fanOut(deviceId, capName, await api.deviceState.getCapSlice.query({
2760
+ deviceId,
2761
+ capName
2762
+ }) ?? void 0);
2763
+ },
2764
+ watch(deviceId, capName, cb) {
2765
+ const k = keyOf(deviceId, capName);
2766
+ let set = listeners.get(k);
2767
+ if (!set) {
2768
+ set = /* @__PURE__ */ new Set();
2769
+ listeners.set(k, set);
2770
+ }
2771
+ set.add(cb);
2772
+ ensureBridge();
2773
+ return () => {
2774
+ set.delete(cb);
2775
+ if (set.size === 0) listeners.delete(k);
2776
+ closeBridgeIfIdle();
2777
+ };
2778
+ },
2779
+ async write(deviceId, capName, slice) {
2780
+ await api.deviceState.setCapSlice.mutate({
2781
+ deviceId,
2782
+ capName,
2783
+ slice
2784
+ });
2785
+ }
2786
+ };
2787
+ }
2788
+ /**
2712
2789
  * Mirror source — reads from a shared map populated by a
2713
2790
  * `SystemManager` warm-boot + push event handler. Refresh is a no-op
2714
2791
  * (the SystemManager owns the update loop). `watch()` registers in a
@@ -3188,6 +3265,8 @@ function createDeviceProxy(api, binding, opts) {
3188
3265
  getTrack: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getTrack", "query", input),
3189
3266
  listTracks: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listTracks", "query", input),
3190
3267
  listRecentTracks: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listRecentTracks", "query", input),
3268
+ listGroups: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listGroups", "query", input),
3269
+ getGroup: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getGroup", "query", input),
3191
3270
  clearTracks: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "clearTracks", "mutation", input),
3192
3271
  getMotionEvents: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getMotionEvents", "query", input),
3193
3272
  getObjectEvents: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getObjectEvents", "query", input),
@@ -4075,6 +4154,12 @@ Object.defineProperty(exports, "createEvent", {
4075
4154
  return createEvent;
4076
4155
  }
4077
4156
  });
4157
+ Object.defineProperty(exports, "createEventBusSliceSource", {
4158
+ enumerable: true,
4159
+ get: function() {
4160
+ return createEventBusSliceSource;
4161
+ }
4162
+ });
4078
4163
  Object.defineProperty(exports, "createLazyTrpcSource", {
4079
4164
  enumerable: true,
4080
4165
  get: function() {
@@ -2709,6 +2709,83 @@ function createLazyTrpcSource(api) {
2709
2709
  };
2710
2710
  }
2711
2711
  /**
2712
+ * Addon-process slice source — the one that actually reaches a forked child.
2713
+ *
2714
+ * Identical cache/refresh/write to {@link createLazyTrpcSource}. The push
2715
+ * channel is `eventBus.subscribe({ category: 'device.state-changed' })`
2716
+ * instead of `api.live.onEvent`. On a UDS child that subscribe is what
2717
+ * populates `RegisterMessage.eventPatterns`, which is what the parent's
2718
+ * `broadcastEventToChildren` filters on. Without it the child never
2719
+ * declares interest and the 30 s `refresh()` timer was the only path a
2720
+ * zone edit took to analytics (live, device 617, 2026-07-16).
2721
+ */
2722
+ function createEventBusSliceSource(deps) {
2723
+ const { eventBus, api } = deps;
2724
+ const cache = /* @__PURE__ */ new Map();
2725
+ const listeners = /* @__PURE__ */ new Map();
2726
+ let offBus = null;
2727
+ const keyOf = (deviceId, capName) => `${deviceId}:${capName}`;
2728
+ const fanOut = (deviceId, capName, slice) => {
2729
+ const k = keyOf(deviceId, capName);
2730
+ cache.set(k, slice);
2731
+ const set = listeners.get(k);
2732
+ if (!set) return;
2733
+ for (const cb of set) try {
2734
+ cb(slice);
2735
+ } catch {}
2736
+ };
2737
+ const ensureBridge = () => {
2738
+ if (offBus) return;
2739
+ offBus = eventBus.subscribe({ category: DEVICE_STATE_EVENT_CATEGORY }, (event) => {
2740
+ const data = event.data;
2741
+ if (typeof data !== "object" || data === null) return;
2742
+ const deviceId = Reflect.get(data, "deviceId");
2743
+ const capName = Reflect.get(data, "capName");
2744
+ if (typeof deviceId !== "number" || typeof capName !== "string") return;
2745
+ fanOut(deviceId, capName, Reflect.get(data, "slice"));
2746
+ });
2747
+ };
2748
+ const closeBridgeIfIdle = () => {
2749
+ if (offBus === null) return;
2750
+ if (listeners.size > 0) return;
2751
+ offBus();
2752
+ offBus = null;
2753
+ };
2754
+ return {
2755
+ read(deviceId, capName) {
2756
+ return cache.get(keyOf(deviceId, capName));
2757
+ },
2758
+ async refresh(deviceId, capName) {
2759
+ fanOut(deviceId, capName, await api.deviceState.getCapSlice.query({
2760
+ deviceId,
2761
+ capName
2762
+ }) ?? void 0);
2763
+ },
2764
+ watch(deviceId, capName, cb) {
2765
+ const k = keyOf(deviceId, capName);
2766
+ let set = listeners.get(k);
2767
+ if (!set) {
2768
+ set = /* @__PURE__ */ new Set();
2769
+ listeners.set(k, set);
2770
+ }
2771
+ set.add(cb);
2772
+ ensureBridge();
2773
+ return () => {
2774
+ set.delete(cb);
2775
+ if (set.size === 0) listeners.delete(k);
2776
+ closeBridgeIfIdle();
2777
+ };
2778
+ },
2779
+ async write(deviceId, capName, slice) {
2780
+ await api.deviceState.setCapSlice.mutate({
2781
+ deviceId,
2782
+ capName,
2783
+ slice
2784
+ });
2785
+ }
2786
+ };
2787
+ }
2788
+ /**
2712
2789
  * Mirror source — reads from a shared map populated by a
2713
2790
  * `SystemManager` warm-boot + push event handler. Refresh is a no-op
2714
2791
  * (the SystemManager owns the update loop). `watch()` registers in a
@@ -3188,6 +3265,8 @@ function createDeviceProxy(api, binding, opts) {
3188
3265
  getTrack: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getTrack", "query", input),
3189
3266
  listTracks: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listTracks", "query", input),
3190
3267
  listRecentTracks: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listRecentTracks", "query", input),
3268
+ listGroups: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listGroups", "query", input),
3269
+ getGroup: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getGroup", "query", input),
3191
3270
  clearTracks: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "clearTracks", "mutation", input),
3192
3271
  getMotionEvents: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getMotionEvents", "query", input),
3193
3272
  getObjectEvents: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getObjectEvents", "query", input),
@@ -3775,4 +3854,4 @@ function sleepCancellable(ms, signal) {
3775
3854
  });
3776
3855
  }
3777
3856
  //#endregion
3778
- export { EncodedPacketSchema as $, expandCapMethods as A, ReadinessTimeoutError as B, DeviceRole as C, WELL_KNOWN_TABS as Ct, DEVICE_SETTINGS_CONTRIBUTION_METHODS as D, hydrateSchema as Dt, DEFAULT_RUNTIME_STATE_DURABILITY as E, collectHydratedFieldValues as Et, CAP_NODE_PIN_CONTEXT_KEY as F, BrokerStatusSchema as G, readinessKey as H, nodePin as I, CamStreamKindSchema as J, CAM_PROFILE_ORDER as K, readNodePin as L, method as M, resolveCapMount as N, DEVICE_STATUS_METHOD as O, resolveHydratedFieldValue as Ot, systemMethod as P, DecodedFrameSchema as Q, toNodeId as R, DeviceFeature as S, isEvent as St, adminUiCapability as T, collectHydratedFieldEntries as Tt, scopeKey as U, emitDownForOwnedCaps as V, BrokerStatsSchema as W, CameraStreamSchema as X, CamStreamResolutionSchema as Y, DecodedAudioChunkSchema as Z, createSliceHandle as _, BaseAddon as _t, asJsonObject as a, StreamSourceEntrySchema$1 as at, viewerUiCapability as b, createEvent as bt, parseJsonArray as c, SubscribeAudioChunksResultSchema as ct, BOOT_RECOVERY_BACKOFF_MS as d, makeProfileBrokerId as dt, FrameHandleFormatSchema as et, DEVICE_SCOPED_CAPS as f, makeSourceBrokerId as ft, createMirrorSource as g, DisposerChain as gt, createLazyTrpcSource as h, DATAPLANE_SECRET_HEADER as ht, asJsonArray as i, ProfileSlotStatusSchema as it, isDeviceConfigCap as j, event as k, parseJsonObject as l, SubscribeFramesInputSchema as lt, createDeviceProxy as m, selectAssignedProfileSlots as mt, sleepCancellable as n, ProfileRtspEntrySchema as nt, asNumber as o, StreamSourceSchema as ot, isDeviceScopedCap as p, parseProfileBrokerId as pt, CamProfileSchema as q, asBoolean as r, ProfileSlotSchema as rt, asString as s, SubscribeAudioChunksInputSchema as st, sleep as t, FrameHandleSchema as tt, parseJsonUnknown as u, SubscribeFramesResultSchema as ut, RawStateResultSchema as v, normalizeAddonInitResult as vt, DeviceType as w, WELL_KNOWN_TAB_MAP as wt, ChargingStatus as x, emitReadiness as xt, deviceOpsCapability as y, createDurableState as yt, ReadinessRegistry as z };
3857
+ export { DecodedFrameSchema as $, event as A, ReadinessRegistry as B, DeviceFeature as C, isEvent as Ct, DEFAULT_RUNTIME_STATE_DURABILITY as D, collectHydratedFieldValues as Dt, adminUiCapability as E, collectHydratedFieldEntries as Et, systemMethod as F, BrokerStatsSchema as G, emitDownForOwnedCaps as H, CAP_NODE_PIN_CONTEXT_KEY as I, CamProfileSchema as J, BrokerStatusSchema as K, nodePin as L, isDeviceConfigCap as M, method as N, DEVICE_SETTINGS_CONTRIBUTION_METHODS as O, hydrateSchema as Ot, resolveCapMount as P, DecodedAudioChunkSchema as Q, readNodePin as R, ChargingStatus as S, emitReadiness as St, DeviceType as T, WELL_KNOWN_TAB_MAP as Tt, readinessKey as U, ReadinessTimeoutError as V, scopeKey as W, CamStreamResolutionSchema as X, CamStreamKindSchema as Y, CameraStreamSchema as Z, createMirrorSource as _, DisposerChain as _t, asJsonObject as a, ProfileSlotStatusSchema as at, deviceOpsCapability as b, createDurableState as bt, parseJsonArray as c, SubscribeAudioChunksInputSchema as ct, BOOT_RECOVERY_BACKOFF_MS as d, SubscribeFramesResultSchema as dt, EncodedPacketSchema as et, DEVICE_SCOPED_CAPS as f, makeProfileBrokerId as ft, createLazyTrpcSource as g, DATAPLANE_SECRET_HEADER as gt, createEventBusSliceSource as h, selectAssignedProfileSlots as ht, asJsonArray as i, ProfileSlotSchema as it, expandCapMethods as j, DEVICE_STATUS_METHOD as k, resolveHydratedFieldValue as kt, parseJsonObject as l, SubscribeAudioChunksResultSchema as lt, createDeviceProxy as m, parseProfileBrokerId as mt, sleepCancellable as n, FrameHandleSchema as nt, asNumber as o, StreamSourceEntrySchema$1 as ot, isDeviceScopedCap as p, makeSourceBrokerId as pt, CAM_PROFILE_ORDER as q, asBoolean as r, ProfileRtspEntrySchema as rt, asString as s, StreamSourceSchema as st, sleep as t, FrameHandleFormatSchema as tt, parseJsonUnknown as u, SubscribeFramesInputSchema as ut, createSliceHandle as v, BaseAddon as vt, DeviceRole as w, WELL_KNOWN_TABS as wt, viewerUiCapability as x, createEvent as xt, RawStateResultSchema as y, normalizeAddonInitResult as yt, toNodeId as z };
@@ -127,6 +127,32 @@ export declare const ModelVariantGroupSchema: z.ZodObject<{
127
127
  resolution: z.ZodOptional<z.ZodNumber>;
128
128
  }, z.core.$strip>;
129
129
  export type ModelVariantGroup = z.infer<typeof ModelVariantGroupSchema>;
130
+ /**
131
+ * Where a catalog entry came from. The pipeline stepper partitions the picker
132
+ * by this id (CamStack / Frigate / Scrypted / Custom). Absent on older durable
133
+ * registry rows — {@link inferModelProvider} fills it at read time. Built-in
134
+ * catalog entries omit it and `getSchema` treats them as `camstack`.
135
+ */
136
+ export declare const MODEL_PROVIDER_IDS: readonly ["camstack", "frigate", "scrypted", "custom"];
137
+ export declare const ModelProviderIdSchema: z.ZodEnum<{
138
+ custom: "custom";
139
+ camstack: "camstack";
140
+ frigate: "frigate";
141
+ scrypted: "scrypted";
142
+ }>;
143
+ export type ModelProviderId = (typeof MODEL_PROVIDER_IDS)[number];
144
+ export interface InferModelProviderInput {
145
+ readonly id: string;
146
+ readonly provider?: ModelProviderId;
147
+ readonly description?: string;
148
+ }
149
+ /**
150
+ * Resolve a catalog entry's picker provider. An explicit stamp always wins;
151
+ * otherwise Frigate/Scrypted are recognised from id prefix or description.
152
+ * Unstamped BYO registry rows fall through to `custom`. Family `yolov9` is
153
+ * NOT a Scrypted signal — CamStack ships that family too.
154
+ */
155
+ export declare function inferModelProvider(entry: InferModelProviderInput): ModelProviderId;
130
156
  export declare const ModelCatalogEntrySchema: z.ZodObject<{
131
157
  id: z.ZodString;
132
158
  name: z.ZodString;
@@ -245,6 +271,12 @@ export declare const ModelCatalogEntrySchema: z.ZodObject<{
245
271
  }>>;
246
272
  resolution: z.ZodOptional<z.ZodNumber>;
247
273
  }, z.core.$strip>>;
274
+ provider: z.ZodOptional<z.ZodEnum<{
275
+ custom: "custom";
276
+ camstack: "camstack";
277
+ frigate: "frigate";
278
+ scrypted: "scrypted";
279
+ }>>;
248
280
  classMap: z.ZodOptional<z.ZodObject<{
249
281
  mapping: z.ZodRecord<z.ZodString, z.ZodEnum<{
250
282
  person: "person";
@@ -484,6 +516,12 @@ export declare const ConvertResultSchema: z.ZodObject<{
484
516
  }>>;
485
517
  resolution: z.ZodOptional<z.ZodNumber>;
486
518
  }, z.core.$strip>>;
519
+ provider: z.ZodOptional<z.ZodEnum<{
520
+ custom: "custom";
521
+ camstack: "camstack";
522
+ frigate: "frigate";
523
+ scrypted: "scrypted";
524
+ }>>;
487
525
  classMap: z.ZodOptional<z.ZodObject<{
488
526
  mapping: z.ZodRecord<z.ZodString, z.ZodEnum<{
489
527
  person: "person";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/types",
3
- "version": "1.2.100",
3
+ "version": "1.2.102",
4
4
  "description": "Shared types, interfaces, and model catalogs for the CamStack detection ecosystem",
5
5
  "keywords": [
6
6
  "camstack",