@veripublica/epubveri-wasm 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/README.md +102 -0
- package/epubveri.d.ts +65 -0
- package/epubveri.js +9 -0
- package/epubveri_bg.js +193 -0
- package/epubveri_bg.wasm +0 -0
- package/package.json +31 -0
package/README.md
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# epubveri-wasm
|
|
2
|
+
|
|
3
|
+
WebAssembly bindings for [**epubveri**](https://github.com/veripublica/epubveri) — a
|
|
4
|
+
pure-Rust EPUB validator. Validate an `.epub` **entirely in the browser** (or any JS
|
|
5
|
+
runtime): no JVM, no server round-trip, no native dependencies. The bytes never leave
|
|
6
|
+
the page.
|
|
7
|
+
|
|
8
|
+
This is the WASM delivery of epubveri, a small/fast/embeddable alternative to the
|
|
9
|
+
official Java **epubcheck**. It reuses epubcheck-compatible message IDs (`RSC-…`,
|
|
10
|
+
`OPF-…`, `HTM-…`, …) so existing toolchains recognize the output.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
npm install @veripublica/epubveri-wasm
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Usage (bundlers — webpack / Vite / Rollup)
|
|
19
|
+
|
|
20
|
+
The published package is built for **bundlers**, so there's no manual init step —
|
|
21
|
+
your bundler loads the `.wasm` for you:
|
|
22
|
+
|
|
23
|
+
```js
|
|
24
|
+
import { validate, version } from "@veripublica/epubveri-wasm";
|
|
25
|
+
|
|
26
|
+
const bytes = new Uint8Array(await file.arrayBuffer()); // a File / fetched .epub
|
|
27
|
+
const report = validate(bytes, undefined); // second arg: profile or undefined
|
|
28
|
+
|
|
29
|
+
console.log(report.valid, report.errors, report.warnings);
|
|
30
|
+
for (const m of report.messages) {
|
|
31
|
+
console.log(`${m.severity} ${m.id}: ${m.text}`, m.location ?? "");
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Using it **directly in a browser without a bundler**? Build the `web` target
|
|
36
|
+
instead (`wasm-pack build . --target web`), which exposes an async `init()` you
|
|
37
|
+
`await` once before calling `validate()` — that's what the demo below uses.
|
|
38
|
+
|
|
39
|
+
### Return shape (fully typed — real `.d.ts` ships in the package)
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
interface Report {
|
|
43
|
+
valid: boolean; // true when there are zero ERROR-severity messages
|
|
44
|
+
errors: number;
|
|
45
|
+
warnings: number;
|
|
46
|
+
messages: Message[];
|
|
47
|
+
}
|
|
48
|
+
interface Message {
|
|
49
|
+
id: string; // epubcheck-compatible, e.g. "RSC-005"
|
|
50
|
+
severity: string; // "ERROR" | "WARNING" | "INFO"
|
|
51
|
+
text: string; // epubveri's own message wording
|
|
52
|
+
location?: string; // path/element hint, when available
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function validate(bytes: Uint8Array, profile?: string | null): Report;
|
|
56
|
+
function version(): string;
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Profiles
|
|
60
|
+
|
|
61
|
+
`profile` mirrors epubcheck's `--profile` flag: pass `"dict"`, `"edupub"`, `"idx"`,
|
|
62
|
+
`"preview"`, or `undefined`/`null` for default behavior. Unknown names are treated as
|
|
63
|
+
`undefined` (permissive).
|
|
64
|
+
|
|
65
|
+
### One CLI-only difference
|
|
66
|
+
|
|
67
|
+
The `PKG-016` check (the `.epub` **file extension** should be lowercase) is filename-
|
|
68
|
+
based and is **not** reported here — this entry point only ever sees bytes, never a
|
|
69
|
+
filename. Everything else matches the native CLI/library exactly.
|
|
70
|
+
|
|
71
|
+
## Try the demo
|
|
72
|
+
|
|
73
|
+
The `demo/` folder has a zero-dependency drag-and-drop page. From the crate root:
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
wasm-pack build . --target web --out-name epubveri # produces pkg/
|
|
77
|
+
# then serve this folder over HTTP (wasm needs http://, not file://):
|
|
78
|
+
# any static server works, e.g. `miniserve .` or `python3 -m http.server`
|
|
79
|
+
# open http://localhost:8000/demo/
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Building from source
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
cargo install wasm-pack
|
|
86
|
+
|
|
87
|
+
# the published npm package (bundler target, @veripublica scope):
|
|
88
|
+
wasm-pack build . --target bundler --scope veripublica --out-name epubveri
|
|
89
|
+
|
|
90
|
+
# or the web target used by the demo above:
|
|
91
|
+
wasm-pack build . --target web --out-name epubveri
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The generated package lands in `pkg/` (git-ignored). Each `--target`
|
|
95
|
+
(`bundler` / `web` / `nodejs`) emits different JS glue, so pick the one that
|
|
96
|
+
matches how you'll load it; use `--target nodejs` for Node.
|
|
97
|
+
|
|
98
|
+
## License
|
|
99
|
+
|
|
100
|
+
Dual-licensed: **AGPL-3.0-only OR a commercial license** (`LicenseRef-veripublica-Commercial`).
|
|
101
|
+
Open-source use is free under the AGPL; closed/commercial embedders should contact the
|
|
102
|
+
author for a commercial license. See the main repository for details.
|
package/epubveri.d.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
/**
|
|
4
|
+
* One diagnostic, mirroring [`epubveri::report::Message`] with the message ID
|
|
5
|
+
* and severity flattened to strings for the JS boundary.
|
|
6
|
+
*/
|
|
7
|
+
export interface Message {
|
|
8
|
+
/**
|
|
9
|
+
* epubcheck-compatible message ID, e.g. `\"RSC-005\"`.
|
|
10
|
+
*/
|
|
11
|
+
id: string;
|
|
12
|
+
/**
|
|
13
|
+
* `\"ERROR\"`, `\"WARNING\"`, or `\"INFO\"`.
|
|
14
|
+
*/
|
|
15
|
+
severity: string;
|
|
16
|
+
/**
|
|
17
|
+
* Human-readable message text (epubveri\'s own wording).
|
|
18
|
+
*/
|
|
19
|
+
text: string;
|
|
20
|
+
/**
|
|
21
|
+
* Optional location hint (path / element), when the check provides one.
|
|
22
|
+
*/
|
|
23
|
+
location: string | undefined;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The full validation result for one EPUB.
|
|
28
|
+
*/
|
|
29
|
+
export interface Report {
|
|
30
|
+
/**
|
|
31
|
+
* `true` when there are zero `ERROR`-severity messages (warnings are allowed).
|
|
32
|
+
*/
|
|
33
|
+
valid: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Count of `ERROR`-severity messages.
|
|
36
|
+
*/
|
|
37
|
+
errors: number;
|
|
38
|
+
/**
|
|
39
|
+
* Count of `WARNING`-severity messages.
|
|
40
|
+
*/
|
|
41
|
+
warnings: number;
|
|
42
|
+
/**
|
|
43
|
+
* Every diagnostic, in the order the validator produced them.
|
|
44
|
+
*/
|
|
45
|
+
messages: Message[];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Validate raw EPUB bytes and return a typed [`Report`].
|
|
51
|
+
*
|
|
52
|
+
* `profile` mirrors the CLI `--profile` flag — pass `"dict"`, `"edupub"`,
|
|
53
|
+
* `"idx"`, `"preview"`, or `undefined`/`null` for default behavior. Unknown
|
|
54
|
+
* names behave like `undefined` (permissive).
|
|
55
|
+
*
|
|
56
|
+
* Note: the CLI-only PKG-016 check (the `.epub` file extension should be
|
|
57
|
+
* lowercase) is filename-based and intentionally not reachable here — this
|
|
58
|
+
* entry point only ever sees bytes, never a filename.
|
|
59
|
+
*/
|
|
60
|
+
export function validate(bytes: Uint8Array, profile?: string | null): Report;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* The `epubveri-wasm` crate version (matches this crate's `Cargo.toml`).
|
|
64
|
+
*/
|
|
65
|
+
export function version(): string;
|
package/epubveri.js
ADDED
package/epubveri_bg.js
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validate raw EPUB bytes and return a typed [`Report`].
|
|
3
|
+
*
|
|
4
|
+
* `profile` mirrors the CLI `--profile` flag — pass `"dict"`, `"edupub"`,
|
|
5
|
+
* `"idx"`, `"preview"`, or `undefined`/`null` for default behavior. Unknown
|
|
6
|
+
* names behave like `undefined` (permissive).
|
|
7
|
+
*
|
|
8
|
+
* Note: the CLI-only PKG-016 check (the `.epub` file extension should be
|
|
9
|
+
* lowercase) is filename-based and intentionally not reachable here — this
|
|
10
|
+
* entry point only ever sees bytes, never a filename.
|
|
11
|
+
* @param {Uint8Array} bytes
|
|
12
|
+
* @param {string | null} [profile]
|
|
13
|
+
* @returns {Report}
|
|
14
|
+
*/
|
|
15
|
+
export function validate(bytes, profile) {
|
|
16
|
+
const ptr0 = passArray8ToWasm0(bytes, wasm.__wbindgen_malloc);
|
|
17
|
+
const len0 = WASM_VECTOR_LEN;
|
|
18
|
+
var ptr1 = isLikeNone(profile) ? 0 : passStringToWasm0(profile, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
19
|
+
var len1 = WASM_VECTOR_LEN;
|
|
20
|
+
const ret = wasm.validate(ptr0, len0, ptr1, len1);
|
|
21
|
+
return ret;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The `epubveri-wasm` crate version (matches this crate's `Cargo.toml`).
|
|
26
|
+
* @returns {string}
|
|
27
|
+
*/
|
|
28
|
+
export function version() {
|
|
29
|
+
let deferred1_0;
|
|
30
|
+
let deferred1_1;
|
|
31
|
+
try {
|
|
32
|
+
const ret = wasm.version();
|
|
33
|
+
deferred1_0 = ret[0];
|
|
34
|
+
deferred1_1 = ret[1];
|
|
35
|
+
return getStringFromWasm0(ret[0], ret[1]);
|
|
36
|
+
} finally {
|
|
37
|
+
wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export function __wbg_Error_92b29b0548f8b746(arg0, arg1) {
|
|
41
|
+
const ret = Error(getStringFromWasm0(arg0, arg1));
|
|
42
|
+
return ret;
|
|
43
|
+
}
|
|
44
|
+
export function __wbg_String_8564e559799eccda(arg0, arg1) {
|
|
45
|
+
const ret = String(arg1);
|
|
46
|
+
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
47
|
+
const len1 = WASM_VECTOR_LEN;
|
|
48
|
+
getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
|
|
49
|
+
getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
|
|
50
|
+
}
|
|
51
|
+
export function __wbg___wbindgen_throw_344f42d3211c4765(arg0, arg1) {
|
|
52
|
+
throw new Error(getStringFromWasm0(arg0, arg1));
|
|
53
|
+
}
|
|
54
|
+
export function __wbg_new_32b398fb48b6d94a() {
|
|
55
|
+
const ret = new Array();
|
|
56
|
+
return ret;
|
|
57
|
+
}
|
|
58
|
+
export function __wbg_new_da52cf8fe3429cb2() {
|
|
59
|
+
const ret = new Object();
|
|
60
|
+
return ret;
|
|
61
|
+
}
|
|
62
|
+
export function __wbg_set_6be42768c690e380(arg0, arg1, arg2) {
|
|
63
|
+
arg0[arg1] = arg2;
|
|
64
|
+
}
|
|
65
|
+
export function __wbg_set_8a16b38e4805b298(arg0, arg1, arg2) {
|
|
66
|
+
arg0[arg1 >>> 0] = arg2;
|
|
67
|
+
}
|
|
68
|
+
export function __wbindgen_cast_0000000000000001(arg0) {
|
|
69
|
+
// Cast intrinsic for `F64 -> Externref`.
|
|
70
|
+
const ret = arg0;
|
|
71
|
+
return ret;
|
|
72
|
+
}
|
|
73
|
+
export function __wbindgen_cast_0000000000000002(arg0, arg1) {
|
|
74
|
+
// Cast intrinsic for `Ref(String) -> Externref`.
|
|
75
|
+
const ret = getStringFromWasm0(arg0, arg1);
|
|
76
|
+
return ret;
|
|
77
|
+
}
|
|
78
|
+
export function __wbindgen_cast_0000000000000003(arg0) {
|
|
79
|
+
// Cast intrinsic for `U64 -> Externref`.
|
|
80
|
+
const ret = BigInt.asUintN(64, arg0);
|
|
81
|
+
return ret;
|
|
82
|
+
}
|
|
83
|
+
export function __wbindgen_init_externref_table() {
|
|
84
|
+
const table = wasm.__wbindgen_externrefs;
|
|
85
|
+
const offset = table.grow(4);
|
|
86
|
+
table.set(0, undefined);
|
|
87
|
+
table.set(offset + 0, undefined);
|
|
88
|
+
table.set(offset + 1, null);
|
|
89
|
+
table.set(offset + 2, true);
|
|
90
|
+
table.set(offset + 3, false);
|
|
91
|
+
}
|
|
92
|
+
let cachedDataViewMemory0 = null;
|
|
93
|
+
function getDataViewMemory0() {
|
|
94
|
+
if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {
|
|
95
|
+
cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
|
|
96
|
+
}
|
|
97
|
+
return cachedDataViewMemory0;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function getStringFromWasm0(ptr, len) {
|
|
101
|
+
return decodeText(ptr >>> 0, len);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
let cachedUint8ArrayMemory0 = null;
|
|
105
|
+
function getUint8ArrayMemory0() {
|
|
106
|
+
if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
|
|
107
|
+
cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
|
|
108
|
+
}
|
|
109
|
+
return cachedUint8ArrayMemory0;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function isLikeNone(x) {
|
|
113
|
+
return x === undefined || x === null;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function passArray8ToWasm0(arg, malloc) {
|
|
117
|
+
const ptr = malloc(arg.length * 1, 1) >>> 0;
|
|
118
|
+
getUint8ArrayMemory0().set(arg, ptr / 1);
|
|
119
|
+
WASM_VECTOR_LEN = arg.length;
|
|
120
|
+
return ptr;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function passStringToWasm0(arg, malloc, realloc) {
|
|
124
|
+
if (realloc === undefined) {
|
|
125
|
+
const buf = cachedTextEncoder.encode(arg);
|
|
126
|
+
const ptr = malloc(buf.length, 1) >>> 0;
|
|
127
|
+
getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
|
|
128
|
+
WASM_VECTOR_LEN = buf.length;
|
|
129
|
+
return ptr;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
let len = arg.length;
|
|
133
|
+
let ptr = malloc(len, 1) >>> 0;
|
|
134
|
+
|
|
135
|
+
const mem = getUint8ArrayMemory0();
|
|
136
|
+
|
|
137
|
+
let offset = 0;
|
|
138
|
+
|
|
139
|
+
for (; offset < len; offset++) {
|
|
140
|
+
const code = arg.charCodeAt(offset);
|
|
141
|
+
if (code > 0x7F) break;
|
|
142
|
+
mem[ptr + offset] = code;
|
|
143
|
+
}
|
|
144
|
+
if (offset !== len) {
|
|
145
|
+
if (offset !== 0) {
|
|
146
|
+
arg = arg.slice(offset);
|
|
147
|
+
}
|
|
148
|
+
ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
|
|
149
|
+
const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
|
|
150
|
+
const ret = cachedTextEncoder.encodeInto(arg, view);
|
|
151
|
+
|
|
152
|
+
offset += ret.written;
|
|
153
|
+
ptr = realloc(ptr, len, offset, 1) >>> 0;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
WASM_VECTOR_LEN = offset;
|
|
157
|
+
return ptr;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
|
|
161
|
+
cachedTextDecoder.decode();
|
|
162
|
+
const MAX_SAFARI_DECODE_BYTES = 2146435072;
|
|
163
|
+
let numBytesDecoded = 0;
|
|
164
|
+
function decodeText(ptr, len) {
|
|
165
|
+
numBytesDecoded += len;
|
|
166
|
+
if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) {
|
|
167
|
+
cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
|
|
168
|
+
cachedTextDecoder.decode();
|
|
169
|
+
numBytesDecoded = len;
|
|
170
|
+
}
|
|
171
|
+
return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const cachedTextEncoder = new TextEncoder();
|
|
175
|
+
|
|
176
|
+
if (!('encodeInto' in cachedTextEncoder)) {
|
|
177
|
+
cachedTextEncoder.encodeInto = function (arg, view) {
|
|
178
|
+
const buf = cachedTextEncoder.encode(arg);
|
|
179
|
+
view.set(buf);
|
|
180
|
+
return {
|
|
181
|
+
read: arg.length,
|
|
182
|
+
written: buf.length
|
|
183
|
+
};
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
let WASM_VECTOR_LEN = 0;
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
let wasm;
|
|
191
|
+
export function __wbg_set_wasm(val) {
|
|
192
|
+
wasm = val;
|
|
193
|
+
}
|
package/epubveri_bg.wasm
ADDED
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@veripublica/epubveri-wasm",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"description": "WebAssembly bindings for epubveri — a pure-Rust, JVM-free EPUB validator that runs in the browser.",
|
|
5
|
+
"version": "0.1.0",
|
|
6
|
+
"license": "AGPL-3.0-only OR LicenseRef-veripublica-Commercial",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/veripublica/epubveri"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"epubveri_bg.wasm",
|
|
13
|
+
"epubveri.js",
|
|
14
|
+
"epubveri_bg.js",
|
|
15
|
+
"epubveri.d.ts"
|
|
16
|
+
],
|
|
17
|
+
"main": "epubveri.js",
|
|
18
|
+
"homepage": "https://github.com/veripublica/epubveri",
|
|
19
|
+
"types": "epubveri.d.ts",
|
|
20
|
+
"sideEffects": [
|
|
21
|
+
"./epubveri.js",
|
|
22
|
+
"./snippets/*"
|
|
23
|
+
],
|
|
24
|
+
"keywords": [
|
|
25
|
+
"epub",
|
|
26
|
+
"epubcheck",
|
|
27
|
+
"validator",
|
|
28
|
+
"wasm",
|
|
29
|
+
"ebook"
|
|
30
|
+
]
|
|
31
|
+
}
|