@camstack/addon-motion-wasm 0.1.1

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.
@@ -0,0 +1,34 @@
1
+ var __getOwnPropNames = Object.getOwnPropertyNames;
2
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
3
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
4
+ }) : x)(function(x) {
5
+ if (typeof require !== "undefined") return require.apply(this, arguments);
6
+ throw Error('Dynamic require of "' + x + '" is not supported');
7
+ });
8
+ var __esm = (fn, res) => function __init() {
9
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
+ };
11
+ var __commonJS = (cb, mod) => function __require2() {
12
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
13
+ };
14
+
15
+ // ../../node_modules/tsup/assets/esm_shims.js
16
+ import path from "path";
17
+ import { fileURLToPath } from "url";
18
+ var getFilename, getDirname, __dirname;
19
+ var init_esm_shims = __esm({
20
+ "../../node_modules/tsup/assets/esm_shims.js"() {
21
+ "use strict";
22
+ getFilename = () => fileURLToPath(import.meta.url);
23
+ getDirname = () => path.dirname(getFilename());
24
+ __dirname = /* @__PURE__ */ getDirname();
25
+ }
26
+ });
27
+
28
+ export {
29
+ __require,
30
+ __commonJS,
31
+ __dirname,
32
+ init_esm_shims
33
+ };
34
+ //# sourceMappingURL=chunk-FXGWBT3O.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../node_modules/tsup/assets/esm_shims.js"],"sourcesContent":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n"],"mappings":";;;;;;;;;;;;;;;AACA,OAAO,UAAU;AACjB,SAAS,qBAAqB;AAF9B,IAIM,aACA,YAEO;AAPb;AAAA;AAAA;AAIA,IAAM,cAAc,MAAM,cAAc,YAAY,GAAG;AACvD,IAAM,aAAa,MAAM,KAAK,QAAQ,YAAY,CAAC;AAE5C,IAAM,YAA4B,2BAAW;AAAA;AAAA;","names":[]}
@@ -0,0 +1,129 @@
1
+ import { BaseAddon, IMotionDetectionProvider, ProviderRegistration, FrameInput, DetectorOutput, SpatialDetection, MotionAnalysisResult, ConfigUISchema, ConfigUISchemaWithValues } from '@camstack/types';
2
+
3
+ declare class MotionWasmAddon extends BaseAddon implements IMotionDetectionProvider {
4
+ private detector;
5
+ private readonly cameras;
6
+ private readonly deviceConfigCache;
7
+ private static readonly DEVICE_CONFIG_TTL_MS;
8
+ /**
9
+ * Per-device {@link DeviceProxy} used for zone gating. Built lazily
10
+ * on first analyze() for a device; the proxy's reactive state
11
+ * handles (`state.zones`, `state.zoneRules`) keep their `.value`
12
+ * fresh via the kernel's runtime-state mirror, so the gate reads
13
+ * are sync and free of bus plumbing inside this addon.
14
+ */
15
+ private readonly proxies;
16
+ /** Unsubscribe pins kept so the slice handles stay subscribed for
17
+ * the camera's lifetime — `.value` only flows through the cache
18
+ * when at least one watcher is active. */
19
+ private readonly proxyUnsubs;
20
+ constructor();
21
+ protected onInitialize(): Promise<ProviderRegistration[]>;
22
+ private static readonly PIPELINE_STEP_KEY;
23
+ /**
24
+ * Pipeline step interface — called by PipelineRunner.
25
+ * Uses single-camera state (one instance per camera via AddonEngineManager).
26
+ */
27
+ process(input: FrameInput): Promise<DetectorOutput & {
28
+ rawDetections: ReadonlyArray<SpatialDetection>;
29
+ }>;
30
+ /**
31
+ * motion-detection cap: analyze a frame, return regions + stats.
32
+ * Per-device state keyed by the numeric deviceId (stringified internally
33
+ * so the pipeline-step sentinel shares the same Map).
34
+ */
35
+ analyze({ deviceId, frame }: {
36
+ deviceId: number;
37
+ frame: FrameInput;
38
+ }): Promise<MotionAnalysisResult>;
39
+ private analyzeInternal;
40
+ /**
41
+ * Resolve (and cache) a {@link DeviceProxy} for the given device.
42
+ * Pins the `state.zones` + `state.zoneRules` slice handles so the
43
+ * kernel runtime-state mirror keeps `.value` warm — subsequent
44
+ * analyze() calls read both slices synchronously without any bus
45
+ * plumbing or per-frame cap query. Returns null on first-call
46
+ * failure (logged) so motion analysis never blocks on zone
47
+ * resolution.
48
+ */
49
+ private ensureProxy;
50
+ /** Drop the proxy + slice subscriptions for a device. */
51
+ private releaseProxy;
52
+ /**
53
+ * Resolve the effective per-device config for a camera. Reads the raw
54
+ * device store and overlays it on top of the schema defaults via
55
+ * `hydrateSchema()`, then narrows to the typed `WasmMotionConfig` shape.
56
+ * Cached with a TTL to avoid hammering the settings store on every frame.
57
+ */
58
+ private getDeviceConfig;
59
+ removeCamera({ deviceId }: {
60
+ deviceId: number;
61
+ }): Promise<void>;
62
+ reset(): Promise<void>;
63
+ protected onShutdown(): Promise<void>;
64
+ protected deviceSettingsSchema(): ConfigUISchema;
65
+ getDeviceSettings(deviceId: number): Promise<ConfigUISchemaWithValues>;
66
+ updateDeviceSettings(deviceId: number, patch: Record<string, unknown>): Promise<void>;
67
+ getDeviceSettingsContribution(input: {
68
+ deviceId: number;
69
+ }): Promise<ConfigUISchemaWithValues | null>;
70
+ getDeviceLiveContribution(_input: {
71
+ deviceId: number;
72
+ }): Promise<ConfigUISchemaWithValues | null>;
73
+ applyDeviceSettingsPatch(input: {
74
+ deviceId: number;
75
+ patch: Record<string, unknown>;
76
+ }): Promise<{
77
+ success: true;
78
+ }>;
79
+ /**
80
+ * Best-effort camera-type check. Used by the settings/live contribution
81
+ * methods to short-circuit on non-camera devices (Lights, Switches,
82
+ * Sensors, Buttons). Returns `true` on lookup failure so a transient
83
+ * device-manager hiccup never silently hides legitimate camera
84
+ * sections.
85
+ */
86
+ private isCameraDevice;
87
+ }
88
+
89
+ interface WasmMotionConfig {
90
+ readonly threshold: number;
91
+ readonly blurRadius: number;
92
+ readonly dilateRadius: number;
93
+ readonly minArea: number;
94
+ }
95
+ interface WasmMotionRegion {
96
+ readonly x: number;
97
+ readonly y: number;
98
+ readonly w: number;
99
+ readonly h: number;
100
+ readonly pixels: number;
101
+ }
102
+ /** Result containing both all regions and those passing minArea filter. */
103
+ interface WasmMotionResult {
104
+ /** All regions from CCL (unfiltered). */
105
+ readonly raw: ReadonlyArray<WasmMotionRegion>;
106
+ /** Regions passing the minArea threshold. */
107
+ readonly filtered: ReadonlyArray<WasmMotionRegion>;
108
+ }
109
+ declare class WasmMotionDetector {
110
+ private wasm;
111
+ private prevOffset;
112
+ private currOffset;
113
+ private regionOffset;
114
+ /** Load the WASM module. Call once before detect(). */
115
+ load(): Promise<void>;
116
+ /** Initialize for given frame dimensions. Call when resolution changes. */
117
+ init(w: number, h: number): void;
118
+ /**
119
+ * Detect motion between previous and current grayscale frames.
120
+ *
121
+ * @param prevGray - previous frame (Uint8Array, width×height)
122
+ * @param currGray - current frame (Uint8Array, width×height)
123
+ * @param config - detection parameters (optional, uses defaults)
124
+ * @returns raw (all CCL regions) + filtered (passing minArea) regions
125
+ */
126
+ detect(prevGray: Uint8Array | Buffer, currGray: Uint8Array | Buffer, config?: Partial<WasmMotionConfig>): WasmMotionResult;
127
+ }
128
+
129
+ export { MotionWasmAddon, type WasmMotionConfig, WasmMotionDetector, type WasmMotionRegion };
@@ -0,0 +1,129 @@
1
+ import { BaseAddon, IMotionDetectionProvider, ProviderRegistration, FrameInput, DetectorOutput, SpatialDetection, MotionAnalysisResult, ConfigUISchema, ConfigUISchemaWithValues } from '@camstack/types';
2
+
3
+ declare class MotionWasmAddon extends BaseAddon implements IMotionDetectionProvider {
4
+ private detector;
5
+ private readonly cameras;
6
+ private readonly deviceConfigCache;
7
+ private static readonly DEVICE_CONFIG_TTL_MS;
8
+ /**
9
+ * Per-device {@link DeviceProxy} used for zone gating. Built lazily
10
+ * on first analyze() for a device; the proxy's reactive state
11
+ * handles (`state.zones`, `state.zoneRules`) keep their `.value`
12
+ * fresh via the kernel's runtime-state mirror, so the gate reads
13
+ * are sync and free of bus plumbing inside this addon.
14
+ */
15
+ private readonly proxies;
16
+ /** Unsubscribe pins kept so the slice handles stay subscribed for
17
+ * the camera's lifetime — `.value` only flows through the cache
18
+ * when at least one watcher is active. */
19
+ private readonly proxyUnsubs;
20
+ constructor();
21
+ protected onInitialize(): Promise<ProviderRegistration[]>;
22
+ private static readonly PIPELINE_STEP_KEY;
23
+ /**
24
+ * Pipeline step interface — called by PipelineRunner.
25
+ * Uses single-camera state (one instance per camera via AddonEngineManager).
26
+ */
27
+ process(input: FrameInput): Promise<DetectorOutput & {
28
+ rawDetections: ReadonlyArray<SpatialDetection>;
29
+ }>;
30
+ /**
31
+ * motion-detection cap: analyze a frame, return regions + stats.
32
+ * Per-device state keyed by the numeric deviceId (stringified internally
33
+ * so the pipeline-step sentinel shares the same Map).
34
+ */
35
+ analyze({ deviceId, frame }: {
36
+ deviceId: number;
37
+ frame: FrameInput;
38
+ }): Promise<MotionAnalysisResult>;
39
+ private analyzeInternal;
40
+ /**
41
+ * Resolve (and cache) a {@link DeviceProxy} for the given device.
42
+ * Pins the `state.zones` + `state.zoneRules` slice handles so the
43
+ * kernel runtime-state mirror keeps `.value` warm — subsequent
44
+ * analyze() calls read both slices synchronously without any bus
45
+ * plumbing or per-frame cap query. Returns null on first-call
46
+ * failure (logged) so motion analysis never blocks on zone
47
+ * resolution.
48
+ */
49
+ private ensureProxy;
50
+ /** Drop the proxy + slice subscriptions for a device. */
51
+ private releaseProxy;
52
+ /**
53
+ * Resolve the effective per-device config for a camera. Reads the raw
54
+ * device store and overlays it on top of the schema defaults via
55
+ * `hydrateSchema()`, then narrows to the typed `WasmMotionConfig` shape.
56
+ * Cached with a TTL to avoid hammering the settings store on every frame.
57
+ */
58
+ private getDeviceConfig;
59
+ removeCamera({ deviceId }: {
60
+ deviceId: number;
61
+ }): Promise<void>;
62
+ reset(): Promise<void>;
63
+ protected onShutdown(): Promise<void>;
64
+ protected deviceSettingsSchema(): ConfigUISchema;
65
+ getDeviceSettings(deviceId: number): Promise<ConfigUISchemaWithValues>;
66
+ updateDeviceSettings(deviceId: number, patch: Record<string, unknown>): Promise<void>;
67
+ getDeviceSettingsContribution(input: {
68
+ deviceId: number;
69
+ }): Promise<ConfigUISchemaWithValues | null>;
70
+ getDeviceLiveContribution(_input: {
71
+ deviceId: number;
72
+ }): Promise<ConfigUISchemaWithValues | null>;
73
+ applyDeviceSettingsPatch(input: {
74
+ deviceId: number;
75
+ patch: Record<string, unknown>;
76
+ }): Promise<{
77
+ success: true;
78
+ }>;
79
+ /**
80
+ * Best-effort camera-type check. Used by the settings/live contribution
81
+ * methods to short-circuit on non-camera devices (Lights, Switches,
82
+ * Sensors, Buttons). Returns `true` on lookup failure so a transient
83
+ * device-manager hiccup never silently hides legitimate camera
84
+ * sections.
85
+ */
86
+ private isCameraDevice;
87
+ }
88
+
89
+ interface WasmMotionConfig {
90
+ readonly threshold: number;
91
+ readonly blurRadius: number;
92
+ readonly dilateRadius: number;
93
+ readonly minArea: number;
94
+ }
95
+ interface WasmMotionRegion {
96
+ readonly x: number;
97
+ readonly y: number;
98
+ readonly w: number;
99
+ readonly h: number;
100
+ readonly pixels: number;
101
+ }
102
+ /** Result containing both all regions and those passing minArea filter. */
103
+ interface WasmMotionResult {
104
+ /** All regions from CCL (unfiltered). */
105
+ readonly raw: ReadonlyArray<WasmMotionRegion>;
106
+ /** Regions passing the minArea threshold. */
107
+ readonly filtered: ReadonlyArray<WasmMotionRegion>;
108
+ }
109
+ declare class WasmMotionDetector {
110
+ private wasm;
111
+ private prevOffset;
112
+ private currOffset;
113
+ private regionOffset;
114
+ /** Load the WASM module. Call once before detect(). */
115
+ load(): Promise<void>;
116
+ /** Initialize for given frame dimensions. Call when resolution changes. */
117
+ init(w: number, h: number): void;
118
+ /**
119
+ * Detect motion between previous and current grayscale frames.
120
+ *
121
+ * @param prevGray - previous frame (Uint8Array, width×height)
122
+ * @param currGray - current frame (Uint8Array, width×height)
123
+ * @param config - detection parameters (optional, uses defaults)
124
+ * @returns raw (all CCL regions) + filtered (passing minArea) regions
125
+ */
126
+ detect(prevGray: Uint8Array | Buffer, currGray: Uint8Array | Buffer, config?: Partial<WasmMotionConfig>): WasmMotionResult;
127
+ }
128
+
129
+ export { MotionWasmAddon, type WasmMotionConfig, WasmMotionDetector, type WasmMotionRegion };