@camstack/types 1.2.41 → 1.2.43

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 (43) hide show
  1. package/dist/addon.js +1 -1
  2. package/dist/addon.mjs +1 -1
  3. package/dist/canonical-hash-7nfBbEqR.mjs +35 -0
  4. package/dist/canonical-hash-BcZHRHIx.js +40 -0
  5. package/dist/cap-call-context.d.ts +26 -0
  6. package/dist/capabilities/index.d.ts +5 -5
  7. package/dist/capabilities/notification-rules.cap.d.ts +41 -0
  8. package/dist/capabilities/pipeline-analytics.cap.d.ts +92 -4
  9. package/dist/capabilities/pipeline-orchestrator.cap.d.ts +149 -0
  10. package/dist/capabilities/pipeline-runner.cap.d.ts +119 -1
  11. package/dist/capabilities/platform-probe.cap.d.ts +3 -3
  12. package/dist/capabilities/privacy-mask.cap.d.ts +69 -9
  13. package/dist/capabilities/recording.cap.d.ts +30 -0
  14. package/dist/capabilities/snapshot.cap.d.ts +1 -1
  15. package/dist/capabilities/stream-broker.cap.d.ts +304 -0
  16. package/dist/capabilities/stream-params.cap.d.ts +8 -4
  17. package/dist/device/device-profile.d.ts +12 -4
  18. package/dist/device/system-mirror.d.ts +11 -0
  19. package/dist/encode-profile.d.ts +2 -0
  20. package/dist/ffmpeg/encode-defaults.d.ts +107 -0
  21. package/dist/ffmpeg/hwaccel.d.ts +98 -0
  22. package/dist/ffmpeg/invocation.d.ts +348 -0
  23. package/dist/ffmpeg/process.d.ts +135 -0
  24. package/dist/ffmpeg/sharing-key.d.ts +91 -0
  25. package/dist/generated/addon-api.d.ts +92 -4
  26. package/dist/generated/device-proxy.d.ts +2 -2
  27. package/dist/generated/method-access-map.d.ts +1 -1
  28. package/dist/generated/system-proxy.d.ts +2 -2
  29. package/dist/index.d.ts +7 -0
  30. package/dist/index.js +2069 -42
  31. package/dist/index.mjs +2006 -43
  32. package/dist/interfaces/camera-switches.d.ts +375 -0
  33. package/dist/interfaces/inference-engine.d.ts +24 -3
  34. package/dist/interfaces/ops-log.d.ts +4 -0
  35. package/dist/interfaces/pipeline-runner-capability.d.ts +9 -1
  36. package/dist/node.d.ts +2 -0
  37. package/dist/node.js +270 -36
  38. package/dist/node.mjs +269 -36
  39. package/dist/pipeline/native-lease.d.ts +150 -0
  40. package/dist/{sleep-DTce7-ch.js → sleep-Bx9IIoT0.js} +43 -1
  41. package/dist/{sleep-CXimb854.mjs → sleep-DtstvzWm.mjs} +38 -2
  42. package/dist/utils/addon-id.d.ts +30 -0
  43. package/package.json +1 -1
@@ -0,0 +1,150 @@
1
+ /**
2
+ * THE native-frame **lease** knobs — TTL, RAM budget and demand window for the
3
+ * decode worker's native-resolution frame retention.
4
+ *
5
+ * ## Why they live here and not in the addon that reads them
6
+ *
7
+ * The WRITER is `pipeline-orchestrator` (the cluster-wide settings authority);
8
+ * the READER is a private child process of `addon-pipeline`'s pipeline-runner.
9
+ * Addons never import each other, so a key owned by either side would have to
10
+ * be hand-copied by the other — and a hand-copied key is how a setting silently
11
+ * stops arriving while both sides still look correct. Same reasoning, same
12
+ * placement as `detail-crop.ts` (D52's "one cluster-wide orchestrator setting").
13
+ *
14
+ * ## Why cluster-wide and not per-node
15
+ *
16
+ * The lease is a per-decode-worker RAM window. Its purpose — the late
17
+ * cross-process native crop landing on a full-resolution frame rather than the
18
+ * ≤640 detection fallback — is a property of the PIPELINE, not of a node's
19
+ * hardware: a per-node TTL would mean the same camera produces different crop
20
+ * quality depending on which node the balancer placed it on, and nobody could
21
+ * tell that from the stored media. Node-level RAM pressure is already handled
22
+ * by the per-session budget ceiling, which is itself one of these knobs.
23
+ *
24
+ * ## What each knob costs
25
+ *
26
+ * A retained frame is a full NATIVE-resolution copy in system RAM. With the
27
+ * default pinned-RGB24 lease path (`CAMSTACK_SESSION_PINNED_RGB_CROP`, on):
28
+ * 4K ≈ 24.9 MB/frame, 1080p ≈ 6.2 MB/frame. On the YUV420P path (flag off, and
29
+ * for software-decoded sessions): 4K ≈ 12.4 MB, 1080p ≈ 3.1 MB. Worst-case
30
+ * resident RAM for ONE busy camera ≈ frameBytes × deliveredFps × ttlSeconds,
31
+ * clamped by the budget ceiling. See `docs/design/decode-path.md` → "Lease
32
+ * admission" for what actually gets admitted.
33
+ */
34
+ import { z } from 'zod';
35
+ import type { HydratedSettingsView } from './detail-crop.js';
36
+ /**
37
+ * Store identity of the lease knobs in `pipeline-orchestrator`'s GLOBAL
38
+ * (cluster-wide) settings. Keys are unique across that addon's whole schema, so
39
+ * the reader can walk every section instead of trusting the section id.
40
+ */
41
+ export declare const NATIVE_LEASE_SECTION_ID = "native-lease";
42
+ export declare const NATIVE_LEASE_TTL_KEY = "nativeLeaseTtlMs";
43
+ export declare const NATIVE_LEASE_BUDGET_KEY = "nativeLeaseBudgetMb";
44
+ export declare const NATIVE_LEASE_ACTIVITY_KEY = "nativeLeaseActivityMs";
45
+ export declare const NATIVE_LEASE_ADMISSION_KEY = "nativeLeaseAdmission";
46
+ /**
47
+ * WHICH delivered frames the decode worker retains a native copy of.
48
+ *
49
+ * - `all` — every frame the worker delivered to the runner. The shipped
50
+ * behaviour, and the only correct one if something can ask for a crop of a
51
+ * frame the runner never sent to inference.
52
+ * - `inferred` — only the frames the runner ADMITTED to its detection queue.
53
+ * A native-crop request always names a `frameId` that rode an inference
54
+ * result, so that is the only set a request can name. How much it drops is
55
+ * the two-plane governor's admit ratio and nothing else: measured at ~50% on
56
+ * this cluster, not the ~80% the design sketch assumed, because the governor
57
+ * was not throttling as hard as the sketch supposed. Read
58
+ * `leaseAdmitted`/`leaseOffered` off the metrics line for the camera in front
59
+ * of you rather than quoting a number from here. The newest delivered frame is
60
+ * croppable regardless — it is still the worker's reserved slot, not a lease —
61
+ * which covers the one-frame race between a mark and the supersede that
62
+ * consumes it.
63
+ */
64
+ export declare const NativeLeaseAdmissionSchema: z.ZodEnum<{
65
+ all: "all";
66
+ inferred: "inferred";
67
+ }>;
68
+ export type NativeLeaseAdmission = z.infer<typeof NativeLeaseAdmissionSchema>;
69
+ /**
70
+ * Operator-tunable native-lease settings. Bounds are enforced HERE (not only in
71
+ * the slider) because the value also travels to a forked child process, where a
72
+ * junk number would silently become a 0-length or unbounded retention window.
73
+ */
74
+ export declare const NativeLeaseSettingsSchema: z.ZodObject<{
75
+ ttlMs: z.ZodNumber;
76
+ budgetMb: z.ZodNumber;
77
+ activityMs: z.ZodNumber;
78
+ admission: z.ZodEnum<{
79
+ all: "all";
80
+ inferred: "inferred";
81
+ }>;
82
+ }, z.core.$strip>;
83
+ export type NativeLeaseSettings = z.infer<typeof NativeLeaseSettingsSchema>;
84
+ /**
85
+ * The values in force when the operator has set nothing — byte-for-byte the
86
+ * constants the decode worker shipped with as env-var defaults, so making these
87
+ * settings changed no behaviour on the day it landed.
88
+ */
89
+ export declare const DEFAULT_NATIVE_LEASE_SETTINGS: NativeLeaseSettings;
90
+ /**
91
+ * Only the knobs the operator has ACTUALLY set. Distinguishing "set" from
92
+ * "absent" is what makes the documented precedence (setting > env > default)
93
+ * expressible: an absent knob leaves the env-var escape hatch working.
94
+ */
95
+ export type NativeLeaseSettingsOverride = Partial<NativeLeaseSettings>;
96
+ /** Slider bounds for the operator-facing knobs (orchestrator settings UI). */
97
+ export declare const NATIVE_LEASE_TTL_FIELD: {
98
+ readonly min: 250;
99
+ readonly max: 10000;
100
+ readonly step: 50;
101
+ readonly default: number;
102
+ };
103
+ export declare const NATIVE_LEASE_BUDGET_FIELD: {
104
+ readonly min: 0;
105
+ readonly max: 4096;
106
+ readonly step: 64;
107
+ readonly default: number;
108
+ };
109
+ export declare const NATIVE_LEASE_ACTIVITY_FIELD: {
110
+ readonly min: 0;
111
+ readonly max: 120000;
112
+ readonly step: 1000;
113
+ readonly default: number;
114
+ };
115
+ /** Select options for the admission knob (orchestrator settings UI). */
116
+ export declare const NATIVE_LEASE_ADMISSION_FIELD: {
117
+ readonly options: readonly [{
118
+ readonly value: "all";
119
+ readonly label: "Every delivered frame";
120
+ }, {
121
+ readonly value: "inferred";
122
+ readonly label: "Only frames sent to inference";
123
+ }];
124
+ readonly default: "all" | "inferred";
125
+ };
126
+ /** The four knobs, as a key union. */
127
+ export type NativeLeaseKnob = keyof NativeLeaseSettings;
128
+ /** The three knobs whose value is a bounded integer (everything but `admission`). */
129
+ export type NativeLeaseNumberKnob = 'ttlMs' | 'budgetMb' | 'activityMs';
130
+ /**
131
+ * Narrow a FLAT settings record to the knobs the operator set.
132
+ *
133
+ * Per-FIELD parse, deliberately: a junk TTL must not also discard a valid
134
+ * budget. An absent, out-of-bounds or default-valued knob is OMITTED (not
135
+ * clamped, not defaulted) so the caller can still fall through to the env
136
+ * override — clamping here would turn a typo into a value nobody chose. See
137
+ * {@link readKnob} for why the default counts as unset.
138
+ */
139
+ export declare function readNativeLeaseOverride(config: Readonly<Record<string, unknown>>): NativeLeaseSettingsOverride;
140
+ /**
141
+ * Extract the operator's lease overrides from an
142
+ * `addon-settings.getGlobalSettings` payload.
143
+ *
144
+ * Walks EVERY section rather than looking inside {@link NATIVE_LEASE_SECTION_ID}
145
+ * alone: the keys are unique across the addon's schema, and a section rename
146
+ * must not silently revert the whole cluster to the defaults. A `null` payload
147
+ * (addon mid-boot) means "operator set nothing" — the env/default fallback then
148
+ * applies, which is the correct read of "I could not ask".
149
+ */
150
+ export declare function pickNativeLeaseOverride(view: HydratedSettingsView | null): NativeLeaseSettingsOverride;
@@ -1934,9 +1934,38 @@ var CAP_NODE_PIN_CONTEXT_KEY = "__camstackNodePin";
1934
1934
  /**
1935
1935
  * Build the tRPC request options that pin a single capability call to `nodeId`.
1936
1936
  * Pass as the second argument to `.query(input, …)` / `.mutate(input, …)`.
1937
+ *
1938
+ * ## The id is normalised here, and it has to be
1939
+ *
1940
+ * A forked addon reads its own node from `ctx.kernel.localNodeId`, and inside a
1941
+ * worker that value is a RUNNER id — `hub/export-hap`, not `hub`. Routing
1942
+ * compares a pin against real node ids, so such a pin matches nothing and the
1943
+ * call fails with `no provider registered for cap "…"`. The local-first
1944
+ * resolver already guarded against this (`localNodeId.split('/')[0]`), which
1945
+ * made the hazard invisible: unpinned calls worked, and only an explicit pin —
1946
+ * the thing you reach for when you specifically need THIS node — silently
1947
+ * addressed a node that does not exist.
1948
+ *
1949
+ * Cost of it being missing: `addon-export-hap` pinned `decoder.getInfo` to its
1950
+ * own node to read the host's hardware-decode backend. It never once answered,
1951
+ * so every HomeKit egress transcode decoded in SOFTWARE — including 4K H.265 —
1952
+ * while D67's whole premise was that the decoder addon is the authority on
1953
+ * hardware. The warn said `decoding in SOFTWARE` and read as "this node has no
1954
+ * hardware", which was false.
1955
+ *
1956
+ * Normalising in the ONE constructor fixes every caller at once, which is why
1957
+ * it is here and not at the call sites.
1937
1958
  */
1938
1959
  function nodePin(nodeId) {
1939
- return { context: { [CAP_NODE_PIN_CONTEXT_KEY]: nodeId } };
1960
+ return { context: { [CAP_NODE_PIN_CONTEXT_KEY]: toNodeId(nodeId) } };
1961
+ }
1962
+ /**
1963
+ * A runner id is `<nodeId>/<addonId>`; a node id has no slash. Taking the head
1964
+ * is idempotent, so passing an already-clean id costs nothing.
1965
+ */
1966
+ function toNodeId(idOrRunnerId) {
1967
+ const head = idOrRunnerId.split("/")[0];
1968
+ return head === void 0 || head.length === 0 ? idOrRunnerId : head;
1940
1969
  }
1941
1970
  /**
1942
1971
  * Read a per-call node pin out of a tRPC `op.context` (transport side).
@@ -3103,6 +3132,8 @@ function createDeviceProxy(api, binding, opts) {
3103
3132
  updateRule: (input) => dispatch("notification-rules", "notificationRules", "updateRule", "mutation", input),
3104
3133
  deleteRule: (input) => dispatch("notification-rules", "notificationRules", "deleteRule", "mutation", input),
3105
3134
  setRuleEnabled: (input) => dispatch("notification-rules", "notificationRules", "setRuleEnabled", "mutation", input),
3135
+ listDeviceMutes: (input) => dispatch("notification-rules", "notificationRules", "listDeviceMutes", "query", input),
3136
+ setDeviceMuted: (input) => dispatch("notification-rules", "notificationRules", "setDeviceMuted", "mutation", input),
3106
3137
  testRule: (input) => dispatch("notification-rules", "notificationRules", "testRule", "mutation", input),
3107
3138
  getConditionCatalog: (input) => dispatch("notification-rules", "notificationRules", "getConditionCatalog", "query", input),
3108
3139
  getHistory: (input) => dispatch("notification-rules", "notificationRules", "getHistory", "query", input),
@@ -3153,6 +3184,7 @@ function createDeviceProxy(api, binding, opts) {
3153
3184
  pruneTracksBefore: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "pruneTracksBefore", "mutation", input),
3154
3185
  wipeAllAnalytics: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "wipeAllAnalytics", "mutation", input),
3155
3186
  deleteTracks: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "deleteTracks", "mutation", input),
3187
+ setTrackFlags: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "setTrackFlags", "mutation", input),
3156
3188
  getEventStoreFootprint: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getEventStoreFootprint", "query", input),
3157
3189
  pruneEvents: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "pruneEvents", "mutation", input),
3158
3190
  deleteDeviceEvents: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "deleteDeviceEvents", "mutation", input),
@@ -3177,6 +3209,7 @@ function createDeviceProxy(api, binding, opts) {
3177
3209
  privacyMask: {
3178
3210
  getOptions: (input) => dispatch("privacy-mask", "privacyMask", "getOptions", "query", input),
3179
3211
  setMask: (input) => dispatch("privacy-mask", "privacyMask", "setMask", "mutation", input),
3212
+ setAudioEnabled: (input) => dispatch("privacy-mask", "privacyMask", "setAudioEnabled", "mutation", input),
3180
3213
  getStatus: (input) => dispatch("privacy-mask", "privacyMask", "getStatus", "query", input)
3181
3214
  },
3182
3215
  ptz: {
@@ -3388,6 +3421,8 @@ function createDeviceProxy(api, binding, opts) {
3388
3421
  setCameraStepOverride: (input) => dispatchSystem("pipelineOrchestrator", "setCameraStepOverride", "mutation", input),
3389
3422
  setCameraPipelineForAgent: (input) => dispatchSystem("pipelineOrchestrator", "setCameraPipelineForAgent", "mutation", input),
3390
3423
  resolvePipeline: (input) => dispatchSystem("pipelineOrchestrator", "resolvePipeline", "query", input),
3424
+ getCameraSwitches: (input) => dispatchSystem("pipelineOrchestrator", "getCameraSwitches", "query", input),
3425
+ setCameraSwitch: (input) => dispatchSystem("pipelineOrchestrator", "setCameraSwitch", "mutation", input),
3391
3426
  getCameraStatus: (input) => dispatchSystem("pipelineOrchestrator", "getCameraStatus", "query", input),
3392
3427
  getDeviceSettingsContribution: (input) => dispatchSystem("pipelineOrchestrator", "getDeviceSettingsContribution", "query", input),
3393
3428
  getDeviceLiveContribution: (input) => dispatchSystem("pipelineOrchestrator", "getDeviceLiveContribution", "query", input),
@@ -3409,6 +3444,7 @@ function createDeviceProxy(api, binding, opts) {
3409
3444
  getDeviceConfig: (input) => dispatchSystem("recording", "getDeviceConfig", "query", input),
3410
3445
  locateSegment: (input) => dispatchSystem("recording", "locateSegment", "query", input),
3411
3446
  readSegmentBytes: (input) => dispatchSystem("recording", "readSegmentBytes", "query", input),
3447
+ readGopBytes: (input) => dispatchSystem("recording", "readGopBytes", "query", input),
3412
3448
  setDeviceConfig: (input) => dispatchSystem("recording", "setDeviceConfig", "mutation", input),
3413
3449
  rescanStorage: (input) => dispatchSystem("recording", "rescanStorage", "mutation", input),
3414
3450
  pruneFootage: (input) => dispatchSystem("recording", "pruneFootage", "mutation", input),
@@ -4124,6 +4160,12 @@ Object.defineProperty(exports, "systemMethod", {
4124
4160
  return systemMethod;
4125
4161
  }
4126
4162
  });
4163
+ Object.defineProperty(exports, "toNodeId", {
4164
+ enumerable: true,
4165
+ get: function() {
4166
+ return toNodeId;
4167
+ }
4168
+ });
4127
4169
  Object.defineProperty(exports, "viewerUiCapability", {
4128
4170
  enumerable: true,
4129
4171
  get: function() {
@@ -1934,9 +1934,38 @@ var CAP_NODE_PIN_CONTEXT_KEY = "__camstackNodePin";
1934
1934
  /**
1935
1935
  * Build the tRPC request options that pin a single capability call to `nodeId`.
1936
1936
  * Pass as the second argument to `.query(input, …)` / `.mutate(input, …)`.
1937
+ *
1938
+ * ## The id is normalised here, and it has to be
1939
+ *
1940
+ * A forked addon reads its own node from `ctx.kernel.localNodeId`, and inside a
1941
+ * worker that value is a RUNNER id — `hub/export-hap`, not `hub`. Routing
1942
+ * compares a pin against real node ids, so such a pin matches nothing and the
1943
+ * call fails with `no provider registered for cap "…"`. The local-first
1944
+ * resolver already guarded against this (`localNodeId.split('/')[0]`), which
1945
+ * made the hazard invisible: unpinned calls worked, and only an explicit pin —
1946
+ * the thing you reach for when you specifically need THIS node — silently
1947
+ * addressed a node that does not exist.
1948
+ *
1949
+ * Cost of it being missing: `addon-export-hap` pinned `decoder.getInfo` to its
1950
+ * own node to read the host's hardware-decode backend. It never once answered,
1951
+ * so every HomeKit egress transcode decoded in SOFTWARE — including 4K H.265 —
1952
+ * while D67's whole premise was that the decoder addon is the authority on
1953
+ * hardware. The warn said `decoding in SOFTWARE` and read as "this node has no
1954
+ * hardware", which was false.
1955
+ *
1956
+ * Normalising in the ONE constructor fixes every caller at once, which is why
1957
+ * it is here and not at the call sites.
1937
1958
  */
1938
1959
  function nodePin(nodeId) {
1939
- return { context: { [CAP_NODE_PIN_CONTEXT_KEY]: nodeId } };
1960
+ return { context: { [CAP_NODE_PIN_CONTEXT_KEY]: toNodeId(nodeId) } };
1961
+ }
1962
+ /**
1963
+ * A runner id is `<nodeId>/<addonId>`; a node id has no slash. Taking the head
1964
+ * is idempotent, so passing an already-clean id costs nothing.
1965
+ */
1966
+ function toNodeId(idOrRunnerId) {
1967
+ const head = idOrRunnerId.split("/")[0];
1968
+ return head === void 0 || head.length === 0 ? idOrRunnerId : head;
1940
1969
  }
1941
1970
  /**
1942
1971
  * Read a per-call node pin out of a tRPC `op.context` (transport side).
@@ -3103,6 +3132,8 @@ function createDeviceProxy(api, binding, opts) {
3103
3132
  updateRule: (input) => dispatch("notification-rules", "notificationRules", "updateRule", "mutation", input),
3104
3133
  deleteRule: (input) => dispatch("notification-rules", "notificationRules", "deleteRule", "mutation", input),
3105
3134
  setRuleEnabled: (input) => dispatch("notification-rules", "notificationRules", "setRuleEnabled", "mutation", input),
3135
+ listDeviceMutes: (input) => dispatch("notification-rules", "notificationRules", "listDeviceMutes", "query", input),
3136
+ setDeviceMuted: (input) => dispatch("notification-rules", "notificationRules", "setDeviceMuted", "mutation", input),
3106
3137
  testRule: (input) => dispatch("notification-rules", "notificationRules", "testRule", "mutation", input),
3107
3138
  getConditionCatalog: (input) => dispatch("notification-rules", "notificationRules", "getConditionCatalog", "query", input),
3108
3139
  getHistory: (input) => dispatch("notification-rules", "notificationRules", "getHistory", "query", input),
@@ -3153,6 +3184,7 @@ function createDeviceProxy(api, binding, opts) {
3153
3184
  pruneTracksBefore: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "pruneTracksBefore", "mutation", input),
3154
3185
  wipeAllAnalytics: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "wipeAllAnalytics", "mutation", input),
3155
3186
  deleteTracks: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "deleteTracks", "mutation", input),
3187
+ setTrackFlags: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "setTrackFlags", "mutation", input),
3156
3188
  getEventStoreFootprint: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getEventStoreFootprint", "query", input),
3157
3189
  pruneEvents: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "pruneEvents", "mutation", input),
3158
3190
  deleteDeviceEvents: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "deleteDeviceEvents", "mutation", input),
@@ -3177,6 +3209,7 @@ function createDeviceProxy(api, binding, opts) {
3177
3209
  privacyMask: {
3178
3210
  getOptions: (input) => dispatch("privacy-mask", "privacyMask", "getOptions", "query", input),
3179
3211
  setMask: (input) => dispatch("privacy-mask", "privacyMask", "setMask", "mutation", input),
3212
+ setAudioEnabled: (input) => dispatch("privacy-mask", "privacyMask", "setAudioEnabled", "mutation", input),
3180
3213
  getStatus: (input) => dispatch("privacy-mask", "privacyMask", "getStatus", "query", input)
3181
3214
  },
3182
3215
  ptz: {
@@ -3388,6 +3421,8 @@ function createDeviceProxy(api, binding, opts) {
3388
3421
  setCameraStepOverride: (input) => dispatchSystem("pipelineOrchestrator", "setCameraStepOverride", "mutation", input),
3389
3422
  setCameraPipelineForAgent: (input) => dispatchSystem("pipelineOrchestrator", "setCameraPipelineForAgent", "mutation", input),
3390
3423
  resolvePipeline: (input) => dispatchSystem("pipelineOrchestrator", "resolvePipeline", "query", input),
3424
+ getCameraSwitches: (input) => dispatchSystem("pipelineOrchestrator", "getCameraSwitches", "query", input),
3425
+ setCameraSwitch: (input) => dispatchSystem("pipelineOrchestrator", "setCameraSwitch", "mutation", input),
3391
3426
  getCameraStatus: (input) => dispatchSystem("pipelineOrchestrator", "getCameraStatus", "query", input),
3392
3427
  getDeviceSettingsContribution: (input) => dispatchSystem("pipelineOrchestrator", "getDeviceSettingsContribution", "query", input),
3393
3428
  getDeviceLiveContribution: (input) => dispatchSystem("pipelineOrchestrator", "getDeviceLiveContribution", "query", input),
@@ -3409,6 +3444,7 @@ function createDeviceProxy(api, binding, opts) {
3409
3444
  getDeviceConfig: (input) => dispatchSystem("recording", "getDeviceConfig", "query", input),
3410
3445
  locateSegment: (input) => dispatchSystem("recording", "locateSegment", "query", input),
3411
3446
  readSegmentBytes: (input) => dispatchSystem("recording", "readSegmentBytes", "query", input),
3447
+ readGopBytes: (input) => dispatchSystem("recording", "readGopBytes", "query", input),
3412
3448
  setDeviceConfig: (input) => dispatchSystem("recording", "setDeviceConfig", "mutation", input),
3413
3449
  rescanStorage: (input) => dispatchSystem("recording", "rescanStorage", "mutation", input),
3414
3450
  pruneFootage: (input) => dispatchSystem("recording", "pruneFootage", "mutation", input),
@@ -3656,4 +3692,4 @@ function sleepCancellable(ms, signal) {
3656
3692
  });
3657
3693
  }
3658
3694
  //#endregion
3659
- export { ProfileRtspEntrySchema as $, method as A, scopeKey as B, DeviceType as C, collectHydratedFieldValues as Ct, event as D, DEVICE_STATUS_METHOD as E, readNodePin as F, CamStreamKindSchema as G, BrokerStatusSchema as H, ReadinessRegistry as I, DecodedAudioChunkSchema as J, CamStreamResolutionSchema as K, ReadinessTimeoutError as L, systemMethod as M, CAP_NODE_PIN_CONTEXT_KEY as N, expandCapMethods as O, nodePin as P, FrameHandleSchema as Q, emitDownForOwnedCaps as R, DeviceRole as S, collectHydratedFieldEntries as St, DEVICE_SETTINGS_CONTRIBUTION_METHODS as T, resolveHydratedFieldValue as Tt, CAM_PROFILE_ORDER as U, BrokerStatsSchema as V, CamProfileSchema as W, EncodedPacketSchema as X, DecodedFrameSchema as Y, FrameHandleFormatSchema as Z, RawStateResultSchema as _, createEvent as _t, asJsonObject as a, SubscribeAudioChunksResultSchema as at, ChargingStatus as b, WELL_KNOWN_TABS as bt, parseJsonArray as c, makeProfileBrokerId as ct, DEVICE_SCOPED_CAPS as d, selectAssignedProfileSlots as dt, ProfileSlotSchema as et, isDeviceScopedCap as f, DATAPLANE_SECRET_HEADER as ft, createSliceHandle as g, createDurableState as gt, createMirrorSource as h, normalizeAddonInitResult as ht, asJsonArray as i, SubscribeAudioChunksInputSchema as it, resolveCapMount as j, isDeviceConfigCap as k, parseJsonObject as l, makeSourceBrokerId as lt, createLazyTrpcSource as m, BaseAddon as mt, sleepCancellable as n, StreamSourceEntrySchema$1 as nt, asNumber as o, SubscribeFramesInputSchema as ot, createDeviceProxy as p, DisposerChain as pt, CameraStreamSchema as q, asBoolean as r, StreamSourceSchema as rt, asString as s, SubscribeFramesResultSchema as st, sleep as t, ProfileSlotStatusSchema as tt, parseJsonUnknown as u, parseProfileBrokerId as ut, deviceOpsCapability as v, emitReadiness as vt, adminUiCapability as w, hydrateSchema as wt, DeviceFeature as x, WELL_KNOWN_TAB_MAP as xt, viewerUiCapability as y, isEvent as yt, readinessKey as z };
3695
+ export { FrameHandleSchema as $, method as A, readinessKey as B, DeviceType as C, collectHydratedFieldEntries as Ct, event as D, DEVICE_STATUS_METHOD as E, resolveHydratedFieldValue as Et, readNodePin as F, CamProfileSchema as G, BrokerStatsSchema as H, toNodeId as I, CameraStreamSchema as J, CamStreamKindSchema as K, ReadinessRegistry as L, systemMethod as M, CAP_NODE_PIN_CONTEXT_KEY as N, expandCapMethods as O, nodePin as P, FrameHandleFormatSchema as Q, ReadinessTimeoutError as R, DeviceRole as S, WELL_KNOWN_TAB_MAP as St, DEVICE_SETTINGS_CONTRIBUTION_METHODS as T, hydrateSchema as Tt, BrokerStatusSchema as U, scopeKey as V, CAM_PROFILE_ORDER as W, DecodedFrameSchema as X, DecodedAudioChunkSchema as Y, EncodedPacketSchema as Z, RawStateResultSchema as _, createDurableState as _t, asJsonObject as a, SubscribeAudioChunksInputSchema as at, ChargingStatus as b, isEvent as bt, parseJsonArray as c, SubscribeFramesResultSchema as ct, DEVICE_SCOPED_CAPS as d, parseProfileBrokerId as dt, ProfileRtspEntrySchema as et, isDeviceScopedCap as f, selectAssignedProfileSlots as ft, createSliceHandle as g, normalizeAddonInitResult as gt, createMirrorSource as h, BaseAddon as ht, asJsonArray as i, StreamSourceSchema as it, resolveCapMount as j, isDeviceConfigCap as k, parseJsonObject as l, makeProfileBrokerId as lt, createLazyTrpcSource as m, DisposerChain as mt, sleepCancellable as n, ProfileSlotStatusSchema as nt, asNumber as o, SubscribeAudioChunksResultSchema as ot, createDeviceProxy as p, DATAPLANE_SECRET_HEADER as pt, CamStreamResolutionSchema as q, asBoolean as r, StreamSourceEntrySchema$1 as rt, asString as s, SubscribeFramesInputSchema as st, sleep as t, ProfileSlotSchema as tt, parseJsonUnknown as u, makeSourceBrokerId as ut, deviceOpsCapability as v, createEvent as vt, adminUiCapability as w, collectHydratedFieldValues as wt, DeviceFeature as x, WELL_KNOWN_TABS as xt, viewerUiCapability as y, emitReadiness as yt, emitDownForOwnedCaps as z };
@@ -0,0 +1,30 @@
1
+ /**
2
+ * The addon id as the REGISTRY, the wire and the durable stores spell it.
3
+ *
4
+ * `AddonContext.id` does not agree with itself across the two context
5
+ * factories:
6
+ *
7
+ * - a FORKED addon gets the bare manifest id
8
+ * (`kernel/moleculer/addon-context-factory.ts` → `id: addonId`);
9
+ * - an addon co-located in hub-main gets it PREFIXED
10
+ * (`server/backend/src/core/addon/addon-registry.service.ts` →
11
+ * ``id: `addon:${addonId}` ``).
12
+ *
13
+ * Everything an addon might compare `ctx.id` AGAINST carries the bare form:
14
+ * `DeviceBindingEntry.providerAddonId`, the `device-manager` bindings store's
15
+ * `wrapperAddonId`, `CapabilityRegistry` provider keys, manifest ids.
16
+ *
17
+ * So `entry.providerAddonId === this.ctx.id` is silently, permanently false
18
+ * for a builtin — and only for a builtin, which is why it survives a green
19
+ * suite whose fake supplies the bare id. That is exactly how camera 615's
20
+ * virtual doorbell latched `unbound` for twelve hours on 2026-08-07 while its
21
+ * binding was intact ([D72](../../../../docs/decisions/adr-0072.md)).
22
+ *
23
+ * Route every comparison between `ctx.id` and a registry/store addon id
24
+ * through {@link isSameAddonId}. `scripts/check-addon-id-comparison.ts`
25
+ * enforces it in the processes where the prefix exists.
26
+ */
27
+ /** The manifest id, whichever spelling of `ctx.id` you were handed. */
28
+ export declare function bareAddonId(id: string): string;
29
+ /** True when both ids name the same addon, prefixed or not. */
30
+ export declare function isSameAddonId(a: string, b: string): boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/types",
3
- "version": "1.2.41",
3
+ "version": "1.2.43",
4
4
  "description": "Shared types, interfaces, and model catalogs for the CamStack detection ecosystem",
5
5
  "keywords": [
6
6
  "camstack",