nothing-cookiesinject 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 +108 -0
  2. package/index.d.ts +36 -0
  3. package/index.ts +105 -0
  4. package/package.json +12 -0
package/Readme.Md ADDED
@@ -0,0 +1,108 @@
1
+ # nothing-cookiesinject
2
+
3
+ Injects cookies from a JSON file into the browser **before page JS runs**, solving the WhatsApp Web authentication race condition that `SessionManager` alone cannot fix.
4
+
5
+ The C++ side (`PiggyCookieInject`) hooks `loadStarted` — not `loadFinished` — so cookies are in the store before WAWeb's WebSocket auth check fires.
6
+
7
+ ---
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ npm install nothing-cookiesinject
13
+ ```
14
+
15
+ ---
16
+
17
+ ## Usage
18
+
19
+ ```js
20
+ const piggy = require('nothing-browser').default;
21
+ const cookiesinject = require('nothing-cookiesinject');
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
+ cookiesinject({ cookieFile: './wa-cookies.json' })
29
+ );
30
+
31
+ // Save cookies after first authentication so they're available on next restart
32
+ piggy.whatsapp.on('authenticated', async () => {
33
+ const cookies = await piggy.whatsapp.cookies.list();
34
+ fs.writeFileSync('./wa-cookies.json', JSON.stringify(cookies, null, 2));
35
+ console.log('Cookies saved — next restart will skip the QR code');
36
+ });
37
+
38
+ piggy.whatsapp.on('cookies:injected', (d) =>
39
+ console.log(`${d.count} cookies injected (${d.skipped} skipped)`)
40
+ );
41
+
42
+ await piggy.whatsapp.navigate();
43
+ ```
44
+
45
+ ---
46
+
47
+ ## Options
48
+
49
+ | Option | Type | Default | Description |
50
+ |---|---|---|---|
51
+ | `cookieFile` | `string` | `'./wa-cookies.json'` | Path to the cookies JSON file |
52
+ | `onInjected` | `function` | — | Called every time C++ injects cookies |
53
+
54
+ ---
55
+
56
+ ## Events
57
+
58
+ | Event | Data | When |
59
+ |---|---|---|
60
+ | `cookies:injected` | `{ tabId, count, skipped, file }` | Every page load — C++ injected cookies before WAWeb booted |
61
+
62
+ ---
63
+
64
+ ## API (`site.cookieinject`)
65
+
66
+ ```js
67
+ // Re-read file and inject into current tab right now
68
+ await piggy.whatsapp.cookieinject.reload();
69
+
70
+ // Check plugin status
71
+ const status = await piggy.whatsapp.cookieinject.status();
72
+ // { active: true, file: './wa-cookies.json', injected: 14 }
73
+
74
+ // Swap cookie file without restarting
75
+ await piggy.whatsapp.cookieinject.setFile('./backup-cookies.json');
76
+ ```
77
+
78
+ ---
79
+
80
+ ## Cookie file format
81
+
82
+ The file must be a JSON array. Domain **must** have a leading dot:
83
+
84
+ ```json
85
+ [
86
+ {
87
+ "name": "sid",
88
+ "value": "abc123",
89
+ "domain": ".whatsapp.net",
90
+ "path": "/",
91
+ "secure": true,
92
+ "httpOnly": true,
93
+ "expires": 1735689600
94
+ }
95
+ ]
96
+ ```
97
+
98
+ > ⚠️ `.whatsapp.net` not `whatsapp.net` — the C++ normalises this automatically, but your exported file should already have the dot to avoid confusion.
99
+
100
+ ---
101
+
102
+ ## Notes
103
+
104
+ - To force a fresh QR scan: call `site.storage.clear()` before navigating (requires `nothing-innerstorage`)
105
+ - This plugin was made upon request — report any issues found
106
+ - 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
107
+ - Do **not** call `session.reload()` alongside this plugin — it injects at the wrong timing and will conflict
108
+ - On first run, if `wa-cookies.json` does not exist yet, the plugin loads silently and activates automatically once the file appears after your first QR scan
package/index.d.ts ADDED
@@ -0,0 +1,36 @@
1
+ export interface CookieInjectOptions {
2
+ /** Path to the cookies JSON file. Default: './wa-cookies.json' */
3
+ cookieFile?: string;
4
+ /** Called every time C++ injects cookies into the page. */
5
+ onInjected?: (data: { tabId: string; count: number; skipped: number; file: string }) => void;
6
+ }
7
+
8
+ export interface CookieInjectAPI {
9
+ /** Re-read the cookie file from disk and inject immediately into the current tab. */
10
+ reload(): Promise<string>;
11
+ /** Alias for reload — force-inject cookies right now. */
12
+ inject(): Promise<string>;
13
+ /** Check plugin status: whether it's active and how many cookies it last injected. */
14
+ status(): Promise<{ active: boolean; file: string; injected: number }>;
15
+ /** Point the C++ plugin at a different cookie file without restarting. */
16
+ setFile(file: string): Promise<string>;
17
+ }
18
+
19
+ /**
20
+ * nothing-cookiesinject plugin factory.
21
+ *
22
+ * ```js
23
+ * await piggy.extend(cookiesinject({ cookieFile: './wa-cookies.json' }));
24
+ * ```
25
+ */
26
+ declare function cookiesinject(opts?: CookieInjectOptions): (site: any) => Promise<any>;
27
+
28
+ export default cookiesinject;
29
+ export = cookiesinject;
30
+
31
+ declare module 'nothing-browser' {
32
+ interface PiggySite {
33
+ /** Cookie injection API — added by nothing-cookiesinject */
34
+ cookieinject: CookieInjectAPI;
35
+ }
36
+ }
package/index.ts ADDED
@@ -0,0 +1,105 @@
1
+ 'use strict';
2
+
3
+ // nothing-cookiesinject
4
+ // Wraps the C++ PiggyCookieInject plugin already compiled into the binary.
5
+ // Injects cookies from a JSON file into the browser BEFORE page JS runs,
6
+ // solving the WAWeb authentication race condition that SessionManager alone
7
+ // cannot fix (it injects too late — after WAWeb's auth check fires).
8
+ //
9
+ // C++ events this listens for:
10
+ // cookies:injected { tabId, count, skipped, file }
11
+ //
12
+ // C++ commands this sends:
13
+ // cookieinject.setFile { file } → "cookie file updated: path"
14
+ // cookieinject.reload {} → "re-injected N cookies"
15
+ // cookieinject.inject {} → "injected N cookies into tab X"
16
+ // cookieinject.status {} → { active, file, injected }
17
+
18
+ /**
19
+ * @param {object} opts
20
+ * @param {string} [opts.cookieFile='./wa-cookies.json'] Path to the cookies JSON file.
21
+ * @param {function} [opts.onInjected] Called when C++ injects cookies.
22
+ * @returns {function} Plugin installer — pass to piggy.extend() or call manually.
23
+ */
24
+ module.exports = function cookiesinject(opts) {
25
+ opts = opts || {};
26
+
27
+ var cookieFile = opts.cookieFile || './wa-cookies.json';
28
+
29
+ return async function install(site) {
30
+ if (!site || typeof site.on !== 'function') {
31
+ throw new Error(
32
+ '[nothing-cookiesinject] install() received an invalid site object. ' +
33
+ 'Make sure you registered the site with { single: true } and called piggy.extend() after piggy.register().'
34
+ );
35
+ }
36
+
37
+ // _send is guaranteed by piggy.extend() before any installer runs.
38
+ // If you're calling install() manually (without extend()), wire it yourself:
39
+ // site._send = (cmd, payload) => yourClient.send(cmd, { tabId: 'default', ...payload });
40
+ if (typeof site._send !== 'function') {
41
+ throw new Error(
42
+ '[nothing-cookiesinject] site._send is not available. ' +
43
+ 'Use piggy.extend() to install plugins — it wires _send automatically. ' +
44
+ 'If installing manually, attach site._send before calling install().'
45
+ );
46
+ }
47
+
48
+ // Tell C++ which file to use. Only if the file already exists —
49
+ // on a first run there are no cookies yet, so we skip this.
50
+ // C++ will still activate when the file appears (after first QR auth).
51
+ var fs = require('fs');
52
+ if (fs.existsSync(cookieFile)) {
53
+ await site._send('cookieinject.setFile', { file: cookieFile });
54
+ }
55
+
56
+ // ── Event listeners ──────────────────────────────────────────────────────
57
+
58
+ site.on('cookies:injected', function(data) {
59
+ if (typeof opts.onInjected === 'function') opts.onInjected(data);
60
+ });
61
+
62
+ // ── Attach API to site ───────────────────────────────────────────────────
63
+
64
+ site.cookieinject = {
65
+ /**
66
+ * Re-read the cookie file from disk and inject immediately into the current tab.
67
+ * @returns {Promise<string>}
68
+ */
69
+ reload: function() {
70
+ return site._send('cookieinject.reload', {});
71
+ },
72
+
73
+ /**
74
+ * Alias for reload — force-inject cookies into the tab right now.
75
+ * @returns {Promise<string>}
76
+ */
77
+ inject: function() {
78
+ return site._send('cookieinject.inject', {});
79
+ },
80
+
81
+ /**
82
+ * Check whether the C++ plugin is active and how many cookies it last injected.
83
+ * @returns {Promise<{ active: boolean, file: string, injected: number }>}
84
+ */
85
+ status: function() {
86
+ return site._send('cookieinject.status', {});
87
+ },
88
+
89
+ /**
90
+ * Point the C++ plugin at a different cookie file without restarting.
91
+ * File must be a JSON array — see README for the required format.
92
+ * @param {string} file
93
+ * @returns {Promise<string>}
94
+ */
95
+ setFile: function(file) {
96
+ if (!file || typeof file !== 'string') {
97
+ return Promise.reject(new Error('[nothing-cookiesinject] setFile() requires a non-empty file path'));
98
+ }
99
+ return site._send('cookieinject.setFile', { file: file });
100
+ },
101
+ };
102
+
103
+ return site;
104
+ };
105
+ };
package/package.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "nothing-cookiesinject",
3
+ "version": "1.0.0",
4
+ "description": "nothing-browser plugin — injects cookies before page JS runs via the C++ PiggyCookieInject engine, fixing the WAWeb auth race condition",
5
+ "main": "index.js",
6
+ "types": "index.d.ts",
7
+ "license": "MIT",
8
+ "keywords": ["nothing-browser", "piggy", "whatsapp", "cookies", "session", "plugin"],
9
+ "peerDependencies": {
10
+ "nothing-browser": "*"
11
+ }
12
+ }