browser-cdp 0.6.3 → 0.6.4
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/README.md +74 -0
- package/cli.js +2 -0
- package/package.json +1 -1
- package/src/storage.js +170 -0
package/README.md
CHANGED
|
@@ -45,6 +45,15 @@ browser-cdp cookies export [--path=FILE]
|
|
|
45
45
|
browser-cdp cookies import <file>
|
|
46
46
|
browser-cdp cookies clear
|
|
47
47
|
|
|
48
|
+
# Manage localStorage/sessionStorage
|
|
49
|
+
browser-cdp storage get <key>
|
|
50
|
+
browser-cdp storage set <key> <value>
|
|
51
|
+
browser-cdp storage list
|
|
52
|
+
browser-cdp storage clear
|
|
53
|
+
browser-cdp storage export [--path=FILE]
|
|
54
|
+
browser-cdp storage import <file>
|
|
55
|
+
# Add --session for sessionStorage instead of localStorage
|
|
56
|
+
|
|
48
57
|
# Show page performance metrics
|
|
49
58
|
browser-cdp insights [--json]
|
|
50
59
|
|
|
@@ -123,6 +132,20 @@ browser-cdp cookies import session.json
|
|
|
123
132
|
# Clear all cookies
|
|
124
133
|
browser-cdp cookies clear
|
|
125
134
|
|
|
135
|
+
# Get/set localStorage values
|
|
136
|
+
browser-cdp storage get authToken
|
|
137
|
+
browser-cdp storage set theme dark
|
|
138
|
+
|
|
139
|
+
# List all storage keys
|
|
140
|
+
browser-cdp storage list
|
|
141
|
+
|
|
142
|
+
# Export/import storage
|
|
143
|
+
browser-cdp storage export
|
|
144
|
+
browser-cdp storage import storage.json
|
|
145
|
+
|
|
146
|
+
# Work with sessionStorage
|
|
147
|
+
browser-cdp storage get tempData --session
|
|
148
|
+
|
|
126
149
|
# Get page performance insights
|
|
127
150
|
browser-cdp insights
|
|
128
151
|
# Returns: TTFB, First Paint, FCP, DOM loaded, resources, memory
|
|
@@ -187,6 +210,57 @@ Delete all cookies from the browser:
|
|
|
187
210
|
browser-cdp cookies clear
|
|
188
211
|
```
|
|
189
212
|
|
|
213
|
+
## Storage Command
|
|
214
|
+
|
|
215
|
+
The `storage` command provides localStorage and sessionStorage management:
|
|
216
|
+
|
|
217
|
+
### Get/Set Values
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
browser-cdp storage get authToken # Get from localStorage
|
|
221
|
+
browser-cdp storage set theme dark # Set in localStorage
|
|
222
|
+
browser-cdp storage set tempData "session" --session # Set in sessionStorage
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### List Keys
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
browser-cdp storage list # List localStorage keys
|
|
229
|
+
browser-cdp storage list --session # List sessionStorage keys
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Export/Import
|
|
233
|
+
|
|
234
|
+
Save storage to a JSON file for backup or restore:
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
browser-cdp storage export # Saves to storage.json
|
|
238
|
+
browser-cdp storage export --path app-state.json # Save to specific file
|
|
239
|
+
browser-cdp storage import app-state.json # Restore from file
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Output format:
|
|
243
|
+
```json
|
|
244
|
+
{
|
|
245
|
+
"authToken": "eyJhbGciOiJIUzI1NiIs...",
|
|
246
|
+
"theme": "dark"
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Clear Storage
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
browser-cdp storage clear # Clear localStorage
|
|
254
|
+
browser-cdp storage clear --session # Clear sessionStorage
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### localStorage vs sessionStorage
|
|
258
|
+
|
|
259
|
+
| Storage Type | Lifetime | Scope | Flag |
|
|
260
|
+
|--------------|----------|-------|------|
|
|
261
|
+
| localStorage | Permanent | Per origin | (default) |
|
|
262
|
+
| sessionStorage | Tab session | Per tab | `--session` |
|
|
263
|
+
|
|
190
264
|
## Pre-started Browser
|
|
191
265
|
|
|
192
266
|
If you already have a browser running with CDP enabled, the CLI will connect to it:
|
package/cli.js
CHANGED
|
@@ -22,6 +22,7 @@ const commands = {
|
|
|
22
22
|
console: "./src/console.js",
|
|
23
23
|
network: "./src/network.js",
|
|
24
24
|
cookies: "./src/cookies.js",
|
|
25
|
+
storage: "./src/storage.js",
|
|
25
26
|
insights: "./src/insights.js",
|
|
26
27
|
lighthouse: "./src/lighthouse.js",
|
|
27
28
|
};
|
|
@@ -43,6 +44,7 @@ function printUsage() {
|
|
|
43
44
|
console.log(" console Stream browser console output");
|
|
44
45
|
console.log(" network Stream network requests/responses");
|
|
45
46
|
console.log(" cookies Export/import/clear browser cookies");
|
|
47
|
+
console.log(" storage Manage localStorage/sessionStorage");
|
|
46
48
|
console.log(" insights Show page performance metrics");
|
|
47
49
|
console.log(" lighthouse Run Lighthouse audit");
|
|
48
50
|
console.log("");
|
package/package.json
CHANGED
package/src/storage.js
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { chromium } from "playwright";
|
|
5
|
+
import { DEFAULT_PORT, getActivePage } from "./utils.js";
|
|
6
|
+
|
|
7
|
+
const args = process.argv.slice(2);
|
|
8
|
+
const subcommand = args[0];
|
|
9
|
+
const showHelp = args.includes("--help") || args.includes("-h");
|
|
10
|
+
const useSessionStorage = args.includes("--session");
|
|
11
|
+
const storageType = useSessionStorage ? "sessionStorage" : "localStorage";
|
|
12
|
+
|
|
13
|
+
function printUsage() {
|
|
14
|
+
console.log("Usage: storage <subcommand> [options]");
|
|
15
|
+
console.log("");
|
|
16
|
+
console.log("Subcommands:");
|
|
17
|
+
console.log(" get <key> Get value for key");
|
|
18
|
+
console.log(" set <key> <value> Set key to value");
|
|
19
|
+
console.log(" list List all keys");
|
|
20
|
+
console.log(" clear Clear all storage");
|
|
21
|
+
console.log(" export Export storage to JSON file");
|
|
22
|
+
console.log(" import <file> Import storage from JSON file");
|
|
23
|
+
console.log("");
|
|
24
|
+
console.log("Options:");
|
|
25
|
+
console.log(" --session Use sessionStorage instead of localStorage");
|
|
26
|
+
console.log(" --path <file> Output file path for export (default: storage.json)");
|
|
27
|
+
console.log("");
|
|
28
|
+
console.log("Examples:");
|
|
29
|
+
console.log(" storage get token");
|
|
30
|
+
console.log(" storage set theme dark");
|
|
31
|
+
console.log(" storage list");
|
|
32
|
+
console.log(" storage export");
|
|
33
|
+
console.log(" storage export --path session.json --session");
|
|
34
|
+
console.log(" storage import session.json");
|
|
35
|
+
console.log(" storage clear");
|
|
36
|
+
process.exit(0);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (!subcommand || showHelp) {
|
|
40
|
+
printUsage();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (!["get", "set", "list", "clear", "export", "import"].includes(subcommand)) {
|
|
44
|
+
console.error(`Unknown subcommand: ${subcommand}`);
|
|
45
|
+
console.log("Available: get, set, list, clear, export, import");
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const browser = await chromium.connectOverCDP(`http://localhost:${DEFAULT_PORT}`);
|
|
50
|
+
const contexts = browser.contexts();
|
|
51
|
+
const context = contexts[0];
|
|
52
|
+
|
|
53
|
+
if (!context) {
|
|
54
|
+
console.error("No browser context found");
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const pages = context.pages();
|
|
59
|
+
const page = getActivePage(pages);
|
|
60
|
+
|
|
61
|
+
if (!page) {
|
|
62
|
+
console.error("No active tab found");
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const positionalArgs = args.filter((a) => !a.startsWith("--"));
|
|
67
|
+
|
|
68
|
+
if (subcommand === "get") {
|
|
69
|
+
const key = positionalArgs[1];
|
|
70
|
+
|
|
71
|
+
if (!key) {
|
|
72
|
+
console.error("Error: get requires a key");
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const result = await page.evaluate(
|
|
77
|
+
([storageType, key]) => window[storageType].getItem(key),
|
|
78
|
+
[storageType, key]
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
if (result === null) {
|
|
82
|
+
console.error(`Key "${key}" not found in ${storageType}`);
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
console.log(result);
|
|
87
|
+
} else if (subcommand === "set") {
|
|
88
|
+
const key = positionalArgs[1];
|
|
89
|
+
const value = positionalArgs.slice(2).join(" ");
|
|
90
|
+
|
|
91
|
+
if (!key || value === "") {
|
|
92
|
+
console.error("Error: set requires <key> <value>");
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
await page.evaluate(
|
|
97
|
+
([storageType, key, value]) => window[storageType].setItem(key, value),
|
|
98
|
+
[storageType, key, value]
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
console.log(`Set ${key} in ${storageType}`);
|
|
102
|
+
} else if (subcommand === "list") {
|
|
103
|
+
const keys = await page.evaluate(
|
|
104
|
+
(storageType) => Object.keys(window[storageType]),
|
|
105
|
+
storageType
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
if (keys.length === 0) {
|
|
109
|
+
console.log(`No keys found in ${storageType}`);
|
|
110
|
+
} else {
|
|
111
|
+
console.log(`Keys in ${storageType}:`);
|
|
112
|
+
keys.forEach((key) => console.log(` ${key}`));
|
|
113
|
+
}
|
|
114
|
+
} else if (subcommand === "clear") {
|
|
115
|
+
await page.evaluate((storageType) => window[storageType].clear(), storageType);
|
|
116
|
+
|
|
117
|
+
console.log(`Cleared all ${storageType}`);
|
|
118
|
+
} else if (subcommand === "export") {
|
|
119
|
+
const pathIdx = args.findIndex((a) => a === "--path");
|
|
120
|
+
const outputFile = pathIdx !== -1 ? args[pathIdx + 1] : "storage.json";
|
|
121
|
+
|
|
122
|
+
const data = await page.evaluate((storageType) => {
|
|
123
|
+
const storage = window[storageType];
|
|
124
|
+
const result = {};
|
|
125
|
+
for (let i = 0; i < storage.length; i++) {
|
|
126
|
+
const key = storage.key(i);
|
|
127
|
+
result[key] = storage.getItem(key);
|
|
128
|
+
}
|
|
129
|
+
return result;
|
|
130
|
+
}, storageType);
|
|
131
|
+
|
|
132
|
+
writeFileSync(outputFile, JSON.stringify(data, null, 2));
|
|
133
|
+
const count = Object.keys(data).length;
|
|
134
|
+
console.log(`Exported ${count} item(s) from ${storageType} to ${outputFile}`);
|
|
135
|
+
} else if (subcommand === "import") {
|
|
136
|
+
const importFile = positionalArgs[1];
|
|
137
|
+
|
|
138
|
+
if (!importFile) {
|
|
139
|
+
console.error("Error: import requires a file path");
|
|
140
|
+
process.exit(1);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
let data;
|
|
144
|
+
try {
|
|
145
|
+
data = JSON.parse(readFileSync(importFile, "utf8"));
|
|
146
|
+
} catch (error) {
|
|
147
|
+
console.error(`Error reading file: ${error.message}`);
|
|
148
|
+
process.exit(1);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (typeof data !== "object" || Array.isArray(data)) {
|
|
152
|
+
console.error("Error: Storage file must contain a JSON object");
|
|
153
|
+
process.exit(1);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
await page.evaluate(
|
|
157
|
+
([storageType, data]) => {
|
|
158
|
+
const storage = window[storageType];
|
|
159
|
+
for (const [key, value] of Object.entries(data)) {
|
|
160
|
+
storage.setItem(key, value);
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
[storageType, data]
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
const count = Object.keys(data).length;
|
|
167
|
+
console.log(`Imported ${count} item(s) to ${storageType} from ${importFile}`);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
await browser.close();
|