@smartspectra/node-sdk 3.4.0-rc.5 → 3.4.0-rc.7
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/README.md +27 -7
- package/js/camera-selection.js +57 -0
- package/js/constants.js +12 -3
- package/js/ffi.js +71 -12
- package/js/index.d.ts +71 -14
- package/js/index.js +4 -0
- package/js/messages/generated.d.ts +166 -8
- package/js/messages/generated.js +565 -37
- package/js/renderer/index.d.ts +2 -0
- package/js/smartspectra.js +50 -12
- package/package.json +9 -7
package/js/renderer/index.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ export {
|
|
|
18
18
|
ValidationCode,
|
|
19
19
|
SmartSpectraErrorCode,
|
|
20
20
|
FrameTransform,
|
|
21
|
+
MetricType,
|
|
21
22
|
breathingMetrics,
|
|
22
23
|
cardioMetrics,
|
|
23
24
|
faceMetrics,
|
|
@@ -31,6 +32,7 @@ export type {
|
|
|
31
32
|
ValidationCodeValue,
|
|
32
33
|
SmartSpectraErrorCodeValue,
|
|
33
34
|
FrameTransformValue,
|
|
35
|
+
MetricTypeValue,
|
|
34
36
|
SmartSpectraOptions,
|
|
35
37
|
} from '../../js/index';
|
|
36
38
|
|
package/js/smartspectra.js
CHANGED
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
|
-
const { Session, ensurePreconfigured } = require('./ffi');
|
|
8
|
+
const { Session, ensurePreconfigured, availableCameras } = require('./ffi');
|
|
9
|
+
const { CameraSelection, normalizeCameraSelection, normalizeCameraOptions } = require('./camera-selection');
|
|
9
10
|
const {
|
|
10
11
|
ProcessingStatus,
|
|
11
12
|
SmartSpectraLogLevel,
|
|
@@ -13,6 +14,7 @@ const {
|
|
|
13
14
|
ValidationCode,
|
|
14
15
|
SmartSpectraErrorCode,
|
|
15
16
|
FrameTransform,
|
|
17
|
+
MetricType,
|
|
16
18
|
breathingMetrics,
|
|
17
19
|
cardioMetrics,
|
|
18
20
|
faceMetrics,
|
|
@@ -41,6 +43,9 @@ class SmartSpectraSDK {
|
|
|
41
43
|
/** SDK package version (matches `package.json#version`). */
|
|
42
44
|
static get version() { return PACKAGE_VERSION; }
|
|
43
45
|
|
|
46
|
+
/** Discover cameras without a session, authentication, or capture. */
|
|
47
|
+
static availableCameras() { return availableCameras(); }
|
|
48
|
+
|
|
44
49
|
/**
|
|
45
50
|
* @param {Object} [options]
|
|
46
51
|
* @param {string} [options.apiKey]
|
|
@@ -64,7 +69,9 @@ class SmartSpectraSDK {
|
|
|
64
69
|
// consumed by start(). Shape: { kind: 'custom'|'camera'|'file', ... }.
|
|
65
70
|
// The last use* call wins.
|
|
66
71
|
this._source = null;
|
|
72
|
+
this._explicitCameraSelection = false;
|
|
67
73
|
this._session = null; // lazy: created on start()
|
|
74
|
+
this._destroyPromise = null;
|
|
68
75
|
}
|
|
69
76
|
|
|
70
77
|
// ---------- public API --------------------------------------------------
|
|
@@ -92,6 +99,7 @@ class SmartSpectraSDK {
|
|
|
92
99
|
* Spatial transform applied to every pushed frame.
|
|
93
100
|
*/
|
|
94
101
|
useCustomInput(frameTransform = DEFAULT_FRAME_TRANSFORM) {
|
|
102
|
+
if (this._explicitCameraSelection) this._requireSourceSelectionAllowed();
|
|
95
103
|
this._source = { kind: 'custom', frameTransform: frameTransform | 0 };
|
|
96
104
|
return this;
|
|
97
105
|
}
|
|
@@ -101,14 +109,28 @@ class SmartSpectraSDK {
|
|
|
101
109
|
* pumps frames internally on start() — no sendFrame() needed. Returns
|
|
102
110
|
* `this` for chaining.
|
|
103
111
|
*
|
|
104
|
-
*
|
|
112
|
+
* Selection is stopped-only and resolved at startup. Explicit requests never
|
|
113
|
+
* fall back. Stop/start/reset retain the selection. Capture options are separate.
|
|
114
|
+
* The deprecated useCamera(options) overload retains index-based capture
|
|
115
|
+
* and the legacy source lifecycle; omit options for camera index zero.
|
|
105
116
|
*
|
|
106
117
|
* Captures from a camera in THIS process (headless / Node use). In an
|
|
107
118
|
* Electron app the camera is normally owned by the renderer via
|
|
108
119
|
* getUserMedia — use the renderer SDK's useMediaStream() there instead.
|
|
109
120
|
*/
|
|
110
|
-
useCamera(options =
|
|
111
|
-
|
|
121
|
+
useCamera(selection = null, options = {}) {
|
|
122
|
+
const isSelection = selection !== null && typeof selection === 'object' && 'kind' in selection;
|
|
123
|
+
if (!isSelection && arguments.length < 2) {
|
|
124
|
+
if (this._explicitCameraSelection) this._requireSourceSelectionAllowed();
|
|
125
|
+
this._source = { kind: 'camera', options: selection };
|
|
126
|
+
this._explicitCameraSelection = false;
|
|
127
|
+
return this;
|
|
128
|
+
}
|
|
129
|
+
this._requireSourceSelectionAllowed();
|
|
130
|
+
const request = normalizeCameraSelection(selection);
|
|
131
|
+
const capture = normalizeCameraOptions(options);
|
|
132
|
+
this._source = { kind: 'camera', selection: request, options: capture };
|
|
133
|
+
this._explicitCameraSelection = true;
|
|
112
134
|
return this;
|
|
113
135
|
}
|
|
114
136
|
|
|
@@ -123,6 +145,7 @@ class SmartSpectraSDK {
|
|
|
123
145
|
* { timestampsPath?, interframeDelayMs?, startOffsetMs?, maxDurationMs?, frameTransform? }
|
|
124
146
|
*/
|
|
125
147
|
useFile(videoPath, options = null) {
|
|
148
|
+
if (this._explicitCameraSelection) this._requireSourceSelectionAllowed();
|
|
126
149
|
if (typeof videoPath !== 'string' || !videoPath) {
|
|
127
150
|
throw new TypeError('useFile: videoPath must be a non-empty string');
|
|
128
151
|
}
|
|
@@ -134,9 +157,10 @@ class SmartSpectraSDK {
|
|
|
134
157
|
* Initialize the session and start the configured input source. Returns
|
|
135
158
|
* once running — for custom input the graph is armed for sendFrame(); for
|
|
136
159
|
* camera/file the SDK pumps frames itself. Configure a source with
|
|
137
|
-
* useCustomInput()
|
|
160
|
+
* useCustomInput(), useCamera(), or useFile() first.
|
|
138
161
|
*/
|
|
139
162
|
start() {
|
|
163
|
+
if (this._explicitCameraSelection) this._requireSourceSelectionAllowed();
|
|
140
164
|
const source = this._source;
|
|
141
165
|
if (!source) {
|
|
142
166
|
throw new Error(
|
|
@@ -149,7 +173,8 @@ class SmartSpectraSDK {
|
|
|
149
173
|
this._session.startCustom(source.frameTransform);
|
|
150
174
|
break;
|
|
151
175
|
case 'camera':
|
|
152
|
-
this._session.startCamera(source.options);
|
|
176
|
+
if (source.selection) this._session.startCamera(source.selection, source.options);
|
|
177
|
+
else this._session.startLegacyCamera(source.options);
|
|
153
178
|
break;
|
|
154
179
|
case 'file':
|
|
155
180
|
this._session.startFile(
|
|
@@ -177,14 +202,14 @@ class SmartSpectraSDK {
|
|
|
177
202
|
}
|
|
178
203
|
|
|
179
204
|
/**
|
|
180
|
-
* Recover from a kError state.
|
|
181
|
-
*
|
|
182
|
-
*
|
|
205
|
+
* Recover from a kError state. Clears the input source for legacy callers.
|
|
206
|
+
* After useCamera(selection, options), retains the selected input.
|
|
207
|
+
* Typed selection requires any pending stopAsync() to settle before reset.
|
|
183
208
|
*/
|
|
184
209
|
reset() {
|
|
185
210
|
if (!this._session) return;
|
|
186
|
-
this._session.reset();
|
|
187
|
-
this._source = null;
|
|
211
|
+
this._session.reset(this._explicitCameraSelection);
|
|
212
|
+
if (!this._explicitCameraSelection) this._source = null;
|
|
188
213
|
}
|
|
189
214
|
|
|
190
215
|
/**
|
|
@@ -239,15 +264,26 @@ class SmartSpectraSDK {
|
|
|
239
264
|
* replacement session, since SDK state is process-global.
|
|
240
265
|
*/
|
|
241
266
|
destroy() {
|
|
267
|
+
if (this._destroyPromise) return this._destroyPromise;
|
|
242
268
|
if (!this._session) return Promise.resolve();
|
|
243
269
|
const teardown = this._session.destroy();
|
|
244
270
|
this._session = null;
|
|
245
271
|
this._source = null;
|
|
246
|
-
|
|
272
|
+
this._destroyPromise = Promise.resolve(teardown).finally(() => { this._destroyPromise = null; });
|
|
273
|
+
return this._destroyPromise;
|
|
247
274
|
}
|
|
248
275
|
|
|
249
276
|
// ---------- internal ----------------------------------------------------
|
|
250
277
|
|
|
278
|
+
_requireSourceSelectionAllowed() {
|
|
279
|
+
if (this._destroyPromise) {
|
|
280
|
+
throw Object.assign(new Error('SmartSpectra is shutting down'), {
|
|
281
|
+
code: SmartSpectraErrorCode.kInvalidState, retryable: false,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
this._session?.assertSourceSelectionAllowed();
|
|
285
|
+
}
|
|
286
|
+
|
|
251
287
|
_ensureSession() {
|
|
252
288
|
if (this._session) return;
|
|
253
289
|
// ARTERIAL_PRESSURE_TRACE, EDA_TRACE, and micromotion metrics need the
|
|
@@ -289,12 +325,14 @@ class SmartSpectraSDK {
|
|
|
289
325
|
|
|
290
326
|
module.exports = {
|
|
291
327
|
SmartSpectraSDK,
|
|
328
|
+
CameraSelection,
|
|
292
329
|
SmartSpectraLogLevel,
|
|
293
330
|
ProcessingStatus,
|
|
294
331
|
PixelFormat,
|
|
295
332
|
ValidationCode,
|
|
296
333
|
SmartSpectraErrorCode,
|
|
297
334
|
FrameTransform,
|
|
335
|
+
MetricType,
|
|
298
336
|
breathingMetrics,
|
|
299
337
|
cardioMetrics,
|
|
300
338
|
faceMetrics,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smartspectra/node-sdk",
|
|
3
|
-
"version": "3.4.0-rc.
|
|
3
|
+
"version": "3.4.0-rc.7",
|
|
4
4
|
"description": "Node.js (Electron) FFI binding for SmartSpectra vitals measurement",
|
|
5
5
|
"author": "Presage Technologies, Inc.",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -40,7 +40,8 @@
|
|
|
40
40
|
"scripts": {
|
|
41
41
|
"prepare": "node scripts/gen-proto.cjs",
|
|
42
42
|
"build:proto": "node scripts/gen-proto.cjs",
|
|
43
|
-
"test": "node --test test/log-level-pin.js test/renderer-timestamp.js test/smoke.js",
|
|
43
|
+
"test": "npm run test:types && node --test test/log-level-pin.js test/renderer-timestamp.js test/camera-selection.js test/reset-lifecycle.js test/smoke.js",
|
|
44
|
+
"test:types": "tsc --noEmit --strict --skipLibCheck --target es2022 --module nodenext test/camera-selection-types.ts",
|
|
44
45
|
"test:models-allowlist": "node test/models-allowlist.js"
|
|
45
46
|
},
|
|
46
47
|
"keywords": [
|
|
@@ -70,14 +71,15 @@
|
|
|
70
71
|
"dependencies": {
|
|
71
72
|
"koffi": "^2.10.0",
|
|
72
73
|
"protobufjs": "^7.6.5",
|
|
73
|
-
"@smartspectra/node-sdk-linux-x64": "3.4.0-rc.
|
|
74
|
-
"@smartspectra/node-sdk-linux-arm64": "3.4.0-rc.
|
|
75
|
-
"@smartspectra/node-sdk-darwin-arm64": "3.4.0-rc.
|
|
76
|
-
"@smartspectra/node-sdk-win32-x64": "3.4.0-rc.
|
|
74
|
+
"@smartspectra/node-sdk-linux-x64": "3.4.0-rc.7",
|
|
75
|
+
"@smartspectra/node-sdk-linux-arm64": "3.4.0-rc.7",
|
|
76
|
+
"@smartspectra/node-sdk-darwin-arm64": "3.4.0-rc.7",
|
|
77
|
+
"@smartspectra/node-sdk-win32-x64": "3.4.0-rc.7"
|
|
77
78
|
},
|
|
78
79
|
"devDependencies": {
|
|
79
80
|
"@types/node": "^24.0.0",
|
|
80
|
-
"protobufjs-cli": "^1.1.3"
|
|
81
|
+
"protobufjs-cli": "^1.1.3",
|
|
82
|
+
"typescript": "^6.0.2"
|
|
81
83
|
},
|
|
82
84
|
"_overrides_doc": "tmp is pulled in transitively (protobufjs-cli → tmp) as a build-only devDependency; it is never a runtime dependency and is not shipped to consumers (the published tarball ships js/ + prebuilds only, no node_modules). Pinned to an exact version (not a >= range) to clear GHSA-ph9p-34f9-6g65 (path traversal, affects tmp <0.2.6) and GHSA-7c78-jf6q-g5cm (type-confusion bypass of the 0.2.6 _assertPath guard, affects tmp >=0.2.6) AND to keep installs deterministic — an open range would let a future install pull a brand-new, not-yet-vetted release. Bump deliberately. Drop this once protobufjs-cli ships a release whose tmp range is already >=0.2.7.",
|
|
83
85
|
"overrides": {
|