@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 +13 -0
- package/README.md +409 -0
- package/js/constants.js +125 -0
- package/js/ffi.js +494 -0
- package/js/index.d.ts +282 -0
- package/js/index.js +60 -0
- package/js/main/index.d.ts +32 -0
- package/js/main/index.js +404 -0
- package/js/messages/generated.d.ts +2083 -0
- package/js/messages/generated.js +5810 -0
- package/js/messages/index.d.ts +27 -0
- package/js/messages/index.js +67 -0
- package/js/preload/index.js +116 -0
- package/js/renderer/index.d.ts +154 -0
- package/js/renderer/index.js +670 -0
- package/js/resolve-native.js +113 -0
- package/js/smartspectra.js +293 -0
- package/package.json +81 -0
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;
|