@iam-protocol/pulse-sdk 0.3.5 → 0.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iam-protocol/pulse-sdk",
3
- "version": "0.3.5",
3
+ "version": "0.3.7",
4
4
  "description": "Client-side SDK for IAM Protocol — sensor capture, TBH generation, ZK proof construction",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
package/src/pulse.ts CHANGED
@@ -40,9 +40,18 @@ async function extractFeatures(data: SensorData): Promise<number[]> {
40
40
  const audioFeatures = await extractSpeakerFeatures(data.audio);
41
41
 
42
42
  const hasMotion = data.motion.length >= MIN_MOTION_SAMPLES;
43
- const motionFeatures = hasMotion
44
- ? extractMotionFeatures(data.motion)
45
- : extractMouseDynamics(data.touch);
43
+ const hasTouch = data.touch.length >= MIN_TOUCH_SAMPLES;
44
+
45
+ // On mobile (both IMU and touch available), use touch/pointer dynamics for
46
+ // kinematic features. Stationary IMU reads constant gravity — the derivatives
47
+ // are near-zero and produce identical features across sessions. Finger tracing
48
+ // has natural inter-session variance because no two paths are identical.
49
+ const motionFeatures =
50
+ hasMotion && hasTouch
51
+ ? extractMouseDynamics(data.touch)
52
+ : hasMotion
53
+ ? extractMotionFeatures(data.motion)
54
+ : extractMouseDynamics(data.touch);
46
55
 
47
56
  const touchFeatures = extractTouchFeatures(data.touch);
48
57
  return fuseFeatures(audioFeatures, motionFeatures, touchFeatures);
@@ -92,6 +101,19 @@ async function processSensorData(
92
101
  };
93
102
  }
94
103
 
104
+ // Re-verification requires audio + at least one other modality.
105
+ // Audio-only fingerprints lack inter-session variance from motion/touch,
106
+ // producing identical SimHash results that fail the min_distance constraint.
107
+ const hasPreviousData = loadVerificationData() !== null;
108
+ if (hasPreviousData && !hasMotion && !hasTouch) {
109
+ return {
110
+ success: false,
111
+ commitment: new Uint8Array(32),
112
+ isFirstVerification: false,
113
+ error: "Insufficient sensor data for re-verification. Please trace the curve and allow motion access.",
114
+ };
115
+ }
116
+
95
117
  // Extract features
96
118
  const features = await extractFeatures(sensorData);
97
119
 
@@ -432,30 +454,30 @@ export class PulseSDK {
432
454
  const session = this.createSession(touchElement);
433
455
  const stopPromises: Promise<void>[] = [];
434
456
 
435
- // Audio
457
+ // Motion first — requires user gesture on iOS (gesture expires after getUserMedia)
436
458
  try {
437
- await session.startAudio();
459
+ await session.startMotion();
460
+ } catch {
461
+ /* unexpected error — motion already skipped or idle */
462
+ }
463
+ if (session.isMotionCapturing()) {
438
464
  stopPromises.push(
439
465
  new Promise<void>((r) => setTimeout(r, DEFAULT_CAPTURE_MS))
440
- .then(() => session.stopAudio())
466
+ .then(() => session.stopMotion())
441
467
  .then(() => {})
442
468
  );
443
- } catch (err: any) {
444
- throw new Error(`Audio capture failed: ${err?.message ?? "microphone unavailable"}`);
445
469
  }
446
470
 
447
- // MotionstartMotion auto-skips if permission denied (no throw)
471
+ // Audio second getUserMedia works without a gesture on secure origins
448
472
  try {
449
- await session.startMotion();
450
- } catch {
451
- /* unexpected error — motion already skipped or idle */
452
- }
453
- if (session.isMotionCapturing()) {
473
+ await session.startAudio();
454
474
  stopPromises.push(
455
475
  new Promise<void>((r) => setTimeout(r, DEFAULT_CAPTURE_MS))
456
- .then(() => session.stopMotion())
476
+ .then(() => session.stopAudio())
457
477
  .then(() => {})
458
478
  );
479
+ } catch (err: any) {
480
+ throw new Error(`Audio capture failed: ${err?.message ?? "microphone unavailable"}`);
459
481
  }
460
482
 
461
483
  // Touch