@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/js/index.d.ts ADDED
@@ -0,0 +1,282 @@
1
+ // index.d.ts
2
+ // Copyright (C) 2026 Presage Technologies, Inc.
3
+ //
4
+ // SPDX-License-Identifier: LicenseRef-Proprietary
5
+
6
+ /** Processing lifecycle status. Integer values are stable across SDK versions. */
7
+ export declare const ProcessingStatus: {
8
+ readonly kUninitialized: 0;
9
+ readonly kIdle: 1;
10
+ readonly kStarting: 2;
11
+ readonly kRunning: 3;
12
+ readonly kStopping: 4;
13
+ readonly kError: 5;
14
+ };
15
+ export type ProcessingStatusValue = typeof ProcessingStatus[keyof typeof ProcessingStatus];
16
+
17
+ /** Pixel format of a raw frame buffer passed to sendFrame(). */
18
+ export declare const PixelFormat: {
19
+ readonly kRGB: 0;
20
+ readonly kBGR: 1;
21
+ readonly kRGBA: 2;
22
+ readonly kBGRA: 3;
23
+ readonly kNV12: 4;
24
+ readonly kNV21: 5;
25
+ readonly kYUYV: 6;
26
+ };
27
+ export type PixelFormatValue = typeof PixelFormat[keyof typeof PixelFormat];
28
+
29
+ /** Measurement-readiness codes delivered via the 'validationStatus' event. */
30
+ export declare const ValidationCode: {
31
+ readonly kOk: 0;
32
+ readonly kNoFaceFound: 1;
33
+ readonly kMultipleFacesFound: 2;
34
+ readonly kFaceNotCentered: 3;
35
+ readonly kFaceSizeOutOfRange: 4;
36
+ readonly kTooDark: 5;
37
+ readonly kTooBright: 6;
38
+ readonly kChestNotVisible: 7;
39
+ readonly kCameraTuning: 10;
40
+ readonly kFrameRateTooLow: 11;
41
+ };
42
+ export type ValidationCodeValue = typeof ValidationCode[keyof typeof ValidationCode];
43
+
44
+ /** Error codes on errors thrown by lifecycle methods and delivered via the 'error' event. */
45
+ export declare const SmartSpectraErrorCode: {
46
+ readonly kOk: 0;
47
+ readonly kInvalidState: 1;
48
+ readonly kAuthenticationFailed: 2;
49
+ readonly kConfigurationFailed: 3;
50
+ readonly kCreditExhausted: 4;
51
+ readonly kNetworkError: 5;
52
+ readonly kServerError: 6;
53
+ readonly kInputUnavailable: 7;
54
+ readonly kProcessingFailed: 8;
55
+ readonly kFrameConversionFailed: 9;
56
+ readonly kNonMonotonicTimestamp: 10;
57
+ readonly kTimestampGap: 11;
58
+ };
59
+ export type SmartSpectraErrorCodeValue = typeof SmartSpectraErrorCode[keyof typeof SmartSpectraErrorCode];
60
+
61
+ /** Frame transform applied by the SDK to every pushed frame. */
62
+ export declare const FrameTransform: {
63
+ readonly kNone: 0;
64
+ readonly kRotate90CW: 1;
65
+ readonly kRotate90CCW: 2;
66
+ readonly kRotate180: 3;
67
+ readonly kMirrorHorizontal: 4;
68
+ readonly kMirrorVertical: 5;
69
+ };
70
+ export type FrameTransformValue = typeof FrameTransform[keyof typeof FrameTransform];
71
+
72
+ /** Options passed to the SmartSpectra constructor. */
73
+ export interface SmartSpectraOptions {
74
+ /** API key for server-validated auth. */
75
+ apiKey?: string;
76
+
77
+ /**
78
+ * MetricType integer codes. Defaults to `breathingMetrics` when omitted.
79
+ */
80
+ requestedMetrics?: number[];
81
+
82
+ /** Also emit an accumulated metrics packet at the end of each session. */
83
+ enableAccumulatedOutput?: boolean;
84
+ }
85
+
86
+ /** Playback options for useFile(). */
87
+ export interface VideoFileOptions {
88
+ /** Path to a per-frame timestamps file (one timestamp per line). */
89
+ timestampsPath?: string | null;
90
+ /** Throttle between frames in ms; omit/0 = as fast as possible. */
91
+ interframeDelayMs?: number;
92
+ /** Seek this far into the file before playback (ms); omit/0 = start. */
93
+ startOffsetMs?: number;
94
+ /** Stop after this much content (ms); omit/0 = no limit. */
95
+ maxDurationMs?: number;
96
+ /** Spatial transform applied to every frame. */
97
+ frameTransform?: FrameTransformValue;
98
+ }
99
+
100
+ /** Camera capture options for useCamera(). */
101
+ export interface CameraOptions {
102
+ /** Camera device index; omit/0 = default device. */
103
+ deviceIndex?: number;
104
+ /** Capture width in px; omit/0 = SDK default. */
105
+ width?: number;
106
+ /** Capture height in px; omit/0 = SDK default. */
107
+ height?: number;
108
+ /** Capture frame rate; omit/0 = SDK default. */
109
+ fps?: number;
110
+ /** Spatial transform applied to every frame. */
111
+ frameTransform?: FrameTransformValue;
112
+ }
113
+
114
+ /**
115
+ * Vitals measurement entry point. Owns one processing pipeline and surfaces
116
+ * lifecycle events via `on()`. Lifecycle methods throw a JS `Error` on
117
+ * failure with numeric `code` (a `SmartSpectraErrorCode` value), `message`,
118
+ * and boolean `retryable` properties.
119
+ *
120
+ * @example
121
+ * ```ts
122
+ * import { SmartSpectraSDK, PixelFormat, decodeMetrics } from '@smartspectra/node-sdk';
123
+ *
124
+ * const sdk = new SmartSpectraSDK({ apiKey: 'YOUR_KEY' });
125
+ * sdk.on('metrics', (buf, ts) => console.log(decodeMetrics(buf)));
126
+ * sdk.useCustomInput();
127
+ * sdk.start();
128
+ * sdk.sendFrame(rgbBuf, width, height, stride, PixelFormat.kRGB, timestampUs);
129
+ * await sdk.destroy();
130
+ * ```
131
+ */
132
+ export declare class SmartSpectraSDK {
133
+ /** SDK package version. */
134
+ static readonly version: string;
135
+
136
+ constructor(options?: SmartSpectraOptions);
137
+
138
+ /** Initialize and begin a custom-input session. */
139
+ start(): void;
140
+ /** Request the session to stop. Idempotent. */
141
+ stop(): void;
142
+ /** Async variant of stop() — the native stop blocks until the pipeline drains; prefer this in event-loop-sensitive contexts. */
143
+ stopAsync(): Promise<void>;
144
+ /** Rebuild the processing pipeline after kError; source must be reconfigured before next start(). */
145
+ reset(): void;
146
+ /**
147
+ * Block until the session reaches a terminal state (idle or error), or the
148
+ * timeout elapses. Returns true if the session settled, false on timeout.
149
+ * `timeoutMs <= 0` (the default) waits indefinitely. Use after
150
+ * `useFile()` + `start()` to block until end-of-file.
151
+ */
152
+ waitUntilComplete(timeoutMs?: number): boolean;
153
+ /**
154
+ * Tear down the session. Idempotent. Await before constructing a
155
+ * replacement session when teardown ordering matters, since native SDK
156
+ * state is process-global.
157
+ */
158
+ destroy(): Promise<void>;
159
+
160
+ /**
161
+ * Dispatch an on-demand insight prompt; returns the request id. The
162
+ * matching Insight response arrives asynchronously through the
163
+ * `'insight'` event with the same id.
164
+ */
165
+ requestInsight(text: string): number;
166
+
167
+ /** Current ProcessingStatus integer value. */
168
+ readonly processingStatus: ProcessingStatusValue;
169
+
170
+ /**
171
+ * Select the custom frame-push input source (push frames via
172
+ * `sendFrame()` after `start()`). Returns `this` for chaining; call
173
+ * before `start()`.
174
+ *
175
+ * @param frameTransform Defaults to `FrameTransform.kNone`.
176
+ */
177
+ useCustomInput(frameTransform?: FrameTransformValue): this;
178
+
179
+ /**
180
+ * Select a live camera as the input source. The SDK opens the camera and
181
+ * pumps frames internally on `start()` — no `sendFrame()` needed. Returns
182
+ * `this` for chaining. Captures in THIS process — for Electron, prefer
183
+ * the renderer SDK's `useMediaStream()`.
184
+ */
185
+ useCamera(options?: CameraOptions): this;
186
+
187
+ /**
188
+ * Select a pre-recorded video file as the input source. `start()` begins
189
+ * playback (non-blocking, on SDK worker threads); use
190
+ * `waitUntilComplete()` or watch `'processingStatus'` for the idle
191
+ * transition to detect
192
+ * end-of-file. Returns `this` for chaining.
193
+ */
194
+ useFile(videoPath: string, options?: VideoFileOptions): this;
195
+
196
+ /**
197
+ * Submits a raw video frame. Requires `useCustomInput()` + `start()`
198
+ * first.
199
+ *
200
+ * @param buffer Raw pixel data (Uint8Array or Buffer).
201
+ * @param width Frame width in pixels.
202
+ * @param height Frame height in pixels.
203
+ * @param stride Row stride in bytes.
204
+ * @param pixelFormat One of the PixelFormat constants.
205
+ * @param timestampUs Capture time in microseconds; must be strictly increasing.
206
+ * @returns true if the frame was accepted.
207
+ */
208
+ sendFrame(
209
+ buffer: Uint8Array | Buffer,
210
+ width: number,
211
+ height: number,
212
+ stride: number,
213
+ pixelFormat: PixelFormatValue,
214
+ timestampUs: number,
215
+ ): boolean;
216
+
217
+ /**
218
+ * Register a callback for a named event. Replaces any previously
219
+ * registered callback for the same event. Returns `this` for chaining.
220
+ *
221
+ * | Event | Callback signature |
222
+ * |------------------------|------------------------------------------------------------------------------------|
223
+ * | `'processingStatus'` | `(status: ProcessingStatusValue) => void` |
224
+ * | `'validationStatus'` | `(code: ValidationCodeValue, timestampUs: number, hint: string) => void` |
225
+ * | `'metrics'` | `(buf: Buffer, timestampUs: number) => void` |
226
+ * | `'accumulatedMetrics'` | `(buf: Buffer, timestampUs: number) => void` |
227
+ * | `'insight'` | `(buf: Buffer, requestId: number) => void` |
228
+ * | `'error'` | `(code: SmartSpectraErrorCodeValue, message: string, retryable: boolean) => void` |
229
+ * | `'frameSentThrough'` | `(sent: boolean, timestampUs: number) => void` |
230
+ * | `'videoOutput'` | `(buf: Buffer, width: number, height: number, stride: number, pixelFormat: PixelFormatValue, timestampUs: number) => void` |
231
+ *
232
+ * `'videoOutput'` delivers a processed frame for the caller to render in
233
+ * its own UI. `buf` is borrowed for the callback only — it is copied before
234
+ * delivery, so retaining it is safe. Mainly useful for the custom-input /
235
+ * headless path.
236
+ */
237
+ on(event: 'processingStatus', callback: (status: ProcessingStatusValue) => void): this;
238
+ on(event: 'validationStatus', callback: (code: ValidationCodeValue, timestampUs: number, hint: string) => void): this;
239
+ on(event: 'metrics', callback: (buf: Buffer, timestampUs: number) => void): this;
240
+ on(event: 'accumulatedMetrics', callback: (buf: Buffer, timestampUs: number) => void): this;
241
+ on(event: 'insight', callback: (buf: Buffer, requestId: number) => void): this;
242
+ on(event: 'error', callback: (code: SmartSpectraErrorCodeValue, message: string, retryable: boolean) => void): this;
243
+ on(event: 'frameSentThrough', callback: (sent: boolean, timestampUs: number) => void): this;
244
+ on(event: 'videoOutput', callback: (buf: Buffer, width: number, height: number, stride: number, pixelFormat: PixelFormatValue, timestampUs: number) => void): this;
245
+ }
246
+
247
+ /**
248
+ * MetricType integer codes grouped by measurement type. Spread into
249
+ * `requestedMetrics`; omitting it is equivalent to passing
250
+ * `breathingMetrics`.
251
+ *
252
+ * @example
253
+ * ```ts
254
+ * import { SmartSpectra, breathingMetrics, cardioMetrics } from '@smartspectra/node-sdk';
255
+ *
256
+ * const ss = new SmartSpectra({
257
+ * apiKey: 'YOUR_KEY',
258
+ * requestedMetrics: [...breathingMetrics, ...cardioMetrics],
259
+ * });
260
+ * ```
261
+ */
262
+ export declare const breathingMetrics: readonly number[];
263
+ export declare const cardioMetrics: readonly number[];
264
+ export declare const faceMetrics: readonly number[];
265
+ export declare const micromotionMetrics: readonly number[];
266
+ export declare const edaMetrics: readonly number[];
267
+ /** Default metric bundle used when `requestedMetrics` is omitted. */
268
+ export declare const defaultSupportedMetrics: readonly number[];
269
+
270
+ /**
271
+ * Register a protobuf Metrics class exposing `deserializeBinary(buf)`
272
+ * (google-protobuf) or `decode(buf)` (protobufjs). `decodeMetrics()` will
273
+ * use it; otherwise the raw Buffer is returned.
274
+ */
275
+ export declare function setMetricsClass(cls: unknown): void;
276
+
277
+ /**
278
+ * Deserialize a protobuf Metrics buffer from the 'metrics' or
279
+ * 'accumulatedMetrics' events. Returns the decoded message if a class has
280
+ * been registered via `setMetricsClass`, otherwise the raw Buffer.
281
+ */
282
+ export declare function decodeMetrics(buf: Buffer): unknown;
package/js/index.js ADDED
@@ -0,0 +1,60 @@
1
+ // index.js
2
+ // Copyright (C) 2026 Presage Technologies, Inc.
3
+ //
4
+ // SPDX-License-Identifier: LicenseRef-Proprietary
5
+
6
+ 'use strict';
7
+
8
+ const {
9
+ SmartSpectraSDK,
10
+ ProcessingStatus,
11
+ PixelFormat,
12
+ ValidationCode,
13
+ SmartSpectraErrorCode,
14
+ FrameTransform,
15
+ breathingMetrics,
16
+ cardioMetrics,
17
+ faceMetrics,
18
+ micromotionMetrics,
19
+ edaMetrics,
20
+ defaultSupportedMetrics,
21
+ } = require('./smartspectra');
22
+
23
+ // Eagerly register the bundled Metrics class so `decodeMetrics(buf)` works
24
+ // without setup. Renderer-side consumers must require
25
+ // `@smartspectra/node-sdk/messages` directly — this package root pulls in
26
+ // koffi, which can't be bundled into a browser context.
27
+ const { Metrics: DefaultMetricsClass } = require('./messages');
28
+
29
+ let MetricsClass = DefaultMetricsClass;
30
+
31
+ function setMetricsClass(cls) {
32
+ MetricsClass = cls;
33
+ }
34
+
35
+ function decodeMetrics(buf) {
36
+ if (MetricsClass && typeof MetricsClass.deserializeBinary === 'function') {
37
+ return MetricsClass.deserializeBinary(buf);
38
+ }
39
+ if (MetricsClass && typeof MetricsClass.decode === 'function') {
40
+ return MetricsClass.decode(buf); // protobufjs-style
41
+ }
42
+ return buf;
43
+ }
44
+
45
+ module.exports = {
46
+ SmartSpectraSDK,
47
+ ProcessingStatus,
48
+ PixelFormat,
49
+ ValidationCode,
50
+ SmartSpectraErrorCode,
51
+ FrameTransform,
52
+ breathingMetrics,
53
+ cardioMetrics,
54
+ faceMetrics,
55
+ micromotionMetrics,
56
+ edaMetrics,
57
+ defaultSupportedMetrics,
58
+ decodeMetrics,
59
+ setMetricsClass,
60
+ };
@@ -0,0 +1,32 @@
1
+ // js/main/index.d.ts
2
+ // Copyright (C) 2026 Presage Technologies, Inc.
3
+ //
4
+ // SPDX-License-Identifier: LicenseRef-Proprietary
5
+
6
+ import type { BrowserWindow } from 'electron';
7
+
8
+ export { SmartSpectraSDK, ProcessingStatus } from '../../js/index';
9
+
10
+ /** Options for `bindSmartSpectraIpc`. */
11
+ export interface BindSmartSpectraIpcOptions {
12
+ /**
13
+ * Optional logger for diagnostic messages from the IPC bridge.
14
+ * Defaults to `console`.
15
+ */
16
+ logger?: (level: 'info' | 'warn' | 'error', msg: string) => void;
17
+ }
18
+
19
+ /**
20
+ * Wires the per-window IPC channel that backs `@smartspectra/node-sdk/renderer`.
21
+ *
22
+ * Call once per `BrowserWindow` that hosts a renderer using the helper. The
23
+ * binding tracks the window via `'closed'` and releases its SDK + port when
24
+ * the window goes away, so apps don't need explicit teardown.
25
+ *
26
+ * One-time SDK initialization runs on the first call. Host apps don't manage
27
+ * it.
28
+ */
29
+ export declare function bindSmartSpectraIpc(
30
+ window: BrowserWindow,
31
+ options?: BindSmartSpectraIpcOptions,
32
+ ): void;