mirror of
https://github.com/ruvnet/ruflo.git
synced 2026-09-14 14:01:28 +08:00
feat(watermark): add browser/Deno ESM entry (@claude-flow/watermark 0.2.0) (#3041)
Adds a `@claude-flow/watermark/web` ESM entry (wasm-pack `--target web`) so the package works in browsers, Deno, and bundlers — not just Node. Instantiate once with `await init()` (auto-fetches the wasm in a browser; accepts bytes/URL/ Response), then the same ergonomic API (Watermarker, detect, detectSelfSync, detectExact) as the Node build. - package.json: conditional exports (`.` = Node CJS/ESM, `./web` = browser ESM, `./package.json` re-exported); web/ marked ESM via a nested package.json. - build:wasm now builds both nodejs and web targets. - Added test/smoke-web.mjs; `npm test` runs Node + web. Both verified, plus a fresh dual-entry tarball install (node z=64.7, web z=64.7). Bumps to 0.2.0 (new capability, backward-compatible). No removal tooling. Claude-Session: https://claude.ai/code/session_01VYDa3Hah5VJLS2ceEuTLKz
This commit is contained in:
@@ -63,11 +63,35 @@ console.log(r.zScore, r.log10P, r.isWatermarked(1e-6)); // strong, true
|
||||
key sees nothing. Confidence grows with the number of low-stakes token choices,
|
||||
so short or low-entropy (factual/code) text carries little to no mark.
|
||||
|
||||
## Browser / Deno / bundler
|
||||
|
||||
The `@claude-flow/watermark/web` entry is an ESM build. Instantiate the WASM once
|
||||
with `await init()`, then use the same API. In a browser, `init()` with no
|
||||
argument fetches the sibling `.wasm`; pass a `URL` / `Response` / bytes to
|
||||
override.
|
||||
|
||||
```js
|
||||
import { init, Watermarker, detect } from '@claude-flow/watermark/web';
|
||||
|
||||
await init(); // browser: auto-fetches the wasm
|
||||
|
||||
const wm = new Watermarker({ key: '8F3A91C7', scheme: 'gumbel' });
|
||||
const tokens = Uint32Array.from({ length: 128 }, (_, i) => i);
|
||||
const probs = new Float32Array(128).fill(1 / 128);
|
||||
const out = new Uint32Array(600);
|
||||
for (let i = 0; i < out.length; i++) out[i] = tokens[wm.step(tokens, probs)];
|
||||
wm.free();
|
||||
|
||||
console.log(detect(out, { key: '8F3A91C7', scheme: 'gumbel' }).isWatermarked(1e-6));
|
||||
```
|
||||
|
||||
The `.` entry is the Node (CommonJS) build shown earlier; the `/web` entry is for
|
||||
browser / Deno / bundlers.
|
||||
|
||||
## Scope
|
||||
|
||||
This build targets Node (CommonJS). The bindings are generated from the Rust
|
||||
crate with `npm run build:wasm` (`wasm-pack --target nodejs`); browser/bundler
|
||||
targets can be produced the same way (`--target web`/`bundler`). The crate
|
||||
exposes more than this WASM surface — the Bayesian/Higher-Criticism detectors,
|
||||
the robustness-evaluation harness, the Darwin/flywheel detector tuner, and the
|
||||
authorized un-marked-generation governance path are Rust-only for now.
|
||||
Bindings are generated from the Rust crate with `npm run build:wasm`
|
||||
(`wasm-pack`, both `nodejs` and `web` targets). The crate exposes more than this
|
||||
WASM surface — the Bayesian/Higher-Criticism detectors, the robustness-evaluation
|
||||
harness, the Darwin/flywheel detector tuner, and the authorized un-marked-
|
||||
generation governance path are Rust-only for now.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@claude-flow/watermark",
|
||||
"version": "0.1.0",
|
||||
"description": "SynthID-Text-style LLM text watermarking (generation + detection) as a WASM module — Tournament / non-distortionary / distortion-free schemes, indel-robust and short-text detectors. No watermark-removal tooling.",
|
||||
"version": "0.2.0",
|
||||
"description": "SynthID-Text-style LLM text watermarking (generation + detection) as a WASM module — Tournament / non-distortionary / distortion-free schemes, indel-robust and short-text detectors. Node + browser. No watermark-removal tooling.",
|
||||
"license": "MIT",
|
||||
"author": "rUv <ruv@ruv.net>",
|
||||
"homepage": "https://github.com/ruvnet/ruflo/tree/main/v3/crates/ruflo-watermark",
|
||||
@@ -24,6 +24,18 @@
|
||||
"type": "commonjs",
|
||||
"main": "index.js",
|
||||
"types": "index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./index.d.ts",
|
||||
"require": "./index.js",
|
||||
"import": "./index.js"
|
||||
},
|
||||
"./web": {
|
||||
"types": "./web/index.d.ts",
|
||||
"import": "./web/index.mjs"
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"files": [
|
||||
"index.js",
|
||||
"index.d.ts",
|
||||
@@ -31,6 +43,13 @@
|
||||
"wasm/ruflo_watermark_bg.wasm",
|
||||
"wasm/ruflo_watermark.d.ts",
|
||||
"wasm/ruflo_watermark_bg.wasm.d.ts",
|
||||
"web/package.json",
|
||||
"web/index.mjs",
|
||||
"web/index.d.ts",
|
||||
"web/ruflo_watermark.js",
|
||||
"web/ruflo_watermark_bg.wasm",
|
||||
"web/ruflo_watermark.d.ts",
|
||||
"web/ruflo_watermark_bg.wasm.d.ts",
|
||||
"README.md"
|
||||
],
|
||||
"engines": {
|
||||
@@ -41,6 +60,8 @@
|
||||
},
|
||||
"scripts": {
|
||||
"build:wasm": "bash scripts/build-wasm.sh",
|
||||
"test": "node test/smoke.cjs"
|
||||
"test": "node test/smoke.cjs && node test/smoke-web.mjs",
|
||||
"test:node": "node test/smoke.cjs",
|
||||
"test:web": "node test/smoke-web.mjs"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
# Regenerate the WASM bindings in ./wasm from the ruflo-watermark Rust crate.
|
||||
# Regenerate the WASM bindings from the ruflo-watermark Rust crate: the Node
|
||||
# (CommonJS) build in ./wasm and the browser/Deno (ESM) build in ./web.
|
||||
#
|
||||
# Requires: rustup + wasm32-unknown-unknown target + wasm-pack.
|
||||
# rustup target add wasm32-unknown-unknown
|
||||
@@ -12,15 +13,19 @@ set -euo pipefail
|
||||
here="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
crate="$here/../../crates/ruflo-watermark"
|
||||
|
||||
CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_RUSTFLAGS="" RUSTFLAGS="" \
|
||||
wasm-pack build --release --target nodejs \
|
||||
--out-dir "$crate/pkg-nodejs" --out-name ruflo_watermark \
|
||||
"$crate" -- --features wasm
|
||||
build() { # <target> <out-dir>
|
||||
CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_RUSTFLAGS="" RUSTFLAGS="" \
|
||||
wasm-pack build --release --target "$1" \
|
||||
--out-dir "$crate/$2" --out-name ruflo_watermark \
|
||||
"$crate" -- --features wasm
|
||||
}
|
||||
|
||||
cp "$crate/pkg-nodejs/ruflo_watermark.js" \
|
||||
"$crate/pkg-nodejs/ruflo_watermark_bg.wasm" \
|
||||
"$crate/pkg-nodejs/ruflo_watermark.d.ts" \
|
||||
"$crate/pkg-nodejs/ruflo_watermark_bg.wasm.d.ts" \
|
||||
"$here/wasm/"
|
||||
files=(ruflo_watermark.js ruflo_watermark_bg.wasm ruflo_watermark.d.ts ruflo_watermark_bg.wasm.d.ts)
|
||||
|
||||
echo "Rebuilt wasm/ from $crate"
|
||||
build nodejs pkg-nodejs
|
||||
for f in "${files[@]}"; do cp "$crate/pkg-nodejs/$f" "$here/wasm/"; done
|
||||
|
||||
build web pkg-web
|
||||
for f in "${files[@]}"; do cp "$crate/pkg-web/$f" "$here/web/"; done
|
||||
|
||||
echo "Rebuilt wasm/ (nodejs) and web/ (browser) from $crate"
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
// Web-entry smoke test, run under Node ESM: init the WASM from bytes, then
|
||||
// generate + detect through the browser-facing API. Mirrors what a browser does
|
||||
// after `await init()` (in a browser, init() auto-fetches the .wasm).
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { init, isReady, Watermarker, detect, detectSelfSync, detectExact } from '../web/index.mjs';
|
||||
|
||||
const here = dirname(fileURLToPath(import.meta.url));
|
||||
const wasmBytes = readFileSync(join(here, '..', 'web', 'ruflo_watermark_bg.wasm'));
|
||||
|
||||
let ok = true;
|
||||
const check = (name, cond, detail) => {
|
||||
console.log(` ${cond ? 'ok: ' : 'FAIL:'} ${name} — ${detail}`);
|
||||
if (!cond) ok = false;
|
||||
};
|
||||
|
||||
// Guard before init.
|
||||
let threw = false;
|
||||
try {
|
||||
detect(Uint32Array.from([1, 2, 3]), { key: 'k' });
|
||||
} catch {
|
||||
threw = true;
|
||||
}
|
||||
check('throws before init()', threw, `isReady=${isReady()}`);
|
||||
|
||||
await init(wasmBytes);
|
||||
check('isReady() after init', isReady(), 'true');
|
||||
|
||||
const KEY = '8F3A91C7';
|
||||
const VOCAB = 128;
|
||||
const tokens = Uint32Array.from({ length: VOCAB }, (_, i) => i);
|
||||
const probs = new Float32Array(VOCAB).fill(1 / VOCAB);
|
||||
|
||||
for (const scheme of ['tournament', 'tournament_nd', 'gumbel']) {
|
||||
const wm = new Watermarker({ key: KEY, scheme, layers: 6 });
|
||||
const out = new Uint32Array(600);
|
||||
for (let i = 0; i < 600; i++) out[i] = tokens[wm.step(tokens, probs)];
|
||||
wm.free();
|
||||
const hit = detect(out, { key: KEY, scheme, layers: 6 });
|
||||
const wrong = detect(out, { key: 'WRONG', scheme, layers: 6 });
|
||||
check(`${scheme}: detects own output`, hit.isWatermarked(1e-6), `z=${hit.zScore.toFixed(1)}`);
|
||||
check(`${scheme}: wrong key rejected`, !wrong.isWatermarked(1e-6), `z=${wrong.zScore.toFixed(2)}`);
|
||||
}
|
||||
|
||||
const g = new Watermarker({ key: KEY, scheme: 'gumbel' });
|
||||
const gs = new Uint32Array(600);
|
||||
for (let i = 0; i < 600; i++) gs[i] = tokens[g.step(tokens, probs)];
|
||||
g.free();
|
||||
check('self-sync detector fires', detectSelfSync(gs, { key: KEY }).zScore > 8, 'z>8');
|
||||
check('exact short-text detector fires', detectExact(gs.slice(0, 120), { key: KEY }).log10P < -3, 'log10p<-3');
|
||||
|
||||
console.log(ok ? '\nWEB SMOKE OK' : '\nWEB SMOKE FAILED');
|
||||
process.exit(ok ? 0 : 1);
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
// Types for @claude-flow/watermark/web (browser / Deno / bundler entry).
|
||||
import type { Detection, Scheme, WatermarkerOptions, SelfSyncOptions } from '../index.d.ts';
|
||||
|
||||
export type { Detection, Scheme, WatermarkerOptions, SelfSyncOptions };
|
||||
|
||||
/** WASM init input: fetched URL/Response, raw bytes, or a compiled module. */
|
||||
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
|
||||
|
||||
/** Instantiate the WASM module. Await once before any other call. */
|
||||
export function init(input?: InitInput | Promise<InitInput>): Promise<void>;
|
||||
|
||||
/** True once `init()` has completed. */
|
||||
export function isReady(): boolean;
|
||||
|
||||
export class Watermarker {
|
||||
constructor(opts: WatermarkerOptions);
|
||||
step(tokens: Uint32Array | number[], probs: Float32Array | number[]): number;
|
||||
free(): void;
|
||||
}
|
||||
|
||||
export function detect(tokens: Uint32Array | number[], opts: WatermarkerOptions): Detection;
|
||||
export function detectSelfSync(tokens: Uint32Array | number[], opts: SelfSyncOptions): Detection;
|
||||
export function detectExact(tokens: Uint32Array | number[], opts: SelfSyncOptions): Detection;
|
||||
|
||||
export const SCHEMES: ReadonlySet<Scheme>;
|
||||
@@ -0,0 +1,89 @@
|
||||
// @claude-flow/watermark/web — browser / Deno / bundler ESM entry.
|
||||
//
|
||||
// The WASM must be instantiated before use: `await init()` once, then use the
|
||||
// same ergonomic API as the Node build. In a browser, `init()` with no argument
|
||||
// fetches the sibling `ruflo_watermark_bg.wasm`; pass a URL / Response /
|
||||
// BufferSource / WebAssembly.Module to override (e.g. in Node tests).
|
||||
//
|
||||
// Generation + detection only — no watermark-removal surface.
|
||||
|
||||
import initWasm, {
|
||||
WasmWatermarker,
|
||||
detect as _detect,
|
||||
detect_selfsync as _detectSelfSync,
|
||||
detect_exact as _detectExact,
|
||||
} from './ruflo_watermark.js';
|
||||
|
||||
let _ready = false;
|
||||
|
||||
/** Instantiate the WASM module. Await once before any other call. */
|
||||
export async function init(input) {
|
||||
if (_ready) return;
|
||||
// Non-deprecated wasm-bindgen call shape; no arg => browser auto-fetch.
|
||||
await initWasm(input === undefined ? undefined : { module_or_path: input });
|
||||
_ready = true;
|
||||
}
|
||||
|
||||
/** True once `init()` has completed. */
|
||||
export function isReady() {
|
||||
return _ready;
|
||||
}
|
||||
|
||||
function assertReady() {
|
||||
if (!_ready) throw new Error('@claude-flow/watermark/web: call `await init()` before use');
|
||||
}
|
||||
|
||||
const SCHEMES = new Set(['tournament', 'tournament_nd', 'gumbel']);
|
||||
const enc = new TextEncoder();
|
||||
const toKeyBytes = (k) => (typeof k === 'string' ? enc.encode(k) : k);
|
||||
const toU32 = (a) => (a instanceof Uint32Array ? a : Uint32Array.from(a));
|
||||
const toF32 = (a) => (a instanceof Float32Array ? a : Float32Array.from(a));
|
||||
function normScheme(s) {
|
||||
const v = s || 'gumbel';
|
||||
if (!SCHEMES.has(v)) throw new RangeError(`unknown scheme "${v}" (tournament | tournament_nd | gumbel)`);
|
||||
return v;
|
||||
}
|
||||
function shape(r) {
|
||||
const out = {
|
||||
zScore: r.z_score,
|
||||
pValue: r.p_value,
|
||||
log10P: r.log10_p,
|
||||
scoredPositions: r.scored_positions,
|
||||
isWatermarked(alpha = 1e-6) {
|
||||
return out.log10P <= Math.log10(alpha);
|
||||
},
|
||||
};
|
||||
r.free();
|
||||
return out;
|
||||
}
|
||||
|
||||
/** Streaming watermarked sampler (call `await init()` first). */
|
||||
export class Watermarker {
|
||||
constructor({ key, scheme = 'gumbel', contextWidth = 4, layers = 6 } = {}) {
|
||||
assertReady();
|
||||
this._inner = new WasmWatermarker(toKeyBytes(key), contextWidth, layers, normScheme(scheme));
|
||||
}
|
||||
step(tokens, probs) {
|
||||
return this._inner.step(toU32(tokens), toF32(probs));
|
||||
}
|
||||
free() {
|
||||
this._inner.free();
|
||||
}
|
||||
}
|
||||
|
||||
export function detect(tokens, { key, scheme = 'gumbel', contextWidth = 4, layers = 6 } = {}) {
|
||||
assertReady();
|
||||
return shape(_detect(toU32(tokens), toKeyBytes(key), contextWidth, layers, normScheme(scheme)));
|
||||
}
|
||||
|
||||
export function detectSelfSync(tokens, { key, contextWidth = 4 } = {}) {
|
||||
assertReady();
|
||||
return shape(_detectSelfSync(toU32(tokens), toKeyBytes(key), contextWidth));
|
||||
}
|
||||
|
||||
export function detectExact(tokens, { key, contextWidth = 4 } = {}) {
|
||||
assertReady();
|
||||
return shape(_detectExact(toU32(tokens), toKeyBytes(key), contextWidth));
|
||||
}
|
||||
|
||||
export { SCHEMES };
|
||||
@@ -0,0 +1 @@
|
||||
{ "type": "module" }
|
||||
@@ -0,0 +1,93 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
/**
|
||||
* Detection result, JS-facing (fields via getters).
|
||||
*/
|
||||
export class WasmDetection {
|
||||
private constructor();
|
||||
free(): void;
|
||||
[Symbol.dispose](): void;
|
||||
readonly log10_p: number;
|
||||
readonly p_value: number;
|
||||
readonly scored_positions: number;
|
||||
readonly z_score: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Streaming watermarked sampler, JS-facing.
|
||||
*/
|
||||
export class WasmWatermarker {
|
||||
free(): void;
|
||||
[Symbol.dispose](): void;
|
||||
/**
|
||||
* `key_material`: arbitrary secret bytes (e.g. a hex string's bytes).
|
||||
* `scheme`: `"tournament"` | `"tournament_nd"` | `"gumbel"` (default gumbel).
|
||||
*/
|
||||
constructor(key_material: Uint8Array, context_width: number, layers: number, scheme: string);
|
||||
/**
|
||||
* Emit one token: returns the index into `tokens`/`probs` of the chosen
|
||||
* candidate. Advances the rolling context.
|
||||
*/
|
||||
step(tokens: Uint32Array, probs: Float32Array): number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect a watermark over an emitted token id sequence, using the named scheme.
|
||||
*/
|
||||
export function detect(tokens: Uint32Array, key_material: Uint8Array, context_width: number, layers: number, scheme: string): WasmDetection;
|
||||
|
||||
/**
|
||||
* Exact-null short-text detection (Gumbel, exact Gamma tail): correct p-values
|
||||
* at small token counts where the normal approximation misleads. See `bayes.rs`.
|
||||
*/
|
||||
export function detect_exact(tokens: Uint32Array, key_material: Uint8Array, context_width: number): WasmDetection;
|
||||
|
||||
/**
|
||||
* Indel-robust detection (Gumbel self-sync): far stronger than the standard
|
||||
* detector on edited / repetitive text. See `align.rs`.
|
||||
*/
|
||||
export function detect_selfsync(tokens: Uint32Array, key_material: Uint8Array, context_width: number): WasmDetection;
|
||||
|
||||
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
|
||||
|
||||
export interface InitOutput {
|
||||
readonly memory: WebAssembly.Memory;
|
||||
readonly __wbg_wasmdetection_free: (a: number, b: number) => void;
|
||||
readonly __wbg_wasmwatermarker_free: (a: number, b: number) => void;
|
||||
readonly detect: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => number;
|
||||
readonly detect_exact: (a: number, b: number, c: number, d: number, e: number) => number;
|
||||
readonly detect_selfsync: (a: number, b: number, c: number, d: number, e: number) => number;
|
||||
readonly wasmdetection_log10_p: (a: number) => number;
|
||||
readonly wasmdetection_p_value: (a: number) => number;
|
||||
readonly wasmdetection_scored_positions: (a: number) => number;
|
||||
readonly wasmdetection_z_score: (a: number) => number;
|
||||
readonly wasmwatermarker_new: (a: number, b: number, c: number, d: number, e: number, f: number) => number;
|
||||
readonly wasmwatermarker_step: (a: number, b: number, c: number, d: number, e: number) => number;
|
||||
readonly __wbindgen_externrefs: WebAssembly.Table;
|
||||
readonly __wbindgen_malloc: (a: number, b: number) => number;
|
||||
readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
||||
readonly __wbindgen_start: () => void;
|
||||
}
|
||||
|
||||
export type SyncInitInput = BufferSource | WebAssembly.Module;
|
||||
|
||||
/**
|
||||
* Instantiates the given `module`, which can either be bytes or
|
||||
* a precompiled `WebAssembly.Module`.
|
||||
*
|
||||
* @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated.
|
||||
*
|
||||
* @returns {InitOutput}
|
||||
*/
|
||||
export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput;
|
||||
|
||||
/**
|
||||
* If `module_or_path` is {RequestInfo} or {URL}, makes a request and
|
||||
* for everything else, calls `WebAssembly.instantiate` directly.
|
||||
*
|
||||
* @param {{ module_or_path: InitInput | Promise<InitInput> }} module_or_path - Passing `InitInput` directly is deprecated.
|
||||
*
|
||||
* @returns {Promise<InitOutput>}
|
||||
*/
|
||||
export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise<InitInput> } | InitInput | Promise<InitInput>): Promise<InitOutput>;
|
||||
@@ -0,0 +1,398 @@
|
||||
/* @ts-self-types="./ruflo_watermark.d.ts" */
|
||||
|
||||
/**
|
||||
* Detection result, JS-facing (fields via getters).
|
||||
*/
|
||||
export class WasmDetection {
|
||||
static __wrap(ptr) {
|
||||
const obj = Object.create(WasmDetection.prototype);
|
||||
obj.__wbg_ptr = ptr;
|
||||
WasmDetectionFinalization.register(obj, obj.__wbg_ptr, obj);
|
||||
return obj;
|
||||
}
|
||||
__destroy_into_raw() {
|
||||
const ptr = this.__wbg_ptr;
|
||||
this.__wbg_ptr = 0;
|
||||
WasmDetectionFinalization.unregister(this);
|
||||
return ptr;
|
||||
}
|
||||
free() {
|
||||
const ptr = this.__destroy_into_raw();
|
||||
wasm.__wbg_wasmdetection_free(ptr, 0);
|
||||
}
|
||||
/**
|
||||
* @returns {number}
|
||||
*/
|
||||
get log10_p() {
|
||||
const ret = wasm.wasmdetection_log10_p(this.__wbg_ptr);
|
||||
return ret;
|
||||
}
|
||||
/**
|
||||
* @returns {number}
|
||||
*/
|
||||
get p_value() {
|
||||
const ret = wasm.wasmdetection_p_value(this.__wbg_ptr);
|
||||
return ret;
|
||||
}
|
||||
/**
|
||||
* @returns {number}
|
||||
*/
|
||||
get scored_positions() {
|
||||
const ret = wasm.wasmdetection_scored_positions(this.__wbg_ptr);
|
||||
return ret >>> 0;
|
||||
}
|
||||
/**
|
||||
* @returns {number}
|
||||
*/
|
||||
get z_score() {
|
||||
const ret = wasm.wasmdetection_z_score(this.__wbg_ptr);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
if (Symbol.dispose) WasmDetection.prototype[Symbol.dispose] = WasmDetection.prototype.free;
|
||||
|
||||
/**
|
||||
* Streaming watermarked sampler, JS-facing.
|
||||
*/
|
||||
export class WasmWatermarker {
|
||||
__destroy_into_raw() {
|
||||
const ptr = this.__wbg_ptr;
|
||||
this.__wbg_ptr = 0;
|
||||
WasmWatermarkerFinalization.unregister(this);
|
||||
return ptr;
|
||||
}
|
||||
free() {
|
||||
const ptr = this.__destroy_into_raw();
|
||||
wasm.__wbg_wasmwatermarker_free(ptr, 0);
|
||||
}
|
||||
/**
|
||||
* `key_material`: arbitrary secret bytes (e.g. a hex string's bytes).
|
||||
* `scheme`: `"tournament"` | `"tournament_nd"` | `"gumbel"` (default gumbel).
|
||||
* @param {Uint8Array} key_material
|
||||
* @param {number} context_width
|
||||
* @param {number} layers
|
||||
* @param {string} scheme
|
||||
*/
|
||||
constructor(key_material, context_width, layers, scheme) {
|
||||
const ptr0 = passArray8ToWasm0(key_material, wasm.__wbindgen_malloc);
|
||||
const len0 = WASM_VECTOR_LEN;
|
||||
const ptr1 = passStringToWasm0(scheme, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
const len1 = WASM_VECTOR_LEN;
|
||||
const ret = wasm.wasmwatermarker_new(ptr0, len0, context_width, layers, ptr1, len1);
|
||||
this.__wbg_ptr = ret;
|
||||
WasmWatermarkerFinalization.register(this, this.__wbg_ptr, this);
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Emit one token: returns the index into `tokens`/`probs` of the chosen
|
||||
* candidate. Advances the rolling context.
|
||||
* @param {Uint32Array} tokens
|
||||
* @param {Float32Array} probs
|
||||
* @returns {number}
|
||||
*/
|
||||
step(tokens, probs) {
|
||||
const ptr0 = passArray32ToWasm0(tokens, wasm.__wbindgen_malloc);
|
||||
const len0 = WASM_VECTOR_LEN;
|
||||
const ptr1 = passArrayF32ToWasm0(probs, wasm.__wbindgen_malloc);
|
||||
const len1 = WASM_VECTOR_LEN;
|
||||
const ret = wasm.wasmwatermarker_step(this.__wbg_ptr, ptr0, len0, ptr1, len1);
|
||||
return ret >>> 0;
|
||||
}
|
||||
}
|
||||
if (Symbol.dispose) WasmWatermarker.prototype[Symbol.dispose] = WasmWatermarker.prototype.free;
|
||||
|
||||
/**
|
||||
* Detect a watermark over an emitted token id sequence, using the named scheme.
|
||||
* @param {Uint32Array} tokens
|
||||
* @param {Uint8Array} key_material
|
||||
* @param {number} context_width
|
||||
* @param {number} layers
|
||||
* @param {string} scheme
|
||||
* @returns {WasmDetection}
|
||||
*/
|
||||
export function detect(tokens, key_material, context_width, layers, scheme) {
|
||||
const ptr0 = passArray32ToWasm0(tokens, wasm.__wbindgen_malloc);
|
||||
const len0 = WASM_VECTOR_LEN;
|
||||
const ptr1 = passArray8ToWasm0(key_material, wasm.__wbindgen_malloc);
|
||||
const len1 = WASM_VECTOR_LEN;
|
||||
const ptr2 = passStringToWasm0(scheme, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
const len2 = WASM_VECTOR_LEN;
|
||||
const ret = wasm.detect(ptr0, len0, ptr1, len1, context_width, layers, ptr2, len2);
|
||||
return WasmDetection.__wrap(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exact-null short-text detection (Gumbel, exact Gamma tail): correct p-values
|
||||
* at small token counts where the normal approximation misleads. See `bayes.rs`.
|
||||
* @param {Uint32Array} tokens
|
||||
* @param {Uint8Array} key_material
|
||||
* @param {number} context_width
|
||||
* @returns {WasmDetection}
|
||||
*/
|
||||
export function detect_exact(tokens, key_material, context_width) {
|
||||
const ptr0 = passArray32ToWasm0(tokens, wasm.__wbindgen_malloc);
|
||||
const len0 = WASM_VECTOR_LEN;
|
||||
const ptr1 = passArray8ToWasm0(key_material, wasm.__wbindgen_malloc);
|
||||
const len1 = WASM_VECTOR_LEN;
|
||||
const ret = wasm.detect_exact(ptr0, len0, ptr1, len1, context_width);
|
||||
return WasmDetection.__wrap(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indel-robust detection (Gumbel self-sync): far stronger than the standard
|
||||
* detector on edited / repetitive text. See `align.rs`.
|
||||
* @param {Uint32Array} tokens
|
||||
* @param {Uint8Array} key_material
|
||||
* @param {number} context_width
|
||||
* @returns {WasmDetection}
|
||||
*/
|
||||
export function detect_selfsync(tokens, key_material, context_width) {
|
||||
const ptr0 = passArray32ToWasm0(tokens, wasm.__wbindgen_malloc);
|
||||
const len0 = WASM_VECTOR_LEN;
|
||||
const ptr1 = passArray8ToWasm0(key_material, wasm.__wbindgen_malloc);
|
||||
const len1 = WASM_VECTOR_LEN;
|
||||
const ret = wasm.detect_selfsync(ptr0, len0, ptr1, len1, context_width);
|
||||
return WasmDetection.__wrap(ret);
|
||||
}
|
||||
function __wbg_get_imports() {
|
||||
const import0 = {
|
||||
__proto__: null,
|
||||
__wbg___wbindgen_throw_bb96b2010945f0bc: function(arg0, arg1) {
|
||||
throw new Error(getStringFromWasm0(arg0, arg1));
|
||||
},
|
||||
__wbindgen_init_externref_table: function() {
|
||||
const table = wasm.__wbindgen_externrefs;
|
||||
const offset = table.grow(4);
|
||||
table.set(0, undefined);
|
||||
table.set(offset + 0, undefined);
|
||||
table.set(offset + 1, null);
|
||||
table.set(offset + 2, true);
|
||||
table.set(offset + 3, false);
|
||||
},
|
||||
};
|
||||
return {
|
||||
__proto__: null,
|
||||
"./ruflo_watermark_bg.js": import0,
|
||||
};
|
||||
}
|
||||
|
||||
const WasmDetectionFinalization = (typeof FinalizationRegistry === 'undefined')
|
||||
? { register: () => {}, unregister: () => {} }
|
||||
: new FinalizationRegistry(ptr => wasm.__wbg_wasmdetection_free(ptr, 1));
|
||||
const WasmWatermarkerFinalization = (typeof FinalizationRegistry === 'undefined')
|
||||
? { register: () => {}, unregister: () => {} }
|
||||
: new FinalizationRegistry(ptr => wasm.__wbg_wasmwatermarker_free(ptr, 1));
|
||||
|
||||
let cachedFloat32ArrayMemory0 = null;
|
||||
function getFloat32ArrayMemory0() {
|
||||
if (cachedFloat32ArrayMemory0 === null || cachedFloat32ArrayMemory0.byteLength === 0) {
|
||||
cachedFloat32ArrayMemory0 = new Float32Array(wasm.memory.buffer);
|
||||
}
|
||||
return cachedFloat32ArrayMemory0;
|
||||
}
|
||||
|
||||
function getStringFromWasm0(ptr, len) {
|
||||
return decodeText(ptr >>> 0, len);
|
||||
}
|
||||
|
||||
let cachedUint32ArrayMemory0 = null;
|
||||
function getUint32ArrayMemory0() {
|
||||
if (cachedUint32ArrayMemory0 === null || cachedUint32ArrayMemory0.byteLength === 0) {
|
||||
cachedUint32ArrayMemory0 = new Uint32Array(wasm.memory.buffer);
|
||||
}
|
||||
return cachedUint32ArrayMemory0;
|
||||
}
|
||||
|
||||
let cachedUint8ArrayMemory0 = null;
|
||||
function getUint8ArrayMemory0() {
|
||||
if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
|
||||
cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
|
||||
}
|
||||
return cachedUint8ArrayMemory0;
|
||||
}
|
||||
|
||||
function passArray32ToWasm0(arg, malloc) {
|
||||
const ptr = malloc(arg.length * 4, 4) >>> 0;
|
||||
getUint32ArrayMemory0().set(arg, ptr / 4);
|
||||
WASM_VECTOR_LEN = arg.length;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
function passArray8ToWasm0(arg, malloc) {
|
||||
const ptr = malloc(arg.length * 1, 1) >>> 0;
|
||||
getUint8ArrayMemory0().set(arg, ptr / 1);
|
||||
WASM_VECTOR_LEN = arg.length;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
function passArrayF32ToWasm0(arg, malloc) {
|
||||
const ptr = malloc(arg.length * 4, 4) >>> 0;
|
||||
getFloat32ArrayMemory0().set(arg, ptr / 4);
|
||||
WASM_VECTOR_LEN = arg.length;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
function passStringToWasm0(arg, malloc, realloc) {
|
||||
if (realloc === undefined) {
|
||||
const buf = cachedTextEncoder.encode(arg);
|
||||
const ptr = malloc(buf.length, 1) >>> 0;
|
||||
getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
|
||||
WASM_VECTOR_LEN = buf.length;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
let len = arg.length;
|
||||
let ptr = malloc(len, 1) >>> 0;
|
||||
|
||||
const mem = getUint8ArrayMemory0();
|
||||
|
||||
let offset = 0;
|
||||
|
||||
for (; offset < len; offset++) {
|
||||
const code = arg.charCodeAt(offset);
|
||||
if (code > 0x7F) break;
|
||||
mem[ptr + offset] = code;
|
||||
}
|
||||
if (offset !== len) {
|
||||
if (offset !== 0) {
|
||||
arg = arg.slice(offset);
|
||||
}
|
||||
ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
|
||||
const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
|
||||
const ret = cachedTextEncoder.encodeInto(arg, view);
|
||||
|
||||
offset += ret.written;
|
||||
ptr = realloc(ptr, len, offset, 1) >>> 0;
|
||||
}
|
||||
|
||||
WASM_VECTOR_LEN = offset;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
|
||||
cachedTextDecoder.decode();
|
||||
const MAX_SAFARI_DECODE_BYTES = 2146435072;
|
||||
let numBytesDecoded = 0;
|
||||
function decodeText(ptr, len) {
|
||||
numBytesDecoded += len;
|
||||
if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) {
|
||||
cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
|
||||
cachedTextDecoder.decode();
|
||||
numBytesDecoded = len;
|
||||
}
|
||||
return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
|
||||
}
|
||||
|
||||
const cachedTextEncoder = new TextEncoder();
|
||||
|
||||
if (!('encodeInto' in cachedTextEncoder)) {
|
||||
cachedTextEncoder.encodeInto = function (arg, view) {
|
||||
const buf = cachedTextEncoder.encode(arg);
|
||||
view.set(buf);
|
||||
return {
|
||||
read: arg.length,
|
||||
written: buf.length
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
let WASM_VECTOR_LEN = 0;
|
||||
|
||||
let wasmModule, wasmInstance, wasm;
|
||||
function __wbg_finalize_init(instance, module) {
|
||||
wasmInstance = instance;
|
||||
wasm = instance.exports;
|
||||
wasmModule = module;
|
||||
cachedFloat32ArrayMemory0 = null;
|
||||
cachedUint32ArrayMemory0 = null;
|
||||
cachedUint8ArrayMemory0 = null;
|
||||
wasm.__wbindgen_start();
|
||||
return wasm;
|
||||
}
|
||||
|
||||
async function __wbg_load(module, imports) {
|
||||
if (typeof Response === 'function' && module instanceof Response) {
|
||||
if (!module.ok) {
|
||||
throw new Error(`failed to fetch Wasm: ${module.status} ${module.statusText} fetching '${module.url}'`);
|
||||
}
|
||||
|
||||
if (typeof WebAssembly.instantiateStreaming === 'function') {
|
||||
try {
|
||||
return await WebAssembly.instantiateStreaming(module, imports);
|
||||
} catch (e) {
|
||||
const validResponse = expectedResponseType(module.type);
|
||||
|
||||
if (validResponse && module.headers.get('Content-Type') !== 'application/wasm') {
|
||||
console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
|
||||
|
||||
} else { throw e; }
|
||||
}
|
||||
}
|
||||
|
||||
const bytes = await module.arrayBuffer();
|
||||
return await WebAssembly.instantiate(bytes, imports);
|
||||
} else {
|
||||
const instance = await WebAssembly.instantiate(module, imports);
|
||||
|
||||
if (instance instanceof WebAssembly.Instance) {
|
||||
return { instance, module };
|
||||
} else {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
function expectedResponseType(type) {
|
||||
switch (type) {
|
||||
case 'basic': case 'cors': case 'default': return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function initSync(module) {
|
||||
if (wasm !== undefined) return wasm;
|
||||
|
||||
|
||||
if (module !== undefined) {
|
||||
if (Object.getPrototypeOf(module) === Object.prototype) {
|
||||
({module} = module)
|
||||
} else {
|
||||
console.warn('using deprecated parameters for `initSync()`; pass a single object instead')
|
||||
}
|
||||
}
|
||||
|
||||
const imports = __wbg_get_imports();
|
||||
if (!(module instanceof WebAssembly.Module)) {
|
||||
module = new WebAssembly.Module(module);
|
||||
}
|
||||
const instance = new WebAssembly.Instance(module, imports);
|
||||
return __wbg_finalize_init(instance, module);
|
||||
}
|
||||
|
||||
async function __wbg_init(module_or_path) {
|
||||
if (wasm !== undefined) return wasm;
|
||||
|
||||
|
||||
if (module_or_path !== undefined) {
|
||||
if (Object.getPrototypeOf(module_or_path) === Object.prototype) {
|
||||
({module_or_path} = module_or_path)
|
||||
} else {
|
||||
console.warn('using deprecated parameters for the initialization function; pass a single object instead')
|
||||
}
|
||||
}
|
||||
|
||||
if (module_or_path === undefined) {
|
||||
module_or_path = new URL('ruflo_watermark_bg.wasm', import.meta.url);
|
||||
}
|
||||
const imports = __wbg_get_imports();
|
||||
|
||||
if (typeof module_or_path === 'string' || (typeof Request === 'function' && module_or_path instanceof Request) || (typeof URL === 'function' && module_or_path instanceof URL)) {
|
||||
module_or_path = fetch(module_or_path);
|
||||
}
|
||||
|
||||
const { instance, module } = await __wbg_load(await module_or_path, imports);
|
||||
|
||||
return __wbg_finalize_init(instance, module);
|
||||
}
|
||||
|
||||
export { initSync, __wbg_init as default };
|
||||
Binary file not shown.
@@ -0,0 +1,18 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export const memory: WebAssembly.Memory;
|
||||
export const __wbg_wasmdetection_free: (a: number, b: number) => void;
|
||||
export const __wbg_wasmwatermarker_free: (a: number, b: number) => void;
|
||||
export const detect: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => number;
|
||||
export const detect_exact: (a: number, b: number, c: number, d: number, e: number) => number;
|
||||
export const detect_selfsync: (a: number, b: number, c: number, d: number, e: number) => number;
|
||||
export const wasmdetection_log10_p: (a: number) => number;
|
||||
export const wasmdetection_p_value: (a: number) => number;
|
||||
export const wasmdetection_scored_positions: (a: number) => number;
|
||||
export const wasmdetection_z_score: (a: number) => number;
|
||||
export const wasmwatermarker_new: (a: number, b: number, c: number, d: number, e: number, f: number) => number;
|
||||
export const wasmwatermarker_step: (a: number, b: number, c: number, d: number, e: number) => number;
|
||||
export const __wbindgen_externrefs: WebAssembly.Table;
|
||||
export const __wbindgen_malloc: (a: number, b: number) => number;
|
||||
export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
||||
export const __wbindgen_start: () => void;
|
||||
@@ -12,3 +12,4 @@
|
||||
.ruvector/
|
||||
/pkg
|
||||
/pkg-nodejs
|
||||
/pkg-web
|
||||
|
||||
Reference in New Issue
Block a user