@entros/pulse-sdk 1.5.0 → 1.5.1

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/README.md CHANGED
@@ -5,6 +5,8 @@
5
5
 
6
6
  Client-side SDK for the Entros Protocol. Captures behavioral biometrics (voice, motion, touch), extracts 134 statistical features, generates a Groth16 zero-knowledge proof, and submits for on-chain verification on Solana. Raw biometric data stays on-device — only derived features and the proof are transmitted.
7
7
 
8
+ > **Looking for a drop-in?** Most integrators want [`@entros/verify`](https://github.com/entros-protocol/entros-verify) — a popup-pattern React component that wraps this SDK and ships verification in five lines of JSX. Use this package directly when you need to own the verification UX (custom capture canvas, branded loading states, mobile-native).
9
+
8
10
  ## Install
9
11
 
10
12
  ```bash
package/dist/index.js CHANGED
@@ -599,6 +599,26 @@ function extractFormantRatios(samples, sampleRate, frameSize, hopSize) {
599
599
  return { f1f2, f2f3 };
600
600
  }
601
601
 
602
+ // src/yield.ts
603
+ function yieldToMainThread() {
604
+ return new Promise((resolve) => {
605
+ if (typeof MessageChannel !== "undefined") {
606
+ const channel = new MessageChannel();
607
+ channel.port1.onmessage = () => {
608
+ channel.port1.close();
609
+ resolve();
610
+ };
611
+ channel.port2.postMessage(null);
612
+ return;
613
+ }
614
+ if (typeof setTimeout !== "undefined") {
615
+ setTimeout(resolve, 0);
616
+ return;
617
+ }
618
+ resolve();
619
+ });
620
+ }
621
+
602
622
  // src/extraction/speaker.ts
603
623
  function getFrameSize(sampleRate) {
604
624
  const MIN_F0 = 50;
@@ -831,6 +851,7 @@ async function extractSpeakerFeaturesDetailed(audio) {
831
851
  normalizedSamples = samples;
832
852
  }
833
853
  const { f0, amplitudes: normalizedAmplitudes, periods } = await detectF0Contour(normalizedSamples, sampleRate);
854
+ await yieldToMainThread();
834
855
  const amplitudes = [];
835
856
  for (let i = 0; i < numFrames; i++) {
836
857
  const start = i * hopSize;
@@ -855,6 +876,7 @@ async function extractSpeakerFeaturesDetailed(audio) {
855
876
  const hnrStats = condense(hnrValues);
856
877
  const hnrEntropy = entropy(hnrValues);
857
878
  const hnrFeatures = [hnrStats.mean, hnrStats.variance, hnrStats.skewness, hnrStats.kurtosis, hnrEntropy];
879
+ await yieldToMainThread();
858
880
  const { f1f2, f2f3 } = extractFormantRatios(normalizedSamples, sampleRate, frameSize, hopSize);
859
881
  const f1f2Stats = condense(f1f2);
860
882
  const f2f3Stats = condense(f2f3);
@@ -868,6 +890,7 @@ async function extractSpeakerFeaturesDetailed(audio) {
868
890
  f2f3Stats.skewness,
869
891
  f2f3Stats.kurtosis
870
892
  ];
893
+ await yieldToMainThread();
871
894
  const ltasFeatures = await computeLTAS(samples, sampleRate);
872
895
  const voicingFeatures = [voicedRatio];
873
896
  const ampStats = condense(amplitudes);
@@ -4302,10 +4325,13 @@ async function extractFeatures(data) {
4302
4325
  const { features: audioFeatures, f0Contour } = await extractSpeakerFeaturesDetailed(
4303
4326
  data.audio
4304
4327
  );
4328
+ await yieldToMainThread();
4305
4329
  const hasMotion = data.motion.length >= MIN_MOTION_SAMPLES;
4306
4330
  const hasTouch = data.touch.length >= MIN_TOUCH_SAMPLES;
4307
4331
  const motionFeatures = hasMotion && hasTouch ? extractMouseDynamics(data.touch) : hasMotion ? extractMotionFeatures(data.motion) : extractMouseDynamics(data.touch);
4332
+ await yieldToMainThread();
4308
4333
  const touchFeatures = extractTouchFeatures(data.touch);
4334
+ await yieldToMainThread();
4309
4335
  const accelMagnitude = hasMotion && f0Contour.length > 0 ? extractAccelerationMagnitude(data.motion, f0Contour.length) : [];
4310
4336
  return {
4311
4337
  raw: fuseRawFeatures(audioFeatures, motionFeatures, touchFeatures),
@@ -4319,6 +4345,7 @@ var MIN_MOTION_SAMPLES = 10;
4319
4345
  var MIN_TOUCH_SAMPLES = 10;
4320
4346
  async function extractFingerprintAndValidate(sensorData, config, walletAddress, onProgress) {
4321
4347
  onProgress?.("Extracting features...");
4348
+ await yieldToMainThread();
4322
4349
  const {
4323
4350
  raw: features,
4324
4351
  normalized: normalizedFeatures,
@@ -4333,6 +4360,7 @@ async function extractFingerprintAndValidate(sensorData, config, walletAddress,
4333
4360
  const tbh = await generateTBH(fingerprint);
4334
4361
  let signedReceipt;
4335
4362
  onProgress?.("Validating...");
4363
+ await yieldToMainThread();
4336
4364
  if (config.relayerUrl && walletAddress) {
4337
4365
  try {
4338
4366
  const baseUrl = new URL(config.relayerUrl);