@camera.ui/cli 0.0.48 → 0.0.50

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 (54) hide show
  1. package/LICENSE.md +1 -1
  2. package/README.md +10 -1
  3. package/dist/commands/artifacts.d.ts +9 -0
  4. package/dist/commands/artifacts.js +107 -0
  5. package/dist/commands/artifacts.js.map +1 -0
  6. package/dist/commands/bundle.d.ts +19 -1
  7. package/dist/commands/bundle.js +368 -56
  8. package/dist/commands/bundle.js.map +1 -1
  9. package/dist/commands/create.js +140 -93
  10. package/dist/commands/create.js.map +1 -1
  11. package/dist/commands/publish.js +77 -36
  12. package/dist/commands/publish.js.map +1 -1
  13. package/dist/index.js +11 -4
  14. package/dist/index.js.map +1 -1
  15. package/dist/types.d.ts +21 -5
  16. package/dist/utils/banners.d.ts +3 -1
  17. package/dist/utils/banners.js +15 -11
  18. package/dist/utils/banners.js.map +1 -1
  19. package/dist/utils/logger.d.ts +12 -24
  20. package/dist/utils/logger.js +57 -83
  21. package/dist/utils/logger.js.map +1 -1
  22. package/dist/utils/parser.d.ts +11 -4
  23. package/dist/utils/parser.js +27 -186
  24. package/dist/utils/parser.js.map +1 -1
  25. package/dist/utils/templates.d.ts +13 -1
  26. package/dist/utils/templates.js +148 -68
  27. package/dist/utils/templates.js.map +1 -1
  28. package/dist/utils/utils.js +13 -11
  29. package/dist/utils/utils.js.map +1 -1
  30. package/dist/utils/versions.js +1 -2
  31. package/dist/utils/versions.js.map +1 -1
  32. package/package.json +29 -43
  33. package/templates/base/README.md +2 -2
  34. package/templates/base/SECURITY.md +1 -1
  35. package/templates/base/package.json +2 -3
  36. package/templates/base/updates.config.js +1 -1
  37. package/templates/go/go.mod +5 -0
  38. package/templates/go/postinstall.js +35 -0
  39. package/templates/go/src/main.go +51 -0
  40. package/templates/python/requirements.txt +1 -1
  41. package/templates/python/ruff.toml +2 -2
  42. package/templates/python/src/main.py +299 -28
  43. package/templates/typescript/contract.ts +36 -0
  44. package/templates/typescript/eslint.config.js +13 -3
  45. package/templates/typescript/package.eslint.json +2 -2
  46. package/templates/typescript/package.json +4 -4
  47. package/templates/typescript/src/index.ts +96 -27
  48. package/templates/typescript/src/sensor.ts +207 -0
  49. package/CHANGELOG.md +0 -8
  50. package/CONTRIBUTING.md +0 -1
  51. package/scripts/chmod.js +0 -17
  52. package/templates/base/cameraui.config.js +0 -10
  53. package/templates/base/eslint.config.js +0 -64
  54. package/templates/base/src/index.js +0 -41
@@ -0,0 +1,207 @@
1
+ import { ClassifierDetectorSensor, LightControl, MotionSensor } from '@camera.ui/sdk';
2
+
3
+ import type { CameraDevice, ClassifierResult, Detection, JsonSchema, ModelSpec, VideoFrameData } from '@camera.ui/sdk';
4
+
5
+ // ============ MOTION SENSOR (External Events) ============
6
+
7
+ /**
8
+ * Example Motion Sensor
9
+ *
10
+ * Use this for external motion sources:
11
+ * - ONVIF camera events
12
+ * - SMTP notifications
13
+ * - Webhook triggers
14
+ * - API polling
15
+ *
16
+ * For frame-based detection, extend MotionDetectorSensor instead.
17
+ */
18
+ export class ExampleMotionSensor extends MotionSensor {
19
+ constructor(name: string) {
20
+ super(name);
21
+ }
22
+
23
+ /**
24
+ * Trigger motion from external event
25
+ */
26
+ trigger(detections: Detection[] = []): void {
27
+ this.detected = true;
28
+ this.detections = detections;
29
+ }
30
+
31
+ /**
32
+ * Clear motion state
33
+ */
34
+ reset(): void {
35
+ this.detected = false;
36
+ this.detections = [];
37
+ }
38
+ }
39
+
40
+ // ============ LIGHT CONTROL ============
41
+
42
+ /**
43
+ * Example Light Control
44
+ *
45
+ * Bidirectional control sensor - consumers can read and write state.
46
+ * Implements setOn/setBrightness to handle state changes.
47
+ */
48
+ export class ExampleLightControl extends LightControl {
49
+ private cameraDevice: CameraDevice;
50
+
51
+ /**
52
+ * Storage schema for per-sensor configuration
53
+ * These settings are persisted and shown in the UI.
54
+ */
55
+ schema: JsonSchema[] = [
56
+ {
57
+ type: 'number',
58
+ key: 'defaultBrightness',
59
+ title: 'Default Brightness',
60
+ description: 'Default brightness level (0-100)',
61
+ defaultValue: 100,
62
+ minimum: 0,
63
+ maximum: 100,
64
+ store: true,
65
+ },
66
+ {
67
+ type: 'boolean',
68
+ key: 'autoOff',
69
+ title: 'Auto-Off',
70
+ description: 'Automatically turn off after timeout',
71
+ defaultValue: false,
72
+ store: true,
73
+ },
74
+ ];
75
+
76
+ constructor(camera: CameraDevice, name = 'Light') {
77
+ super(name);
78
+ this.cameraDevice = camera;
79
+
80
+ // Initialize state
81
+ this.on = false;
82
+ this.brightness = 100;
83
+
84
+ // Log state changes
85
+ this.onPropertyChanged.subscribe(({ property, value }) => {
86
+ this.cameraDevice.logger.debug(`${this.name}: ${property} = ${value}`);
87
+ });
88
+ }
89
+
90
+ /**
91
+ * Called when consumer sets 'on' property
92
+ */
93
+ async setOn(value: boolean): Promise<void> {
94
+ this.cameraDevice.logger.log(`Light turned ${value ? 'ON' : 'OFF'}`);
95
+ this.on = value;
96
+
97
+ // Apply default brightness when turning on
98
+ if (value && this.storage) {
99
+ const defaultBrightness = this.storage.values.defaultBrightness ?? 100;
100
+ this.brightness = defaultBrightness;
101
+ }
102
+ }
103
+
104
+ /**
105
+ * Called when consumer sets 'brightness' property
106
+ */
107
+ async setBrightness(value: number): Promise<void> {
108
+ this.cameraDevice.logger.log(`Light brightness: ${value}%`);
109
+ this.brightness = value;
110
+ }
111
+ }
112
+
113
+ // ============ CLASSIFIER (Multi-Provider Example) ============
114
+
115
+ /**
116
+ * Example Classifier Sensor
117
+ *
118
+ * Multi-provider sensor: Multiple classifiers can be registered per camera.
119
+ * Example use cases:
120
+ * - Bird species classifier (triggers on 'bird' from object detection)
121
+ * - Dog breed classifier (triggers on 'dog')
122
+ * - Plant species classifier
123
+ *
124
+ * The DetectionCoordinator calls detectClassifications() when triggerLabels are detected.
125
+ */
126
+ export class ExampleClassifier extends ClassifierDetectorSensor {
127
+ private cameraDevice: CameraDevice;
128
+
129
+ /**
130
+ * Schema for classifier configuration
131
+ */
132
+ schema: JsonSchema[] = [
133
+ {
134
+ type: 'number',
135
+ key: 'confidenceThreshold',
136
+ title: 'Confidence Threshold',
137
+ description: 'Minimum confidence for classifications (0-1)',
138
+ defaultValue: 0.5,
139
+ minimum: 0.1,
140
+ maximum: 1.0,
141
+ step: 0.05,
142
+ store: true,
143
+ },
144
+ ];
145
+
146
+ constructor(camera: CameraDevice, name = 'Classifier') {
147
+ super(name);
148
+ this.cameraDevice = camera;
149
+ }
150
+
151
+ /**
152
+ * Model specification
153
+ *
154
+ * - input: Frame size and format expected by the model
155
+ * - outputLabels: Labels this classifier can output
156
+ * - triggerLabels: Object labels that trigger classification
157
+ */
158
+ get modelSpec(): ModelSpec {
159
+ return {
160
+ input: {
161
+ width: 224,
162
+ height: 224,
163
+ format: 'rgb',
164
+ },
165
+ // Trigger when object detection finds these labels
166
+ triggerLabels: ['animal'],
167
+ };
168
+ }
169
+
170
+ /**
171
+ * Classify objects in a frame
172
+ *
173
+ * Called by DetectionCoordinator when triggerLabels are detected.
174
+ * The frame is pre-scaled to modelSpec.input dimensions.
175
+ */
176
+ async detectClassifications(frame: VideoFrameData, _triggerRegions?: Detection[]): Promise<ClassifierResult> {
177
+ const threshold = this.storage?.values.confidenceThreshold ?? 0.5;
178
+
179
+ // TODO: Implement your classification model here
180
+ // Example: Load TensorFlow model and run inference
181
+ //
182
+ // const predictions = await this.model.classify(frame.data);
183
+ // return {
184
+ // detected: predictions.length > 0,
185
+ // detections: predictions.map(p => ({
186
+ // label: p.label,
187
+ // confidence: p.score,
188
+ // box: triggerRegions?.[0]?.box ?? { x: 0, y: 0, width: 1, height: 1 },
189
+ // })),
190
+ // };
191
+
192
+ this.cameraDevice.logger.debug(`Classifying frame ${frame.width}x${frame.height}, threshold: ${threshold}`);
193
+
194
+ // Return empty result (placeholder)
195
+ return {
196
+ detected: false,
197
+ detections: [],
198
+ };
199
+ }
200
+
201
+ /**
202
+ * Cleanup when sensor is destroyed
203
+ */
204
+ async destroy(): Promise<void> {
205
+ // Release model resources if needed
206
+ }
207
+ }
package/CHANGELOG.md DELETED
@@ -1,8 +0,0 @@
1
- All notable changes to this project will be documented in this file.
2
-
3
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
4
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
5
-
6
- ## [X.X.X] - ???
7
-
8
- - Initial Release
package/CONTRIBUTING.md DELETED
@@ -1 +0,0 @@
1
- # Contributing
package/scripts/chmod.js DELETED
@@ -1,17 +0,0 @@
1
- import { execSync } from 'node:child_process';
2
- import { platform } from 'node:os';
3
- import { dirname, resolve } from 'node:path';
4
- import { fileURLToPath } from 'node:url';
5
-
6
- const __filename = fileURLToPath(import.meta.url);
7
- const __dirname = dirname(__filename);
8
-
9
- const isWindows = platform() === 'win32';
10
-
11
- function chmod() {
12
- const scriptPath = resolve(__dirname, '../dist/index.js');
13
- const arg = isWindows ? 'echo "Skipping chmod command on Windows"' : `chmod +x ${scriptPath}`;
14
- execSync(arg, { stdio: 'inherit' });
15
- }
16
-
17
- chmod();
@@ -1,10 +0,0 @@
1
- const mode = process.env.MODE || 'production';
2
-
3
- const config = {
4
- input: ['src/index.js'],
5
- mode: mode === 'development' ? 'development' : 'production',
6
- external: [],
7
- additionalFiles: [],
8
- };
9
-
10
- export default config;
@@ -1,64 +0,0 @@
1
- import jsLint from '@eslint/js';
2
- import stylistic from '@stylistic/eslint-plugin';
3
- import globals from 'globals';
4
-
5
- export default [
6
- {
7
- files: ['**/*.{js,mjs,cjs,ts,mts}'],
8
- },
9
- {
10
- ignores: ['**/dist/**', '**/node_modules/**', '**/public/**', '**/build/**', '**/bundle/**', '**/test/**', '**/wasm/**', '**/example/**'],
11
- },
12
- jsLint.configs.recommended,
13
- stylistic.configs['disable-legacy'],
14
- stylistic.configs.customize({
15
- indent: 2,
16
- quotes: 'single',
17
- semi: true,
18
- commaDangle: 'always-multiline',
19
- jsx: false,
20
- arrowParens: true,
21
- braceStyle: '1tbs',
22
- blockSpacing: true,
23
- quoteProps: 'as-needed',
24
- }),
25
- {
26
- languageOptions: {
27
- globals: { ...globals.node },
28
- },
29
-
30
- rules: {
31
- '@stylistic/generator-star-spacing': ['error', { before: true, after: false }],
32
-
33
- // Stylistic specific rules
34
- '@stylistic/max-len': ['error', { code: 170, tabWidth: 2 }],
35
- '@stylistic/quotes': ['error', 'single', { avoidEscape: true }],
36
- '@stylistic/operator-linebreak': 'off',
37
- '@stylistic/comma-dangle': [
38
- 'error',
39
- {
40
- arrays: 'always-multiline',
41
- objects: 'always-multiline',
42
- imports: 'always-multiline',
43
- exports: 'only-multiline',
44
- functions: 'always-multiline',
45
- enums: 'always-multiline',
46
- generics: 'always-multiline',
47
- tuples: 'always-multiline',
48
- },
49
- ],
50
-
51
- semi: [1, 'always'],
52
- // quotes: ['error', 'single'],
53
- 'comma-dangle': ['error', 'only-multiline'],
54
- 'no-multiple-empty-lines': ['warn', { max: 1, maxEOF: 0 }],
55
- 'eol-last': ['error', 'always'],
56
- 'space-before-function-paren': ['error', { named: 'never' }],
57
-
58
- 'no-unused-vars': 'off',
59
- 'no-case-declarations': 'off',
60
- 'no-async-promise-executor': 'off',
61
- 'no-control-regex': 'off',
62
- },
63
- },
64
- ];
@@ -1,41 +0,0 @@
1
- export default class SamplePlugin {
2
- constructor(logger, api) {
3
- this.logger = logger;
4
- this.api = api;
5
-
6
- this.camera = new Map();
7
-
8
- this.api.on('finishLaunching', this.start.bind(this));
9
- this.api.on('shutdown', this.stop.bind(this));
10
-
11
- this.api.deviceManager.on('cameraSelected', (cameraDevice) => {
12
- this.logger.log('Camera selected:', cameraDevice.name);
13
-
14
- if (!this.cameras.has(cameraDevice.id)) {
15
- this.cameras.set(cameraDevice.id, cameraDevice);
16
- }
17
- });
18
-
19
- this.api.deviceManager.on('cameraDeselected', (cameraId) => {
20
- const cameraDevice = this.cameras.get(cameraId);
21
- if (cameraDevice) {
22
- this.logger.log('Camera deselected:', cameraDevice.name);
23
- this.cameras.delete(cameraId);
24
- }
25
- });
26
- }
27
-
28
- async configureCameras() {}
29
-
30
- async getCapabilities() {
31
- return [];
32
- }
33
-
34
- start() {
35
- this.logger.log('Finished launching plugin');
36
- }
37
-
38
- stop() {
39
- this.logger.log('Shutting down plugin');
40
- }
41
- }