@smartspectra/node-sdk 3.2.0-rc.6

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/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ # License
2
+
3
+ Copyright © 2026 Presage Security, Inc. d/b/a Presage Technologies. All rights reserved.
4
+
5
+ This software is proprietary to Presage and is made available solely under Presage's Terms of Service, available at <https://physiology.presagetech.com/tos>. Use of this software constitutes acceptance of those Terms. No license, express or implied, is granted to any Presage trademark, trade name, or logo.
6
+
7
+ ## No Warranty
8
+
9
+ The software is provided "AS IS," without warranty of any kind, express or implied, to the fullest extent permitted by applicable law.
10
+
11
+ ## Questions
12
+
13
+ For licensing questions, contact <support@presagetech.com>.
package/README.md ADDED
@@ -0,0 +1,409 @@
1
+ ---
2
+ title: Node.js SDK
3
+ description: Build Node.js apps — including Electron desktop apps — with SmartSpectra via a packaged native runtime loaded through koffi.
4
+ ---
5
+
6
+ # @smartspectra/node-sdk
7
+
8
+ Pure-FFI Node.js (Electron) binding for SmartSpectra vitals measurement.
9
+ [koffi](https://koffi.dev) loads the SmartSpectra C ABI shim at runtime —
10
+ no native addon, no `binding.gyp`, no `electron-rebuild`, no `node-gyp`.
11
+
12
+ ## Start here
13
+
14
+ - Electron sample: [electron-quickstart](https://github.com/Presage-Security/SmartSpectra/tree/main/nodejs/samples/electron-quickstart)
15
+ - API reference: <https://smartspectra.presagetech.com/docs/nodejs/api-reference>
16
+ - Metrics guide: <https://smartspectra.presagetech.com/docs/nodejs/metrics>
17
+
18
+ ## Architecture
19
+
20
+ ```text
21
+ ┌──────────────────────────┐
22
+ │ your Node / Electron app │
23
+ └───────────┬──────────────┘
24
+ │ require('@smartspectra/node-sdk')
25
+ ┌───────────▼──────────────┐
26
+ │ js/index.js │ public surface
27
+ │ js/smartspectra.js │ SmartSpectraSDK class
28
+ │ js/ffi.js │ koffi types + Session
29
+ │ js/resolve-native.js │ shim path resolver
30
+ └───────────┬──────────────┘
31
+ │ koffi.load()
32
+ ┌────────────────────────────────────────┐
33
+ │ @smartspectra/node-sdk-<plat>-<arch>/ │ self-contained native runtime,
34
+ │ libsmartspectra_capi.* │ shipped as a dependency package;
35
+ │ …bundled runtime libraries… │ load paths pre-relocated to
36
+ │ │ @loader_path / $ORIGIN /
37
+ └────────────────────────────────────────┘ adjacent-DLL search
38
+ ```
39
+
40
+ The native runtime ships in per-platform packages
41
+ (`@smartspectra/node-sdk-<plat>-<arch>`) pulled in as dependencies of the main
42
+ package. There is **no install script** in the published tarball and no
43
+ postinstall download; the binding loads the package matching your machine at
44
+ runtime. SDK-thread callbacks are marshalled onto the V8 event loop by koffi
45
+ thread-safe trampolines.
46
+
47
+ ## Supported Platforms
48
+
49
+ | Platform | Status | Notes |
50
+ | --- | --- | --- |
51
+ | macOS Apple Silicon (`darwin-arm64`) | Supported | Electron and headless Node workflows supported |
52
+ | Linux x64 (`linux-x64`) | Supported | Requires glibc 2.35+ |
53
+ | Linux ARM64 (`linux-arm64`) | Supported | Requires glibc 2.35+ |
54
+ | Windows x64 (`win32-x64`) | Supported | Electron and headless Node workflows supported |
55
+
56
+ ## Common Prerequisites
57
+
58
+ | Requirement | Version |
59
+ | --- | --- |
60
+ | Node.js | >= 18 (Node 20 LTS recommended) |
61
+ | Electron (optional) | >= 28 |
62
+
63
+ The native runtime ships in per-platform npm packages pulled in automatically
64
+ as dependencies — no install script and no system libraries to install.
65
+
66
+ Supported platforms: `darwin-arm64`, `linux-x64`, `linux-arm64`, `win32-x64`.
67
+
68
+ On Linux the native runtime is built on Ubuntu 22.04 (Jammy), so it requires
69
+ glibc >= 2.35 — Ubuntu 22.04+, Debian 12+, or any distribution at least that
70
+ new. glibc and libstdc++ are provided by your system, not bundled.
71
+
72
+ ## Installation
73
+
74
+ ```bash
75
+ npm install @smartspectra/node-sdk
76
+ ```
77
+
78
+ Early adopters can track the latest release candidate with the `rc` dist-tag:
79
+
80
+ ```bash
81
+ npm install @smartspectra/node-sdk@rc
82
+ ```
83
+
84
+ The native packages (`@smartspectra/node-sdk-<platform>-<arch>`) come in as
85
+ dependencies and the binding loads the one matching your `platform`/`arch` at
86
+ runtime. Each is self-contained — it bundles everything the binding loads at
87
+ runtime, with paths already rewritten at publish time, so nothing needs to be on
88
+ PATH and no system libraries are required. There is no install script.
89
+
90
+ > **Note** — `npm install` downloads the native runtime for every supported
91
+ > platform (a few hundred MB total), not just your host's. This is expected;
92
+ > only the package matching your machine is loaded at runtime.
93
+
94
+ If your platform is unsupported (no `@smartspectra/node-sdk-<plat>-<arch>` is
95
+ published for it), the first `require()` fails with an actionable error naming
96
+ the missing package.
97
+
98
+ ## Pick Your Integration Path
99
+
100
+ - Electron desktop app: use `@smartspectra/node-sdk/main`,
101
+ `@smartspectra/node-sdk/preload`, and `@smartspectra/node-sdk/renderer`.
102
+ - Headless or server-side Node process: use `@smartspectra/node-sdk`
103
+ directly and push frames with `useCustomInput()` / `sendFrame()`.
104
+ - Runnable reference app: [electron-quickstart](https://github.com/Presage-Security/SmartSpectra/tree/main/nodejs/samples/electron-quickstart)
105
+
106
+ ## Headless Node Quickstart
107
+
108
+ ```ts
109
+ import {
110
+ SmartSpectraSDK, PixelFormat, FrameTransform, ProcessingStatus,
111
+ breathingMetrics, cardioMetrics,
112
+ decodeMetrics, setMetricsClass,
113
+ } from '@smartspectra/node-sdk';
114
+
115
+ // Optional: override the default Metrics decoder.
116
+ // import { Metrics } from './generated/metrics_pb';
117
+ // setMetricsClass(Metrics);
118
+
119
+ const sdk = new SmartSpectraSDK({
120
+ apiKey: 'YOUR_API_KEY',
121
+ requestedMetrics: [...breathingMetrics, ...cardioMetrics],
122
+ });
123
+
124
+ sdk.on('processingStatus', (status) => console.log('Processing status:', status));
125
+ sdk.on('validationStatus', (code, ts, hint) =>
126
+ console.log('Validation:', code, hint, 'at', ts, 'µs'));
127
+ sdk.on('metrics', (buf, ts) => {
128
+ const m = decodeMetrics(buf);
129
+ console.log('Metrics at', ts, 'µs');
130
+ });
131
+ sdk.on('error', (code, message, retryable) =>
132
+ console.error('SmartSpectra error', code, message, 'retryable=', retryable));
133
+
134
+ sdk.useCustomInput(FrameTransform.kNone);
135
+ sdk.start();
136
+
137
+ // In your capture loop:
138
+ sdk.sendFrame(rgbBuf, width, height, width * 3, PixelFormat.kRGB, captureTsUs);
139
+
140
+ // On shutdown:
141
+ await sdk.destroy();
142
+ ```
143
+
144
+ ## API reference
145
+
146
+ The full API — `SmartSpectraSDK` constructor options, methods, events, error
147
+ codes, and enums — lives in the [API reference](docs/api-reference.md),
148
+ generated from the SDK's bundled TypeScript declarations so it tracks the
149
+ published package. For which metrics to request and how to read the decoded
150
+ payloads, see the [metrics guide](docs/metrics.md).
151
+
152
+ <!-- The two members below are not yet emitted by docs-site/scripts/generate-api.ts
153
+ (it doesn't capture fields on the ambient `declare class`); documented here
154
+ until that generator gap is fixed, then they move to the API reference. -->
155
+ Two instance members aren't yet in the generated reference:
156
+
157
+ | Member | Type | Notes |
158
+ | --- | --- | --- |
159
+ | `sdk.processingStatus` | `ProcessingStatusValue` | Current processing status (read-only). |
160
+ | `SmartSpectraSDK.version` | `string` | Static; the SDK package version. |
161
+
162
+ ## Electron integration
163
+
164
+ Runnable sample at [electron-quickstart](https://github.com/Presage-Security/SmartSpectra/tree/main/nodejs/samples/electron-quickstart).
165
+ See its [README](https://github.com/Presage-Security/SmartSpectra/blob/main/nodejs/samples/electron-quickstart/README.md).
166
+
167
+ The package ships these entry points:
168
+
169
+ ```text
170
+ @smartspectra/node-sdk → SmartSpectraSDK (low-level, main process)
171
+ @smartspectra/node-sdk/main → bindSmartSpectraIpc(window)
172
+ @smartspectra/node-sdk/preload → preload bridge (contextBridge)
173
+ @smartspectra/node-sdk/renderer → SmartSpectraSDK (renderer-side, MediaStream input)
174
+ @smartspectra/node-sdk/messages → decodeMetrics(buf) + the generated Metrics class
175
+ ```
176
+
177
+ ### Main process
178
+
179
+ ```ts
180
+ import { app, BrowserWindow } from 'electron';
181
+ import { bindSmartSpectraIpc } from '@smartspectra/node-sdk/main';
182
+
183
+ app.whenReady().then(() => {
184
+ const win = new BrowserWindow({
185
+ webPreferences: {
186
+ preload: require.resolve('@smartspectra/node-sdk/preload'),
187
+ contextIsolation: true,
188
+ sandbox: true,
189
+ },
190
+ });
191
+ bindSmartSpectraIpc(win);
192
+ win.loadFile('index.html');
193
+ });
194
+ ```
195
+
196
+ `bindSmartSpectraIpc` listens on a single private IPC channel, accepts the
197
+ MessagePort the preload ships from the renderer, and owns one
198
+ `SmartSpectraSDK` per renderer connection. SDK teardown happens
199
+ automatically on window close.
200
+
201
+ ### Renderer
202
+
203
+ ```ts
204
+ import { SmartSpectraSDK } from '@smartspectra/node-sdk/renderer';
205
+ import { breathingMetrics, cardioMetrics } from '@smartspectra/node-sdk';
206
+
207
+ const sdk = new SmartSpectraSDK({
208
+ apiKey: 'YOUR_KEY',
209
+ requestedMetrics: [...breathingMetrics, ...cardioMetrics],
210
+ });
211
+
212
+ sdk.on('streamAvailable', (stream) => { videoEl.srcObject = stream; });
213
+ sdk.on('metrics', (buf, ts) => { /* render dashboard */ });
214
+ sdk.on('validationStatus', (code, ts, hint) => { /* show user hint */ });
215
+ sdk.on('error', (code, msg, retryable) => { /* surface in UI */ });
216
+
217
+ await sdk.start(); // SDK acquires the front camera + emits 'streamAvailable'
218
+
219
+ await sdk.requestInsight('How is my breathing?');
220
+ await sdk.stop(); // SDK releases the camera; next start() re-acquires
221
+ sdk.destroy();
222
+ ```
223
+
224
+ Defaults: front-facing camera at 1280x720 / 30 fps, AE/AWB/focus locked
225
+ once the graph reports `Running`. Call `sdk.useMediaStream(stream)` before
226
+ `sdk.start()` to override with a virtual camera,
227
+ `<canvas>.captureStream()`, `desktopCapturer`, etc. Host-supplied streams
228
+ are managed by the host; SDK-acquired streams are released on
229
+ `stop()` / `reset()` / `destroy()`.
230
+
231
+ The renderer uses `MediaStreamTrackProcessor` + `OffscreenCanvas` to
232
+ extract RGBA pixels and ships each frame to the main process via the
233
+ MessagePort. Graph callbacks flow back through the same port.
234
+
235
+ Each control call (`start` / `stop` / `reset` / `requestInsight`) waits for
236
+ an ack from the main process. If the main process crashes or stalls, the
237
+ call rejects after `sendTimeoutMs` (default `30000`) with an `Error` whose
238
+ `code` is `'SMARTSPECTRA_IPC_TIMEOUT'`, so the UI surfaces "main process
239
+ unresponsive" instead of hanging forever. Pass `sendTimeoutMs` to the
240
+ constructor to tune it, or `0` to disable.
241
+
242
+ ### Preload
243
+
244
+ If the app already has a preload script, require this module from it:
245
+
246
+ ```js
247
+ require('@smartspectra/node-sdk/preload');
248
+ ```
249
+
250
+ Otherwise point `webPreferences.preload` directly:
251
+
252
+ ```ts
253
+ preload: require.resolve('@smartspectra/node-sdk/preload')
254
+ ```
255
+
256
+ ### Content Security Policy
257
+
258
+ The renderer runs a Web Worker from a `blob:` URL. If your app sets a CSP,
259
+ allow `blob:` in `worker-src`:
260
+
261
+ ```html
262
+ <meta http-equiv="Content-Security-Policy"
263
+ content="default-src 'self'; worker-src 'self' blob:;">
264
+ ```
265
+
266
+ A `Refused to create a worker from 'blob:…'` console error at `start()`
267
+ time means the policy is blocking the worker.
268
+
269
+ ### Permission flow
270
+
271
+ Camera permission flows through Electron's native handler — the SDK calls
272
+ `navigator.mediaDevices.getUserMedia()` (or the host's stream, if supplied
273
+ via `useMediaStream()`) and Electron surfaces the OS prompt + indicator
274
+ LED. To grant programmatically:
275
+
276
+ ```ts
277
+ import { session } from 'electron';
278
+
279
+ session.defaultSession.setPermissionRequestHandler((wc, permission, callback, details) => {
280
+ // Grant only the camera, and only to your own bundled page — deny everything
281
+ // else so a window that later loads remote content can't auto-grant the camera.
282
+ const url = (details && details.requestingUrl) || (wc && wc.getURL()) || '';
283
+ callback(permission === 'media' && url.startsWith('file://'));
284
+ });
285
+ ```
286
+
287
+ On macOS, add `NSCameraUsageDescription` to `Info.plist`. Windows and
288
+ Linux need no additional entitlements.
289
+
290
+ ## Electron desktop packaging
291
+
292
+ The installed platform package
293
+ `node_modules/@smartspectra/node-sdk-<plat>-<arch>/` ships the full native
294
+ closure — every library `libsmartspectra_capi` needs at runtime, with
295
+ install_names / RPATHs pre-relocated to `@loader_path` (macOS), `$ORIGIN`
296
+ (Linux), or adjacent-directory search (Windows). Include that directory as an
297
+ extra resource and you're done.
298
+
299
+ ### electron-builder
300
+
301
+ Use one block per target OS. electron-builder's `${platform}` macro expands to
302
+ the **build host's** platform, not the build target — so a single
303
+ `${platform}` entry ships the wrong (or no) closure on a cross-build
304
+ (e.g. `electron-builder --win` on a Mac). The per-OS `mac`/`win`/`linux` blocks
305
+ are applied only to their matching target and are cross-build-safe:
306
+
307
+ ```jsonc
308
+ // package.json
309
+ {
310
+ "build": {
311
+ "mac": { "extraResources": [{ "from": "node_modules/@smartspectra/node-sdk-darwin-${arch}/", "to": "smartspectra/" }] },
312
+ "win": { "extraResources": [{ "from": "node_modules/@smartspectra/node-sdk-win32-${arch}/", "to": "smartspectra/" }] },
313
+ "linux": { "extraResources": [{ "from": "node_modules/@smartspectra/node-sdk-linux-${arch}/", "to": "smartspectra/" }] }
314
+ }
315
+ }
316
+ ```
317
+
318
+ ### electron-forge
319
+
320
+ ```js
321
+ // forge.config.js
322
+ module.exports = {
323
+ packagerConfig: {
324
+ extraResource: [
325
+ `node_modules/@smartspectra/node-sdk-${process.platform}-${process.arch}/`,
326
+ ],
327
+ },
328
+ };
329
+ ```
330
+
331
+ > **Cross-builds:** `process.platform`/`process.arch` resolve at config-load
332
+ > time to the **host**, not the build target — so this single line is correct
333
+ > only for native (per-OS-CI) builds. To cross-build, switch on the target
334
+ > (`--platform`/`--arch` passed to `electron-forge package`) and emit the
335
+ > matching `node_modules/@smartspectra/node-sdk-<target>/` path.
336
+
337
+ ### macOS code signing
338
+
339
+ The bundled `.dylib` files are ad-hoc signed so dyld will load them; for
340
+ distribution you'll want to re-sign with your own identity. With
341
+ electron-builder:
342
+
343
+ ```jsonc
344
+ {
345
+ "build": {
346
+ "mac": {
347
+ "hardenedRuntime": true,
348
+ "entitlements": "build/entitlements.mac.plist",
349
+ "extendInfo": { "NSCameraUsageDescription": "Vitals measurement" }
350
+ }
351
+ }
352
+ }
353
+ ```
354
+
355
+ In `entitlements.mac.plist`, allow loading the bundled dylibs:
356
+
357
+ ```xml
358
+ <key>com.apple.security.cs.disable-library-validation</key>
359
+ <true/>
360
+ ```
361
+
362
+ Alternative: re-sign every `.dylib` under
363
+ `node_modules/@smartspectra/node-sdk-darwin-arm64/` with your own identity
364
+ before packaging (preferable for notarization-strict deployments).
365
+
366
+ ### Windows code signing
367
+
368
+ Authenticode-sign each `.dll` under
369
+ `node_modules/@smartspectra/node-sdk-win32-x64/` alongside your app's main
370
+ executable. Windows resolves adjacent DLLs first, so
371
+ placing them in the same directory as `<your-app>.exe` is the simplest
372
+ layout.
373
+
374
+ ### Linux
375
+
376
+ No signing required. The bundled `.so` files have `$ORIGIN` RPATHs so
377
+ they resolve siblings without any `LD_LIBRARY_PATH` plumbing.
378
+
379
+ **glibc floor — Ubuntu 22.04 (Jammy, `GLIBC_2.35`).** The runtime closure is
380
+ built on a Jammy base, so a packaged app (e.g. an AppImage) runs on Ubuntu
381
+ 22.04 and any newer distribution. glibc and the C++ runtime come from the
382
+ host system — they are not vendored in the platform package.
383
+
384
+ ## Performance notes
385
+
386
+ - koffi adds ~100 ns per FFI call — negligible for `sendFrame()` at 30 fps.
387
+ - SDK callbacks arrive on worker threads; koffi marshals them onto the V8
388
+ event loop, so listeners run on the main thread.
389
+ - In Electron, the renderer-side SDK (`@smartspectra/node-sdk/renderer`)
390
+ captures frames in the renderer and ships them to the main process —
391
+ simplest to wire and fine for typical use. For the lowest latency at high
392
+ resolution, capture in the main process instead (`desktopCapturer` or an
393
+ off-screen renderer), since renderer→main IPC adds frame-time latency that
394
+ scales with resolution.
395
+
396
+ ## Troubleshooting
397
+
398
+ | Symptom | Likely cause | Fix |
399
+ | --- | --- | --- |
400
+ | `the native runtime package "@smartspectra/node-sdk-<plat>-<arch>" is not installed` on require | platform unsupported, or a partial/offline install dropped the dependency | Confirm your platform is supported, then re-run `npm install` |
401
+ | `Cannot open shared object file` / `LoadLibrary failed` on require | platform package present but its bundled closure is incomplete or corrupt | Reinstall the platform package (`npm install`) |
402
+ | `kAuthenticationFailed` | API key issue | Check the key + the keychain entitlement on macOS |
403
+ | `kNonMonotonicTimestamp` | Wall-clock timestamps | Use `process.hrtime.bigint() / 1000n` (monotonic) |
404
+
405
+ ## Support
406
+
407
+ - Docs site: <https://smartspectra.presagetech.com/docs/nodejs>
408
+ - GitHub issues: <https://github.com/Presage-Security/SmartSpectra/issues>
409
+ - Email: <support@presagetech.com>
@@ -0,0 +1,125 @@
1
+ // constants.js
2
+ // Copyright (C) 2026 Presage Technologies, Inc.
3
+ //
4
+ // SPDX-License-Identifier: LicenseRef-Proprietary
5
+ //
6
+ // Pure-value exports — public enums and metric bundles. No Node-only
7
+ // dependencies so this module can be bundled into a browser renderer
8
+ // without dragging in koffi, fs, or path.
9
+ //
10
+ // Integer values must match the SmartSpectra C++ headers and
11
+ // metric_types.proto wire values; stable across SDK versions.
12
+
13
+ 'use strict';
14
+
15
+ const ProcessingStatus = Object.freeze({
16
+ kUninitialized: 0,
17
+ kIdle: 1,
18
+ kStarting: 2,
19
+ kRunning: 3,
20
+ kStopping: 4,
21
+ kError: 5,
22
+ });
23
+
24
+ const PixelFormat = Object.freeze({
25
+ kRGB: 0,
26
+ kBGR: 1,
27
+ kRGBA: 2,
28
+ kBGRA: 3,
29
+ kNV12: 4,
30
+ kNV21: 5,
31
+ kYUYV: 6,
32
+ });
33
+
34
+ const ValidationCode = Object.freeze({
35
+ kOk: 0,
36
+ kNoFaceFound: 1,
37
+ kMultipleFacesFound: 2,
38
+ kFaceNotCentered: 3,
39
+ kFaceSizeOutOfRange: 4,
40
+ kTooDark: 5,
41
+ kTooBright: 6,
42
+ kChestNotVisible: 7,
43
+ kCameraTuning: 10,
44
+ kFrameRateTooLow: 11,
45
+ });
46
+
47
+ const SmartSpectraErrorCode = Object.freeze({
48
+ kOk: 0,
49
+ kInvalidState: 1,
50
+ kAuthenticationFailed: 2,
51
+ kConfigurationFailed: 3,
52
+ kCreditExhausted: 4,
53
+ kNetworkError: 5,
54
+ kServerError: 6,
55
+ kInputUnavailable: 7,
56
+ kProcessingFailed: 8,
57
+ kFrameConversionFailed: 9,
58
+ kNonMonotonicTimestamp: 10,
59
+ kTimestampGap: 11,
60
+ });
61
+
62
+ // Spatial transform applied to each pushed frame before it enters the
63
+ // graph. Pass to `useCustomInput(frameTransform)`.
64
+ const FrameTransform = Object.freeze({
65
+ kNone: 0,
66
+ kRotate90CW: 1,
67
+ kRotate90CCW: 2,
68
+ kRotate180: 3,
69
+ kMirrorHorizontal: 4,
70
+ kMirrorVertical: 5,
71
+ });
72
+
73
+ // MetricType integer codes grouped by measurement type. Spread into
74
+ // `requestedMetrics`; omitting `requestedMetrics` is equivalent to passing
75
+ // `breathingMetrics`.
76
+ const breathingMetrics = Object.freeze([
77
+ 0, // CHEST_BREATHING
78
+ 1, // ABDOMEN_BREATHING
79
+ 2, // BREATHING_RATE
80
+ 3, // BREATHING_AMPLITUDE
81
+ 4, // APNEA
82
+ 5, // RESPIRATORY_LINE_LENGTH
83
+ 6, // BASELINE
84
+ 7, // INHALE_EXHALE_RATIO
85
+ ]);
86
+
87
+ const cardioMetrics = Object.freeze([
88
+ 15, // PULSE_RATE
89
+ 16, // ARTERIAL_PRESSURE_TRACE
90
+ 17, // HRV
91
+ ]);
92
+
93
+ const faceMetrics = Object.freeze([
94
+ 11, // FACE_LANDMARKS
95
+ 12, // BLINKING
96
+ 13, // TALKING
97
+ 14, // EXPRESSIONS
98
+ ]);
99
+
100
+ const micromotionMetrics = Object.freeze([
101
+ 8, // GLUTES_MICROMOTION
102
+ 9, // KNEES_MICROMOTION
103
+ ]);
104
+
105
+ const edaMetrics = Object.freeze([
106
+ 10, // EDA_TRACE
107
+ ]);
108
+
109
+ // The default metric bundle used when `requestedMetrics` is omitted; currently
110
+ // equals the breathing bundle.
111
+ const defaultSupportedMetrics = breathingMetrics;
112
+
113
+ module.exports = {
114
+ ProcessingStatus,
115
+ PixelFormat,
116
+ ValidationCode,
117
+ SmartSpectraErrorCode,
118
+ FrameTransform,
119
+ breathingMetrics,
120
+ cardioMetrics,
121
+ faceMetrics,
122
+ micromotionMetrics,
123
+ edaMetrics,
124
+ defaultSupportedMetrics,
125
+ };