@iam-protocol/pulse-sdk 0.3.4 → 0.3.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/dist/index.mjs CHANGED
@@ -30,9 +30,10 @@ async function captureAudio(options = {}) {
30
30
  signal,
31
31
  minDurationMs = MIN_CAPTURE_MS,
32
32
  maxDurationMs = MAX_CAPTURE_MS,
33
- onAudioLevel
33
+ onAudioLevel,
34
+ stream: preAcquiredStream
34
35
  } = options;
35
- const stream = await navigator.mediaDevices.getUserMedia({
36
+ const stream = preAcquiredStream ?? await navigator.mediaDevices.getUserMedia({
36
37
  audio: {
37
38
  sampleRate: TARGET_SAMPLE_RATE,
38
39
  channelCount: 1,
@@ -42,6 +43,7 @@ async function captureAudio(options = {}) {
42
43
  }
43
44
  });
44
45
  const ctx = new AudioContext({ sampleRate: TARGET_SAMPLE_RATE });
46
+ await ctx.resume();
45
47
  const capturedSampleRate = ctx.sampleRate;
46
48
  const source = ctx.createMediaStreamSource(stream);
47
49
  const chunks = [];
@@ -118,7 +120,7 @@ async function captureMotion(options = {}) {
118
120
  minDurationMs = MIN_CAPTURE_MS,
119
121
  maxDurationMs = MAX_CAPTURE_MS
120
122
  } = options;
121
- const hasPermission = await requestMotionPermission();
123
+ const hasPermission = options.permissionGranted ?? await requestMotionPermission();
122
124
  if (!hasPermission) return [];
123
125
  const samples = [];
124
126
  const startTime = performance.now();
@@ -1390,6 +1392,15 @@ async function processSensorData(sensorData, config, wallet, connection) {
1390
1392
  error: "No voice data detected. Please speak the phrase clearly during capture."
1391
1393
  };
1392
1394
  }
1395
+ const hasPreviousData = loadVerificationData() !== null;
1396
+ if (hasPreviousData && !hasMotion && !hasTouch) {
1397
+ return {
1398
+ success: false,
1399
+ commitment: new Uint8Array(32),
1400
+ isFirstVerification: false,
1401
+ error: "Insufficient sensor data for re-verification. Please trace the curve and allow motion access."
1402
+ };
1403
+ }
1393
1404
  const features = await extractFeatures(sensorData);
1394
1405
  const nonZero = features.filter((v) => v !== 0).length;
1395
1406
  console.log(
@@ -1499,12 +1510,25 @@ var PulseSession = class {
1499
1510
  async startAudio(onAudioLevel) {
1500
1511
  if (this.audioStageState !== "idle")
1501
1512
  throw new Error("Audio capture already started");
1513
+ const stream = await navigator.mediaDevices.getUserMedia({
1514
+ audio: {
1515
+ sampleRate: 16e3,
1516
+ channelCount: 1,
1517
+ echoCancellation: false,
1518
+ noiseSuppression: false,
1519
+ autoGainControl: false
1520
+ }
1521
+ });
1502
1522
  this.audioStageState = "capturing";
1503
1523
  this.audioController = new AbortController();
1504
1524
  this.audioPromise = captureAudio({
1505
1525
  signal: this.audioController.signal,
1506
- onAudioLevel
1507
- }).catch(() => null);
1526
+ onAudioLevel,
1527
+ stream
1528
+ }).catch(() => {
1529
+ stream.getTracks().forEach((t) => t.stop());
1530
+ return null;
1531
+ });
1508
1532
  }
1509
1533
  async stopAudio() {
1510
1534
  if (this.audioStageState !== "capturing")
@@ -1520,10 +1544,16 @@ var PulseSession = class {
1520
1544
  async startMotion() {
1521
1545
  if (this.motionStageState !== "idle")
1522
1546
  throw new Error("Motion capture already started");
1547
+ const hasPermission = await requestMotionPermission();
1548
+ if (!hasPermission) {
1549
+ this.motionStageState = "skipped";
1550
+ return;
1551
+ }
1523
1552
  this.motionStageState = "capturing";
1524
1553
  this.motionController = new AbortController();
1525
1554
  this.motionPromise = captureMotion({
1526
- signal: this.motionController.signal
1555
+ signal: this.motionController.signal,
1556
+ permissionGranted: true
1527
1557
  }).catch(() => []);
1528
1558
  }
1529
1559
  async stopMotion() {
@@ -1539,6 +1569,9 @@ var PulseSession = class {
1539
1569
  throw new Error("Motion capture already started");
1540
1570
  this.motionStageState = "skipped";
1541
1571
  }
1572
+ isMotionCapturing() {
1573
+ return this.motionStageState === "capturing";
1574
+ }
1542
1575
  // --- Touch ---
1543
1576
  async startTouch() {
1544
1577
  if (this.touchStageState !== "idle")
@@ -1611,22 +1644,23 @@ var PulseSDK = class {
1611
1644
  const session = this.createSession(touchElement);
1612
1645
  const stopPromises = [];
1613
1646
  try {
1614
- await session.startAudio();
1647
+ await session.startMotion();
1648
+ } catch {
1649
+ }
1650
+ if (session.isMotionCapturing()) {
1615
1651
  stopPromises.push(
1616
- new Promise((r) => setTimeout(r, DEFAULT_CAPTURE_MS)).then(() => session.stopAudio()).then(() => {
1652
+ new Promise((r) => setTimeout(r, DEFAULT_CAPTURE_MS)).then(() => session.stopMotion()).then(() => {
1617
1653
  })
1618
1654
  );
1619
- } catch (err) {
1620
- throw new Error(`Audio capture failed: ${err?.message ?? "microphone unavailable"}`);
1621
1655
  }
1622
1656
  try {
1623
- await session.startMotion();
1657
+ await session.startAudio();
1624
1658
  stopPromises.push(
1625
- new Promise((r) => setTimeout(r, DEFAULT_CAPTURE_MS)).then(() => session.stopMotion()).then(() => {
1659
+ new Promise((r) => setTimeout(r, DEFAULT_CAPTURE_MS)).then(() => session.stopAudio()).then(() => {
1626
1660
  })
1627
1661
  );
1628
- } catch {
1629
- session.skipMotion();
1662
+ } catch (err) {
1663
+ throw new Error(`Audio capture failed: ${err?.message ?? "microphone unavailable"}`);
1630
1664
  }
1631
1665
  if (touchElement) {
1632
1666
  try {