tapirscan 1.2.1 → 1.3.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/LICENSE +220 -0
- package/README.md +384 -226
- package/dist/browser-worker.d.ts +33 -0
- package/dist/browser-worker.js +83 -0
- package/dist/browser.d.ts +44 -0
- package/dist/browser.js +211 -0
- package/dist/freeze.d.ts +6 -0
- package/dist/freeze.js +7 -0
- package/dist/index.d.ts +53 -46
- package/dist/index.js +168 -209
- package/dist/layout.d.ts +19 -0
- package/dist/layout.js +27 -0
- package/dist/multiformat/format-registry.d.ts +26 -0
- package/dist/multiformat/format-registry.js +63 -0
- package/dist/multiformat/formats.d.ts +4 -24
- package/dist/multiformat/formats.js +15 -46
- package/dist/rust-session.d.ts +19 -0
- package/dist/rust-session.js +102 -0
- package/examples/camera.html +28 -29
- package/examples/vite/README.md +31 -0
- package/examples/vite/index.html +14 -0
- package/examples/vite/main.js +33 -0
- package/examples/vite/package.json +16 -0
- package/examples/vite/vite.config.js +6 -0
- package/package.json +28 -11
- package/wasm/build.json +295 -0
- package/wasm/experimental-turbo16.wasm +0 -0
- package/wasm/experimental-turbo2.wasm +0 -0
- package/wasm/experimental-turbo4.wasm +0 -0
- package/wasm/experimental-turbo8.wasm +0 -0
- package/wasm/high.wasm +0 -0
- package/wasm/low.wasm +0 -0
- package/wasm/medium.wasm +0 -0
- package/wasm/very-high.wasm +0 -0
- package/dist/completion-host.d.mts +0 -40
- package/dist/completion-host.mjs +0 -188
- package/dist/detail-20260914/continuity.d.mts +0 -2
- package/dist/detail-20260914/continuity.mjs +0 -62
- package/dist/detail-20260914/detail-proposals-rich.d.mts +0 -13
- package/dist/detail-20260914/detail-proposals-rich.mjs +0 -53
- package/dist/detail-20260914/direct-recovery.d.mts +0 -28
- package/dist/detail-20260914/direct-recovery.mjs +0 -139
- package/dist/detail-20260914/host.d.mts +0 -40
- package/dist/detail-20260914/host.mjs +0 -280
- package/dist/detail-20260914/scanner.d.mts +0 -12
- package/dist/detail-20260914/scanner.mjs +0 -64
- package/dist/detail-20260914/source-evidence.d.mts +0 -10
- package/dist/detail-20260914/source-evidence.mjs +0 -94
- package/dist/detail-canvas.d.ts +0 -35
- package/dist/detail-canvas.js +0 -73
- package/dist/detail-runtime/direct-recovery.d.mts +0 -28
- package/dist/detail-runtime/direct-recovery.mjs +0 -142
- package/dist/detail-runtime/host.d.mts +0 -40
- package/dist/detail-runtime/host.mjs +0 -284
- package/dist/detail-runtime/scanner.d.mts +0 -12
- package/dist/detail-runtime/scanner.mjs +0 -70
- package/dist/detail.d.ts +0 -20
- package/dist/detail.js +0 -84
- package/dist/host.d.ts +0 -112
- package/dist/host.js +0 -184
- package/dist/host64.d.ts +0 -112
- package/dist/host64.js +0 -184
- package/dist/multiformat/coverage.d.ts +0 -7
- package/dist/multiformat/coverage.js +0 -26
- package/dist/multiformat/geometry.d.ts +0 -37
- package/dist/multiformat/geometry.js +0 -132
- package/dist/multiformat/linear-duplicates.d.ts +0 -16
- package/dist/multiformat/linear-duplicates.js +0 -163
- package/dist/multiformat/pixels.d.ts +0 -3
- package/dist/multiformat/pixels.js +0 -36
- package/dist/multiformat/scanner.d.ts +0 -60
- package/dist/multiformat/scanner.js +0 -382
- package/dist/multiformat-host.d.ts +0 -121
- package/dist/multiformat-host.js +0 -207
- package/dist/policy.d.ts +0 -12
- package/dist/policy.js +0 -12
- package/examples/scan-worker.mjs +0 -20
- package/examples/worker-client.mjs +0 -63
- package/wasm/high-shared-retail-portable-20260919.wasm +0 -0
- package/wasm/low-shared-retail-portable-20260919.wasm +0 -0
- package/wasm/medium-shared-retail-portable-20260919.wasm +0 -0
- package/wasm/multiformat.json +0 -7
- package/wasm/multiformat.wasm +0 -0
- package/wasm/very-high-shared-retail-portable-20260919.wasm +0 -0
|
@@ -1,44 +1,10 @@
|
|
|
1
1
|
/** Explicit opt-in formats for the independent Medium extension. */
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
Code39: 32,
|
|
9
|
-
ITF: 64,
|
|
10
|
-
Codabar: 128,
|
|
11
|
-
Code93: 256,
|
|
12
|
-
QRCode: 512,
|
|
13
|
-
DataMatrix: 1024,
|
|
14
|
-
PDF417: 2048,
|
|
15
|
-
Aztec: 4096,
|
|
16
|
-
DataBar: 8192,
|
|
17
|
-
DataBarExpanded: 16384,
|
|
18
|
-
MaxiCode: 131072,
|
|
19
|
-
};
|
|
20
|
-
export const retailFormats = ["EAN13", "UPCA", "EAN8", "UPCE"];
|
|
21
|
-
export const commonLinearFormats = [
|
|
22
|
-
...retailFormats,
|
|
23
|
-
"Code128",
|
|
24
|
-
"Code39",
|
|
25
|
-
"ITF",
|
|
26
|
-
];
|
|
27
|
-
export const commonFormats = [...commonLinearFormats, "QRCode", "DataMatrix"];
|
|
28
|
-
export const linearFormats = [
|
|
29
|
-
...commonLinearFormats,
|
|
30
|
-
"Codabar",
|
|
31
|
-
"Code93",
|
|
32
|
-
"DataBar",
|
|
33
|
-
"DataBarExpanded",
|
|
34
|
-
];
|
|
35
|
-
export const matrixFormats = [
|
|
36
|
-
"QRCode",
|
|
37
|
-
"DataMatrix",
|
|
38
|
-
"PDF417",
|
|
39
|
-
"Aztec",
|
|
40
|
-
"MaxiCode",
|
|
41
|
-
];
|
|
2
|
+
import { commonFormats, commonLinearFormats, formatBits, linearFormats, matrixFormats, retailFormats, } from "./format-registry.js";
|
|
3
|
+
export { commonFormats, commonLinearFormats, formatBits, linearFormats, matrixFormats, retailFormats, };
|
|
4
|
+
/** Own-property check that works in Chrome 91 (`Object.hasOwn` needs Chrome 93). */
|
|
5
|
+
export function hasKey(object, key) {
|
|
6
|
+
return Object.prototype.hasOwnProperty.call(object, key);
|
|
7
|
+
}
|
|
42
8
|
export function resolveFormats(input) {
|
|
43
9
|
if (input === "retail")
|
|
44
10
|
return [...retailFormats];
|
|
@@ -54,15 +20,18 @@ export function resolveFormats(input) {
|
|
|
54
20
|
return [...linearFormats, ...matrixFormats];
|
|
55
21
|
if (input === undefined)
|
|
56
22
|
return [...retailFormats];
|
|
57
|
-
if (typeof input === "string"
|
|
58
|
-
|
|
23
|
+
if (typeof input === "string") {
|
|
24
|
+
if (hasKey(formatBits, input))
|
|
25
|
+
return [input];
|
|
26
|
+
throw new TypeError(`Unsupported barcode format or preset: ${input}`);
|
|
27
|
+
}
|
|
59
28
|
if (!Array.isArray(input) || input.length === 0)
|
|
60
|
-
throw
|
|
29
|
+
throw new TypeError("Choose at least one barcode format.");
|
|
61
30
|
for (const value of input) {
|
|
62
31
|
if (typeof value !== "string")
|
|
63
|
-
throw
|
|
64
|
-
if (!
|
|
65
|
-
throw
|
|
32
|
+
throw new TypeError("Barcode format must be a string.");
|
|
33
|
+
if (!hasKey(formatBits, value))
|
|
34
|
+
throw new TypeError(`Unsupported barcode format: ${value}`);
|
|
66
35
|
}
|
|
67
36
|
return [...new Set(input)];
|
|
68
37
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare class ScannerError extends Error {
|
|
2
|
+
readonly code: string;
|
|
3
|
+
constructor(code: string, message: string);
|
|
4
|
+
}
|
|
5
|
+
export declare class RustScannerSession {
|
|
6
|
+
private exports;
|
|
7
|
+
private handle;
|
|
8
|
+
private constructor();
|
|
9
|
+
static create(bytes: ArrayBuffer, mode: number, formats: number, addOnPolicy: number, experimentalTurbo?: number): Promise<RustScannerSession>;
|
|
10
|
+
scan(image: {
|
|
11
|
+
data: Uint8Array;
|
|
12
|
+
width: number;
|
|
13
|
+
height: number;
|
|
14
|
+
channels: number;
|
|
15
|
+
stride: number;
|
|
16
|
+
}, flags: number, formats: number): unknown;
|
|
17
|
+
dispose(): void;
|
|
18
|
+
private activeExports;
|
|
19
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// Stateless for complete inputs, so one decoder serves every scan.
|
|
2
|
+
const outputDecoder = new TextDecoder();
|
|
3
|
+
export class ScannerError extends Error {
|
|
4
|
+
code;
|
|
5
|
+
constructor(code, message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.code = code;
|
|
8
|
+
this.name = "ScannerError";
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
const exportNames = [
|
|
12
|
+
"tapirscan_abi_version",
|
|
13
|
+
"tapirscan_mode",
|
|
14
|
+
"tapirscan_create",
|
|
15
|
+
"tapirscan_destroy",
|
|
16
|
+
"tapirscan_prepare",
|
|
17
|
+
"tapirscan_input_ptr",
|
|
18
|
+
"tapirscan_input_len",
|
|
19
|
+
"tapirscan_scan",
|
|
20
|
+
"tapirscan_output_ptr",
|
|
21
|
+
"tapirscan_output_len",
|
|
22
|
+
];
|
|
23
|
+
function status(code, operation) {
|
|
24
|
+
if (code === 0)
|
|
25
|
+
return;
|
|
26
|
+
const names = {
|
|
27
|
+
1: "invalid_input",
|
|
28
|
+
2: "disposed",
|
|
29
|
+
4: "engine",
|
|
30
|
+
5: "capacity",
|
|
31
|
+
};
|
|
32
|
+
throw new ScannerError(names[code] ?? `core_${String(code)}`, `${operation} failed (${String(code)})`);
|
|
33
|
+
}
|
|
34
|
+
export class RustScannerSession {
|
|
35
|
+
exports;
|
|
36
|
+
handle;
|
|
37
|
+
constructor(exports, handle) {
|
|
38
|
+
this.exports = exports;
|
|
39
|
+
this.handle = handle;
|
|
40
|
+
}
|
|
41
|
+
static async create(bytes, mode, formats, addOnPolicy, experimentalTurbo = 0) {
|
|
42
|
+
const instance = await WebAssembly.instantiate(bytes, {});
|
|
43
|
+
const exports = instance.instance.exports;
|
|
44
|
+
if (!(exports.memory instanceof WebAssembly.Memory))
|
|
45
|
+
throw new ScannerError("abi_shape", "Missing WASM memory");
|
|
46
|
+
for (const name of exportNames)
|
|
47
|
+
if (typeof exports[name] !== "function")
|
|
48
|
+
throw new ScannerError("abi_shape", `Missing WASM export: ${name}`);
|
|
49
|
+
if (exports.tapirscan_abi_version() !== 2)
|
|
50
|
+
throw new ScannerError("abi_version", "Unsupported scanner ABI");
|
|
51
|
+
if (exports.tapirscan_mode() !== mode)
|
|
52
|
+
throw new ScannerError("abi_mode", "Scanner WASM mode does not match the requested mode");
|
|
53
|
+
const tier = exports.tapirscan_experimental_turbo;
|
|
54
|
+
const actualTurbo = typeof tier === "function" ? tier() : 0;
|
|
55
|
+
if (actualTurbo !== experimentalTurbo)
|
|
56
|
+
throw new ScannerError("abi_turbo", "Scanner WASM does not match the requested experimentalTurbo preset");
|
|
57
|
+
const handle = exports.tapirscan_create(mode, formats, addOnPolicy);
|
|
58
|
+
if (!handle)
|
|
59
|
+
throw new ScannerError("capacity", "Could not create scanner session");
|
|
60
|
+
return new RustScannerSession(exports, handle);
|
|
61
|
+
}
|
|
62
|
+
scan(image, flags, formats) {
|
|
63
|
+
const exports = this.activeExports();
|
|
64
|
+
status(exports.tapirscan_prepare(this.handle, image.width, image.height, image.channels, image.stride), "Image preparation");
|
|
65
|
+
const length = exports.tapirscan_input_len(this.handle);
|
|
66
|
+
const expected = (image.height - 1) * image.stride + image.width * image.channels;
|
|
67
|
+
if (length !== expected)
|
|
68
|
+
throw new ScannerError("abi_shape", "Input allocation mismatch");
|
|
69
|
+
new Uint8Array(exports.memory.buffer, exports.tapirscan_input_ptr(this.handle), length).set(image.data.subarray(0, length));
|
|
70
|
+
const result = exports.tapirscan_scan(this.handle, flags, formats);
|
|
71
|
+
const output = new Uint8Array(exports.memory.buffer, exports.tapirscan_output_ptr(this.handle), exports.tapirscan_output_len(this.handle));
|
|
72
|
+
let decoded;
|
|
73
|
+
try {
|
|
74
|
+
decoded = JSON.parse(outputDecoder.decode(output));
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
throw new ScannerError("invalid_output", "Scanner returned invalid JSON");
|
|
78
|
+
}
|
|
79
|
+
if (result !== 0) {
|
|
80
|
+
const message = decoded && typeof decoded === "object" && "error" in decoded
|
|
81
|
+
? String(decoded.error)
|
|
82
|
+
: `Scan failed (${String(result)})`;
|
|
83
|
+
throw new ScannerError(result === 4 ? "engine" : `core_${String(result)}`, message);
|
|
84
|
+
}
|
|
85
|
+
return decoded;
|
|
86
|
+
}
|
|
87
|
+
dispose() {
|
|
88
|
+
if (!this.handle || !this.exports)
|
|
89
|
+
return;
|
|
90
|
+
const exports = this.exports;
|
|
91
|
+
const handle = this.handle;
|
|
92
|
+
// WASM memory never shrinks: drop the instance so a retained scanner frees it.
|
|
93
|
+
this.exports = undefined;
|
|
94
|
+
this.handle = 0;
|
|
95
|
+
status(exports.tapirscan_destroy(handle), "Scanner disposal");
|
|
96
|
+
}
|
|
97
|
+
activeExports() {
|
|
98
|
+
if (!this.handle || !this.exports)
|
|
99
|
+
throw new ScannerError("disposed", "Scanner is disposed");
|
|
100
|
+
return this.exports;
|
|
101
|
+
}
|
|
102
|
+
}
|
package/examples/camera.html
CHANGED
|
@@ -1,60 +1,59 @@
|
|
|
1
1
|
<!doctype html>
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<meta charset="utf-8" />
|
|
4
|
-
<title>Tapirscan
|
|
4
|
+
<title>Tapirscan camera example</title>
|
|
5
5
|
<button id="start">Start camera</button>
|
|
6
6
|
<button id="stop" disabled>Stop</button>
|
|
7
7
|
<video autoplay muted playsinline style="max-width: 100%"></video>
|
|
8
8
|
<pre role="status"></pre>
|
|
9
9
|
<script type="module">
|
|
10
|
-
|
|
10
|
+
// Serve this package directory and open /examples/camera.html on localhost.
|
|
11
|
+
import { Scanner } from "../dist/browser.js";
|
|
11
12
|
const video = document.querySelector("video");
|
|
12
13
|
const status = document.querySelector("pre");
|
|
13
14
|
const start = document.querySelector("#start");
|
|
14
15
|
const stop = document.querySelector("#stop");
|
|
15
|
-
const canvas = document.createElement("canvas");
|
|
16
|
-
const context = canvas.getContext("2d", { willReadFrequently: true });
|
|
17
|
-
let running = false;
|
|
18
16
|
let scanner;
|
|
19
17
|
let stream;
|
|
18
|
+
|
|
20
19
|
function shutdown() {
|
|
21
|
-
running = false;
|
|
22
20
|
scanner?.dispose();
|
|
23
|
-
scanner = undefined;
|
|
24
21
|
stream?.getTracks().forEach((track) => track.stop());
|
|
25
|
-
stream = undefined;
|
|
22
|
+
scanner = stream = undefined;
|
|
26
23
|
video.srcObject = null;
|
|
24
|
+
start.disabled = false;
|
|
25
|
+
stop.disabled = true;
|
|
27
26
|
}
|
|
27
|
+
|
|
28
28
|
start.onclick = async () => {
|
|
29
29
|
start.disabled = true;
|
|
30
|
-
|
|
30
|
+
let current;
|
|
31
31
|
try {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
// Loads in a worker while the camera starts.
|
|
33
|
+
current = scanner = new Scanner({ formats: ["EAN13", "QRCode"] });
|
|
34
|
+
const camera = await navigator.mediaDevices.getUserMedia({
|
|
35
35
|
video: { facingMode: "environment" },
|
|
36
36
|
});
|
|
37
|
-
if (
|
|
37
|
+
if (scanner !== current) {
|
|
38
|
+
camera.getTracks().forEach((track) => track.stop());
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
stream = camera;
|
|
38
42
|
video.srcObject = stream;
|
|
39
|
-
await video.play();
|
|
40
43
|
stop.disabled = false;
|
|
41
|
-
while (
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
);
|
|
48
|
-
status.textContent = JSON.stringify(result.values);
|
|
49
|
-
// Backpressure: capture only after the previous scan has completed.
|
|
50
|
-
await new Promise(requestAnimationFrame);
|
|
44
|
+
while (scanner === current) {
|
|
45
|
+
// Scan each new frame at most once; awaiting the scan avoids a backlog.
|
|
46
|
+
await new Promise((resolve) => video.requestVideoFrameCallback(resolve));
|
|
47
|
+
if (scanner !== current) break;
|
|
48
|
+
const barcodes = await current.scan(video);
|
|
49
|
+
if (scanner === current) status.textContent = JSON.stringify(barcodes.values);
|
|
51
50
|
}
|
|
52
51
|
} catch (error) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
52
|
+
// Also reached when construction fails: report it and re-enable Start.
|
|
53
|
+
if (scanner === current) {
|
|
54
|
+
status.textContent = error.message;
|
|
55
|
+
shutdown();
|
|
56
|
+
}
|
|
58
57
|
}
|
|
59
58
|
};
|
|
60
59
|
stop.onclick = shutdown;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Vite example
|
|
2
|
+
|
|
3
|
+
Copy this directory into your application workspace, then run:
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
npm install
|
|
7
|
+
npm run dev
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
Choose a barcode photo. `tapirscan/browser` decodes the file and scans it in a
|
|
11
|
+
worker; Vite bundles the worker and WASM files without plugins or copy steps.
|
|
12
|
+
The only configuration is `optimizeDeps.exclude` in `vite.config.js`, which the
|
|
13
|
+
development server needs to serve those files from the package. Retail formats
|
|
14
|
+
are enabled by default.
|
|
15
|
+
|
|
16
|
+
To test a locally built package, install its npm tarball instead of
|
|
17
|
+
the registry dependency before running the example:
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
npm install /absolute/path/to/tapirscan-X.Y.Z.tgz
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Test production hosting, including a subpath:
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
npm run build -- --base=/scanner/
|
|
27
|
+
npm run preview -- --base=/scanner/
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Open `/scanner/` on the preview server. For Svelte and SvelteKit, see the
|
|
31
|
+
[package README](../../README.md#browser-apps-react-and-svelte).
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>Tapirscan with Vite</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<h1>Scan a barcode photo</h1>
|
|
10
|
+
<input type="file" accept="image/*" aria-label="Barcode photo" disabled />
|
|
11
|
+
<pre role="status">Loading scanner…</pre>
|
|
12
|
+
<script type="module" src="/main.js"></script>
|
|
13
|
+
</body>
|
|
14
|
+
</html>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Scanner } from "tapirscan/browser";
|
|
2
|
+
|
|
3
|
+
const input = document.querySelector("input");
|
|
4
|
+
const status = document.querySelector('[role="status"]');
|
|
5
|
+
// Scanning runs in a worker, so the page stays responsive.
|
|
6
|
+
const scanner = new Scanner();
|
|
7
|
+
|
|
8
|
+
scanner.ready.then(
|
|
9
|
+
() => {
|
|
10
|
+
input.disabled = false;
|
|
11
|
+
status.textContent = "Choose a photo.";
|
|
12
|
+
},
|
|
13
|
+
(error) => {
|
|
14
|
+
status.textContent = error.message;
|
|
15
|
+
},
|
|
16
|
+
);
|
|
17
|
+
// Only the latest selection may update the page; scans can finish out of order.
|
|
18
|
+
let latest = 0;
|
|
19
|
+
input.onchange = async () => {
|
|
20
|
+
const file = input.files[0];
|
|
21
|
+
if (!file) return;
|
|
22
|
+
const request = ++latest;
|
|
23
|
+
status.textContent = "Scanning…";
|
|
24
|
+
try {
|
|
25
|
+
const { barcodes } = await scanner.scan(file);
|
|
26
|
+
if (request !== latest) return;
|
|
27
|
+
status.textContent = barcodes.length
|
|
28
|
+
? barcodes.map((barcode) => `${barcode.format} ${barcode.text}`).join("\n")
|
|
29
|
+
: "No barcode found.";
|
|
30
|
+
} catch (error) {
|
|
31
|
+
if (request === latest) status.textContent = error.message;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tapirscan-vite-example",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "vite",
|
|
7
|
+
"build": "vite build",
|
|
8
|
+
"preview": "vite preview"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"tapirscan": "^1.3.0"
|
|
12
|
+
},
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"vite": "^6.3.5"
|
|
15
|
+
}
|
|
16
|
+
}
|
package/package.json
CHANGED
|
@@ -1,31 +1,48 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tapirscan",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Orientation-aware barcode scanning with a Rust/WASM core and four effort modes",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": {
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
9
9
|
"import": "./dist/index.js"
|
|
10
|
-
}
|
|
10
|
+
},
|
|
11
|
+
"./browser": {
|
|
12
|
+
"types": "./dist/browser.d.ts",
|
|
13
|
+
"import": "./dist/browser.js"
|
|
14
|
+
},
|
|
15
|
+
"./wasm/low.wasm": "./wasm/low.wasm",
|
|
16
|
+
"./wasm/medium.wasm": "./wasm/medium.wasm",
|
|
17
|
+
"./wasm/high.wasm": "./wasm/high.wasm",
|
|
18
|
+
"./wasm/very-high.wasm": "./wasm/very-high.wasm",
|
|
19
|
+
"./wasm/experimental-turbo2.wasm": "./wasm/experimental-turbo2.wasm",
|
|
20
|
+
"./wasm/experimental-turbo4.wasm": "./wasm/experimental-turbo4.wasm",
|
|
21
|
+
"./wasm/experimental-turbo8.wasm": "./wasm/experimental-turbo8.wasm",
|
|
22
|
+
"./wasm/experimental-turbo16.wasm": "./wasm/experimental-turbo16.wasm"
|
|
11
23
|
},
|
|
12
24
|
"files": [
|
|
13
25
|
"dist",
|
|
14
26
|
"examples",
|
|
15
|
-
"wasm/multiformat.json",
|
|
16
27
|
"THIRD_PARTY_NOTICES.md",
|
|
17
|
-
"wasm/low
|
|
18
|
-
"wasm/medium
|
|
19
|
-
"wasm/high
|
|
20
|
-
"wasm/very-high
|
|
21
|
-
"wasm/
|
|
28
|
+
"wasm/low.wasm",
|
|
29
|
+
"wasm/medium.wasm",
|
|
30
|
+
"wasm/high.wasm",
|
|
31
|
+
"wasm/very-high.wasm",
|
|
32
|
+
"wasm/experimental-turbo2.wasm",
|
|
33
|
+
"wasm/experimental-turbo4.wasm",
|
|
34
|
+
"wasm/experimental-turbo8.wasm",
|
|
35
|
+
"wasm/experimental-turbo16.wasm",
|
|
36
|
+
"wasm/build.json"
|
|
22
37
|
],
|
|
23
38
|
"scripts": {
|
|
24
|
-
"build": "tsc -p tsconfig.json",
|
|
25
|
-
"test": "node --test test/
|
|
39
|
+
"build": "node scripts/clean-dist.mjs && tsc -p tsconfig.json",
|
|
40
|
+
"test": "node --test test/camera-example.mjs test/scanner.mjs test/shared-retail.mjs test/loading.mjs test/turbo.mjs test/packaging.mjs && tsc --noEmit --strict --skipLibCheck --target ES2022 --module NodeNext test/api-types.ts",
|
|
41
|
+
"test:browser": "node --test --test-timeout=120000 test/browser.mjs",
|
|
26
42
|
"prepack": "npm run build && node scripts/verify-package.mjs"
|
|
27
43
|
},
|
|
28
44
|
"devDependencies": {
|
|
45
|
+
"playwright-core": "1.63.0",
|
|
29
46
|
"typescript": "5.8.3"
|
|
30
47
|
},
|
|
31
48
|
"keywords": [
|
|
@@ -39,7 +56,7 @@
|
|
|
39
56
|
"engines": {
|
|
40
57
|
"node": ">=20"
|
|
41
58
|
},
|
|
42
|
-
"license": "MIT",
|
|
59
|
+
"license": "MIT OR Apache-2.0",
|
|
43
60
|
"author": "Florian Nick",
|
|
44
61
|
"repository": {
|
|
45
62
|
"type": "git",
|