@entros/pulse-sdk 1.0.1 → 1.1.0
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.d.mts +10 -3
- package/dist/index.d.ts +10 -3
- package/dist/index.js +117 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +114 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -1
package/dist/index.mjs
CHANGED
|
@@ -25,7 +25,7 @@ var PROGRAM_IDS = {
|
|
|
25
25
|
var AGENT_REGISTRY_CONFIG = {
|
|
26
26
|
programIdDevnet: "8oo4J9tBB3Hna1jRQ3rWvJjojqM5DYTDJo5cejUuJy3C",
|
|
27
27
|
programIdMainnet: "8oo4dC4JvBLwy5tGgiH3WwK4B9PWxL9Z4XjA2jzkQMbQ",
|
|
28
|
-
metadataKey: "
|
|
28
|
+
metadataKey: "entros:human-operator"
|
|
29
29
|
};
|
|
30
30
|
var SAS_CONFIG = {
|
|
31
31
|
programId: "22zoJMtdu4tQc2PzL74ZUT7FrwgB1Udec8DdW4yw4BdG",
|
|
@@ -2315,6 +2315,116 @@ var PulseSession = class {
|
|
|
2315
2315
|
);
|
|
2316
2316
|
this.touchStageState = "skipped";
|
|
2317
2317
|
}
|
|
2318
|
+
// --- Test hooks (internal builds only) ---
|
|
2319
|
+
/**
|
|
2320
|
+
* @internal Test-only. Primes the session with pre-captured sensor data,
|
|
2321
|
+
* bypassing browser capture APIs. Throws unless built with IAM_INTERNAL_TEST=1.
|
|
2322
|
+
* Stripped from the published .d.ts so npm consumers never see it. Used by the
|
|
2323
|
+
* red team harness to drive the real verification pipeline (extraction →
|
|
2324
|
+
* SimHash → TBH → proof → submit) against synthetic sensor data — never
|
|
2325
|
+
* available to npm consumers.
|
|
2326
|
+
*/
|
|
2327
|
+
__injectSensorData(data) {
|
|
2328
|
+
if (true) {
|
|
2329
|
+
throw new Error(
|
|
2330
|
+
"PulseSession.__injectSensorData is only available in internal test builds. Set IAM_INTERNAL_TEST=1 when building pulse-sdk from source."
|
|
2331
|
+
);
|
|
2332
|
+
}
|
|
2333
|
+
const conflicts = [];
|
|
2334
|
+
if (this.audioStageState === "capturing") conflicts.push("audio");
|
|
2335
|
+
if (this.motionStageState === "capturing") conflicts.push("motion");
|
|
2336
|
+
if (this.touchStageState === "capturing") conflicts.push("touch");
|
|
2337
|
+
if (conflicts.length > 0) {
|
|
2338
|
+
throw new Error(
|
|
2339
|
+
`__injectSensorData: cannot inject while stages are capturing: ${conflicts.join(", ")}. Create a fresh session via sdk.createSession() and inject before any startAudio/startMotion/startTouch call.`
|
|
2340
|
+
);
|
|
2341
|
+
}
|
|
2342
|
+
if (!data.audio || data.audio.samples.length < MIN_AUDIO_SAMPLES) {
|
|
2343
|
+
throw new Error(
|
|
2344
|
+
`__injectSensorData: audio required, minimum ${MIN_AUDIO_SAMPLES} samples (got ${data.audio?.samples.length ?? 0}).`
|
|
2345
|
+
);
|
|
2346
|
+
}
|
|
2347
|
+
if (data.motion.length < MIN_MOTION_SAMPLES) {
|
|
2348
|
+
throw new Error(
|
|
2349
|
+
`__injectSensorData: motion required, minimum ${MIN_MOTION_SAMPLES} samples (got ${data.motion.length}).`
|
|
2350
|
+
);
|
|
2351
|
+
}
|
|
2352
|
+
if (data.touch.length < MIN_TOUCH_SAMPLES) {
|
|
2353
|
+
throw new Error(
|
|
2354
|
+
`__injectSensorData: touch required, minimum ${MIN_TOUCH_SAMPLES} samples (got ${data.touch.length}).`
|
|
2355
|
+
);
|
|
2356
|
+
}
|
|
2357
|
+
this.audioData = data.audio;
|
|
2358
|
+
this.motionData = data.motion;
|
|
2359
|
+
this.touchData = data.touch;
|
|
2360
|
+
this.audioStageState = "captured";
|
|
2361
|
+
this.motionStageState = "captured";
|
|
2362
|
+
this.touchStageState = "captured";
|
|
2363
|
+
}
|
|
2364
|
+
/**
|
|
2365
|
+
* @internal
|
|
2366
|
+
*
|
|
2367
|
+
* Run the validation step of the verify pipeline only: feature extraction
|
|
2368
|
+
* + `/validate-features` POST. Returns the validation outcome without ever
|
|
2369
|
+
* touching the on-chain submission path. Mirrors the production user
|
|
2370
|
+
* flow's pre-payment gate — the validation server runs without requiring
|
|
2371
|
+
* the wallet to have SOL, just like a real user gets a validation result
|
|
2372
|
+
* before being prompted to sign the on-chain mint.
|
|
2373
|
+
*
|
|
2374
|
+
* Note: this is a strict subset of `complete()`. It skips the data-quality
|
|
2375
|
+
* gates and re-verification check that `processSensorData` performs. The
|
|
2376
|
+
* validation server still runs its full pipeline (Tier 1 + Tier 2 +
|
|
2377
|
+
* phrase binding); only the client-side pre-flight checks differ.
|
|
2378
|
+
*
|
|
2379
|
+
* Use case: red team campaigns measuring server-side validation at scale
|
|
2380
|
+
* without per-attempt SOL funding. Build-time gated identically to
|
|
2381
|
+
* `__injectSensorData`; throws in production builds.
|
|
2382
|
+
*/
|
|
2383
|
+
async __validateOnly(walletAddress) {
|
|
2384
|
+
if (true) {
|
|
2385
|
+
throw new Error(
|
|
2386
|
+
"PulseSession.__validateOnly is only available in internal test builds. Set IAM_INTERNAL_TEST=1 when building pulse-sdk from source."
|
|
2387
|
+
);
|
|
2388
|
+
}
|
|
2389
|
+
if (typeof walletAddress !== "string" || walletAddress.length === 0) {
|
|
2390
|
+
throw new Error(
|
|
2391
|
+
"__validateOnly requires a non-empty walletAddress string (used as wallet_id in the /validate-features payload)."
|
|
2392
|
+
);
|
|
2393
|
+
}
|
|
2394
|
+
const active = [];
|
|
2395
|
+
if (this.audioStageState === "capturing") active.push("audio");
|
|
2396
|
+
if (this.motionStageState === "capturing") active.push("motion");
|
|
2397
|
+
if (this.touchStageState === "capturing") active.push("touch");
|
|
2398
|
+
if (active.length > 0) {
|
|
2399
|
+
throw new Error(
|
|
2400
|
+
`Cannot validate: stages still capturing: ${active.join(", ")}`
|
|
2401
|
+
);
|
|
2402
|
+
}
|
|
2403
|
+
if (!this.audioData || this.motionData.length === 0 || this.touchData.length === 0) {
|
|
2404
|
+
throw new Error(
|
|
2405
|
+
"__validateOnly requires sensor data first \u2014 call __injectSensorData() before this."
|
|
2406
|
+
);
|
|
2407
|
+
}
|
|
2408
|
+
const sensorData = {
|
|
2409
|
+
audio: this.audioData,
|
|
2410
|
+
motion: this.motionData,
|
|
2411
|
+
touch: this.touchData,
|
|
2412
|
+
modalities: {
|
|
2413
|
+
audio: true,
|
|
2414
|
+
motion: true,
|
|
2415
|
+
touch: true
|
|
2416
|
+
}
|
|
2417
|
+
};
|
|
2418
|
+
const extraction = await extractFingerprintAndValidate(
|
|
2419
|
+
sensorData,
|
|
2420
|
+
this.config,
|
|
2421
|
+
walletAddress
|
|
2422
|
+
);
|
|
2423
|
+
if (!extraction.ok) {
|
|
2424
|
+
return { validated: false, error: extraction.error };
|
|
2425
|
+
}
|
|
2426
|
+
return { validated: true };
|
|
2427
|
+
}
|
|
2318
2428
|
// --- Complete ---
|
|
2319
2429
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Solana types are optional peer deps
|
|
2320
2430
|
async complete(wallet, connection, onProgress) {
|
|
@@ -2989,7 +3099,10 @@ export {
|
|
|
2989
3099
|
DEFAULT_THRESHOLD,
|
|
2990
3100
|
FINGERPRINT_BITS,
|
|
2991
3101
|
MAX_CAPTURE_MS,
|
|
3102
|
+
MIN_AUDIO_SAMPLES,
|
|
2992
3103
|
MIN_CAPTURE_MS,
|
|
3104
|
+
MIN_MOTION_SAMPLES,
|
|
3105
|
+
MIN_TOUCH_SAMPLES,
|
|
2993
3106
|
PROGRAM_IDS,
|
|
2994
3107
|
PulseSDK,
|
|
2995
3108
|
PulseSession,
|