npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@mlvscan/wasm-core

v1.3.3

Published

WebAssembly core for MLVScan - scanning Unity mods in the browser

Readme

@mlvscan/wasm-core

npm

WebAssembly scanning engine for MLVScan. Runs the full MLVScan.Core malware detection engine entirely in the browser — no server, no uploads, no tracking.

Installation

npm install @mlvscan/wasm-core

Serving the Framework Files

The package ships with a dist/_framework directory containing the .NET WASM runtime. Your build tool must serve these files at runtime. With Vite, use vite-plugin-static-copy:

// vite.config.ts
import { viteStaticCopy } from 'vite-plugin-static-copy'

export default {
  plugins: [
    viteStaticCopy({
      targets: [{
        src: 'node_modules/@mlvscan/wasm-core/dist/_framework',
        dest: '.'
      }]
    })
  ]
}

Then initialize with baseUrl: '/' (the default).

Quick Start

import { initScanner, scanAssembly } from '@mlvscan/wasm-core'

// Initialize once at app startup
await initScanner({ baseUrl: '/' })

// Scan a DLL from a file input
const file = event.target.files[0]
const bytes = new Uint8Array(await file.arrayBuffer())
const result = await scanAssembly(bytes, file.name)

console.log(`Found ${result.summary.totalFindings} issue(s)`)
for (const finding of result.findings) {
  console.log(`[${finding.severity}] ${finding.description} @ ${finding.location}`)
}

API Reference

initScanner(options?)

Loads the .NET WASM runtime. Call once at app startup before scanning. Safe to call multiple times — subsequent calls are no-ops if already initialized.

await initScanner({
  baseUrl: '/',             // Where _framework is served. Defaults to '/'.
  useMock: false,           // Force mock mode (useful for testing). Defaults to false.
  throwOnInitFailure: false // Throw instead of falling back to mock on load failure.
})

If throwOnInitFailure is not set and WASM fails to load, the scanner silently falls back to mock mode (returning zero findings). Use getScannerStatus() to detect this.


scanAssembly(fileBytes, fileName)

Scans a .NET assembly and returns a ScanResult. Auto-initializes if initScanner was not called first.

const result = await scanAssembly(bytes, 'MyMod.dll')

scanAssemblyWithConfig(fileBytes, fileName, config)

Scans with explicit options for deeper analysis (call chains, data flows, developer guidance).

const result = await scanAssemblyWithConfig(bytes, 'MyMod.dll', {
  developerMode: true,
  enableCrossMethodAnalysis: true,
  deepAnalysis: {
    enableDeepAnalysis: true,
    enableNetworkToExecutionCorrelation: true,
  }
})

Status & Utility

| Function | Returns | Description | |---|---|---| | isScannerReady() | boolean | True when init has completed (real or mock). Use to gate the scan button. | | isMockScanner() | boolean | True when running in mock mode. | | getScannerStatus() | ScannerStatus | Full status snapshot — ready, mock, explicit mock, and init error. | | getScannerVersion() | Promise<string> | Scanner engine version (e.g. "1.1.7"). Returns "1.0.0-mock" in mock mode. | | getSchemaVersion() | Promise<string> | Result schema version (e.g. "1.1.0"). | | getInitError() | Error \| null | The error that caused WASM fallback, or null if healthy. |

Scan Modes

The scanMode in ScanConfigInput controls the depth of analysis and what is included in the result:

| Mode | Description | |---|---| | summary (default) | Fast scan. Returns findings with severity and location. | | detailed | Includes callChains — the execution path from entry point to suspicious code. | | developer | Includes dataFlows and developerGuidance with remediation suggestions. |

Handling WASM Load Failures

If the WASM runtime fails to load (e.g. COOP/COEP headers not set, browser incompatibility), the scanner falls back to mock mode automatically. Check the status after init to show an appropriate message:

await initScanner({ baseUrl: '/' })

const status = getScannerStatus()
if (status.initError) {
  console.warn('Scanner unavailable, results will be empty:', status.initError.message)
}

To throw instead of falling back silently:

await initScanner({ baseUrl: '/', throwOnInitFailure: true })

Type Reference

ScanResult

The root object returned by all scan functions.

interface ScanResult {
  schemaVersion: string
  metadata: ScanMetadata       // Core/platform/scanner versions, timestamp, scan mode, platform
  input: ScanInput             // File name, size, optional SHA-256
  summary: ScanSummary         // Total findings and counts by severity
  findings: Finding[]          // Individual security findings
  callChains?: CallChain[]     // Detailed mode: execution paths
  dataFlows?: DataFlowChain[]  // Developer mode: source-to-sink data flows
  developerGuidance?: DeveloperGuidance[] // Developer mode: remediation suggestions
  threatFamilies?: ThreatFamily[] // Optional malware family classification matches
}

Finding

interface Finding {
  id?: string
  ruleId?: string
  description: string
  severity: 'Low' | 'Medium' | 'High' | 'Critical'
  location: string       // Type/method name or file:line
  codeSnippet?: string
  riskScore?: number
  callChainId?: string
  dataFlowChainId?: string
  developerGuidance?: DeveloperGuidance
  callChain?: CallChain
  dataFlowChain?: DataFlowChain
}

ScannerStatus

interface ScannerStatus {
  ready: boolean
  isMock: boolean
  mockRequestedExplicitly: boolean
  initError: Error | null
}

For the full type definitions, see types.ts.

Related

  • MLVScan.Core — The detection engine (NuGet package, CLI, WASM source)
  • MLVScan.Web — React web app built on this package
  • MLVScan — MelonLoader/BepInEx plugin

Architecture Notes

MLVScan.Core is designed to be environment-agnostic. It powers multiple integration points (MelonLoader, BepInEx, WASM, CLI) without containing any mod loader-specific code.


Licensed under GPL-3.0