nothing-qrcpp 1.0.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.
Files changed (4) hide show
  1. package/README.md +99 -0
  2. package/index.d.ts +41 -0
  3. package/index.js +81 -0
  4. package/package.json +12 -0
package/README.md ADDED
@@ -0,0 +1,99 @@
1
+ # nothing-qrcpp
2
+
3
+ Typed event callbacks and manual control API for the C++ QR detector built into the Nothing Browser binary (`PiggyQRDetector`).
4
+
5
+ The detector runs **automatically** — you do not need this package to receive QR events. It exists for discoverability, typed callbacks, and the `site.qr` control API.
6
+
7
+ ---
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ npm install nothing-qrcpp
13
+ ```
14
+
15
+ ---
16
+
17
+ ## Usage
18
+
19
+ ```js
20
+ const piggy = require('nothing-browser').default;
21
+ const qrcpp = require('nothing-qrcpp');
22
+ const fs = require('fs');
23
+
24
+ await piggy.launch({ mode: 'tab', binary: 'headless' });
25
+ await piggy.register('whatsapp', 'https://web.whatsapp.com', { single: true });
26
+
27
+ await piggy.extend(
28
+ qrcpp({
29
+ onQR: (d) => console.log(`Scan this QR (attempt ${d.attempts}):`, d.qrData),
30
+ onScanned: () => console.log('Authenticated!'),
31
+ onTimeout: () => console.log('QR rotated — new one incoming...'),
32
+ })
33
+ );
34
+
35
+ await piggy.whatsapp.navigate();
36
+ ```
37
+
38
+ ### Without this package
39
+
40
+ If you don't want the dependency, you can listen directly — the C++ emits these events regardless:
41
+
42
+ ```js
43
+ piggy.whatsapp.on('qr', (d) => console.log('Scan:', d.qrData));
44
+ piggy.whatsapp.on('qr:scanned', () => console.log('Done!'));
45
+ piggy.whatsapp.on('qr:timeout', () => console.log('Rotated'));
46
+ ```
47
+
48
+ ---
49
+
50
+ ## Options
51
+
52
+ | Option | Type | When called |
53
+ |---|---|---|
54
+ | `onQR` | `function` | New or rotated QR is ready. `data.qrData` is `"data:image/png;base64,..."` |
55
+ | `onScanned` | `function` | QR scanned, WAWeb authenticated |
56
+ | `onTimeout` | `function` | QR expired and rotated (~every 20s) |
57
+
58
+ ---
59
+
60
+ ## Events
61
+
62
+ | Event | Data | When |
63
+ |---|---|---|
64
+ | `qr` | `{ tabId, qrData, attempts }` | New QR ready — `qrData` is a base64 PNG data URL |
65
+ | `qr:scanned` | `{ tabId }` | Canvas disappeared — auth succeeded |
66
+ | `qr:timeout` | `{ tabId }` | QR rotated before being scanned |
67
+
68
+ ---
69
+
70
+ ## API (`site.qr`)
71
+
72
+ ```js
73
+ // Check current QR state
74
+ const state = await piggy.whatsapp.qr.status();
75
+ // { waiting: true, attempts: 2 }
76
+
77
+ // Force an immediate canvas check (skips the 500ms poll interval)
78
+ await piggy.whatsapp.qr.force();
79
+ ```
80
+
81
+ ---
82
+
83
+ ## How the C++ detector works
84
+
85
+ - Polls the page every 500ms for a `<canvas>` matching known WAWeb QR selectors
86
+ - Extracts the canvas as a base64 PNG via `canvas.toDataURL()`
87
+ - Hashes the image to detect rotation — only emits `qr` when the image actually changes
88
+ - Prints the QR to the terminal automatically using iTerm2/Kitty inline image protocol with a plain data URL fallback
89
+ - When the canvas disappears, emits `qr:scanned` and stops polling
90
+
91
+ ---
92
+
93
+ ## Notes
94
+
95
+ - To force a fresh QR scan: call `site.storage.clear()` before navigating (requires `nothing-innerstorage`)
96
+ - This plugin was made upon request — report any issues found
97
+ - This plugin is tailored specifically for WhatsApp sessions. You can use it on other sites but there is no guarantee it will work, and that is not a bug. A general-purpose `nothing-storage` plugin will be released in the future to solve that
98
+ - `qrData` is a `data:image/png;base64,...` URL — render it in a browser, pass it to a QR library, or display it in the terminal. The C++ already prints it automatically
99
+ - The QR is canvas-based in WAWeb — there is no `<img>` tag. Do not try to read it with `find.css()` or `provide.text()`
package/index.d.ts ADDED
@@ -0,0 +1,41 @@
1
+ export interface QRCppOptions {
2
+ /** Called when a new or rotated QR code is ready to scan. */
3
+ onQR?: (data: { tabId: string; qrData: string; attempts: number }) => void;
4
+ /** Called when the QR is scanned and WhatsApp Web authenticates successfully. */
5
+ onScanned?: (data: { tabId: string }) => void;
6
+ /** Called when the QR expires and rotates before being scanned (~every 20s). */
7
+ onTimeout?: (data: { tabId: string }) => void;
8
+ }
9
+
10
+ export interface QRApi {
11
+ /** Check whether C++ is waiting for a QR scan and how many have been shown. */
12
+ status(): Promise<{ waiting: boolean; attempts: number }>;
13
+ /** Force an immediate canvas check without waiting for the next poll interval. */
14
+ force(): Promise<string>;
15
+ }
16
+
17
+ /**
18
+ * nothing-qrcpp plugin factory.
19
+ *
20
+ * The QR detector runs automatically inside the binary — this package adds
21
+ * typed event callbacks and the `site.qr` API for manual control.
22
+ *
23
+ * ```js
24
+ * await piggy.extend(qrcpp({
25
+ * onQR: (d) => console.log('Scan this:', d.qrData),
26
+ * onScanned: () => console.log('Authenticated!'),
27
+ * onTimeout: () => console.log('QR rotated, new one incoming...'),
28
+ * }));
29
+ * ```
30
+ */
31
+ declare function qrcpp(opts?: QRCppOptions): (site: any) => Promise<any>;
32
+
33
+ export default qrcpp;
34
+ export = qrcpp;
35
+
36
+ declare module 'nothing-browser' {
37
+ interface PiggySite {
38
+ /** QR code control API — added by nothing-qrcpp */
39
+ qr: QRApi;
40
+ }
41
+ }
package/index.js ADDED
@@ -0,0 +1,81 @@
1
+ 'use strict';
2
+
3
+ // nothing-qrcpp
4
+ // Wraps the C++ PiggyQRDetector built into the Nothing Browser binary.
5
+ // The QR detector runs automatically — no activation needed.
6
+ // This package is a thin event/API wrapper for discoverability and convenience.
7
+ //
8
+ // C++ events this listens for:
9
+ // qr { tabId, qrData, attempts } — new or rotated QR ready to scan
10
+ // qr:scanned { tabId } — QR canvas disappeared, auth done
11
+ // qr:timeout { tabId } — QR rotated (~every 20s), new one incoming
12
+ //
13
+ // C++ commands this sends:
14
+ // qr.status {} → { waiting: bool, attempts: int }
15
+ // qr.force {} → "qr check triggered"
16
+
17
+ /**
18
+ * @param {object} opts
19
+ * @param {function} [opts.onQR] Called when a new QR code is ready. Receives { tabId, qrData, attempts }.
20
+ * @param {function} [opts.onScanned] Called when the QR is scanned and auth succeeds.
21
+ * @param {function} [opts.onTimeout] Called when the QR rotates before being scanned.
22
+ * @returns {function} Plugin installer — pass to piggy.extend() or call manually.
23
+ */
24
+ module.exports = function qrcpp(opts) {
25
+ opts = opts || {};
26
+
27
+ return async function install(site) {
28
+ if (!site || typeof site.on !== 'function') {
29
+ throw new Error(
30
+ '[nothing-qrcpp] install() received an invalid site object. ' +
31
+ 'Make sure you registered the site with { single: true } and called piggy.extend() after piggy.register().'
32
+ );
33
+ }
34
+
35
+ if (typeof site._send !== 'function') {
36
+ throw new Error(
37
+ '[nothing-qrcpp] site._send is not available. ' +
38
+ 'Use piggy.extend() to install plugins — it wires _send automatically. ' +
39
+ 'If installing manually, attach site._send before calling install().'
40
+ );
41
+ }
42
+
43
+ // ── Event listeners ──────────────────────────────────────────────────────
44
+
45
+ site.on('qr', function(data) {
46
+ if (typeof opts.onQR === 'function') opts.onQR(data);
47
+ });
48
+
49
+ site.on('qr:scanned', function(data) {
50
+ if (typeof opts.onScanned === 'function') opts.onScanned(data);
51
+ });
52
+
53
+ site.on('qr:timeout', function(data) {
54
+ if (typeof opts.onTimeout === 'function') opts.onTimeout(data);
55
+ });
56
+
57
+ // ── Attach API to site ───────────────────────────────────────────────────
58
+
59
+ site.qr = {
60
+ /**
61
+ * Check whether the C++ detector is currently waiting for a QR scan
62
+ * and how many QR codes have been shown this session.
63
+ * @returns {Promise<{ waiting: boolean, attempts: number }>}
64
+ */
65
+ status: function() {
66
+ return site._send('qr.status', {});
67
+ },
68
+
69
+ /**
70
+ * Force the C++ detector to run a canvas check immediately,
71
+ * without waiting for the next poll interval (500ms).
72
+ * @returns {Promise<string>}
73
+ */
74
+ force: function() {
75
+ return site._send('qr.force', {});
76
+ },
77
+ };
78
+
79
+ return site;
80
+ };
81
+ };
package/package.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "nothing-qrcpp",
3
+ "version": "1.0.0",
4
+ "description": "nothing-browser plugin — typed event wrapper and control API for the C++ PiggyQRDetector built into the Nothing Browser binary",
5
+ "main": "index.js",
6
+ "types": "index.d.ts",
7
+ "license": "MIT",
8
+ "keywords": ["nothing-browser", "piggy", "whatsapp", "qr", "qrcode", "plugin"],
9
+ "peerDependencies": {
10
+ "nothing-browser": "*"
11
+ }
12
+ }