quadqr-js 0.7.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.
Binary file
package/docs/API.md ADDED
@@ -0,0 +1,188 @@
1
+ # API Reference
2
+
3
+ ## Core encoding
4
+
5
+ ### `encodeText(text, options?)`
6
+
7
+ Synchronously encodes UTF-8 text.
8
+
9
+ ```js
10
+ const code = encodeText("Hello", {
11
+ ecc: "M",
12
+ version: 5
13
+ });
14
+ ```
15
+
16
+ If `version` is omitted, QuadQR selects the smallest version that fits.
17
+
18
+ ### `encodeBytes(bytes, options?)`
19
+
20
+ Encodes arbitrary bytes.
21
+
22
+ ```js
23
+ const code = encodeBytes(new Uint8Array([1, 2, 3, 4]), { ecc: "Q" });
24
+ ```
25
+
26
+ ## Secure encoding
27
+
28
+ ### `encodeSecureText(text, options)`
29
+
30
+ Encrypts text using Secure Payload v1 and then encodes the encrypted envelope.
31
+
32
+ ```js
33
+ const code = await encodeSecureText("secret", {
34
+ security: {
35
+ mode: "password",
36
+ password: "example-password"
37
+ }
38
+ });
39
+ ```
40
+
41
+ ### `encodeSecureBytes(bytes, options)`
42
+
43
+ The byte-oriented equivalent of `encodeSecureText`.
44
+
45
+ ### `decryptDecoded(result, credentials)`
46
+
47
+ Decrypts a result returned by `decodeMatrix`, `scanImageData`, browser scanning, or Node scanning.
48
+
49
+ ```js
50
+ const result = await decryptDecoded(locked, { password: "example-password" });
51
+ ```
52
+
53
+ For raw-key mode:
54
+
55
+ ```js
56
+ const result = await decryptDecoded(locked, { key: raw256BitKey });
57
+ ```
58
+
59
+ ## Decoding
60
+
61
+ ### `decodeMatrix(matrix, options?)`
62
+
63
+ Decodes an already sampled QuadQR matrix.
64
+
65
+ Secure results are intentionally returned in a locked state:
66
+
67
+ ```js
68
+ {
69
+ secure: true,
70
+ requiresDecryption: true,
71
+ payload: Uint8Array(...),
72
+ security: {
73
+ mode: "password",
74
+ algorithm: "AES-256-GCM"
75
+ }
76
+ }
77
+ ```
78
+
79
+ ## Rendering
80
+
81
+ ### `renderToCanvas(codeOrMatrix, canvas, options?)`
82
+
83
+ Browser canvas renderer.
84
+
85
+ ### `renderToImageData(codeOrMatrix, options?)`
86
+
87
+ Runtime-neutral RGBA renderer. The result has:
88
+
89
+ ```js
90
+ {
91
+ width,
92
+ height,
93
+ data: Uint8ClampedArray
94
+ }
95
+ ```
96
+
97
+ Useful render options include:
98
+
99
+ - `moduleSize`
100
+ - `quietZone`
101
+ - `style`: `classic`, `depth`, `soft`, or `inset`
102
+ - custom palette values
103
+
104
+ ## Image scanning
105
+
106
+ ### `scanImageData(imageData, options?)`
107
+
108
+ Runtime-neutral scanner that accepts RGBA pixels.
109
+
110
+ ### Browser `scanFile(file, options?)`
111
+
112
+ Available from `quadqr` and `quadqr/browser`. Accepts a browser `File`/`Blob`.
113
+
114
+ ### `scanVideoFrame(video, options?)`
115
+
116
+ Scans the current browser video frame.
117
+
118
+ ### `startCameraScanner(video, options?)`
119
+
120
+ Starts a live camera scanner and repeatedly scans frames.
121
+
122
+ ## Node helpers
123
+
124
+ Import from `quadqr/node`.
125
+
126
+ ### `toPNG(codeOrMatrix, options?)`
127
+
128
+ Returns a Node `Buffer` containing a PNG.
129
+
130
+ ### `savePNG(codeOrMatrix, filename, options?)`
131
+
132
+ Writes a PNG file.
133
+
134
+ ### `scanBuffer(buffer, options?)`
135
+
136
+ PNG works with no dependencies. Other image formats can use the consuming application's optional `sharp` installation.
137
+
138
+ ### Node `scanFile(filename, options?)`
139
+
140
+ Reads an image path and scans it.
141
+
142
+ ### `decodePNG(buffer)` / `encodePNG(imageData)`
143
+
144
+ Dependency-free PNG pixel helpers.
145
+
146
+ ## Security utilities
147
+
148
+ - `generateRaw256Key()`
149
+ - `normalizeRaw256Key(key)`
150
+ - `bytesToHex(bytes)`
151
+ - `SECURITY_MODES`
152
+ - `SECURITY_ALGORITHMS`
153
+ - `DEFAULT_PBKDF2_ITERATIONS`
154
+
155
+ ## WASM
156
+
157
+ ### `initWasm(options?)`
158
+
159
+ Loads the bundled optional WASM accelerator and installs it into the normal codec path.
160
+
161
+ ```js
162
+ import { initWasm } from "quadqr";
163
+
164
+ await initWasm();
165
+ ```
166
+
167
+ ### `getWasmState()`
168
+
169
+ Returns the active WASM state or `null`.
170
+
171
+ ### `disableWasm()`
172
+
173
+ Returns the codec to its JavaScript fallback.
174
+
175
+ ## Version/capacity utilities
176
+
177
+ ### `getVersionInfo(version, options?)`
178
+
179
+ Returns matrix and payload information for a specific QuadQR version/ECC profile.
180
+
181
+ ## Benchmark entry
182
+
183
+ ```js
184
+ import {
185
+ buildCapacityComparison,
186
+ benchmarkCodec
187
+ } from "quadqr/benchmark";
188
+ ```
@@ -0,0 +1,83 @@
1
+ # Browser and CDN Usage
2
+
3
+ ## ESM with a bundler
4
+
5
+ ```js
6
+ import {
7
+ encodeText,
8
+ renderToCanvas,
9
+ scanFile,
10
+ startCameraScanner
11
+ } from "quadqr/browser";
12
+ ```
13
+
14
+ The normal `quadqr` entry also works in modern browser bundlers.
15
+
16
+ ## Classic script tag
17
+
18
+ QuadQR publishes a global build that exposes `window.QuadQR` / `globalThis.QuadQR`.
19
+
20
+ ```html
21
+ <script src="https://cdn.jsdelivr.net/npm/quadqr@0.7.0/dist/quadqr.min.js"></script>
22
+ ```
23
+
24
+ Then:
25
+
26
+ ```html
27
+ <script>
28
+ const code = QuadQR.encodeText("Hello CDN");
29
+ QuadQR.renderToCanvas(code, document.querySelector("#qr"), {
30
+ moduleSize: 12,
31
+ quietZone: 4
32
+ });
33
+ </script>
34
+ ```
35
+
36
+ ## unpkg
37
+
38
+ ```html
39
+ <script src="https://unpkg.com/quadqr@0.7.0/dist/quadqr.min.js"></script>
40
+ ```
41
+
42
+ ## CDN ESM
43
+
44
+ You may also load the ESM file directly:
45
+
46
+ ```html
47
+ <script type="module">
48
+ import { encodeText } from "https://cdn.jsdelivr.net/npm/quadqr@0.7.0/dist/browser.js";
49
+ console.log(encodeText("ES module CDN"));
50
+ </script>
51
+ ```
52
+
53
+ ## WASM from a CDN
54
+
55
+ The classic global build remembers its own script URL. Calling:
56
+
57
+ ```js
58
+ await QuadQR.initWasm();
59
+ ```
60
+
61
+ loads the sibling asset:
62
+
63
+ ```text
64
+ dist/wasm/quadqr-core.wasm
65
+ ```
66
+
67
+ from the same package/version URL.
68
+
69
+ You can override the location:
70
+
71
+ ```js
72
+ await QuadQR.initWasm({
73
+ url: "https://example.com/assets/quadqr-core.wasm"
74
+ });
75
+ ```
76
+
77
+ ## Camera requirements
78
+
79
+ Live camera access requires a secure browser context, normally HTTPS or localhost.
80
+
81
+ ## Production recommendation
82
+
83
+ Pin a concrete version such as `@0.7.0` instead of using an unversioned CDN URL. This prevents a future package release from changing a production site unexpectedly.
@@ -0,0 +1,91 @@
1
+ # Getting Started
2
+
3
+ ## Install from npm
4
+
5
+ ```bash
6
+ npm install quadqr
7
+ ```
8
+
9
+ QuadQR 0.7.x targets Node.js 20.19 or newer for the full ESM/CommonJS distribution behavior.
10
+
11
+ ## Generate and decode a matrix
12
+
13
+ ```js
14
+ import { encodeText, decodeMatrix } from "quadqr";
15
+
16
+ const code = encodeText("Hello from QuadQR", { ecc: "M" });
17
+ const decoded = decodeMatrix(code.matrix);
18
+
19
+ console.log(decoded.text);
20
+ ```
21
+
22
+ ## Secure password mode
23
+
24
+ ```js
25
+ import { encodeSecureText, decodeMatrix, decryptDecoded } from "quadqr";
26
+
27
+ const code = await encodeSecureText("Private payload", {
28
+ ecc: "M",
29
+ security: {
30
+ mode: "password",
31
+ password: "correct horse battery staple"
32
+ }
33
+ });
34
+
35
+ const locked = decodeMatrix(code.matrix);
36
+ const unlocked = await decryptDecoded(locked, {
37
+ password: "correct horse battery staple"
38
+ });
39
+
40
+ console.log(unlocked.text);
41
+ ```
42
+
43
+ ## Raw 256-bit key mode
44
+
45
+ ```js
46
+ import {
47
+ bytesToHex,
48
+ encodeSecureText,
49
+ generateRaw256Key
50
+ } from "quadqr";
51
+
52
+ const key = generateRaw256Key();
53
+ console.log(bytesToHex(key));
54
+
55
+ const code = await encodeSecureText("Machine-readable secret", {
56
+ security: {
57
+ mode: "raw-key",
58
+ key
59
+ }
60
+ });
61
+ ```
62
+
63
+ Never place the raw encryption key inside the same QuadQR payload.
64
+
65
+ ## Node.js PNG
66
+
67
+ ```js
68
+ import { encodeText } from "quadqr";
69
+ import { savePNG, scanFile } from "quadqr/node";
70
+
71
+ const code = encodeText("Generated on Node.js");
72
+ await savePNG(code, "quadqr.png", {
73
+ moduleSize: 12,
74
+ quietZone: 4
75
+ });
76
+
77
+ const result = await scanFile("quadqr.png");
78
+ console.log(result.text);
79
+ ```
80
+
81
+ ## Browser script tag
82
+
83
+ ```html
84
+ <script src="https://cdn.jsdelivr.net/npm/quadqr@0.7.0/dist/quadqr.min.js"></script>
85
+ <script>
86
+ const code = QuadQR.encodeText("No build step");
87
+ console.log(code.version, code.matrix);
88
+ </script>
89
+ ```
90
+
91
+ For production sites, pin the exact package version in the CDN URL.
package/docs/NODE.md ADDED
@@ -0,0 +1,92 @@
1
+ # Node.js
2
+
3
+ QuadQR uses the same matrix codec and image scanner in Node.js and the browser. The `quadqr/node` entry only adds Node-specific file and PNG helpers.
4
+
5
+ ## Requirements
6
+
7
+ The package targets Node.js 20.19 or newer.
8
+
9
+ ## ESM
10
+
11
+ ```js
12
+ import { encodeText } from "quadqr";
13
+ import { savePNG, scanFile } from "quadqr/node";
14
+ ```
15
+
16
+ ## CommonJS
17
+
18
+ On supported modern Node versions:
19
+
20
+ ```js
21
+ const QuadQR = require("quadqr");
22
+ const QuadQRNode = require("quadqr/node");
23
+ ```
24
+
25
+ ## Generate PNG
26
+
27
+ ```js
28
+ const code = QuadQR.encodeText("Server generated");
29
+ await QuadQRNode.savePNG(code, "output.png", {
30
+ moduleSize: 12,
31
+ quietZone: 4
32
+ });
33
+ ```
34
+
35
+ `toPNG()` returns a `Buffer` instead of writing it:
36
+
37
+ ```js
38
+ const png = QuadQRNode.toPNG(code);
39
+ ```
40
+
41
+ This is useful for HTTP responses, object storage, email attachments, or database/blob workflows.
42
+
43
+ ## Scan PNG
44
+
45
+ ```js
46
+ const result = await QuadQRNode.scanFile("output.png");
47
+ console.log(result.text);
48
+ ```
49
+
50
+ Or scan an in-memory buffer:
51
+
52
+ ```js
53
+ const result = await QuadQRNode.scanBuffer(pngBuffer);
54
+ ```
55
+
56
+ PNG decoding is dependency-free and supports normal non-interlaced 8-bit RGB/RGBA PNGs plus indexed PNGs.
57
+
58
+ ## JPEG, WebP, and AVIF
59
+
60
+ QuadQR does not force a native image dependency on every user. If your application already uses `sharp`, `scanBuffer()` / `scanFile()` can use it for formats other than PNG.
61
+
62
+ ```bash
63
+ npm install sharp
64
+ ```
65
+
66
+ If `sharp` is not installed, pass decoded RGBA pixels directly to `scanImageData()` or use PNG input.
67
+
68
+ ## Secure Node workflow
69
+
70
+ ```js
71
+ import {
72
+ decryptDecoded,
73
+ encodeSecureText
74
+ } from "quadqr";
75
+ import { savePNG, scanFile } from "quadqr/node";
76
+
77
+ const code = await encodeSecureText("private", {
78
+ security: {
79
+ mode: "password",
80
+ password: process.env.QUADQR_PASSWORD
81
+ }
82
+ });
83
+
84
+ await savePNG(code, "secure.png");
85
+
86
+ const locked = await scanFile("secure.png");
87
+ const unlocked = await decryptDecoded(locked, {
88
+ password: process.env.QUADQR_PASSWORD
89
+ });
90
+
91
+ console.log(unlocked.text);
92
+ ```
@@ -0,0 +1,115 @@
1
+ # Publishing QuadQR to npm
2
+
3
+ This repository is already configured as a public npm package named `quadqr` at version `0.7.0`.
4
+
5
+ Before the first publish, confirm that the package name is available. If it is already owned by somebody else, use a scoped name such as `@akanshsirohi/quadqr` and update the CDN examples accordingly.
6
+
7
+ ## 1. Create/sign in to npm
8
+
9
+ Create an account at https://www.npmjs.com/ and enable two-factor authentication.
10
+
11
+ Then authenticate the CLI:
12
+
13
+ ```bash
14
+ npm login
15
+ ```
16
+
17
+ Check the active account:
18
+
19
+ ```bash
20
+ npm whoami
21
+ ```
22
+
23
+ ## 2. Install repository dependencies
24
+
25
+ QuadQR currently has no runtime dependencies, but run:
26
+
27
+ ```bash
28
+ npm install
29
+ ```
30
+
31
+ so your local package lock and npm metadata are synchronized.
32
+
33
+ ## 3. Verify the package name
34
+
35
+ ```bash
36
+ npm view quadqr
37
+ ```
38
+
39
+ If npm returns a package owned by somebody else, do not publish over it. Change `package.json` to a scoped name that you own.
40
+
41
+ ## 4. Run the full release checks
42
+
43
+ ```bash
44
+ npm test
45
+ npm run benchmark
46
+ npm run pack:check
47
+ ```
48
+
49
+ `pack:check` rebuilds `dist/` and displays exactly what npm will include.
50
+
51
+ You can inspect the final tarball too:
52
+
53
+ ```bash
54
+ npm pack
55
+ ```
56
+
57
+ ## 5. Publish
58
+
59
+ For the current unscoped public package:
60
+
61
+ ```bash
62
+ npm publish
63
+ ```
64
+
65
+ For a scoped public package:
66
+
67
+ ```bash
68
+ npm publish --access public
69
+ ```
70
+
71
+ npm publishing requires an account that satisfies npm's current 2FA/authentication requirements.
72
+
73
+ ## 6. Verify installation from a clean directory
74
+
75
+ ```bash
76
+ mkdir quadqr-consumer-test
77
+ cd quadqr-consumer-test
78
+ npm init -y
79
+ npm install quadqr
80
+ ```
81
+
82
+ Then test ESM, Node PNG, and the CLI.
83
+
84
+ ```bash
85
+ npx quadqr keygen
86
+ npx quadqr encode "Hello from npm" -o hello.png
87
+ npx quadqr decode hello.png
88
+ ```
89
+
90
+ ## 7. Verify CDN availability
91
+
92
+ After npm and CDN caches update, test:
93
+
94
+ ```text
95
+ https://cdn.jsdelivr.net/npm/quadqr@0.7.0/dist/quadqr.min.js
96
+ https://unpkg.com/quadqr@0.7.0/dist/quadqr.min.js
97
+ ```
98
+
99
+ Then call `QuadQR.encodeText(...)` from a plain HTML page.
100
+
101
+ ## Releasing the next version
102
+
103
+ Use semantic versioning:
104
+
105
+ ```bash
106
+ npm version patch
107
+ # or
108
+ npm version minor
109
+ # or
110
+ npm version major
111
+ ```
112
+
113
+ Then run the release checks again and publish.
114
+
115
+ Never reuse an npm version that has already been published. Published package versions are immutable.
package/docs/README.md ADDED
@@ -0,0 +1,26 @@
1
+ # QuadQR Documentation
2
+
3
+ QuadQR is an experimental four-state RGBW matrix symbology. Each data cell carries exactly two bits using red, green, blue, or white. The library adds Spectrum ECC, perspective-aware scanning, optional authenticated encryption, browser camera support, Node.js PNG support, a CDN/global build, and an optional prebuilt WebAssembly accelerator.
4
+
5
+ ## Documentation map
6
+
7
+ - [Getting Started](./GETTING_STARTED.md)
8
+ - [API Reference](./API.md)
9
+ - [Browser and CDN](./BROWSER_CDN.md)
10
+ - [Node.js](./NODE.md)
11
+ - [Secure Payloads](./SECURITY.md)
12
+ - [WASM](./WASM.md)
13
+ - [Publishing to npm](./PUBLISHING.md)
14
+ - [Wire Format](../FORMAT.md)
15
+
16
+ ## Package entry points
17
+
18
+ | Entry | Purpose |
19
+ | --- | --- |
20
+ | `quadqr` | Runtime-neutral core API plus optional WASM loader |
21
+ | `quadqr/browser` | Browser ESM entry |
22
+ | `quadqr/node` | Node.js core plus PNG/file helpers |
23
+ | `quadqr/benchmark` | Capacity and codec benchmark helpers |
24
+ | `quadqr/quadqr.min.js` | Classic browser global bundle for CDNs |
25
+
26
+ The package is designed so the matrix codec is shared across all runtimes. Browser and Node adapters only handle runtime-specific input/output.
@@ -0,0 +1,78 @@
1
+ # Secure Payloads
2
+
3
+ QuadQR Secure Payload v1 is an optional layer above the matrix codec and Spectrum ECC.
4
+
5
+ ```text
6
+ plaintext
7
+ -> encryption/authentication
8
+ -> secure envelope
9
+ -> QuadQR framing
10
+ -> Spectrum ECC
11
+ -> RGBW matrix
12
+ ```
13
+
14
+ Scanning and error correction therefore remain independent from encryption.
15
+
16
+ ## Password mode
17
+
18
+ Password mode uses:
19
+
20
+ - PBKDF2-HMAC-SHA-256
21
+ - random 16-byte salt
22
+ - configurable iteration count, default 600,000
23
+ - AES-256-GCM
24
+ - random 12-byte nonce
25
+ - authenticated metadata
26
+
27
+ ```js
28
+ const code = await encodeSecureText("private", {
29
+ security: {
30
+ mode: "password",
31
+ password: "long unique password"
32
+ }
33
+ });
34
+ ```
35
+
36
+ The password is never stored in the QuadQR symbol.
37
+
38
+ ## Raw 256-bit key mode
39
+
40
+ Raw-key mode accepts exactly 32 random bytes.
41
+
42
+ ```js
43
+ const key = generateRaw256Key();
44
+
45
+ const code = await encodeSecureText("machine secret", {
46
+ security: {
47
+ mode: "raw-key",
48
+ key
49
+ }
50
+ });
51
+ ```
52
+
53
+ By default QuadQR stores only a short SHA-256 fingerprint/key ID so an application can identify the required key without embedding the actual secret.
54
+
55
+ ## Decryption
56
+
57
+ A secure scan stays locked:
58
+
59
+ ```js
60
+ const locked = scanImageData(imageData);
61
+
62
+ if (locked.secure) {
63
+ const unlocked = await decryptDecoded(locked, {
64
+ password: "long unique password"
65
+ });
66
+ }
67
+ ```
68
+
69
+ AES-GCM authentication rejects an incorrect password/key or modified ciphertext.
70
+
71
+ ## Threat model notes
72
+
73
+ - Secure Payload protects payload confidentiality and integrity.
74
+ - It does not hide the fact that a QuadQR symbol exists.
75
+ - Key IDs are routing hints, not secrets.
76
+ - A photographed code can still be copied, so encryption alone is not anti-replay protection.
77
+ - Applications needing ticket/access anti-replay should combine QuadQR with server-side nonce/state validation or signed short-lived tokens.
78
+ - Do not hard-code long-lived raw keys in public client-side JavaScript if those keys are meant to remain secret.
package/docs/WASM.md ADDED
@@ -0,0 +1,36 @@
1
+ # WebAssembly
2
+
3
+ QuadQR ships a small precompiled WebAssembly module at:
4
+
5
+ ```text
6
+ dist/wasm/quadqr-core.wasm
7
+ ```
8
+
9
+ The normal JavaScript codec does not require it. This is intentional: installation, browser loading, serverless execution, and restricted environments should still work when WASM is unavailable.
10
+
11
+ ## Enable it
12
+
13
+ ```js
14
+ import { initWasm } from "quadqr";
15
+
16
+ const state = await initWasm();
17
+ console.log(state);
18
+ ```
19
+
20
+ Current 0.7.x acceleration covers CRC-32, which is used by QuadQR framing integrity checks. Once initialized, encode/decode calls automatically use the installed synchronous accelerator.
21
+
22
+ ## Why start small?
23
+
24
+ QuadQR scanning and Spectrum ECC are still evolving. Keeping the first WASM ABI narrow lets the library ship a stable prebuilt binary without forcing the matrix format to depend on a specific compiler/runtime implementation.
25
+
26
+ Future profiling can move heavier hot paths, such as image classification or selected ECC operations, behind the same optional acceleration layer without changing the public QuadQR wire format.
27
+
28
+ ## Disable
29
+
30
+ ```js
31
+ import { disableWasm } from "quadqr";
32
+
33
+ disableWasm();
34
+ ```
35
+
36
+ The JavaScript fallback is restored immediately.