@camstack/addon-pipeline 1.2.42 → 1.2.44
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/audio-analyzer/index.js +4 -4
- package/dist/audio-analyzer/index.mjs +2 -2
- package/dist/detection-pipeline/index.js +164 -88
- package/dist/detection-pipeline/index.mjs +158 -82
- package/dist/{dist-BdDd3ql_.js → dist-BuFE5rOK.js} +1608 -36
- package/dist/{dist-COK_1Ot8.mjs → dist-DOu93i_g.mjs} +1525 -37
- package/dist/{event-loop-stall-monitor-CWOJtTNc.mjs → event-loop-stall-monitor-CShgQE6l.mjs} +40 -2
- package/dist/{event-loop-stall-monitor-DNFRgNef.js → event-loop-stall-monitor-L08yG6bB.js} +40 -2
- package/dist/{model-download-service-Cp9f4dk6-fsdDExML.js → model-download-service-D8B-4ktF-7-YxE9Wx.js} +2 -2
- package/dist/{model-download-service-Cp9f4dk6-CwUb5v3Y.mjs → model-download-service-D8B-4ktF-BB7oZL3y.mjs} +2 -2
- package/dist/motion-wasm/index.js +1 -1
- package/dist/motion-wasm/index.mjs +1 -1
- package/dist/pipeline-runner/index.js +496 -67
- package/dist/pipeline-runner/index.mjs +496 -67
- package/dist/recorder/index.js +194 -11
- package/dist/recorder/index.mjs +191 -8
- package/dist/session-decode/decode-worker-child.js +197 -24
- package/dist/session-decode/decode-worker-child.mjs +197 -24
- package/dist/stream-broker/_stub.js +2 -2
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-C8ovZN0g.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-DiXoZnou.mjs} +2 -2
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BRc-m6W-.mjs +26 -0
- package/dist/stream-broker/{_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-DAjAxXHm.mjs → _virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-B_hakWAb.mjs} +1 -1
- package/dist/stream-broker/{hostInit-mEtjQWcr.mjs → hostInit-khRXMnjl.mjs} +2 -2
- package/dist/stream-broker/index.js +17331 -14101
- package/dist/stream-broker/index.mjs +17330 -14100
- package/dist/stream-broker/remoteEntry.js +1 -1
- package/dist/worker-protocol-BOXlUhWO.mjs +244 -0
- package/dist/worker-protocol-VURr0nUh.js +279 -0
- package/embed-dist/assets/{MaskShapeCanvas-DI4BY7W2-C0TIfr0G.js → MaskShapeCanvas-DI4BY7W2-DHZuYYjH.js} +1 -1
- package/embed-dist/assets/{MotionZonesSettings-NcxxQN8r-x0SkfHwv.js → MotionZonesSettings-NcxxQN8r-jFDOzPCD.js} +1 -1
- package/embed-dist/assets/{PrivacyMaskSettings-APgPLF7p-BoaAB4Ta.js → PrivacyMaskSettings-APgPLF7p-BPBXgIX8.js} +1 -1
- package/embed-dist/assets/{index-BgRdCCVy.js → index-4CtQAybX.js} +12 -12
- package/embed-dist/assets/index-DC63og2c.css +2 -0
- package/embed-dist/index.html +2 -2
- package/package.json +1 -1
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-SU_6F3Y7.mjs +0 -26
- package/dist/worker-protocol-D7RzZIla.mjs +0 -77
- package/dist/worker-protocol-DextwlTX.js +0 -94
- package/embed-dist/assets/index-CGdwTcwE.css +0 -2
|
@@ -30,7 +30,7 @@ async function d(e) {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
async function f() {
|
|
33
|
-
return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-
|
|
33
|
+
return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-DiXoZnou.mjs")).catch((e) => {
|
|
34
34
|
throw l = void 0, e;
|
|
35
35
|
}), l;
|
|
36
36
|
}
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { g as NativeLeaseSettingsSchema, h as NativeLeaseAdmissionSchema, l as DEFAULT_NATIVE_LEASE_SETTINGS } from "./dist-DOu93i_g.mjs";
|
|
2
|
+
//#region src/session-decode/native-lease-config.ts
|
|
3
|
+
/**
|
|
4
|
+
* Resolution of the native-frame lease knobs for one decode worker.
|
|
5
|
+
*
|
|
6
|
+
* ## Where the values come from
|
|
7
|
+
*
|
|
8
|
+
* The knobs are cluster-wide `pipeline-orchestrator` settings
|
|
9
|
+
* (`@camstack/types` → `pipeline/native-lease.ts`). The pipeline-runner reads
|
|
10
|
+
* them over the hub-routed `addon-settings` cap
|
|
11
|
+
* (`pipeline-runner/native-lease-settings-source.ts`) and injects the ones the
|
|
12
|
+
* operator actually SET into the child's environment at `fork` time
|
|
13
|
+
* ({@link nativeLeaseSettingEnv}, consumed by `fork-decode-worker.ts`). The
|
|
14
|
+
* child resolves them at module load ({@link resolveNativeLeaseKnobs}).
|
|
15
|
+
*
|
|
16
|
+
* Env-on-fork rather than an init message on purpose: the lease store and the
|
|
17
|
+
* demand gate are constructed with the worker, before the first `start` message
|
|
18
|
+
* arrives, and a knob that can change after construction is a knob that has two
|
|
19
|
+
* values during a session.
|
|
20
|
+
*
|
|
21
|
+
* ## Precedence — setting > env > default
|
|
22
|
+
*
|
|
23
|
+
* 1. **setting** — the operator set the knob in the orchestrator's global
|
|
24
|
+
* settings. Wins, because a value someone deliberately chose in the UI must
|
|
25
|
+
* not be silently overruled by a shell variable nobody can see from there.
|
|
26
|
+
* 2. **env** — {@link NATIVE_LEASE_ENV_VARS}, the pre-settings mechanism, kept
|
|
27
|
+
* as an emergency / dev override. It applies only while the corresponding
|
|
28
|
+
* setting is UNSET. "Unset" includes a knob sitting AT its shipped default:
|
|
29
|
+
* `addon-settings.getGlobalSettings` hydrates an unstored field with the
|
|
30
|
+
* schema default and offers no way to tell the two apart, so treating the
|
|
31
|
+
* default as a choice would have retired every env var on the day this
|
|
32
|
+
* shipped. Move the slider off the default and the setting takes over; move
|
|
33
|
+
* it back and the env var returns. See `readNativeLeaseOverride`.
|
|
34
|
+
* 3. **default** — {@link DEFAULT_NATIVE_LEASE_SETTINGS}, byte-for-byte the
|
|
35
|
+
* constants the worker shipped with.
|
|
36
|
+
*
|
|
37
|
+
* A value that fails its bounds at ANY level falls through to the next one
|
|
38
|
+
* rather than being clamped: clamping turns a typo into a number nobody chose,
|
|
39
|
+
* and this one governs how much RAM a busy camera holds.
|
|
40
|
+
*
|
|
41
|
+
* The GPU surface ring (`CAMSTACK_SESSION_NATIVE_CROP_RING`) is deliberately
|
|
42
|
+
* NOT here — see its docblock in `decode-worker-child.ts` for why it stays
|
|
43
|
+
* env-only.
|
|
44
|
+
*/
|
|
45
|
+
/** Every knob, in the order the spawn line names them. */
|
|
46
|
+
var NATIVE_LEASE_KNOBS = [
|
|
47
|
+
"ttlMs",
|
|
48
|
+
"budgetMb",
|
|
49
|
+
"activityMs",
|
|
50
|
+
"admission"
|
|
51
|
+
];
|
|
52
|
+
/** Emergency / dev override env vars (pre-settings; lowest precedence but the default). */
|
|
53
|
+
var NATIVE_LEASE_ENV_VARS = {
|
|
54
|
+
ttlMs: "CAMSTACK_SESSION_NATIVE_LEASE_TTL_MS",
|
|
55
|
+
budgetMb: "CAMSTACK_SESSION_NATIVE_LEASE_BUDGET_MB",
|
|
56
|
+
activityMs: "CAMSTACK_SESSION_NATIVE_LEASE_ACTIVITY_MS",
|
|
57
|
+
admission: "CAMSTACK_SESSION_NATIVE_LEASE_ADMISSION"
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Env vars the PARENT writes at fork time to carry an operator setting into the
|
|
61
|
+
* child. Distinct names from {@link NATIVE_LEASE_ENV_VARS} so the child can tell
|
|
62
|
+
* "the operator chose this" from "a shell variable set this" and log the source
|
|
63
|
+
* honestly — with one shared name that distinction is unrecoverable.
|
|
64
|
+
*/
|
|
65
|
+
var NATIVE_LEASE_SETTING_ENV_VARS = {
|
|
66
|
+
ttlMs: "CAMSTACK_SESSION_NATIVE_LEASE_TTL_MS_SETTING",
|
|
67
|
+
budgetMb: "CAMSTACK_SESSION_NATIVE_LEASE_BUDGET_MB_SETTING",
|
|
68
|
+
activityMs: "CAMSTACK_SESSION_NATIVE_LEASE_ACTIVITY_MS_SETTING",
|
|
69
|
+
admission: "CAMSTACK_SESSION_NATIVE_LEASE_ADMISSION_SETTING"
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Parse one env value through the knob's own Zod bound. Returns `null` for
|
|
73
|
+
* absent, non-numeric, or out-of-bounds input — the caller then falls through
|
|
74
|
+
* to the next precedence level.
|
|
75
|
+
*/
|
|
76
|
+
function parseKnob(knob, raw) {
|
|
77
|
+
if (raw === void 0 || raw.trim() === "") return null;
|
|
78
|
+
const parsed = NativeLeaseSettingsSchema.shape[knob].safeParse(Number(raw));
|
|
79
|
+
return parsed.success ? parsed.data : null;
|
|
80
|
+
}
|
|
81
|
+
/** {@link parseKnob} for the one knob whose value is a word, not a number. */
|
|
82
|
+
function parseAdmission(raw) {
|
|
83
|
+
if (raw === void 0) return null;
|
|
84
|
+
const parsed = NativeLeaseAdmissionSchema.safeParse(raw.trim());
|
|
85
|
+
return parsed.success ? parsed.data : null;
|
|
86
|
+
}
|
|
87
|
+
/** Resolve one NUMERIC knob across the three precedence levels. */
|
|
88
|
+
function resolveKnob(knob, env) {
|
|
89
|
+
const fromSetting = parseKnob(knob, env[NATIVE_LEASE_SETTING_ENV_VARS[knob]]);
|
|
90
|
+
if (fromSetting !== null) return {
|
|
91
|
+
value: fromSetting,
|
|
92
|
+
source: "setting"
|
|
93
|
+
};
|
|
94
|
+
const fromEnv = parseKnob(knob, env[NATIVE_LEASE_ENV_VARS[knob]]);
|
|
95
|
+
if (fromEnv !== null) return {
|
|
96
|
+
value: fromEnv,
|
|
97
|
+
source: "env"
|
|
98
|
+
};
|
|
99
|
+
return {
|
|
100
|
+
value: DEFAULT_NATIVE_LEASE_SETTINGS[knob],
|
|
101
|
+
source: "default"
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/** {@link resolveKnob} for `admission`. Same precedence, different parser. */
|
|
105
|
+
function resolveAdmission(env) {
|
|
106
|
+
const fromSetting = parseAdmission(env[NATIVE_LEASE_SETTING_ENV_VARS.admission]);
|
|
107
|
+
if (fromSetting !== null) return {
|
|
108
|
+
value: fromSetting,
|
|
109
|
+
source: "setting"
|
|
110
|
+
};
|
|
111
|
+
const fromEnv = parseAdmission(env[NATIVE_LEASE_ENV_VARS.admission]);
|
|
112
|
+
if (fromEnv !== null) return {
|
|
113
|
+
value: fromEnv,
|
|
114
|
+
source: "env"
|
|
115
|
+
};
|
|
116
|
+
return {
|
|
117
|
+
value: DEFAULT_NATIVE_LEASE_SETTINGS.admission,
|
|
118
|
+
source: "default"
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
/** Resolve all four lease knobs from an environment. Pure. */
|
|
122
|
+
function resolveNativeLeaseKnobs(env) {
|
|
123
|
+
const ttlMs = resolveKnob("ttlMs", env);
|
|
124
|
+
const budgetMb = resolveKnob("budgetMb", env);
|
|
125
|
+
const activityMs = resolveKnob("activityMs", env);
|
|
126
|
+
const admission = resolveAdmission(env);
|
|
127
|
+
return {
|
|
128
|
+
values: {
|
|
129
|
+
ttlMs: ttlMs.value,
|
|
130
|
+
budgetMb: budgetMb.value,
|
|
131
|
+
activityMs: activityMs.value,
|
|
132
|
+
admission: admission.value
|
|
133
|
+
},
|
|
134
|
+
sources: {
|
|
135
|
+
ttlMs: ttlMs.source,
|
|
136
|
+
budgetMb: budgetMb.source,
|
|
137
|
+
activityMs: activityMs.source,
|
|
138
|
+
admission: admission.source
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* The env fragment the parent merges into a decode worker's `fork` environment.
|
|
144
|
+
* Emits ONLY the knobs the operator actually set — an empty result leaves the
|
|
145
|
+
* env override fully functional, which is the whole point of the distinction.
|
|
146
|
+
*/
|
|
147
|
+
function nativeLeaseSettingEnv(override) {
|
|
148
|
+
const out = {};
|
|
149
|
+
for (const knob of NATIVE_LEASE_KNOBS) {
|
|
150
|
+
const value = override[knob];
|
|
151
|
+
if (value !== void 0) out[NATIVE_LEASE_SETTING_ENV_VARS[knob]] = String(value);
|
|
152
|
+
}
|
|
153
|
+
return out;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* The one-line spawn diagnostic. Names the effective value AND its source for
|
|
157
|
+
* every knob: without the source, a log saying `ttlMs=2800` cannot distinguish
|
|
158
|
+
* "the operator's setting arrived" from "someone left a shell variable set", and
|
|
159
|
+
* a setting that silently fails to arrive is exactly the failure the distinct
|
|
160
|
+
* env-var names exist to make visible.
|
|
161
|
+
*/
|
|
162
|
+
function formatNativeLeaseKnobs(resolved) {
|
|
163
|
+
const part = (knob) => `${knob}=${resolved.values[knob]} source=${resolved.sources[knob]}`;
|
|
164
|
+
return `native lease knobs — ${NATIVE_LEASE_KNOBS.map(part).join("; ")}`;
|
|
165
|
+
}
|
|
166
|
+
//#endregion
|
|
167
|
+
//#region src/session-decode/worker-protocol.ts
|
|
168
|
+
/**
|
|
169
|
+
* Classify a worker diagnostic line into a {@link WorkerLogLevel}. Failure /
|
|
170
|
+
* fault lines surface at `warn` (visible at the default log level so a
|
|
171
|
+
* native-crop failure is finally seen in `addons.getLogs`); routine
|
|
172
|
+
* provenance / transition / lifecycle lines stay `debug`. Pure + exported so
|
|
173
|
+
* the mapping is unit-testable without spawning a worker.
|
|
174
|
+
*/
|
|
175
|
+
function logLevelForLine(line) {
|
|
176
|
+
return /\b(fail(?:ed|ure)?|error|exception|unhandled rejection|corrupt|EIO|EINVAL)\b/i.test(line) ? "warn" : "debug";
|
|
177
|
+
}
|
|
178
|
+
function isRecord(value) {
|
|
179
|
+
return typeof value === "object" && value !== null;
|
|
180
|
+
}
|
|
181
|
+
function isFiniteNumber(value) {
|
|
182
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
183
|
+
}
|
|
184
|
+
function isWorkerFrameFormat(value) {
|
|
185
|
+
return value === "rgb" || value === "gray";
|
|
186
|
+
}
|
|
187
|
+
function isWorkerLogLevel(value) {
|
|
188
|
+
return value === "debug" || value === "info" || value === "warn" || value === "error";
|
|
189
|
+
}
|
|
190
|
+
function isWorkerCropRegion(value) {
|
|
191
|
+
return isRecord(value) && isFiniteNumber(value.left) && isFiniteNumber(value.top) && isFiniteNumber(value.width) && isFiniteNumber(value.height);
|
|
192
|
+
}
|
|
193
|
+
function isWorkerResizeTarget(value) {
|
|
194
|
+
return isRecord(value) && isFiniteNumber(value.width) && isFiniteNumber(value.height);
|
|
195
|
+
}
|
|
196
|
+
function isFrameImageOptions(value) {
|
|
197
|
+
if (!isRecord(value)) return false;
|
|
198
|
+
if (value.crop !== void 0 && !isWorkerCropRegion(value.crop)) return false;
|
|
199
|
+
if (value.resize !== void 0 && !isWorkerResizeTarget(value.resize)) return false;
|
|
200
|
+
if (value.format !== void 0 && !isWorkerFrameFormat(value.format)) return false;
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
function isNormalizedBbox(value) {
|
|
204
|
+
return isRecord(value) && isFiniteNumber(value.x) && isFiniteNumber(value.y) && isFiniteNumber(value.w) && isFiniteNumber(value.h);
|
|
205
|
+
}
|
|
206
|
+
function isVideoFrameSource(value) {
|
|
207
|
+
return isRecord(value) && typeof value.restreamUrl === "string" && isFiniteNumber(value.deviceId) && typeof value.codec === "string";
|
|
208
|
+
}
|
|
209
|
+
function isVideoFrameGenOptions(value) {
|
|
210
|
+
if (!isRecord(value)) return false;
|
|
211
|
+
if (value.fps !== void 0 && !isFiniteNumber(value.fps)) return false;
|
|
212
|
+
if (value.format !== void 0 && !isWorkerFrameFormat(value.format)) return false;
|
|
213
|
+
return true;
|
|
214
|
+
}
|
|
215
|
+
/** Discriminated-union guard for {@link WorkerRequest} — no `as` casts. */
|
|
216
|
+
function isWorkerRequest(value) {
|
|
217
|
+
if (!isRecord(value)) return false;
|
|
218
|
+
switch (value.kind) {
|
|
219
|
+
case "start": return isVideoFrameSource(value.source) && isVideoFrameGenOptions(value.opts);
|
|
220
|
+
case "pull": return true;
|
|
221
|
+
case "toBuffer": return isFiniteNumber(value.frameId) && (value.opts === void 0 || isFrameImageOptions(value.opts));
|
|
222
|
+
case "nativeCrop": return isFiniteNumber(value.requestId) && isFiniteNumber(value.frameId) && isNormalizedBbox(value.bbox) && (value.maxWidth === void 0 || isFiniteNumber(value.maxWidth));
|
|
223
|
+
case "releaseNativeLease":
|
|
224
|
+
case "markInferred": return isFiniteNumber(value.frameId);
|
|
225
|
+
case "stop": return true;
|
|
226
|
+
default: return false;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
/** Discriminated-union guard for {@link WorkerReply} — no `as` casts. */
|
|
230
|
+
function isWorkerReply(value) {
|
|
231
|
+
if (!isRecord(value)) return false;
|
|
232
|
+
switch (value.kind) {
|
|
233
|
+
case "frame": return isFiniteNumber(value.frameId) && isFiniteNumber(value.timestamp) && isFiniteNumber(value.width) && isFiniteNumber(value.height) && isWorkerFrameFormat(value.format);
|
|
234
|
+
case "buffer": return isFiniteNumber(value.frameId) && value.bytes instanceof Uint8Array;
|
|
235
|
+
case "nativeCropResult": return isFiniteNumber(value.requestId) && value.bytes instanceof Uint8Array && isFiniteNumber(value.width) && isFiniteNumber(value.height);
|
|
236
|
+
case "nativeCropMiss": return isFiniteNumber(value.requestId) && (value.reason === void 0 || typeof value.reason === "string");
|
|
237
|
+
case "ended": return true;
|
|
238
|
+
case "error": return typeof value.message === "string" && (value.frameId === void 0 || isFiniteNumber(value.frameId));
|
|
239
|
+
case "log": return isWorkerLogLevel(value.level) && typeof value.message === "string";
|
|
240
|
+
default: return false;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
//#endregion
|
|
244
|
+
export { nativeLeaseSettingEnv as a, formatNativeLeaseKnobs as i, isWorkerRequest as n, resolveNativeLeaseKnobs as o, logLevelForLine as r, isWorkerReply as t };
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
const require_dist = require("./dist-BuFE5rOK.js");
|
|
2
|
+
//#region src/session-decode/native-lease-config.ts
|
|
3
|
+
/**
|
|
4
|
+
* Resolution of the native-frame lease knobs for one decode worker.
|
|
5
|
+
*
|
|
6
|
+
* ## Where the values come from
|
|
7
|
+
*
|
|
8
|
+
* The knobs are cluster-wide `pipeline-orchestrator` settings
|
|
9
|
+
* (`@camstack/types` → `pipeline/native-lease.ts`). The pipeline-runner reads
|
|
10
|
+
* them over the hub-routed `addon-settings` cap
|
|
11
|
+
* (`pipeline-runner/native-lease-settings-source.ts`) and injects the ones the
|
|
12
|
+
* operator actually SET into the child's environment at `fork` time
|
|
13
|
+
* ({@link nativeLeaseSettingEnv}, consumed by `fork-decode-worker.ts`). The
|
|
14
|
+
* child resolves them at module load ({@link resolveNativeLeaseKnobs}).
|
|
15
|
+
*
|
|
16
|
+
* Env-on-fork rather than an init message on purpose: the lease store and the
|
|
17
|
+
* demand gate are constructed with the worker, before the first `start` message
|
|
18
|
+
* arrives, and a knob that can change after construction is a knob that has two
|
|
19
|
+
* values during a session.
|
|
20
|
+
*
|
|
21
|
+
* ## Precedence — setting > env > default
|
|
22
|
+
*
|
|
23
|
+
* 1. **setting** — the operator set the knob in the orchestrator's global
|
|
24
|
+
* settings. Wins, because a value someone deliberately chose in the UI must
|
|
25
|
+
* not be silently overruled by a shell variable nobody can see from there.
|
|
26
|
+
* 2. **env** — {@link NATIVE_LEASE_ENV_VARS}, the pre-settings mechanism, kept
|
|
27
|
+
* as an emergency / dev override. It applies only while the corresponding
|
|
28
|
+
* setting is UNSET. "Unset" includes a knob sitting AT its shipped default:
|
|
29
|
+
* `addon-settings.getGlobalSettings` hydrates an unstored field with the
|
|
30
|
+
* schema default and offers no way to tell the two apart, so treating the
|
|
31
|
+
* default as a choice would have retired every env var on the day this
|
|
32
|
+
* shipped. Move the slider off the default and the setting takes over; move
|
|
33
|
+
* it back and the env var returns. See `readNativeLeaseOverride`.
|
|
34
|
+
* 3. **default** — {@link DEFAULT_NATIVE_LEASE_SETTINGS}, byte-for-byte the
|
|
35
|
+
* constants the worker shipped with.
|
|
36
|
+
*
|
|
37
|
+
* A value that fails its bounds at ANY level falls through to the next one
|
|
38
|
+
* rather than being clamped: clamping turns a typo into a number nobody chose,
|
|
39
|
+
* and this one governs how much RAM a busy camera holds.
|
|
40
|
+
*
|
|
41
|
+
* The GPU surface ring (`CAMSTACK_SESSION_NATIVE_CROP_RING`) is deliberately
|
|
42
|
+
* NOT here — see its docblock in `decode-worker-child.ts` for why it stays
|
|
43
|
+
* env-only.
|
|
44
|
+
*/
|
|
45
|
+
/** Every knob, in the order the spawn line names them. */
|
|
46
|
+
var NATIVE_LEASE_KNOBS = [
|
|
47
|
+
"ttlMs",
|
|
48
|
+
"budgetMb",
|
|
49
|
+
"activityMs",
|
|
50
|
+
"admission"
|
|
51
|
+
];
|
|
52
|
+
/** Emergency / dev override env vars (pre-settings; lowest precedence but the default). */
|
|
53
|
+
var NATIVE_LEASE_ENV_VARS = {
|
|
54
|
+
ttlMs: "CAMSTACK_SESSION_NATIVE_LEASE_TTL_MS",
|
|
55
|
+
budgetMb: "CAMSTACK_SESSION_NATIVE_LEASE_BUDGET_MB",
|
|
56
|
+
activityMs: "CAMSTACK_SESSION_NATIVE_LEASE_ACTIVITY_MS",
|
|
57
|
+
admission: "CAMSTACK_SESSION_NATIVE_LEASE_ADMISSION"
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Env vars the PARENT writes at fork time to carry an operator setting into the
|
|
61
|
+
* child. Distinct names from {@link NATIVE_LEASE_ENV_VARS} so the child can tell
|
|
62
|
+
* "the operator chose this" from "a shell variable set this" and log the source
|
|
63
|
+
* honestly — with one shared name that distinction is unrecoverable.
|
|
64
|
+
*/
|
|
65
|
+
var NATIVE_LEASE_SETTING_ENV_VARS = {
|
|
66
|
+
ttlMs: "CAMSTACK_SESSION_NATIVE_LEASE_TTL_MS_SETTING",
|
|
67
|
+
budgetMb: "CAMSTACK_SESSION_NATIVE_LEASE_BUDGET_MB_SETTING",
|
|
68
|
+
activityMs: "CAMSTACK_SESSION_NATIVE_LEASE_ACTIVITY_MS_SETTING",
|
|
69
|
+
admission: "CAMSTACK_SESSION_NATIVE_LEASE_ADMISSION_SETTING"
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Parse one env value through the knob's own Zod bound. Returns `null` for
|
|
73
|
+
* absent, non-numeric, or out-of-bounds input — the caller then falls through
|
|
74
|
+
* to the next precedence level.
|
|
75
|
+
*/
|
|
76
|
+
function parseKnob(knob, raw) {
|
|
77
|
+
if (raw === void 0 || raw.trim() === "") return null;
|
|
78
|
+
const parsed = require_dist.NativeLeaseSettingsSchema.shape[knob].safeParse(Number(raw));
|
|
79
|
+
return parsed.success ? parsed.data : null;
|
|
80
|
+
}
|
|
81
|
+
/** {@link parseKnob} for the one knob whose value is a word, not a number. */
|
|
82
|
+
function parseAdmission(raw) {
|
|
83
|
+
if (raw === void 0) return null;
|
|
84
|
+
const parsed = require_dist.NativeLeaseAdmissionSchema.safeParse(raw.trim());
|
|
85
|
+
return parsed.success ? parsed.data : null;
|
|
86
|
+
}
|
|
87
|
+
/** Resolve one NUMERIC knob across the three precedence levels. */
|
|
88
|
+
function resolveKnob(knob, env) {
|
|
89
|
+
const fromSetting = parseKnob(knob, env[NATIVE_LEASE_SETTING_ENV_VARS[knob]]);
|
|
90
|
+
if (fromSetting !== null) return {
|
|
91
|
+
value: fromSetting,
|
|
92
|
+
source: "setting"
|
|
93
|
+
};
|
|
94
|
+
const fromEnv = parseKnob(knob, env[NATIVE_LEASE_ENV_VARS[knob]]);
|
|
95
|
+
if (fromEnv !== null) return {
|
|
96
|
+
value: fromEnv,
|
|
97
|
+
source: "env"
|
|
98
|
+
};
|
|
99
|
+
return {
|
|
100
|
+
value: require_dist.DEFAULT_NATIVE_LEASE_SETTINGS[knob],
|
|
101
|
+
source: "default"
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/** {@link resolveKnob} for `admission`. Same precedence, different parser. */
|
|
105
|
+
function resolveAdmission(env) {
|
|
106
|
+
const fromSetting = parseAdmission(env[NATIVE_LEASE_SETTING_ENV_VARS.admission]);
|
|
107
|
+
if (fromSetting !== null) return {
|
|
108
|
+
value: fromSetting,
|
|
109
|
+
source: "setting"
|
|
110
|
+
};
|
|
111
|
+
const fromEnv = parseAdmission(env[NATIVE_LEASE_ENV_VARS.admission]);
|
|
112
|
+
if (fromEnv !== null) return {
|
|
113
|
+
value: fromEnv,
|
|
114
|
+
source: "env"
|
|
115
|
+
};
|
|
116
|
+
return {
|
|
117
|
+
value: require_dist.DEFAULT_NATIVE_LEASE_SETTINGS.admission,
|
|
118
|
+
source: "default"
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
/** Resolve all four lease knobs from an environment. Pure. */
|
|
122
|
+
function resolveNativeLeaseKnobs(env) {
|
|
123
|
+
const ttlMs = resolveKnob("ttlMs", env);
|
|
124
|
+
const budgetMb = resolveKnob("budgetMb", env);
|
|
125
|
+
const activityMs = resolveKnob("activityMs", env);
|
|
126
|
+
const admission = resolveAdmission(env);
|
|
127
|
+
return {
|
|
128
|
+
values: {
|
|
129
|
+
ttlMs: ttlMs.value,
|
|
130
|
+
budgetMb: budgetMb.value,
|
|
131
|
+
activityMs: activityMs.value,
|
|
132
|
+
admission: admission.value
|
|
133
|
+
},
|
|
134
|
+
sources: {
|
|
135
|
+
ttlMs: ttlMs.source,
|
|
136
|
+
budgetMb: budgetMb.source,
|
|
137
|
+
activityMs: activityMs.source,
|
|
138
|
+
admission: admission.source
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* The env fragment the parent merges into a decode worker's `fork` environment.
|
|
144
|
+
* Emits ONLY the knobs the operator actually set — an empty result leaves the
|
|
145
|
+
* env override fully functional, which is the whole point of the distinction.
|
|
146
|
+
*/
|
|
147
|
+
function nativeLeaseSettingEnv(override) {
|
|
148
|
+
const out = {};
|
|
149
|
+
for (const knob of NATIVE_LEASE_KNOBS) {
|
|
150
|
+
const value = override[knob];
|
|
151
|
+
if (value !== void 0) out[NATIVE_LEASE_SETTING_ENV_VARS[knob]] = String(value);
|
|
152
|
+
}
|
|
153
|
+
return out;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* The one-line spawn diagnostic. Names the effective value AND its source for
|
|
157
|
+
* every knob: without the source, a log saying `ttlMs=2800` cannot distinguish
|
|
158
|
+
* "the operator's setting arrived" from "someone left a shell variable set", and
|
|
159
|
+
* a setting that silently fails to arrive is exactly the failure the distinct
|
|
160
|
+
* env-var names exist to make visible.
|
|
161
|
+
*/
|
|
162
|
+
function formatNativeLeaseKnobs(resolved) {
|
|
163
|
+
const part = (knob) => `${knob}=${resolved.values[knob]} source=${resolved.sources[knob]}`;
|
|
164
|
+
return `native lease knobs — ${NATIVE_LEASE_KNOBS.map(part).join("; ")}`;
|
|
165
|
+
}
|
|
166
|
+
//#endregion
|
|
167
|
+
//#region src/session-decode/worker-protocol.ts
|
|
168
|
+
/**
|
|
169
|
+
* Classify a worker diagnostic line into a {@link WorkerLogLevel}. Failure /
|
|
170
|
+
* fault lines surface at `warn` (visible at the default log level so a
|
|
171
|
+
* native-crop failure is finally seen in `addons.getLogs`); routine
|
|
172
|
+
* provenance / transition / lifecycle lines stay `debug`. Pure + exported so
|
|
173
|
+
* the mapping is unit-testable without spawning a worker.
|
|
174
|
+
*/
|
|
175
|
+
function logLevelForLine(line) {
|
|
176
|
+
return /\b(fail(?:ed|ure)?|error|exception|unhandled rejection|corrupt|EIO|EINVAL)\b/i.test(line) ? "warn" : "debug";
|
|
177
|
+
}
|
|
178
|
+
function isRecord(value) {
|
|
179
|
+
return typeof value === "object" && value !== null;
|
|
180
|
+
}
|
|
181
|
+
function isFiniteNumber(value) {
|
|
182
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
183
|
+
}
|
|
184
|
+
function isWorkerFrameFormat(value) {
|
|
185
|
+
return value === "rgb" || value === "gray";
|
|
186
|
+
}
|
|
187
|
+
function isWorkerLogLevel(value) {
|
|
188
|
+
return value === "debug" || value === "info" || value === "warn" || value === "error";
|
|
189
|
+
}
|
|
190
|
+
function isWorkerCropRegion(value) {
|
|
191
|
+
return isRecord(value) && isFiniteNumber(value.left) && isFiniteNumber(value.top) && isFiniteNumber(value.width) && isFiniteNumber(value.height);
|
|
192
|
+
}
|
|
193
|
+
function isWorkerResizeTarget(value) {
|
|
194
|
+
return isRecord(value) && isFiniteNumber(value.width) && isFiniteNumber(value.height);
|
|
195
|
+
}
|
|
196
|
+
function isFrameImageOptions(value) {
|
|
197
|
+
if (!isRecord(value)) return false;
|
|
198
|
+
if (value.crop !== void 0 && !isWorkerCropRegion(value.crop)) return false;
|
|
199
|
+
if (value.resize !== void 0 && !isWorkerResizeTarget(value.resize)) return false;
|
|
200
|
+
if (value.format !== void 0 && !isWorkerFrameFormat(value.format)) return false;
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
function isNormalizedBbox(value) {
|
|
204
|
+
return isRecord(value) && isFiniteNumber(value.x) && isFiniteNumber(value.y) && isFiniteNumber(value.w) && isFiniteNumber(value.h);
|
|
205
|
+
}
|
|
206
|
+
function isVideoFrameSource(value) {
|
|
207
|
+
return isRecord(value) && typeof value.restreamUrl === "string" && isFiniteNumber(value.deviceId) && typeof value.codec === "string";
|
|
208
|
+
}
|
|
209
|
+
function isVideoFrameGenOptions(value) {
|
|
210
|
+
if (!isRecord(value)) return false;
|
|
211
|
+
if (value.fps !== void 0 && !isFiniteNumber(value.fps)) return false;
|
|
212
|
+
if (value.format !== void 0 && !isWorkerFrameFormat(value.format)) return false;
|
|
213
|
+
return true;
|
|
214
|
+
}
|
|
215
|
+
/** Discriminated-union guard for {@link WorkerRequest} — no `as` casts. */
|
|
216
|
+
function isWorkerRequest(value) {
|
|
217
|
+
if (!isRecord(value)) return false;
|
|
218
|
+
switch (value.kind) {
|
|
219
|
+
case "start": return isVideoFrameSource(value.source) && isVideoFrameGenOptions(value.opts);
|
|
220
|
+
case "pull": return true;
|
|
221
|
+
case "toBuffer": return isFiniteNumber(value.frameId) && (value.opts === void 0 || isFrameImageOptions(value.opts));
|
|
222
|
+
case "nativeCrop": return isFiniteNumber(value.requestId) && isFiniteNumber(value.frameId) && isNormalizedBbox(value.bbox) && (value.maxWidth === void 0 || isFiniteNumber(value.maxWidth));
|
|
223
|
+
case "releaseNativeLease":
|
|
224
|
+
case "markInferred": return isFiniteNumber(value.frameId);
|
|
225
|
+
case "stop": return true;
|
|
226
|
+
default: return false;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
/** Discriminated-union guard for {@link WorkerReply} — no `as` casts. */
|
|
230
|
+
function isWorkerReply(value) {
|
|
231
|
+
if (!isRecord(value)) return false;
|
|
232
|
+
switch (value.kind) {
|
|
233
|
+
case "frame": return isFiniteNumber(value.frameId) && isFiniteNumber(value.timestamp) && isFiniteNumber(value.width) && isFiniteNumber(value.height) && isWorkerFrameFormat(value.format);
|
|
234
|
+
case "buffer": return isFiniteNumber(value.frameId) && value.bytes instanceof Uint8Array;
|
|
235
|
+
case "nativeCropResult": return isFiniteNumber(value.requestId) && value.bytes instanceof Uint8Array && isFiniteNumber(value.width) && isFiniteNumber(value.height);
|
|
236
|
+
case "nativeCropMiss": return isFiniteNumber(value.requestId) && (value.reason === void 0 || typeof value.reason === "string");
|
|
237
|
+
case "ended": return true;
|
|
238
|
+
case "error": return typeof value.message === "string" && (value.frameId === void 0 || isFiniteNumber(value.frameId));
|
|
239
|
+
case "log": return isWorkerLogLevel(value.level) && typeof value.message === "string";
|
|
240
|
+
default: return false;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
//#endregion
|
|
244
|
+
Object.defineProperty(exports, "formatNativeLeaseKnobs", {
|
|
245
|
+
enumerable: true,
|
|
246
|
+
get: function() {
|
|
247
|
+
return formatNativeLeaseKnobs;
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
Object.defineProperty(exports, "isWorkerReply", {
|
|
251
|
+
enumerable: true,
|
|
252
|
+
get: function() {
|
|
253
|
+
return isWorkerReply;
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
Object.defineProperty(exports, "isWorkerRequest", {
|
|
257
|
+
enumerable: true,
|
|
258
|
+
get: function() {
|
|
259
|
+
return isWorkerRequest;
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
Object.defineProperty(exports, "logLevelForLine", {
|
|
263
|
+
enumerable: true,
|
|
264
|
+
get: function() {
|
|
265
|
+
return logLevelForLine;
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
Object.defineProperty(exports, "nativeLeaseSettingEnv", {
|
|
269
|
+
enumerable: true,
|
|
270
|
+
get: function() {
|
|
271
|
+
return nativeLeaseSettingEnv;
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
Object.defineProperty(exports, "resolveNativeLeaseKnobs", {
|
|
275
|
+
enumerable: true,
|
|
276
|
+
get: function() {
|
|
277
|
+
return resolveNativeLeaseKnobs;
|
|
278
|
+
}
|
|
279
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{d as e,f as t,g as n,h as r,m as i,p as a}from"./index-
|
|
1
|
+
import{d as e,f as t,g as n,h as r,m as i,p as a}from"./index-4CtQAybX.js";var o=n(t()),s=n(e(),1),c=Math.PI/180;function l(){return typeof window<`u`&&({}.toString.call(window)===`[object Window]`||{}.toString.call(window)===`[object global]`)}var u=typeof global<`u`?global:typeof window<`u`?window:typeof WorkerGlobalScope<`u`?self:{},d={_global:u,version:`10.3.0`,isBrowser:l(),isUnminified:/param/.test(function(e){}.toString()),dblClickWindow:400,getAngle(e){return d.angleDeg?e*c:e},enableTrace:!1,pointerEventsEnabled:!0,autoDrawEnabled:!0,hitOnDragEnabled:!1,capturePointerEventsEnabled:!1,_mouseListenClick:!1,_touchListenClick:!1,_pointerListenClick:!1,_mouseInDblClickWindow:!1,_touchInDblClickWindow:!1,_pointerInDblClickWindow:!1,_mouseDblClickPointerId:null,_touchDblClickPointerId:null,_pointerDblClickPointerId:null,_renderBackend:`web`,legacyTextRendering:!1,pixelRatio:typeof window<`u`&&window.devicePixelRatio||1,dragDistance:3,angleDeg:!0,showWarnings:!0,dragButtons:[0,1],isDragging(){return d.DD.isDragging},isTransforming(){return d.Transformer?.isTransforming()??!1},isDragReady(){return!!d.DD.node},releaseCanvasOnDestroy:!0,document:u.document,_injectGlobal(e){u.Konva!==void 0&&console.error(`Several Konva instances detected. It is not recommended to use multiple Konva instances in the same environment.`),u.Konva=e}},f=e=>{d[e.prototype.getClassName()]=e};d._injectGlobal(d);var p=`Konva.js unsupported environment.
|
|
2
2
|
|
|
3
3
|
Looks like you are trying to use Konva.js in Node.js environment. because "document" object is undefined.
|
|
4
4
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as e,c as t,d as n,f as r,g as i,l as a,o,r as s,s as c,u as l}from"./index-
|
|
1
|
+
import{a as e,c as t,d as n,f as r,g as i,l as a,o,r as s,s as c,u as l}from"./index-4CtQAybX.js";import{MaskShapeCanvas as u}from"./MaskShapeCanvas-DI4BY7W2-DHZuYYjH.js";var d=i(r(),1),f=i(n(),1),p=o(`grid-2x2`,[[`path`,{d:`M12 3v18`,key:`108xh3`}],[`path`,{d:`M3 12h18`,key:`1i2n21`}],[`rect`,{x:`3`,y:`3`,width:`18`,height:`18`,rx:`2`,key:`h1oib`}]]),m=110,h=`motion-zones`,g=0,_=[1,2,3],v=1,y=`rounded-md border border-border bg-surface px-2 py-1 text-[11px] font-medium text-foreground-subtle hover:bg-surface-hover disabled:opacity-40 transition-colors`,b=`rounded-md border border-primary/50 bg-primary/15 px-2.5 py-1 text-[11px] font-medium text-primary hover:bg-primary/25 disabled:opacity-40 transition-colors`;function x(e,t,n){let r=t*n,i=Array.from({length:r});for(let t=0;t<r;t+=1)i[t]=e[t]===!0;return i}function S(e,t){if(e.length!==t.length)return!1;for(let n=0;n<e.length;n+=1)if(e[n]!==t[n])return!1;return!0}function C(e,t){return Math.ceil(e/t)}function w(e,t,n){return Math.min(n-1,Math.floor((e+.5)/t*n))}function T(e,t,n,r){let i=C(t,r),a=C(n,r),o=Array.from({length:i*a},()=>!1);for(let r=0;r<n;r+=1){let s=w(r,n,a);for(let n=0;n<t;n+=1)e[r*t+n]===!0&&(o[s*i+w(n,t,i)]=!0)}return o}function E(e,t,n,r){let i=C(t,r),a=C(n,r),o=Array.from({length:t*n},()=>!1);for(let r=0;r<n;r+=1){let s=w(r,n,a);for(let n=0;n<t;n+=1)o[r*t+n]=e[s*i+w(n,t,i)]===!0}return o}function D({deviceId:n}){let r=t(l().trpcClient,n),[i,o]=(0,d.useState)(null),[w,D]=(0,d.useState)(!1),[O,k]=(0,d.useState)(null),[A,j]=(0,d.useState)(null),[M,N]=(0,d.useState)(v),[P,F]=(0,d.useState)(!1),[I,L]=(0,d.useState)(!1),R=(0,d.useRef)(!1);(0,d.useEffect)(()=>{if(!r)return;let e=!1;return R.current=!1,o(null),D(!1),k(null),j(null),N(v),L(!1),(async()=>{try{let t=await r.motionZones?.getOptions({});if(e)return;if(!t)throw Error(`device proxy not ready`);if(o(t),R.current)return;let n=await r.motionZones?.getStatus({});if(e)return;if(!n)throw Error(`device proxy not ready`);R.current=!0;let i=n.regions.find(e=>e.shape.kind===`grid`),a=x(i?i.shape.cells:[],t.grid.width,t.grid.height);j(a),k(T(a,t.grid.width,t.grid.height,v))}catch(t){if(e)return;c(t)?D(!0):console.error(`Motion Zones load failed`,t)}})(),()=>{e=!0}},[r]);let z=i?i.grid.width:0,B=i?i.grid.height:0,V=C(z,M),H=C(B,M),U=(0,d.useMemo)(()=>O&&i?E(O,z,B,M):null,[O,i,z,B,M]),W=(0,d.useMemo)(()=>U!==null&&A!==null&&!S(U,A),[U,A]),G=(0,d.useMemo)(()=>U?U.reduce((e,t)=>t?e+1:e,0):0,[U]),K=z*B,q=V*H,J=(0,d.useCallback)(e=>{q>0&&k(Array.from({length:q},()=>e))},[q]),Y=(0,d.useCallback)(()=>{k(e=>e&&e.map(e=>!e))},[]),X=(0,d.useCallback)(()=>{A&&i&&k(T(A,z,B,M))},[A,i,z,B,M]),Z=(0,d.useCallback)(e=>{e===M||!i||k(t=>{if(!t)return N(e),t;let n=T(E(t,z,B,M),z,B,e);return N(e),n})},[M,i,z,B]),Q=(0,d.useMemo)(()=>i&&O?[{id:g,shape:{kind:`grid`,gridWidth:V,gridHeight:H,cells:[...O]}}]:[],[i,O,V,H]),$=(0,d.useCallback)((e,t)=>{t.kind===`grid`&&k(t.cells)},[]),ee=(0,d.useCallback)(async()=>{if(!(!r||!O||!i)){F(!0);try{let e=E(O,i.grid.width,i.grid.height,M),t={kind:`grid`,gridWidth:i.grid.width,gridHeight:i.grid.height,cells:e};await r.motionZones?.setZone({patch:{regions:[{id:g,enabled:!0,shape:t}]}});let n=await r.motionZones?.getStatus({});if(n){let e=n.regions.find(e=>e.shape.kind===`grid`),t=x(e?e.shape.cells:[],i.grid.width,i.grid.height);j(t),k(T(t,i.grid.width,i.grid.height,M))}}catch(e){console.error(`Motion Zones save failed`,e)}finally{F(!1)}}},[r,O,i,M]);a((0,d.useMemo)(()=>I&&!w&&i&&O?{id:h,order:m,node:(0,f.jsx)(u,{transparent:!0,items:Q,supportedShapes:[`grid`],grid:{width:V,height:H},selectedId:g,onSelect:()=>{},onShapeChange:$,onDrawComplete:()=>{},drawingKind:null})}:null,[I,w,i,O,Q,$,V,H]));let te=!w&&i!==null&&O!==null;return r?(0,f.jsx)(e,{title:`Motion Zones`,icon:(0,f.jsx)(p,{className:`h-3.5 w-3.5 text-foreground-subtle`}),children:(0,f.jsx)(`div`,{className:`flex flex-col gap-3`,children:w?(0,f.jsx)(`p`,{className:`${s} leading-relaxed`,children:`This camera doesn't expose an on-board motion zones grid.`}):te?(0,f.jsxs)(f.Fragment,{children:[(0,f.jsxs)(`p`,{className:`${s} leading-relaxed`,children:[`Toggle `,(0,f.jsx)(`strong`,{className:`text-foreground`,children:`Edit grid`}),` to paint the region directly on the live frame, then `,(0,f.jsx)(`strong`,{className:`text-foreground`,children:`Save`}),` to push the mask to the camera. Pick a bigger`,` `,(0,f.jsx)(`strong`,{className:`text-foreground`,children:`Cell size`}),` for quicker, broad-stroke painting — it's resampled to the camera's native `,i.grid.width,`×`,i.grid.height,` grid on save (×1 is the finest).`]}),(0,f.jsxs)(`div`,{className:`flex items-center gap-2 flex-wrap`,children:[(0,f.jsx)(`button`,{type:`button`,onClick:()=>L(e=>!e),disabled:P,"aria-pressed":I,className:I?b:y,children:I?`Done editing`:`Edit grid`}),(0,f.jsx)(`button`,{type:`button`,onClick:()=>J(!0),disabled:P,className:y,children:`All on`}),(0,f.jsx)(`button`,{type:`button`,onClick:()=>J(!1),disabled:P,className:y,children:`All off`}),(0,f.jsx)(`button`,{type:`button`,onClick:Y,disabled:P,className:y,children:`Invert`}),(0,f.jsxs)(`div`,{className:`flex items-center gap-1 ml-1`,role:`group`,"aria-label":`Cell size`,children:[(0,f.jsx)(`span`,{className:`${s} mr-0.5`,children:`Cell size`}),_.map(e=>(0,f.jsxs)(`button`,{type:`button`,onClick:()=>Z(e),disabled:P,"aria-pressed":M===e,title:e===1?`Camera grid ${z}×${B} (finest)`:`${C(z,e)}×${C(B,e)} painting grid · cells ×${e} bigger`,className:M===e?b:y,children:[`×`,e]},e))]}),(0,f.jsxs)(`span`,{className:`${s} ml-1 tabular-nums`,children:[G,` / `,K,` cells · `,i.grid.width,`×`,i.grid.height,M===1?``:` · paint ${V}×${H}`]}),(0,f.jsx)(`span`,{className:`flex-1`}),(0,f.jsx)(`button`,{type:`button`,onClick:X,disabled:P||!W,className:`rounded-md border border-border bg-surface px-2 py-1 text-[11px] text-foreground-subtle hover:bg-surface-hover disabled:opacity-40 transition-colors`,children:`Revert`}),(0,f.jsx)(`button`,{type:`button`,onClick:()=>void ee(),disabled:P||!W,className:b,children:P?`Saving…`:`Save`})]})]}):(0,f.jsx)(`p`,{className:`${s} leading-relaxed`,children:`Loading the camera's grid…`})})}):null}export{D as MotionZonesSettings};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as e,c as t,d as n,f as r,g as i,i as a,l as o,n as s,o as c,r as l,s as u,t as d,u as ee}from"./index-
|
|
1
|
+
import{a as e,c as t,d as n,f as r,g as i,i as a,l as o,n as s,o as c,r as l,s as u,t as d,u as ee}from"./index-4CtQAybX.js";import{MaskShapeCanvas as te}from"./MaskShapeCanvas-DI4BY7W2-DHZuYYjH.js";var f=i(r(),1),p=i(n(),1),m=c(`hexagon`,[[`path`,{d:`M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z`,key:`yt0hxn`}]]),h=120,g=`privacy-mask`,_=`rounded-md border border-border bg-surface px-2 py-1 text-[11px] font-medium text-foreground-subtle hover:bg-surface-hover disabled:opacity-40 transition-colors`,v=`rounded-md border border-primary/50 bg-primary/15 px-2.5 py-1 text-[11px] font-medium text-primary hover:bg-primary/25 disabled:opacity-40 transition-colors`;function y(e){return e.kind===`rect`||e.kind===`polygon`?e:null}function b(e){let t=new Set(e.map(e=>e.id)),n=0;for(;t.has(n);)n+=1;return n}function x(e,t){if(e.length!==t.length)return!1;for(let n=0;n<e.length;n+=1)if(JSON.stringify(e[n])!==JSON.stringify(t[n]))return!1;return!0}function S({deviceId:n}){let r=t(ee().trpcClient,n),[i,c]=(0,f.useState)(null),[S,C]=(0,f.useState)(!1),[w,T]=(0,f.useState)(null),[E,D]=(0,f.useState)(null),[O,k]=(0,f.useState)(!1),[A,j]=(0,f.useState)(!1),[M,N]=(0,f.useState)(null),[P,F]=(0,f.useState)(null),I=(0,f.useRef)(!1);(0,f.useEffect)(()=>{if(!r)return;let e=!1;return I.current=!1,c(null),C(!1),T(null),D(null),j(!1),N(null),F(null),(async()=>{try{let t=await r.privacyMask?.getOptions({});if(e)return;if(!t)throw Error(`device proxy not ready`);if(c(t),I.current)return;let n=await r.privacyMask?.getStatus({});if(e)return;if(!n)throw Error(`device proxy not ready`);I.current=!0;let i={enabled:n.enabled,regions:n.regions};D(i),T(i)}catch(t){if(e)return;u(t)?C(!0):console.error(`Privacy Mask load failed`,t)}})(),()=>{e=!0}},[r]);let L=(0,f.useMemo)(()=>w!==null&&E!==null&&(w.enabled!==E.enabled||!x(w.regions,E.regions)),[w,E]),R=w?w.regions.length:0,z=i?i.maxRegions:0,B=(0,f.useRef)(0);(0,f.useEffect)(()=>{B.current=z},[z]);let V=z>0&&R>=z,H=(0,f.useCallback)(()=>{T(e=>e&&{...e,enabled:!e.enabled})},[]),U=(0,f.useCallback)(e=>{N(typeof e==`number`?e:null)},[]),W=(0,f.useMemo)(()=>w?w.regions.map(e=>({id:e.id,shape:e.shape,enabled:e.enabled,label:`Zone ${String(e.id)}`})):[],[w]),G=(0,f.useCallback)((e,t)=>{let n=y(t);n&&T(t=>t&&{...t,regions:t.regions.map(t=>t.id===e?{...t,shape:n}:t)})},[]),K=(0,f.useCallback)(e=>{let t=y(e);t&&(F(null),T(e=>{if(!e)return e;let n=B.current;if(n>0&&e.regions.length>=n)return e;let r=b(e.regions),i={id:r,enabled:!0,shape:t};return N(r),{...e,regions:[...e.regions,i]}}))},[]),q=(0,f.useCallback)(e=>{j(!0),N(null),F(e)},[]),J=(0,f.useCallback)(e=>{j(!0),F(null),N(e)},[]),Y=(0,f.useCallback)(e=>{N(t=>t===e?null:t),T(t=>t&&{...t,regions:t.regions.filter(t=>t.id!==e)})},[]),X=(0,f.useCallback)(()=>{F(null),N(null),E&&T({enabled:E.enabled,regions:E.regions})},[E]),Z=(0,f.useCallback)(async()=>{if(!(!r||!w)){k(!0);try{await r.privacyMask?.setMask({patch:{enabled:w.enabled,regions:[...w.regions]}});let e=await r.privacyMask?.getStatus({});if(e){let t={enabled:e.enabled,regions:e.regions};D(t),T(t)}}catch(e){console.error(`Privacy Mask save failed`,e)}finally{k(!1)}}},[r,w]),ne=(0,f.useCallback)(()=>{j(e=>(e&&(F(null),N(null)),!e))},[]),Q=i?.supportedShapes??[];o((0,f.useMemo)(()=>A&&!S&&i&&w?{id:g,order:h,node:(0,p.jsx)(te,{transparent:!0,items:W,supportedShapes:Q,polygonVertices:i.polygonVertices,selectedId:M,onSelect:U,onShapeChange:G,onDrawComplete:K,drawingKind:P})}:null,[A,S,i,w,W,Q,M,U,G,K,P]));let re=i?.supportedShapes.includes(`rect`)??!1,ie=i?.supportedShapes.includes(`polygon`)??!1,$=i!==null&&(i.maxRegions<=0||i.supportedShapes.length===0),ae=!S&&!$&&i!==null&&w!==null;return r?(0,p.jsx)(e,{title:`Privacy Mask`,icon:(0,p.jsx)(d,{className:`h-3.5 w-3.5 text-foreground-subtle`}),children:(0,p.jsx)(`div`,{className:`flex flex-col gap-3`,children:S||$?(0,p.jsx)(`p`,{className:`${l} leading-relaxed`,children:`This camera doesn't support an on-board privacy mask.`}):ae?(0,p.jsxs)(p.Fragment,{children:[(0,p.jsxs)(`p`,{className:`${l} leading-relaxed`,children:[`Toggle `,(0,p.jsx)(`strong`,{className:`text-foreground`,children:`Edit mask`}),` to draw blanked-out zones on the live frame, then `,(0,p.jsx)(`strong`,{className:`text-foreground`,children:`Save`}),` to push them to the camera. Drag a rectangle to move, its corner to resize; drag polygon vertices, click an edge midpoint to add one, or right-click a vertex to remove it.`]}),(0,p.jsxs)(`div`,{className:`flex items-center gap-2 flex-wrap`,children:[(0,p.jsx)(`button`,{type:`button`,onClick:ne,disabled:O,"aria-pressed":A,className:A?v:_,children:A?`Done editing`:`Edit mask`}),(0,p.jsx)(`button`,{type:`button`,onClick:H,disabled:O,"aria-pressed":w.enabled,className:w.enabled?v:_,children:w.enabled?`Mask on`:`Mask off`}),re&&(0,p.jsx)(`button`,{type:`button`,onClick:()=>q(`rect`),disabled:O||V,"aria-pressed":P===`rect`,className:P===`rect`?v:_,title:V?`Maximum zones reached`:`Add a rectangle zone`,children:`+ Rect`}),ie&&(0,p.jsx)(`button`,{type:`button`,onClick:()=>q(`polygon`),disabled:O||V,"aria-pressed":P===`polygon`,className:P===`polygon`?v:_,title:V?`Maximum zones reached`:`Add a polygon zone`,children:`+ Polygon`}),(0,p.jsxs)(`span`,{className:`${l} ml-1 tabular-nums`,children:[R,` / `,z,` zones`]}),(0,p.jsx)(`span`,{className:`flex-1`}),(0,p.jsx)(`button`,{type:`button`,onClick:X,disabled:O||!L,className:`rounded-md border border-border bg-surface px-2 py-1 text-[11px] text-foreground-subtle hover:bg-surface-hover disabled:opacity-40 transition-colors`,children:`Revert`}),(0,p.jsx)(`button`,{type:`button`,onClick:()=>void Z(),disabled:O||!L,className:v,children:O?`Saving…`:`Save`})]}),R>0?(0,p.jsx)(`div`,{className:`flex flex-col gap-1`,children:w.regions.map(e=>{let t=M===e.id,n=e.shape.kind===`polygon`?m:s;return(0,p.jsxs)(`div`,{className:`flex items-center gap-2 rounded-md border px-2 py-1 transition-colors ${t?`border-primary/50 bg-primary/10`:`border-border bg-surface`}`,children:[(0,p.jsxs)(`button`,{type:`button`,onClick:()=>J(e.id),disabled:O,className:`flex flex-1 items-center gap-2 text-left text-[11px] font-medium text-foreground-subtle hover:text-foreground disabled:opacity-40 transition-colors`,children:[(0,p.jsx)(n,{className:`h-3.5 w-3.5 shrink-0`}),(0,p.jsxs)(`span`,{children:[`Zone `,e.id]}),(0,p.jsx)(`span`,{className:`text-foreground-faint capitalize`,children:e.shape.kind})]}),(0,p.jsx)(`button`,{type:`button`,onClick:()=>Y(e.id),disabled:O,"aria-label":`Delete zone ${String(e.id)}`,title:`Delete zone`,className:`inline-flex h-6 w-6 items-center justify-center rounded border border-border bg-surface text-foreground-subtle hover:border-red-400/40 hover:bg-red-500/10 hover:text-red-400 disabled:opacity-40 transition-colors`,children:(0,p.jsx)(a,{className:`h-3.5 w-3.5`})})]},e.id)})}):null]}):(0,p.jsx)(`p`,{className:`${l} leading-relaxed`,children:`Loading the camera's privacy mask…`})})}):null}export{S as PrivacyMaskSettings};
|