@svrnsec/pulse 0.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/index.d.ts ADDED
@@ -0,0 +1,588 @@
1
+ /**
2
+ * @sovereign/pulse — TypeScript Declarations
3
+ */
4
+
5
+ // =============================================================================
6
+ // Core pulse() API
7
+ // =============================================================================
8
+
9
+ export interface PulseOptions {
10
+ /**
11
+ * Server-issued challenge nonce — required in self-hosted mode.
12
+ * Omit when using apiKey (hosted API fetches its own nonce).
13
+ */
14
+ nonce?: string;
15
+ /**
16
+ * Sovereign hosted API key — enables zero-config mode.
17
+ * When set, pulse() handles challenge + verify automatically.
18
+ * Get a key at https://sovereign.dev
19
+ */
20
+ apiKey?: string;
21
+ /** Hosted API base URL. Default: 'https://api.sovereign.dev' */
22
+ apiUrl?: string;
23
+ /** Options forwarded to the hosted verify endpoint (minJitterScore, requireBio, etc.) */
24
+ verifyOptions?: Partial<ValidateOptions>;
25
+ /** Number of WASM matrix-multiply iterations. Default: 200 */
26
+ iterations?: number;
27
+ /** How long to listen for mouse/keyboard bio signals (ms). Default: 3000 */
28
+ bioWindowMs?: number;
29
+ /** Run cold/load/hot phases for entropy-jitter ratio. Default: true */
30
+ phased?: boolean;
31
+ /** Use adaptive early exit (faster for obvious VMs). Default: true */
32
+ adaptive?: boolean;
33
+ /** Stop early if VM/HW signal reaches this confidence. Default: 0.85 */
34
+ adaptiveThreshold?: number;
35
+ /** Custom WASM binary URL/path (optional). */
36
+ wasmPath?: string;
37
+ /** Progress callback — called at each pipeline stage. */
38
+ onProgress?: (stage: PulseStage, meta?: ProgressMeta) => void;
39
+ }
40
+
41
+ export type PulseStage =
42
+ | 'start'
43
+ | 'entropy_batch'
44
+ | 'entropy_done'
45
+ | 'canvas_done'
46
+ | 'audio_done'
47
+ | 'bio_done'
48
+ | 'analysis_done'
49
+ | 'complete';
50
+
51
+ export interface ProgressMeta {
52
+ /** Current iteration count (during adaptive probe). */
53
+ iterations?: number;
54
+ /** Max iterations configured. */
55
+ maxIterations?: number;
56
+ /** Percentage complete (0–100). */
57
+ pct?: number;
58
+ /** Preliminary verdict from adaptive probe. */
59
+ earlyVerdict?: 'vm' | 'physical' | 'borderline' | 'uncertain';
60
+ /** Estimated milliseconds remaining. */
61
+ etaMs?: number;
62
+ /** Current VM confidence (0–1). */
63
+ vmConf?: number;
64
+ /** Current physical hardware confidence (0–1). */
65
+ hwConf?: number;
66
+ }
67
+
68
+ export interface PulseCommitment {
69
+ /** Statistical summary payload (~1.6KB). Send this to your server. */
70
+ payload: ProofPayload;
71
+ /** BLAKE3 hex hash of the canonical payload. */
72
+ hash: string;
73
+ /**
74
+ * Server validation result — only present when using apiKey (hosted mode).
75
+ * Undefined in self-hosted mode; validate server-side with validateProof().
76
+ */
77
+ result?: ValidationResult;
78
+ }
79
+
80
+ export function pulse(opts: PulseOptions): Promise<PulseCommitment>;
81
+
82
+ // =============================================================================
83
+ // React Hook (import from '@sovereign/pulse/react')
84
+ // =============================================================================
85
+
86
+ export interface UsePulseOptions {
87
+ /** Sovereign hosted API key. Handles nonce + verify automatically. */
88
+ apiKey?: string;
89
+ /** Hosted API base URL. Default: 'https://api.sovereign.dev' */
90
+ apiUrl?: string;
91
+ /** Self-hosted challenge endpoint URL. */
92
+ challengeUrl?: string;
93
+ /** Self-hosted verify endpoint URL. */
94
+ verifyUrl?: string;
95
+ /** Number of WASM matrix-multiply iterations. Default: 200 */
96
+ iterations?: number;
97
+ /** Bio collection window in milliseconds. Default: 3000 */
98
+ bioWindowMs?: number;
99
+ /** Enable adaptive early exit. Default: true */
100
+ adaptive?: boolean;
101
+ /** Run immediately on mount. Default: false */
102
+ autoRun?: boolean;
103
+ /** Called when proof + result are ready. */
104
+ onResult?: (result: ValidationResult | null, commitment: PulseCommitment) => void;
105
+ /** Called on error. */
106
+ onError?: (error: Error) => void;
107
+ }
108
+
109
+ export interface UsePulseReturn {
110
+ /** Trigger the probe manually. */
111
+ run: () => Promise<void>;
112
+ /** Reset all state back to idle. */
113
+ reset: () => void;
114
+ /** Current pipeline stage. */
115
+ stage: PulseStage | null;
116
+ /** Probe progress 0–100. */
117
+ pct: number;
118
+ /** Live VM confidence 0–1 (updates during entropy_batch stages). */
119
+ vmConf: number;
120
+ /** Live HW confidence 0–1. */
121
+ hwConf: number;
122
+ /** Preliminary verdict from adaptive probe, or null if still uncertain. */
123
+ earlyVerdict: 'vm' | 'physical' | 'borderline' | 'uncertain' | null;
124
+ /** The BLAKE3 commitment. Available after probe completes. */
125
+ proof: PulseCommitment | null;
126
+ /** Server validation result. Available after verify completes (hosted/verifyUrl mode). */
127
+ result: ValidationResult | null;
128
+ /** True while probe is in progress. */
129
+ isRunning: boolean;
130
+ /** True when probe has completed (pass or fail). */
131
+ isReady: boolean;
132
+ /** Any error thrown during the probe. */
133
+ error: Error | null;
134
+ }
135
+
136
+ /** React hook — import from '@sovereign/pulse/react' */
137
+ export declare function usePulse(opts?: UsePulseOptions): UsePulseReturn;
138
+
139
+ // =============================================================================
140
+ // Fingerprint class (high-level API)
141
+ // =============================================================================
142
+
143
+ export class Fingerprint {
144
+ /** Collect all hardware signals and return a Fingerprint instance. */
145
+ static collect(opts: PulseOptions): Promise<Fingerprint>;
146
+
147
+ /** True if the device is likely a VM, AI endpoint, or sanitised cloud env. */
148
+ readonly isSynthetic: boolean;
149
+
150
+ /** Confidence in the isSynthetic verdict (0–100). */
151
+ readonly confidence: number;
152
+
153
+ /**
154
+ * Final normalised score [0.0, 1.0] after all three analysis stages.
155
+ * Higher = more physical.
156
+ */
157
+ readonly score: number;
158
+
159
+ /**
160
+ * Dynamic passing threshold for this specific proof [0.55, 0.67].
161
+ * Lower when more evidence was collected; higher for minimal-evidence proofs.
162
+ */
163
+ readonly threshold: number;
164
+
165
+ /**
166
+ * Evidence weight [0, 1] — reflects how much data was collected.
167
+ * 1.0 = 200 iterations + phased + bio + audio + canvas
168
+ */
169
+ readonly evidenceWeight: number;
170
+
171
+ /** Confidence tier. */
172
+ readonly tier: 'high' | 'medium' | 'low' | 'uncertain';
173
+
174
+ /**
175
+ * Timing profile of the device.
176
+ * - `'analog-fog'` — real hardware, natural Brownian noise
177
+ * - `'picket-fence'` — VM steal-time bursts at regular intervals
178
+ * - `'burst-scheduler'` — irregular VM scheduling (VMware-style)
179
+ * - `'hypervisor-flat'` — completely flat (heavy datacenter VM)
180
+ * - `'near-physical'` — ambiguous (Nitro, GPU passthrough)
181
+ */
182
+ readonly profile: 'analog-fog' | 'picket-fence' | 'burst-scheduler' | 'hypervisor-flat' | 'near-physical' | 'unknown';
183
+
184
+ /** Detected cloud provider / hypervisor identifier. */
185
+ readonly providerId: string;
186
+
187
+ /** Human-readable provider label (e.g. "DigitalOcean Droplet (KVM)"). */
188
+ readonly providerLabel: string;
189
+
190
+ /**
191
+ * Estimated hypervisor scheduler quantum in milliseconds.
192
+ * `null` if the device appears to be physical hardware.
193
+ */
194
+ readonly schedulerQuantumMs: number | null;
195
+
196
+ /**
197
+ * Entropy-Jitter Ratio — key signal for real silicon vs VM.
198
+ * - ≥ 1.08 → thermal feedback confirmed (real hardware)
199
+ * - ~1.00 → hypervisor clock (VM)
200
+ * - `null` → phased collection not run
201
+ */
202
+ readonly entropyJitterRatio: number | null;
203
+
204
+ /** Top diagnostic flag from the heuristic engine. */
205
+ readonly topFlag: string;
206
+
207
+ /** All diagnostic flags. */
208
+ readonly flags: string[];
209
+
210
+ /** Heuristic engine findings with severity labels. */
211
+ readonly findings: HeuristicFinding[];
212
+
213
+ /** Confirmed physical properties (positive evidence). */
214
+ readonly physicalEvidence: PhysicalEvidence[];
215
+
216
+ /**
217
+ * Stable, privacy-safe 16-char hex hardware identifier.
218
+ * Stable per device, changes if GPU/driver changes, not reversible.
219
+ */
220
+ hardwareId(): string;
221
+
222
+ /** Key metrics summary for logging / debugging. */
223
+ metrics(): FingerprintMetrics;
224
+
225
+ /** Full diagnostic report. */
226
+ report(): FingerprintReport;
227
+
228
+ /** Returns the BLAKE3 commitment to send to your server. */
229
+ toCommitment(): PulseCommitment;
230
+
231
+ toString(): string;
232
+ toJSON(): FingerprintReport;
233
+ }
234
+
235
+ export interface HeuristicFinding {
236
+ id: string;
237
+ label: string;
238
+ severity: 'critical' | 'high' | 'medium' | 'info';
239
+ detail: string;
240
+ penalty: number;
241
+ }
242
+
243
+ export interface PhysicalEvidence {
244
+ id: string;
245
+ label: string;
246
+ detail: string;
247
+ value: number;
248
+ }
249
+
250
+ export interface FingerprintMetrics {
251
+ // Final verdict
252
+ score: number; // stage-3 final score
253
+ threshold: number; // dynamic passing threshold [0.55, 0.67]
254
+ evidenceWeight: number; // how much evidence was collected [0, 1]
255
+ isSynthetic: boolean;
256
+ // Score pipeline
257
+ rawScore: number;
258
+ adjustedScore: number;
259
+ finalScore: number;
260
+ heuristicAdjustment: number;
261
+ coherenceAdjustment: number;
262
+ // Timing signals
263
+ cv: number | null;
264
+ hurstExponent: number | null;
265
+ quantizationEntropy: number | null;
266
+ autocorrLag1: number | null;
267
+ autocorrLag50: number | null;
268
+ outlierRate: number | null;
269
+ thermalPattern: string | null;
270
+ entropyJitterRatio: number | null;
271
+ picketFence: boolean;
272
+ // Coherence signals
273
+ coherenceFlags: string[];
274
+ physicalFlags: string[];
275
+ hardOverride: 'vm' | null;
276
+ // Provider
277
+ provider: string;
278
+ providerConfidence: number;
279
+ schedulerQuantumMs: number | null;
280
+ // Hardware
281
+ webglRenderer: string | null;
282
+ isSoftwareRenderer: boolean;
283
+ hardwareId: string;
284
+ }
285
+
286
+ export interface FingerprintReport {
287
+ verdict: {
288
+ isSynthetic: boolean;
289
+ score: number;
290
+ threshold: number;
291
+ confidence: number;
292
+ tier: string;
293
+ profile: string;
294
+ provider: string;
295
+ topFlag: string;
296
+ hardOverride: 'vm' | null;
297
+ evidenceWeight: number;
298
+ };
299
+ pipeline: {
300
+ rawScore: number;
301
+ adjustedScore: number;
302
+ finalScore: number;
303
+ heuristicAdjustment: number;
304
+ coherenceAdjustment: number;
305
+ dynamicThreshold: number;
306
+ };
307
+ metrics: FingerprintMetrics;
308
+ findings: HeuristicFinding[];
309
+ physicalEvidence: PhysicalEvidence[];
310
+ coherenceChecks: CoherenceCheck[];
311
+ coherenceBonuses: CoherenceBonus[];
312
+ phases: PhaseReport | null;
313
+ }
314
+
315
+ export interface PhaseReport {
316
+ cold: { qe: number; mean: number };
317
+ hot: { qe: number; mean: number };
318
+ entropyJitterRatio: number;
319
+ }
320
+
321
+ // =============================================================================
322
+ // Server-side validation
323
+ // =============================================================================
324
+
325
+ export interface ValidateOptions {
326
+ /** Minimum jitter score [0–1]. Default: 0.55 */
327
+ minJitterScore?: number;
328
+ /** Max proof age in milliseconds. Default: 300000 (5 min) */
329
+ maxAgeMs?: number;
330
+ /** Tolerated future clock skew. Default: 30000 */
331
+ clockSkewMs?: number;
332
+ /** Reject proofs with no bio activity. Default: false */
333
+ requireBio?: boolean;
334
+ /** Reject software WebGL renderers. Default: true */
335
+ blockSoftwareRenderer?: boolean;
336
+ /**
337
+ * Async nonce validator — must mark nonce as consumed atomically.
338
+ * Returns true if nonce is valid and unused.
339
+ */
340
+ checkNonce?: (nonce: string) => Promise<boolean>;
341
+ }
342
+
343
+ export interface ValidationResult {
344
+ valid: boolean;
345
+ score: number;
346
+ confidence: 'high' | 'medium' | 'low' | 'rejected';
347
+ reasons: string[];
348
+ riskFlags: string[];
349
+ meta: {
350
+ receivedAt: number;
351
+ proofAge: number;
352
+ jitterScore: number;
353
+ canvasRenderer: string | null;
354
+ bioActivity: boolean;
355
+ };
356
+ }
357
+
358
+ export function validateProof(
359
+ payload: ProofPayload,
360
+ hash: string,
361
+ opts?: ValidateOptions
362
+ ): Promise<ValidationResult>;
363
+
364
+ export function generateNonce(): string;
365
+
366
+ // =============================================================================
367
+ // Heuristic engine (advanced)
368
+ // =============================================================================
369
+
370
+ export interface HeuristicReport {
371
+ penalty: number;
372
+ bonus: number;
373
+ netAdjustment: number;
374
+ findings: HeuristicFinding[];
375
+ bonuses: PhysicalEvidence[];
376
+ entropyJitterRatio: number | null;
377
+ entropyJitterScore: number;
378
+ /**
379
+ * Set to 'vm' when a mathematical impossibility is detected in the phase data,
380
+ * specifically when the stored EJR value contradicts the stored QE values.
381
+ * This is a hard kill — isSynthetic returns true regardless of all other scores.
382
+ */
383
+ hardOverride: 'vm' | null;
384
+ picketFence: {
385
+ detected: boolean;
386
+ dominantLag: number | null;
387
+ peakAC: number;
388
+ baseline: number;
389
+ detail: string;
390
+ };
391
+ coherenceFlags: string[];
392
+ }
393
+
394
+ export function runHeuristicEngine(opts: {
395
+ jitter: JitterAnalysis;
396
+ phases: PhasedData | null;
397
+ autocorrelations: Record<string, number>;
398
+ }): HeuristicReport;
399
+
400
+ // =============================================================================
401
+ // Provider detection (advanced)
402
+ // =============================================================================
403
+
404
+ export interface ProviderResult {
405
+ providerId: string;
406
+ providerLabel: string;
407
+ profile: string;
408
+ confidence: number;
409
+ isVirtualized: boolean;
410
+ signals: Record<string, number | boolean | string[]>;
411
+ alternatives: Array<{ id: string; label: string }>;
412
+ rendererHints: string[];
413
+ schedulerQuantumMs: number | null;
414
+ }
415
+
416
+ export function detectProvider(opts: {
417
+ jitter: JitterAnalysis;
418
+ autocorrelations: Record<string, number>;
419
+ canvas: CanvasFingerprint | null;
420
+ phases: PhasedData | null;
421
+ }): ProviderResult;
422
+
423
+ // =============================================================================
424
+ // Proof payload structure
425
+ // =============================================================================
426
+
427
+ export interface ProofPayload {
428
+ version: number;
429
+ timestamp: number;
430
+ nonce: string;
431
+ signals: {
432
+ entropy: Record<string, number | string | null>;
433
+ bio: Record<string, number | boolean | null>;
434
+ canvas: {
435
+ webglRenderer: string | null;
436
+ webglVendor: string | null;
437
+ webglVersion: 1 | 2 | null;
438
+ webglPixelHash: string | null;
439
+ canvas2dHash: string | null;
440
+ extensionCount: number;
441
+ isSoftwareRenderer: boolean;
442
+ available: boolean;
443
+ };
444
+ audio: Record<string, number | boolean | null>;
445
+ };
446
+ classification: {
447
+ jitterScore: number;
448
+ adjustedScore?: number;
449
+ finalScore?: number;
450
+ dynamicThreshold?: number;
451
+ flags: string[];
452
+ };
453
+ heuristic?: Record<string, unknown>;
454
+ provider?: {
455
+ id: string;
456
+ label: string;
457
+ profile: string;
458
+ confidence: number;
459
+ schedulerQuantum: number | null;
460
+ };
461
+ coherence?: {
462
+ netAdjustment: number;
463
+ dynamicThreshold: number;
464
+ evidenceWeight: number;
465
+ coherenceFlags: string[];
466
+ physicalFlags: string[];
467
+ hardOverride: 'vm' | null;
468
+ };
469
+ }
470
+
471
+ // =============================================================================
472
+ // Coherence analysis (stage 3)
473
+ // =============================================================================
474
+
475
+ export interface CoherenceCheck {
476
+ id: string;
477
+ label: string;
478
+ severity: 'critical' | 'high' | 'medium' | 'info';
479
+ detail: string;
480
+ penalty: number;
481
+ }
482
+
483
+ export interface CoherenceBonus {
484
+ id: string;
485
+ label: string;
486
+ detail: string;
487
+ value: number;
488
+ }
489
+
490
+ export interface CoherenceReport {
491
+ penalty: number;
492
+ bonus: number;
493
+ netAdjustment: number;
494
+ checks: CoherenceCheck[];
495
+ bonuses: CoherenceBonus[];
496
+ hardOverride: 'vm' | null;
497
+ /** Dynamic threshold [0.55, 0.67] — lower when more evidence collected. */
498
+ dynamicThreshold: number;
499
+ /** Evidence weight [0, 1] */
500
+ evidenceWeight: number;
501
+ coherenceFlags: string[];
502
+ physicalFlags: string[];
503
+ }
504
+
505
+ export function runCoherenceAnalysis(opts: {
506
+ timings: number[];
507
+ jitter: JitterAnalysis;
508
+ phases?: PhasedData | null;
509
+ batches?: object[] | null;
510
+ bio?: object;
511
+ canvas?: CanvasFingerprint | null;
512
+ audio?: object;
513
+ }): CoherenceReport;
514
+
515
+ export function computeServerDynamicThreshold(payload: ProofPayload): number;
516
+
517
+ // =============================================================================
518
+ // Internal types (exported for advanced consumers)
519
+ // =============================================================================
520
+
521
+ export interface JitterAnalysis {
522
+ score: number;
523
+ flags: string[];
524
+ stats: TimingStats | null;
525
+ autocorrelations: Record<string, number>;
526
+ hurstExponent: number;
527
+ quantizationEntropy: number;
528
+ thermalSignature: { slope: number; pattern: string; r2: number };
529
+ outlierRate: number;
530
+ }
531
+
532
+ export interface TimingStats {
533
+ n: number; mean: number; std: number; cv: number;
534
+ min: number; max: number;
535
+ p5: number; p25: number; p50: number; p75: number; p95: number; p99: number;
536
+ skewness: number; kurtosis: number;
537
+ }
538
+
539
+ export interface CanvasFingerprint {
540
+ webglRenderer: string | null;
541
+ webglVendor: string | null;
542
+ webglVersion: 1 | 2 | null;
543
+ webglPixelHash: string | null;
544
+ canvas2dHash: string | null;
545
+ extensionCount: number;
546
+ extensions: string[];
547
+ isSoftwareRenderer: boolean;
548
+ available: boolean;
549
+ }
550
+
551
+ export interface PhasedData {
552
+ cold: { qe: number; mean: number };
553
+ load: { qe: number; mean: number };
554
+ hot: { qe: number; mean: number };
555
+ entropyJitterRatio: number;
556
+ }
557
+
558
+ // =============================================================================
559
+ // SVRN Registry
560
+ // =============================================================================
561
+
562
+ export interface SvrnSignature {
563
+ version: number;
564
+ id: string;
565
+ profile: string;
566
+ provider: string;
567
+ class: string;
568
+ metrics: Record<string, { lo: number; hi: number; mid: number; label: string } | null>;
569
+ rendererClass: string;
570
+ isSynthetic: boolean;
571
+ hwLabel: string | null;
572
+ osHint: string | null;
573
+ date: string;
574
+ }
575
+
576
+ export interface RegistryMatch {
577
+ matched: boolean;
578
+ profile: object | null;
579
+ similarity: number;
580
+ alternatives: Array<{ name: string; similarity: number }>;
581
+ }
582
+
583
+ export interface SignatureComparison {
584
+ sameClass: boolean;
585
+ similarity: number;
586
+ profileMatch: boolean;
587
+ providerMatch: boolean;
588
+ }
package/package.json ADDED
@@ -0,0 +1,93 @@
1
+ {
2
+ "name": "@svrnsec/pulse",
3
+ "version": "0.1.0",
4
+ "description": "Physical Turing Test — Hardware-Biological Symmetry Protocol distinguishing real consumer devices from sanitised datacenter VMs.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "Aaron Miller",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/ayronny14-alt/Svrn-Pulse-Security.git"
11
+ },
12
+ "homepage": "https://github.com/ayronny14-alt/Svrn-Pulse-Security#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/ayronny14-alt/Svrn-Pulse-Security/issues"
15
+ },
16
+ "types": "index.d.ts",
17
+ "publishConfig": {
18
+ "access": "public",
19
+ "registry": "https://registry.npmjs.org/"
20
+ },
21
+ "exports": {
22
+ ".": {
23
+ "browser": "./dist/pulse.esm.js",
24
+ "import": "./dist/pulse.esm.js",
25
+ "require": "./dist/pulse.cjs.js"
26
+ },
27
+ "./validator": {
28
+ "node": "./src/proof/validator.js",
29
+ "import": "./src/proof/validator.js"
30
+ },
31
+ "./registry": {
32
+ "import": "./src/registry/serializer.js",
33
+ "node": "./src/registry/serializer.js"
34
+ },
35
+ "./middleware/express": {
36
+ "import": "./src/middleware/express.js",
37
+ "node": "./src/middleware/express.js"
38
+ },
39
+ "./middleware/next": {
40
+ "import": "./src/middleware/next.js",
41
+ "node": "./src/middleware/next.js"
42
+ },
43
+ "./react": {
44
+ "import": "./src/integrations/react.js"
45
+ }
46
+ },
47
+ "main": "dist/pulse.cjs.js",
48
+ "module": "dist/pulse.esm.js",
49
+ "files": [
50
+ "dist/",
51
+ "pkg/",
52
+ "index.d.ts",
53
+ "src/proof/validator.js",
54
+ "src/proof/fingerprint.js",
55
+ "src/middleware/express.js",
56
+ "src/middleware/next.js",
57
+ "src/registry/serializer.js",
58
+ "src/integrations/react.js",
59
+ "SECURITY.md"
60
+ ],
61
+ "scripts": {
62
+ "build:wasm": "bash build.sh",
63
+ "build:js": "rollup -c rollup.config.js",
64
+ "build": "npm run build:wasm && npm run build:js",
65
+ "dev": "rollup -c rollup.config.js --watch",
66
+ "test": "node --experimental-vm-modules ./node_modules/jest-cli/bin/jest.js",
67
+ "demo": "node demo/node-demo.js"
68
+ },
69
+ "dependencies": {
70
+ "@noble/hashes": "^1.4.0"
71
+ },
72
+ "devDependencies": {
73
+ "@rollup/plugin-commonjs": "^25.0.0",
74
+ "@rollup/plugin-node-resolve": "^15.0.0",
75
+ "@rollup/plugin-wasm": "^6.2.2",
76
+ "@types/jest": "^29.0.0",
77
+ "jest": "^29.0.0",
78
+ "rollup": "^4.0.0"
79
+ },
80
+ "keywords": [
81
+ "physical-turing-test",
82
+ "hardware-fingerprint",
83
+ "bot-detection",
84
+ "wasm",
85
+ "zero-knowledge",
86
+ "anti-vm",
87
+ "jitter-analysis",
88
+ "blake3"
89
+ ],
90
+ "engines": {
91
+ "node": ">=18.0.0"
92
+ }
93
+ }