Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions .github/workflows/wasm-bundlers.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: WASM Bundler Compatibility

on:
push:
branches: ["main"]
pull_request:
branches: ["main"]

jobs:
test-bundlers:
name: Test Bundler Compatibility (Vite/Next/Webpack)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 24

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable

- name: Install wasm-pack
run: cargo install wasm-pack || true

- name: Build WASM package
run: |
cd tooling/sanctifier-wasm
wasm-pack build --target web --out-dir pkg

- name: Test Vite Compatibility
run: |
mkdir -p e2e/vite-test
cd e2e/vite-test
npm init -y
npm install vite
npm install ../../tooling/sanctifier-wasm/pkg
echo "import { analyze } from '@sanctifier/wasm'; console.log(typeof analyze);" > index.js
echo "import { defineConfig } from 'vite'; export default defineConfig({ build: { target: 'esnext' } });" > vite.config.js
npx vite build

- name: Test Webpack Compatibility
run: |
mkdir -p e2e/webpack-test
cd e2e/webpack-test
npm init -y
npm install webpack webpack-cli
npm install ../../tooling/sanctifier-wasm/pkg
echo "import { analyze } from '@sanctifier/wasm'; console.log(typeof analyze);" > index.js
echo "module.exports = { mode: 'production', entry: './index.js', experiments: { asyncWebAssembly: true } };" > webpack.config.js
npx webpack

- name: Test Next.js Compatibility
run: |
mkdir -p e2e/next-test
cd e2e/next-test
npm init -y
npm install next react react-dom
npm install ../../tooling/sanctifier-wasm/pkg
mkdir pages
echo "import { analyze } from '@sanctifier/wasm'; export default function Home() { return <div>{typeof analyze}</div>; }" > pages/index.js
echo "module.exports = { webpack(config) { config.experiments = { ...config.experiments, asyncWebAssembly: true }; return config; } };" > next.config.js
npx next build
13 changes: 12 additions & 1 deletion tooling/sanctifier-wasm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,15 @@ WebAssembly bindings for Sanctifier analysis.

## Offline caching integration

Use `asset_cache_key()` or `cache_metadata().cache_key` when storing wasm assets in CacheStorage or a service worker. The key changes when either package version or schema version changes, so stale assets are safely evicted.
Use `asset_cache_key()` or `cache_metadata().cache_key` when storing wasm assets in CacheStorage or a service worker. The key changes when either package version or schema version changes, so stale assets are safely evicted. This improves release and publishing reliability by providing predictable outputs for frontend applications.

## Web Worker / Parallelization Strategy

To avoid blocking the main UI thread during intensive static analysis, it is recommended to run the `@sanctifier/wasm` module inside a Web Worker. See `examples/web_worker.js` for an implementation reference. By delegating analysis requests to background workers, you can ensure a smooth user experience even on large codebases.

## API Surface Stability for Frontend

The `@sanctifier/wasm` package maintains a strict API surface stability contract for frontend consumers.
- All breaking changes to the exported functions will result in a major version bump.
- The `schema_version()` function returns the data shape version of the analysis output.
- For stable integrations, always check the `schema_version()` or `version()` to implement safe fallback behaviors in the frontend.
42 changes: 42 additions & 0 deletions tooling/sanctifier-wasm/examples/web_worker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* Web Worker Example for @sanctifier/wasm
*
* This demonstrates how to offload WASM analysis to a background worker
* to avoid blocking the main UI thread during intensive static analysis.
*/

import { analyze, version } from '@sanctifier/wasm';

// Handle incoming messages from the main thread
self.onmessage = async (event) => {
const { id, type, source, config } = event.data;

try {
let result;

switch (type) {
case 'ANALYZE':
// Run standard analysis
result = analyze(source);
break;

case 'GET_VERSION':
result = version();
break;

default:
throw new Error(`Unknown analysis task type: ${type}`);
}

// Send results back to the main thread
self.postMessage({ id, status: 'success', data: result });

} catch (error) {
// Send errors back
self.postMessage({
id,
status: 'error',
error: error.message || 'Analysis failed'
});
}
};
21 changes: 20 additions & 1 deletion tooling/sanctifier-wasm/tests/wasm_tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#![cfg(target_arch = "wasm32")]

use sanctifier_wasm::{analyze, analyze_with_config, finding_codes, schema_version, version};
use sanctifier_wasm::{
analyze, analyze_with_config, asset_cache_key, cache_metadata, finding_codes, schema_version,
version,
};
use wasm_bindgen_test::*;

wasm_bindgen_test_configure!(run_in_browser);
Expand Down Expand Up @@ -187,3 +190,19 @@ fn test_analyze_normal_source_unaffected_by_memory_check() {
let result = analyze(source);
assert!(!result.is_null());
}

// ── Caching API Tests ────────────────────────────────────────────────────────

#[wasm_bindgen_test]
fn test_asset_cache_key() {
let key = asset_cache_key();
assert!(!key.is_empty());
assert!(key.contains("sanctifier-wasm:"));
}

#[wasm_bindgen_test]
fn test_cache_metadata() {
let meta = cache_metadata();
assert!(!meta.is_null());
assert!(meta.is_object());
}
Loading