@supernovae-st/qrcode-ai-scanner 0.2.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/Cargo.toml ADDED
@@ -0,0 +1,18 @@
1
+ [package]
2
+ name = "qrcode-ai-scanner-node"
3
+ version.workspace = true
4
+ edition.workspace = true
5
+ description = "Node.js bindings for QR code validation"
6
+ license.workspace = true
7
+ repository.workspace = true
8
+
9
+ [lib]
10
+ crate-type = ["cdylib"]
11
+
12
+ [dependencies]
13
+ qrcode-ai-scanner-core = { path = "../qrcode-ai-scanner-core" }
14
+ napi = "2"
15
+ napi-derive = "2"
16
+
17
+ [build-dependencies]
18
+ napi-build = "2"
package/README.md ADDED
@@ -0,0 +1,356 @@
1
+ <div align="center">
2
+
3
+ # @supernovae-st/qrcode-ai-scanner
4
+
5
+ **Node.js bindings for qrcode-ai-scanner - High-performance QR code validation**
6
+
7
+ [![npm](https://img.shields.io/npm/v/@supernovae-st/qrcode-ai-scanner?style=flat-square&logo=npm&logoColor=white&color=red)](https://www.npmjs.com/package/@supernovae-st/qrcode-ai-scanner)
8
+ [![License](https://img.shields.io/npm/l/@supernovae-st/qrcode-ai-scanner?style=flat-square&color=blue)](LICENSE)
9
+
10
+ *Native Rust performance in Node.js via napi-rs.<br/>Validate AI-generated and artistic QR codes that break standard scanners.*
11
+
12
+ </div>
13
+
14
+ <br/>
15
+
16
+ ## Installation
17
+
18
+ ### From npm (recommended)
19
+
20
+ ```bash
21
+ npm install @supernovae-st/qrcode-ai-scanner
22
+ # or
23
+ yarn add @supernovae-st/qrcode-ai-scanner
24
+ # or
25
+ pnpm add @supernovae-st/qrcode-ai-scanner
26
+ ```
27
+
28
+ ### From GitHub
29
+
30
+ ```bash
31
+ npm install github:supernovae-st/qrcode-ai-scanner
32
+ ```
33
+
34
+ ### Build from source
35
+
36
+ ```bash
37
+ git clone https://github.com/supernovae-st/qrcode-ai-scanner.git
38
+ cd qrcode-ai-scanner/crates/qrcode-ai-scanner-node
39
+ npm install
40
+ npm run build
41
+ ```
42
+
43
+ ### Local usage (without npm registry)
44
+
45
+ After building from source, you can use the package locally in several ways:
46
+
47
+ **Option 1: npm link (symlink)**
48
+
49
+ ```bash
50
+ # In qrcode-ai-scanner-node directory
51
+ npm link
52
+
53
+ # In your project
54
+ npm link @supernovae-st/qrcode-ai-scanner
55
+ ```
56
+
57
+ **Option 2: npm pack (tarball)**
58
+
59
+ ```bash
60
+ # In qrcode-ai-scanner-node directory
61
+ npm pack # Creates qrcodeai-qrcode-ai-scanner-0.1.0.tgz
62
+
63
+ # In your project
64
+ npm install /path/to/qrcodeai-qrcode-ai-scanner-0.1.0.tgz
65
+ ```
66
+
67
+ **Option 3: Direct path in package.json**
68
+
69
+ ```json
70
+ {
71
+ "dependencies": {
72
+ "@supernovae-st/qrcode-ai-scanner": "file:../qrcode-ai-scanner/crates/qrcode-ai-scanner-node"
73
+ }
74
+ }
75
+ ```
76
+
77
+ **Option 4: Direct require**
78
+
79
+ ```javascript
80
+ const scanner = require('/path/to/qrcode-ai-scanner/crates/qrcode-ai-scanner-node');
81
+ ```
82
+
83
+ ## Quick Start
84
+
85
+ ```javascript
86
+ import { readFileSync } from 'fs';
87
+ import { validate, isValid, score, summarize } from '@supernovae-st/qrcode-ai-scanner';
88
+
89
+ const buffer = readFileSync('qr.png');
90
+
91
+ // Simple check - is the QR valid?
92
+ const content = isValid(buffer);
93
+ if (content) {
94
+ console.log(`QR contains: ${content}`);
95
+ }
96
+
97
+ // Get scannability score
98
+ const s = score(buffer);
99
+ console.log(`Score: ${s}/100`);
100
+
101
+ // Get a summary
102
+ const summary = summarize(buffer);
103
+ console.log(summary);
104
+ // { valid: true, score: 85, rating: 'Excellent', productionReady: true, ... }
105
+
106
+ // Full validation with stress tests
107
+ const result = validate(buffer);
108
+ console.log(`Score: ${result.score}`);
109
+ console.log(`Content: ${result.content}`);
110
+ console.log(`Stress tests:`, result.stressOriginal, result.stressDownscale50);
111
+ ```
112
+
113
+ ## API Reference
114
+
115
+ ### Main Functions
116
+
117
+ #### `validate(buffer: Buffer): ValidationResult`
118
+
119
+ Full validation with all stress tests. Returns complete results.
120
+
121
+ ```typescript
122
+ const result = validate(buffer);
123
+ // result.score: 0-100
124
+ // result.decodable: boolean
125
+ // result.content: string | null
126
+ // result.version: number | null
127
+ // result.errorCorrection: 'L' | 'M' | 'Q' | 'H' | null
128
+ // result.stressOriginal: boolean
129
+ // result.stressDownscale50: boolean
130
+ // result.stressBlurLight: boolean
131
+ // ...
132
+ ```
133
+
134
+ #### `validateFast(buffer: Buffer): ValidationResult`
135
+
136
+ Fast validation with reduced stress tests. ~2x faster.
137
+
138
+ ```typescript
139
+ const result = validateFast(buffer);
140
+ // Same return type, but some stress tests skipped
141
+ ```
142
+
143
+ #### `decode(buffer: Buffer): DecodeResult`
144
+
145
+ Decode only, no stress tests. Fastest option.
146
+
147
+ ```typescript
148
+ const result = decode(buffer);
149
+ // result.content: string
150
+ // result.version: number | null
151
+ // result.errorCorrection: 'L' | 'M' | 'Q' | 'H' | null
152
+ ```
153
+
154
+ ### Convenience Helpers
155
+
156
+ #### `isValid(buffer: Buffer): string | null`
157
+
158
+ Check if QR is valid. Returns content or null.
159
+
160
+ ```typescript
161
+ const content = isValid(buffer);
162
+ if (content) {
163
+ console.log(`Valid! Content: ${content}`);
164
+ } else {
165
+ console.log('Invalid QR');
166
+ }
167
+ ```
168
+
169
+ #### `score(buffer: Buffer): number`
170
+
171
+ Get scannability score (0-100).
172
+
173
+ ```typescript
174
+ const s = score(buffer);
175
+ console.log(`${s}/100`);
176
+ ```
177
+
178
+ #### `passesThreshold(buffer: Buffer, minScore: number): boolean`
179
+
180
+ Check if QR meets minimum score.
181
+
182
+ ```typescript
183
+ if (passesThreshold(buffer, 70)) {
184
+ console.log('Production ready!');
185
+ }
186
+ ```
187
+
188
+ #### `isProductionReady(buffer: Buffer): boolean`
189
+
190
+ Check if QR is production-ready (score >= 70).
191
+
192
+ ```typescript
193
+ if (isProductionReady(buffer)) {
194
+ await uploadToProduction(buffer);
195
+ }
196
+ ```
197
+
198
+ #### `summarize(buffer: Buffer): QrSummary`
199
+
200
+ Get a simple summary object.
201
+
202
+ ```typescript
203
+ const summary = summarize(buffer);
204
+ // {
205
+ // valid: true,
206
+ // score: 85,
207
+ // content: 'https://example.com',
208
+ // errorCorrection: 'M',
209
+ // rating: 'Excellent',
210
+ // productionReady: true
211
+ // }
212
+ ```
213
+
214
+ #### `getRating(score: number): string`
215
+
216
+ Convert score to human-readable rating.
217
+
218
+ ```typescript
219
+ getRating(85); // 'Excellent'
220
+ getRating(75); // 'Good'
221
+ getRating(55); // 'Fair'
222
+ getRating(25); // 'Poor'
223
+ ```
224
+
225
+ ## TypeScript
226
+
227
+ Full TypeScript support included:
228
+
229
+ ```typescript
230
+ import type {
231
+ ValidationResult,
232
+ DecodeResult,
233
+ QrSummary
234
+ } from '@supernovae-st/qrcode-ai-scanner';
235
+
236
+ const result: ValidationResult = validate(buffer);
237
+ ```
238
+
239
+ ## Usage Examples
240
+
241
+ ### Express.js API
242
+
243
+ ```typescript
244
+ import express from 'express';
245
+ import multer from 'multer';
246
+ import { validate, isProductionReady } from '@supernovae-st/qrcode-ai-scanner';
247
+
248
+ const app = express();
249
+ const upload = multer();
250
+
251
+ app.post('/validate', upload.single('qr'), (req, res) => {
252
+ const buffer = req.file.buffer;
253
+ const result = validate(buffer);
254
+
255
+ res.json({
256
+ score: result.score,
257
+ content: result.content,
258
+ productionReady: result.score >= 70
259
+ });
260
+ });
261
+
262
+ app.post('/check', upload.single('qr'), (req, res) => {
263
+ const ok = isProductionReady(req.file.buffer);
264
+ res.json({ accepted: ok });
265
+ });
266
+ ```
267
+
268
+ ### Batch Processing
269
+
270
+ ```typescript
271
+ import { readFileSync, readdirSync } from 'fs';
272
+ import { join } from 'path';
273
+ import { score, getRating } from '@supernovae-st/qrcode-ai-scanner';
274
+
275
+ const qrDir = './qr-codes';
276
+ const files = readdirSync(qrDir).filter(f => f.endsWith('.png'));
277
+
278
+ for (const file of files) {
279
+ const buffer = readFileSync(join(qrDir, file));
280
+ const s = score(buffer);
281
+ console.log(`${file}: ${s}/100 (${getRating(s)})`);
282
+ }
283
+ ```
284
+
285
+ ### Next.js API Route
286
+
287
+ ```typescript
288
+ // pages/api/validate.ts
289
+ import type { NextApiRequest, NextApiResponse } from 'next';
290
+ import { validate } from '@supernovae-st/qrcode-ai-scanner';
291
+
292
+ export const config = {
293
+ api: { bodyParser: false }
294
+ };
295
+
296
+ export default async function handler(req: NextApiRequest, res: NextApiResponse) {
297
+ const chunks: Buffer[] = [];
298
+ for await (const chunk of req) {
299
+ chunks.push(chunk);
300
+ }
301
+ const buffer = Buffer.concat(chunks);
302
+
303
+ const result = validate(buffer);
304
+ res.json(result);
305
+ }
306
+ ```
307
+
308
+ ## Score Interpretation
309
+
310
+ | Score | Rating | Recommendation |
311
+ |-------|--------|----------------|
312
+ | 80-100 | Excellent | Safe for all conditions |
313
+ | 70-79 | Good | Production ready |
314
+ | 60-69 | Acceptable | May fail on older phones |
315
+ | 40-59 | Fair | Consider regenerating |
316
+ | 0-39 | Poor | Needs redesign |
317
+
318
+ ## Platform Support
319
+
320
+ Pre-built binaries for:
321
+
322
+ | Platform | Architecture |
323
+ |----------|--------------|
324
+ | macOS | x64, arm64 (M1/M2) |
325
+ | Linux | x64, arm64 |
326
+ | Windows | x64 |
327
+
328
+ ## Performance
329
+
330
+ | Operation | Clean QR | Artistic QR |
331
+ |-----------|----------|-------------|
332
+ | `decode()` | ~20ms | ~200ms |
333
+ | `validateFast()` | ~50ms | ~500ms |
334
+ | `validate()` | ~80ms | ~1000ms |
335
+
336
+ ## License
337
+
338
+ MIT
339
+
340
+ ---
341
+
342
+ <div align="center">
343
+
344
+ Part of [**QR Code AI**](https://qrcode-ai.com) by **Thibaut MÉLEN** & [**SuperNovae Studio**](https://supernovae.studio)
345
+
346
+ <br/>
347
+
348
+ <a href="https://github.com/ThibautMelen">
349
+ <img src="https://avatars.githubusercontent.com/u/20891897?s=200&v=4" alt="Thibaut MÉLEN" width="32"/>
350
+ </a>
351
+ &nbsp;&nbsp;
352
+ <a href="https://github.com/supernovae-st">
353
+ <img src="https://avatars.githubusercontent.com/u/33066282?s=200&v=4" alt="SuperNovae Studio" width="32"/>
354
+ </a>
355
+
356
+ </div>
package/build.rs ADDED
@@ -0,0 +1,5 @@
1
+ extern crate napi_build;
2
+
3
+ fn main() {
4
+ napi_build::setup();
5
+ }
package/index.d.ts ADDED
@@ -0,0 +1,182 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+
4
+ /* auto-generated by NAPI-RS */
5
+
6
+ /** QR code validation result */
7
+ export interface ValidationResult {
8
+ /** Scannability score from 0-100 */
9
+ score: number
10
+ /** Whether the QR code was successfully decoded */
11
+ decodable: boolean
12
+ /** Decoded content of the QR code */
13
+ content?: string
14
+ /** QR code version (1-40) */
15
+ version?: number
16
+ /** Error correction level (L, M, Q, H) */
17
+ errorCorrection?: string
18
+ /** Number of modules in the QR code */
19
+ modules?: number
20
+ /** List of decoders that successfully decoded the QR */
21
+ decodersSuccess: Array<string>
22
+ /** Whether original image was decodable */
23
+ stressOriginal: boolean
24
+ /** Whether 50% downscaled image was decodable */
25
+ stressDownscale50: boolean
26
+ /** Whether 25% downscaled image was decodable */
27
+ stressDownscale25: boolean
28
+ /** Whether lightly blurred image was decodable */
29
+ stressBlurLight: boolean
30
+ /** Whether medium blurred image was decodable */
31
+ stressBlurMedium: boolean
32
+ /** Whether low contrast image was decodable */
33
+ stressLowContrast: boolean
34
+ }
35
+ /** Simple decode result (without stress tests) */
36
+ export interface DecodeResult {
37
+ /** Decoded content of the QR code */
38
+ content: string
39
+ /** QR code version (1-40) */
40
+ version?: number
41
+ /** Error correction level (L, M, Q, H) */
42
+ errorCorrection?: string
43
+ /** Number of modules in the QR code */
44
+ modules?: number
45
+ }
46
+ /**
47
+ * Validate a QR code image and compute scannability score
48
+ *
49
+ * @param imageBuffer - Raw image bytes (PNG, JPEG, etc.)
50
+ * @returns ValidationResult with score, content, and metadata
51
+ */
52
+ export declare function validate(imageBuffer: Buffer): ValidationResult
53
+ /**
54
+ * Fast decode without stress tests (for when you only need content)
55
+ *
56
+ * @param imageBuffer - Raw image bytes (PNG, JPEG, etc.)
57
+ * @returns DecodeResult with content and basic metadata
58
+ */
59
+ export declare function decode(imageBuffer: Buffer): DecodeResult
60
+ /**
61
+ * Fast validation with reduced stress tests (~2x faster)
62
+ *
63
+ * Good for real-time feedback during QR editing.
64
+ *
65
+ * @param imageBuffer - Raw image bytes (PNG, JPEG, etc.)
66
+ * @returns ValidationResult with score, content, and metadata
67
+ */
68
+ export declare function validateFast(imageBuffer: Buffer): ValidationResult
69
+ /**
70
+ * Get only the scannability score (0-100)
71
+ *
72
+ * @param imageBuffer - Raw image bytes (PNG, JPEG, etc.)
73
+ * @returns Score from 0 (unreadable) to 100 (highly scannable)
74
+ */
75
+ export declare function validateScoreOnly(imageBuffer: Buffer): number
76
+ /**
77
+ * Get score using fast validation (~2x faster)
78
+ *
79
+ * @param imageBuffer - Raw image bytes (PNG, JPEG, etc.)
80
+ * @returns Score from 0 (unreadable) to 100 (highly scannable)
81
+ */
82
+ export declare function validateScoreFast(imageBuffer: Buffer): number
83
+ /** Simple summary of QR validation */
84
+ export interface QrSummary {
85
+ /** Whether the QR is valid and decodable */
86
+ valid: boolean
87
+ /** Scannability score (0-100) */
88
+ score: number
89
+ /** Decoded content (empty if invalid) */
90
+ content: string
91
+ /** Error correction level (L/M/Q/H or "N/A") */
92
+ errorCorrection: string
93
+ /** Human-readable rating (Excellent/Good/Fair/Poor) */
94
+ rating: string
95
+ /** Whether this QR is production-ready (score >= 70) */
96
+ productionReady: boolean
97
+ }
98
+ /**
99
+ * Check if QR code is valid (returns content or null)
100
+ *
101
+ * @example
102
+ * ```typescript
103
+ * const content = isValid(buffer);
104
+ * if (content) {
105
+ * console.log(`QR contains: ${content}`);
106
+ * }
107
+ * ```
108
+ *
109
+ * @param imageBuffer - Raw image bytes (PNG, JPEG, etc.)
110
+ * @returns Decoded content string, or null if QR is invalid
111
+ */
112
+ export declare function isValid(imageBuffer: Buffer): string | null
113
+ /**
114
+ * Get scannability score (0-100)
115
+ *
116
+ * @example
117
+ * ```typescript
118
+ * const s = score(buffer);
119
+ * console.log(`Scannability: ${s}/100`);
120
+ * ```
121
+ *
122
+ * @param imageBuffer - Raw image bytes (PNG, JPEG, etc.)
123
+ * @returns Score from 0 (unreadable) to 100 (highly scannable)
124
+ */
125
+ export declare function score(imageBuffer: Buffer): number
126
+ /**
127
+ * Check if QR meets minimum score threshold
128
+ *
129
+ * @example
130
+ * ```typescript
131
+ * if (passesThreshold(buffer, 70)) {
132
+ * console.log('Production ready!');
133
+ * }
134
+ * ```
135
+ *
136
+ * @param imageBuffer - Raw image bytes (PNG, JPEG, etc.)
137
+ * @param minScore - Minimum score required (0-100)
138
+ * @returns true if score >= minScore
139
+ */
140
+ export declare function passesThreshold(imageBuffer: Buffer, minScore: number): boolean
141
+ /**
142
+ * Get production readiness (score >= 70)
143
+ *
144
+ * @example
145
+ * ```typescript
146
+ * if (isProductionReady(buffer)) {
147
+ * await uploadQr(buffer);
148
+ * }
149
+ * ```
150
+ *
151
+ * @param imageBuffer - Raw image bytes (PNG, JPEG, etc.)
152
+ * @returns true if QR is production-ready
153
+ */
154
+ export declare function isProductionReady(imageBuffer: Buffer): boolean
155
+ /**
156
+ * Get simple summary of QR validation
157
+ *
158
+ * @example
159
+ * ```typescript
160
+ * const summary = summarize(buffer);
161
+ * console.log(`${summary.rating}: ${summary.score}/100`);
162
+ * if (summary.productionReady) {
163
+ * console.log(`Content: ${summary.content}`);
164
+ * }
165
+ * ```
166
+ *
167
+ * @param imageBuffer - Raw image bytes (PNG, JPEG, etc.)
168
+ * @returns QrSummary with all key info
169
+ */
170
+ export declare function summarize(imageBuffer: Buffer): QrSummary
171
+ /**
172
+ * Get human-readable rating for a score
173
+ *
174
+ * @example
175
+ * ```typescript
176
+ * const rating = getRating(85); // "Excellent"
177
+ * ```
178
+ *
179
+ * @param score - Score from 0-100
180
+ * @returns Rating string (Excellent/Good/Fair/Poor)
181
+ */
182
+ export declare function getRating(score: number): string