@xbrowser/cli 0.14.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 (55) hide show
  1. package/README.md +858 -0
  2. package/dist/admin-6UTU2RZ2.js +281 -0
  3. package/dist/admin-MDGF4CET.js +285 -0
  4. package/dist/admin-RPJJ5CAF.js +282 -0
  5. package/dist/browser-GWBH6OJK.js +46 -0
  6. package/dist/browser-I2HJZ7IP.js +48 -0
  7. package/dist/browser-R7B255ML.js +46 -0
  8. package/dist/chunk-2ONMTDLK.js +2050 -0
  9. package/dist/chunk-3RG5ZIWI.js +10 -0
  10. package/dist/chunk-43VX3TYN.js +83 -0
  11. package/dist/chunk-ATFTAKMN.js +267 -0
  12. package/dist/chunk-DESA2KMG.js +77 -0
  13. package/dist/chunk-DTJRVA76.js +206 -0
  14. package/dist/chunk-F3ZWFCJJ.js +2051 -0
  15. package/dist/chunk-FF5WHQHN.js +135 -0
  16. package/dist/chunk-HINTG75P.js +77 -0
  17. package/dist/chunk-KDYXFLAC.js +1503 -0
  18. package/dist/chunk-KTSQU4QT.js +29 -0
  19. package/dist/chunk-L53IDAWK.js +68 -0
  20. package/dist/chunk-M7CMBPCA.js +100 -0
  21. package/dist/chunk-NFGO7J2I.js +29 -0
  22. package/dist/chunk-OLB6UJ25.js +438 -0
  23. package/dist/chunk-OPRXFZVE.js +52 -0
  24. package/dist/chunk-RS6YYWTK.js +685 -0
  25. package/dist/chunk-VEDJ5XSQ.js +196 -0
  26. package/dist/chunk-VEKPHQBR.js +47 -0
  27. package/dist/chunk-VUJDJCIN.js +437 -0
  28. package/dist/chunk-YEN2ODUI.js +14 -0
  29. package/dist/chunk-ZZ2TFWIV.js +1382 -0
  30. package/dist/cli.js +11012 -0
  31. package/dist/convert-4DUWZIKH.js +205 -0
  32. package/dist/convert-EKQVHKB4.js +11 -0
  33. package/dist/daemon-client-3IJD6X4B.js +59 -0
  34. package/dist/daemon-client-GX2UYIW4.js +241 -0
  35. package/dist/daemon-client-XWSSQBEA.js +58 -0
  36. package/dist/daemon-main.js +9910 -0
  37. package/dist/extract-EGRXZSSK.js +67 -0
  38. package/dist/extract-JUOQQX4V.js +11 -0
  39. package/dist/filter-OLAE26HN.js +51 -0
  40. package/dist/filter-VID2GGZ7.js +9 -0
  41. package/dist/human-interaction-QPHNDD76.js +8 -0
  42. package/dist/index.d.ts +2313 -0
  43. package/dist/index.js +13839 -0
  44. package/dist/marketplace-FCVN5OTZ.js +706 -0
  45. package/dist/marketplace-FPT5YLKB.js +351 -0
  46. package/dist/marketplace-W545W4FR.js +706 -0
  47. package/dist/network-store-2S5HATEV.js +194 -0
  48. package/dist/network-store-BN6QEZ7R.js +196 -0
  49. package/dist/network-store-YAF5OIBH.js +12 -0
  50. package/dist/parse-action-dsl-DRSPBALP.js +72 -0
  51. package/dist/parse-action-dsl-T3DYC33D.js +74 -0
  52. package/dist/proxy-WKGUCH2C.js +7 -0
  53. package/dist/session-recorder-ILSSV2UC.js +6 -0
  54. package/dist/session-recorder-XET3DNML.js +7 -0
  55. package/package.json +111 -0
@@ -0,0 +1,194 @@
1
+ // src/daemon/network-scorer.ts
2
+ var DEFAULT_WEIGHTS = {
3
+ method: { post: 30, get: 10, other: 5 },
4
+ resourceType: { api: 20, document: 0, static: -50, other: 0 },
5
+ size: { goodRange: 20, tooLarge: -10 },
6
+ content: { isJson: 10, hasDataArray: 15, urlContainsApi: 10 }
7
+ };
8
+ var STATIC_TYPES = /* @__PURE__ */ new Set(["stylesheet", "image", "font", "media"]);
9
+ var DATA_ARRAY_KEYS = /* @__PURE__ */ new Set(["data", "list", "items", "results", "records"]);
10
+ function calcMethodScore(entry, weights) {
11
+ const m = entry.method.toUpperCase();
12
+ if (m === "POST" || m === "PUT" || m === "DELETE") return weights.method.post;
13
+ if (m === "GET") return weights.method.get;
14
+ return weights.method.other;
15
+ }
16
+ function calcResourceTypeScore(entry, weights) {
17
+ const rt = entry.resourceType.toLowerCase();
18
+ if (rt === "xhr" || rt === "fetch") return weights.resourceType.api;
19
+ if (rt === "document") return weights.resourceType.document;
20
+ if (STATIC_TYPES.has(rt)) return weights.resourceType.static;
21
+ return weights.resourceType.other;
22
+ }
23
+ function calcSizeScore(entry, weights) {
24
+ if (entry.size > 1024 * 1024) return weights.size.tooLarge;
25
+ const isJson = entry.contentType.toLowerCase().includes("json");
26
+ if (entry.body !== void 0 && isJson && entry.size > 0 && entry.size < 100 * 1024) {
27
+ return weights.size.goodRange;
28
+ }
29
+ return 0;
30
+ }
31
+ function calcContentScore(entry, weights) {
32
+ let score = 0;
33
+ if (entry.contentType.toLowerCase().includes("json")) {
34
+ score += weights.content.isJson;
35
+ }
36
+ if (typeof entry.body === "object" && entry.body !== null && !Array.isArray(entry.body)) {
37
+ for (const key of Object.keys(entry.body)) {
38
+ if (DATA_ARRAY_KEYS.has(key) && Array.isArray(entry.body[key])) {
39
+ score += weights.content.hasDataArray;
40
+ break;
41
+ }
42
+ }
43
+ }
44
+ const urlLower = entry.url.toLowerCase();
45
+ if (urlLower.includes("/api/") || urlLower.includes("/v1/") || urlLower.includes("/v2/") || urlLower.includes("/graphql")) {
46
+ score += weights.content.urlContainsApi;
47
+ }
48
+ return score;
49
+ }
50
+ function scoreEntry(entry, weights = DEFAULT_WEIGHTS) {
51
+ const method = calcMethodScore(entry, weights);
52
+ const resourceType = calcResourceTypeScore(entry, weights);
53
+ const size = calcSizeScore(entry, weights);
54
+ const content = calcContentScore(entry, weights);
55
+ return {
56
+ ...entry,
57
+ score: method + resourceType + size + content,
58
+ scoreBreakdown: { method, resourceType, size, content }
59
+ };
60
+ }
61
+ function scoreEntries(entries, weights = DEFAULT_WEIGHTS, feedbackFn) {
62
+ return entries.map((e) => {
63
+ const scored = scoreEntry(e, weights);
64
+ if (feedbackFn) {
65
+ scored.score += feedbackFn(e.path, e.method);
66
+ }
67
+ return scored;
68
+ }).sort((a, b) => b.score - a.score);
69
+ }
70
+
71
+ // src/daemon/network-store.ts
72
+ var NetworkCaptureStore = class {
73
+ stores = /* @__PURE__ */ new Map();
74
+ maxEntries;
75
+ constructor(maxEntries = 2e3) {
76
+ this.maxEntries = maxEntries;
77
+ }
78
+ getStore(sessionName) {
79
+ let store = this.stores.get(sessionName);
80
+ if (!store) {
81
+ store = { entries: [], counter: 0 };
82
+ this.stores.set(sessionName, store);
83
+ }
84
+ return store;
85
+ }
86
+ add(sessionName, entry) {
87
+ const store = this.getStore(sessionName);
88
+ store.counter += 1;
89
+ const fullEntry = { ...entry, id: store.counter };
90
+ store.entries.push(fullEntry);
91
+ if (store.entries.length > this.maxEntries) {
92
+ store.entries.splice(0, store.entries.length - this.maxEntries);
93
+ }
94
+ }
95
+ list(sessionName, options) {
96
+ const store = this.getStore(sessionName);
97
+ let entries = store.entries;
98
+ if (options?.filter) {
99
+ const f = options.filter.toLowerCase();
100
+ entries = entries.filter(
101
+ (e) => e.url.toLowerCase().includes(f) || e.path.toLowerCase().includes(f) || e.contentType.toLowerCase().includes(f)
102
+ );
103
+ }
104
+ if (options?.method) {
105
+ const m = options.method.toUpperCase();
106
+ entries = entries.filter((e) => e.method === m);
107
+ }
108
+ const total = entries.length;
109
+ const offset = options?.offset ?? 0;
110
+ const limit = options?.limit ?? 50;
111
+ const captures = entries.slice(offset, offset + limit);
112
+ return { session: sessionName, total, captures };
113
+ }
114
+ inspect(sessionName, id) {
115
+ const store = this.getStore(sessionName);
116
+ const capture = store.entries.find((e) => e.id === id) ?? null;
117
+ return { session: sessionName, capture };
118
+ }
119
+ clear(sessionName) {
120
+ this.stores.delete(sessionName);
121
+ }
122
+ top(sessionName, options) {
123
+ const store = this.getStore(sessionName);
124
+ const feedbackFn = options?.feedbackFn;
125
+ const scored = feedbackFn ? scoreEntries(store.entries, void 0, feedbackFn) : scoreEntries(store.entries);
126
+ const minScore = options?.minScore ?? 0;
127
+ const filtered = scored.filter((e) => e.score >= minScore);
128
+ const limit = options?.limit ?? 20;
129
+ return { session: sessionName, entries: filtered.slice(0, limit) };
130
+ }
131
+ around(sessionName, commandId, cmdLogStore, windowMs = 5e3) {
132
+ const cmd = cmdLogStore.findEntry(sessionName, commandId);
133
+ if (!cmd) return null;
134
+ const netStore = this.getStore(sessionName);
135
+ const before = netStore.entries.filter(
136
+ (e) => e.timestamp >= cmd.timestamp - windowMs && e.timestamp < cmd.timestamp
137
+ );
138
+ const after = netStore.entries.filter(
139
+ (e) => e.timestamp >= cmd.timestamp && e.timestamp < cmd.timestamp + windowMs
140
+ );
141
+ return { command: cmd, before, after, afterCount: after.length };
142
+ }
143
+ clearAll() {
144
+ this.stores.clear();
145
+ }
146
+ };
147
+ var CommandLogStore = class {
148
+ stores = /* @__PURE__ */ new Map();
149
+ maxEntries;
150
+ constructor(maxEntries = 500) {
151
+ this.maxEntries = maxEntries;
152
+ }
153
+ getStore(sessionName) {
154
+ let store = this.stores.get(sessionName);
155
+ if (!store) {
156
+ store = { entries: [], counter: 0 };
157
+ this.stores.set(sessionName, store);
158
+ }
159
+ return store;
160
+ }
161
+ add(sessionName, entry) {
162
+ const store = this.getStore(sessionName);
163
+ store.counter += 1;
164
+ const fullEntry = { ...entry, id: store.counter };
165
+ store.entries.push(fullEntry);
166
+ if (store.entries.length > this.maxEntries) {
167
+ store.entries.splice(0, store.entries.length - this.maxEntries);
168
+ }
169
+ }
170
+ list(sessionName, options) {
171
+ const store = this.getStore(sessionName);
172
+ const offset = options?.offset ?? 0;
173
+ const limit = options?.limit ?? 50;
174
+ return store.entries.slice(offset, offset + limit);
175
+ }
176
+ findEntry(sessionName, id) {
177
+ const store = this.stores.get(sessionName);
178
+ return store?.entries.find((e) => e.id === id) ?? null;
179
+ }
180
+ clear(sessionName) {
181
+ this.stores.delete(sessionName);
182
+ }
183
+ clearAll() {
184
+ this.stores.clear();
185
+ }
186
+ };
187
+ var commandLogStore = new CommandLogStore();
188
+ var networkStore = new NetworkCaptureStore();
189
+ export {
190
+ CommandLogStore,
191
+ NetworkCaptureStore,
192
+ commandLogStore,
193
+ networkStore
194
+ };
@@ -0,0 +1,196 @@
1
+ import "./chunk-3RG5ZIWI.js";
2
+
3
+ // src/daemon/network-scorer.ts
4
+ var DEFAULT_WEIGHTS = {
5
+ method: { post: 30, get: 10, other: 5 },
6
+ resourceType: { api: 20, document: 0, static: -50, other: 0 },
7
+ size: { goodRange: 20, tooLarge: -10 },
8
+ content: { isJson: 10, hasDataArray: 15, urlContainsApi: 10 }
9
+ };
10
+ var STATIC_TYPES = /* @__PURE__ */ new Set(["stylesheet", "image", "font", "media"]);
11
+ var DATA_ARRAY_KEYS = /* @__PURE__ */ new Set(["data", "list", "items", "results", "records"]);
12
+ function calcMethodScore(entry, weights) {
13
+ const m = entry.method.toUpperCase();
14
+ if (m === "POST" || m === "PUT" || m === "DELETE") return weights.method.post;
15
+ if (m === "GET") return weights.method.get;
16
+ return weights.method.other;
17
+ }
18
+ function calcResourceTypeScore(entry, weights) {
19
+ const rt = entry.resourceType.toLowerCase();
20
+ if (rt === "xhr" || rt === "fetch") return weights.resourceType.api;
21
+ if (rt === "document") return weights.resourceType.document;
22
+ if (STATIC_TYPES.has(rt)) return weights.resourceType.static;
23
+ return weights.resourceType.other;
24
+ }
25
+ function calcSizeScore(entry, weights) {
26
+ if (entry.size > 1024 * 1024) return weights.size.tooLarge;
27
+ const isJson = entry.contentType.toLowerCase().includes("json");
28
+ if (entry.body !== void 0 && isJson && entry.size > 0 && entry.size < 100 * 1024) {
29
+ return weights.size.goodRange;
30
+ }
31
+ return 0;
32
+ }
33
+ function calcContentScore(entry, weights) {
34
+ let score = 0;
35
+ if (entry.contentType.toLowerCase().includes("json")) {
36
+ score += weights.content.isJson;
37
+ }
38
+ if (typeof entry.body === "object" && entry.body !== null && !Array.isArray(entry.body)) {
39
+ for (const key of Object.keys(entry.body)) {
40
+ if (DATA_ARRAY_KEYS.has(key) && Array.isArray(entry.body[key])) {
41
+ score += weights.content.hasDataArray;
42
+ break;
43
+ }
44
+ }
45
+ }
46
+ const urlLower = entry.url.toLowerCase();
47
+ if (urlLower.includes("/api/") || urlLower.includes("/v1/") || urlLower.includes("/v2/") || urlLower.includes("/graphql")) {
48
+ score += weights.content.urlContainsApi;
49
+ }
50
+ return score;
51
+ }
52
+ function scoreEntry(entry, weights = DEFAULT_WEIGHTS) {
53
+ const method = calcMethodScore(entry, weights);
54
+ const resourceType = calcResourceTypeScore(entry, weights);
55
+ const size = calcSizeScore(entry, weights);
56
+ const content = calcContentScore(entry, weights);
57
+ return {
58
+ ...entry,
59
+ score: method + resourceType + size + content,
60
+ scoreBreakdown: { method, resourceType, size, content }
61
+ };
62
+ }
63
+ function scoreEntries(entries, weights = DEFAULT_WEIGHTS, feedbackFn) {
64
+ return entries.map((e) => {
65
+ const scored = scoreEntry(e, weights);
66
+ if (feedbackFn) {
67
+ scored.score += feedbackFn(e.path, e.method);
68
+ }
69
+ return scored;
70
+ }).sort((a, b) => b.score - a.score);
71
+ }
72
+
73
+ // src/daemon/network-store.ts
74
+ var NetworkCaptureStore = class {
75
+ stores = /* @__PURE__ */ new Map();
76
+ maxEntries;
77
+ constructor(maxEntries = 2e3) {
78
+ this.maxEntries = maxEntries;
79
+ }
80
+ getStore(sessionName) {
81
+ let store = this.stores.get(sessionName);
82
+ if (!store) {
83
+ store = { entries: [], counter: 0 };
84
+ this.stores.set(sessionName, store);
85
+ }
86
+ return store;
87
+ }
88
+ add(sessionName, entry) {
89
+ const store = this.getStore(sessionName);
90
+ store.counter += 1;
91
+ const fullEntry = { ...entry, id: store.counter };
92
+ store.entries.push(fullEntry);
93
+ if (store.entries.length > this.maxEntries) {
94
+ store.entries.splice(0, store.entries.length - this.maxEntries);
95
+ }
96
+ }
97
+ list(sessionName, options) {
98
+ const store = this.getStore(sessionName);
99
+ let entries = store.entries;
100
+ if (options?.filter) {
101
+ const f = options.filter.toLowerCase();
102
+ entries = entries.filter(
103
+ (e) => e.url.toLowerCase().includes(f) || e.path.toLowerCase().includes(f) || e.contentType.toLowerCase().includes(f)
104
+ );
105
+ }
106
+ if (options?.method) {
107
+ const m = options.method.toUpperCase();
108
+ entries = entries.filter((e) => e.method === m);
109
+ }
110
+ const total = entries.length;
111
+ const offset = options?.offset ?? 0;
112
+ const limit = options?.limit ?? 50;
113
+ const captures = entries.slice(offset, offset + limit);
114
+ return { session: sessionName, total, captures };
115
+ }
116
+ inspect(sessionName, id) {
117
+ const store = this.getStore(sessionName);
118
+ const capture = store.entries.find((e) => e.id === id) ?? null;
119
+ return { session: sessionName, capture };
120
+ }
121
+ clear(sessionName) {
122
+ this.stores.delete(sessionName);
123
+ }
124
+ top(sessionName, options) {
125
+ const store = this.getStore(sessionName);
126
+ const feedbackFn = options?.feedbackFn;
127
+ const scored = feedbackFn ? scoreEntries(store.entries, void 0, feedbackFn) : scoreEntries(store.entries);
128
+ const minScore = options?.minScore ?? 0;
129
+ const filtered = scored.filter((e) => e.score >= minScore);
130
+ const limit = options?.limit ?? 20;
131
+ return { session: sessionName, entries: filtered.slice(0, limit) };
132
+ }
133
+ around(sessionName, commandId, cmdLogStore, windowMs = 5e3) {
134
+ const cmd = cmdLogStore.findEntry(sessionName, commandId);
135
+ if (!cmd) return null;
136
+ const netStore = this.getStore(sessionName);
137
+ const before = netStore.entries.filter(
138
+ (e) => e.timestamp >= cmd.timestamp - windowMs && e.timestamp < cmd.timestamp
139
+ );
140
+ const after = netStore.entries.filter(
141
+ (e) => e.timestamp >= cmd.timestamp && e.timestamp < cmd.timestamp + windowMs
142
+ );
143
+ return { command: cmd, before, after, afterCount: after.length };
144
+ }
145
+ clearAll() {
146
+ this.stores.clear();
147
+ }
148
+ };
149
+ var CommandLogStore = class {
150
+ stores = /* @__PURE__ */ new Map();
151
+ maxEntries;
152
+ constructor(maxEntries = 500) {
153
+ this.maxEntries = maxEntries;
154
+ }
155
+ getStore(sessionName) {
156
+ let store = this.stores.get(sessionName);
157
+ if (!store) {
158
+ store = { entries: [], counter: 0 };
159
+ this.stores.set(sessionName, store);
160
+ }
161
+ return store;
162
+ }
163
+ add(sessionName, entry) {
164
+ const store = this.getStore(sessionName);
165
+ store.counter += 1;
166
+ const fullEntry = { ...entry, id: store.counter };
167
+ store.entries.push(fullEntry);
168
+ if (store.entries.length > this.maxEntries) {
169
+ store.entries.splice(0, store.entries.length - this.maxEntries);
170
+ }
171
+ }
172
+ list(sessionName, options) {
173
+ const store = this.getStore(sessionName);
174
+ const offset = options?.offset ?? 0;
175
+ const limit = options?.limit ?? 50;
176
+ return store.entries.slice(offset, offset + limit);
177
+ }
178
+ findEntry(sessionName, id) {
179
+ const store = this.stores.get(sessionName);
180
+ return store?.entries.find((e) => e.id === id) ?? null;
181
+ }
182
+ clear(sessionName) {
183
+ this.stores.delete(sessionName);
184
+ }
185
+ clearAll() {
186
+ this.stores.clear();
187
+ }
188
+ };
189
+ var commandLogStore = new CommandLogStore();
190
+ var networkStore = new NetworkCaptureStore();
191
+ export {
192
+ CommandLogStore,
193
+ NetworkCaptureStore,
194
+ commandLogStore,
195
+ networkStore
196
+ };
@@ -0,0 +1,12 @@
1
+ import {
2
+ CommandLogStore,
3
+ NetworkCaptureStore,
4
+ commandLogStore,
5
+ networkStore
6
+ } from "./chunk-VEDJ5XSQ.js";
7
+ export {
8
+ CommandLogStore,
9
+ NetworkCaptureStore,
10
+ commandLogStore,
11
+ networkStore
12
+ };
@@ -0,0 +1,72 @@
1
+ // src/lib/parse-action-dsl.ts
2
+ function parseActionDsl(dsl) {
3
+ const trimmed = dsl.trim();
4
+ if (!trimmed) throw new Error("Empty action DSL");
5
+ const spaceIndex = trimmed.indexOf(" ");
6
+ const type = spaceIndex === -1 ? trimmed : trimmed.slice(0, spaceIndex);
7
+ const rest = spaceIndex === -1 ? "" : trimmed.slice(spaceIndex + 1).trim();
8
+ switch (type) {
9
+ case "wait": {
10
+ const num = Number(rest);
11
+ if (rest && !isNaN(num) && Number.isFinite(num)) {
12
+ return { type: "wait", milliseconds: num };
13
+ }
14
+ return { type: "wait", selector: rest };
15
+ }
16
+ case "click": {
17
+ const hasAll = rest.includes("--all");
18
+ const selector = rest.replace("--all", "").trim();
19
+ return { type: "click", selector, ...hasAll ? { all: true } : {} };
20
+ }
21
+ case "write": {
22
+ return { type: "write", text: rest };
23
+ }
24
+ case "press": {
25
+ return { type: "press", key: rest };
26
+ }
27
+ case "scroll": {
28
+ const parts = rest.split(/\s+/);
29
+ let direction;
30
+ let selector;
31
+ for (const part of parts) {
32
+ if (part === "up" || part === "down") {
33
+ direction = part;
34
+ } else if (part && !part.startsWith("--")) {
35
+ selector = part;
36
+ }
37
+ }
38
+ return { type: "scroll", ...direction ? { direction } : {}, ...selector ? { selector } : {} };
39
+ }
40
+ case "screenshot": {
41
+ const fullPage = rest.includes("--full-page");
42
+ const qualityMatch = rest.match(/--quality\s+(\d+)/);
43
+ return {
44
+ type: "screenshot",
45
+ ...fullPage ? { fullPage } : {},
46
+ ...qualityMatch ? { quality: Number(qualityMatch[1]) } : {}
47
+ };
48
+ }
49
+ case "scrape": {
50
+ return { type: "scrape" };
51
+ }
52
+ case "exec": {
53
+ return { type: "executeJavascript", script: rest };
54
+ }
55
+ case "pdf": {
56
+ const landscape = rest.includes("--landscape");
57
+ const formatMatch = rest.match(/--format\s+(\S+)/);
58
+ const scaleMatch = rest.match(/--scale\s+([\d.]+)/);
59
+ return {
60
+ type: "pdf",
61
+ ...landscape ? { landscape } : {},
62
+ ...formatMatch ? { format: formatMatch[1] } : {},
63
+ ...scaleMatch ? { scale: Number(scaleMatch[1]) } : {}
64
+ };
65
+ }
66
+ default:
67
+ throw new Error(`Unknown action type: "${type}". Supported: wait, click, write, press, scroll, screenshot, scrape, exec, pdf`);
68
+ }
69
+ }
70
+ export {
71
+ parseActionDsl
72
+ };
@@ -0,0 +1,74 @@
1
+ import "./chunk-3RG5ZIWI.js";
2
+
3
+ // src/lib/parse-action-dsl.ts
4
+ function parseActionDsl(dsl) {
5
+ const trimmed = dsl.trim();
6
+ if (!trimmed) throw new Error("Empty action DSL");
7
+ const spaceIndex = trimmed.indexOf(" ");
8
+ const type = spaceIndex === -1 ? trimmed : trimmed.slice(0, spaceIndex);
9
+ const rest = spaceIndex === -1 ? "" : trimmed.slice(spaceIndex + 1).trim();
10
+ switch (type) {
11
+ case "wait": {
12
+ const num = Number(rest);
13
+ if (rest && !isNaN(num) && Number.isFinite(num)) {
14
+ return { type: "wait", milliseconds: num };
15
+ }
16
+ return { type: "wait", selector: rest };
17
+ }
18
+ case "click": {
19
+ const hasAll = rest.includes("--all");
20
+ const selector = rest.replace("--all", "").trim();
21
+ return { type: "click", selector, ...hasAll ? { all: true } : {} };
22
+ }
23
+ case "write": {
24
+ return { type: "write", text: rest };
25
+ }
26
+ case "press": {
27
+ return { type: "press", key: rest };
28
+ }
29
+ case "scroll": {
30
+ const parts = rest.split(/\s+/);
31
+ let direction;
32
+ let selector;
33
+ for (const part of parts) {
34
+ if (part === "up" || part === "down") {
35
+ direction = part;
36
+ } else if (part && !part.startsWith("--")) {
37
+ selector = part;
38
+ }
39
+ }
40
+ return { type: "scroll", ...direction ? { direction } : {}, ...selector ? { selector } : {} };
41
+ }
42
+ case "screenshot": {
43
+ const fullPage = rest.includes("--full-page");
44
+ const qualityMatch = rest.match(/--quality\s+(\d+)/);
45
+ return {
46
+ type: "screenshot",
47
+ ...fullPage ? { fullPage } : {},
48
+ ...qualityMatch ? { quality: Number(qualityMatch[1]) } : {}
49
+ };
50
+ }
51
+ case "scrape": {
52
+ return { type: "scrape" };
53
+ }
54
+ case "exec": {
55
+ return { type: "executeJavascript", script: rest };
56
+ }
57
+ case "pdf": {
58
+ const landscape = rest.includes("--landscape");
59
+ const formatMatch = rest.match(/--format\s+(\S+)/);
60
+ const scaleMatch = rest.match(/--scale\s+([\d.]+)/);
61
+ return {
62
+ type: "pdf",
63
+ ...landscape ? { landscape } : {},
64
+ ...formatMatch ? { format: formatMatch[1] } : {},
65
+ ...scaleMatch ? { scale: Number(scaleMatch[1]) } : {}
66
+ };
67
+ }
68
+ default:
69
+ throw new Error(`Unknown action type: "${type}". Supported: wait, click, write, press, scroll, screenshot, scrape, exec, pdf`);
70
+ }
71
+ }
72
+ export {
73
+ parseActionDsl
74
+ };
@@ -0,0 +1,7 @@
1
+ import {
2
+ CDPInterceptorProxy
3
+ } from "./chunk-ZZ2TFWIV.js";
4
+ import "./chunk-3RG5ZIWI.js";
5
+ export {
6
+ CDPInterceptorProxy
7
+ };
@@ -0,0 +1,6 @@
1
+ import {
2
+ SessionRecorder
3
+ } from "./chunk-KDYXFLAC.js";
4
+ export {
5
+ SessionRecorder
6
+ };
@@ -0,0 +1,7 @@
1
+ import {
2
+ SessionRecorder
3
+ } from "./chunk-KDYXFLAC.js";
4
+ import "./chunk-3RG5ZIWI.js";
5
+ export {
6
+ SessionRecorder
7
+ };
package/package.json ADDED
@@ -0,0 +1,111 @@
1
+ {
2
+ "name": "@xbrowser/cli",
3
+ "version": "0.14.0",
4
+ "description": "A self-contained browser automation CLI tool — navigate, click, fill forms, extract data, record & replay sessions via YAML scripts",
5
+ "type": "module",
6
+ "bin": {
7
+ "xbrowser": "dist/cli.js"
8
+ },
9
+ "main": "dist/index.js",
10
+ "types": "dist/index.d.ts",
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "publishConfig": {
15
+ "access": "public"
16
+ },
17
+ "keywords": [
18
+ "browser",
19
+ "automation",
20
+ "cli",
21
+ "playwright",
22
+ "cdp",
23
+ "scraper",
24
+ "puppeteer",
25
+ "web-testing",
26
+ "browser-automation",
27
+ "record-replay",
28
+ "browser automation",
29
+ "web scraping",
30
+ "playwright alternative",
31
+ "puppeteer alternative",
32
+ "selenium alternative",
33
+ "web crawler",
34
+ "headless browser",
35
+ "scrape",
36
+ "crawl",
37
+ "cli tool",
38
+ "command line",
39
+ "browser cli",
40
+ "anti-detection",
41
+ "record replay",
42
+ "seo tool",
43
+ "ai agent",
44
+ "browser plugin"
45
+ ],
46
+ "author": "dyyz1993",
47
+ "license": "MIT",
48
+ "repository": {
49
+ "type": "git",
50
+ "url": "git+https://github.com/dyyz1993/xbrowser.git"
51
+ },
52
+ "bugs": {
53
+ "url": "https://github.com/dyyz1993/xbrowser/issues"
54
+ },
55
+ "homepage": "https://github.com/dyyz1993/xbrowser#readme",
56
+ "scripts": {
57
+ "build": "tsup",
58
+ "dev": "tsup --watch",
59
+ "lint": "eslint src/ bin/ --ext .ts",
60
+ "typecheck": "tsc --noEmit",
61
+ "start": "node dist/cli.js",
62
+ "test": "vitest run",
63
+ "test:watch": "vitest",
64
+ "test:e2e": "vitest run tests/e2e/",
65
+ "validate": "npm run typecheck && npm run lint && npm run build && npm test",
66
+ "prepare": "husky"
67
+ },
68
+ "dependencies": {
69
+ "@dyyz1993/xcli-core": "^0.9.2",
70
+ "@types/react-syntax-highlighter": "^15.5.13",
71
+ "@types/turndown": "^5.0.6",
72
+ "cheerio": "^1.2.0",
73
+ "chrome-remote-interface": "^0.34.0",
74
+ "imapflow": "^1.3.3",
75
+ "lucide-react": "^1.14.0",
76
+ "playwright": "^1.59.0",
77
+ "react-markdown": "^10.1.0",
78
+ "react-syntax-highlighter": "^16.1.1",
79
+ "remark-gfm": "^4.0.1",
80
+ "sharp": "^0.34.5",
81
+ "turndown": "^7.2.4",
82
+ "turndown-plugin-gfm": "^1.0.2",
83
+ "ws": "^8.20.0",
84
+ "yaml": "^2.8.4",
85
+ "zod": "^3.24.0"
86
+ },
87
+ "devDependencies": {
88
+ "@tailwindcss/vite": "^4.2.4",
89
+ "@types/node": "^20.0.0",
90
+ "@types/ws": "^8.18.1",
91
+ "@typescript-eslint/eslint-plugin": "^8.59.2",
92
+ "@typescript-eslint/parser": "^8.59.2",
93
+ "@vitest/coverage-v8": "^3.2.4",
94
+ "eslint": "^10.3.0",
95
+ "eslint-config-prettier": "^10.1.8",
96
+ "husky": "^9.1.7",
97
+ "lint-staged": "^17.0.3",
98
+ "tailwindcss": "^4.2.4",
99
+ "tsup": "^8.0.0",
100
+ "typescript": "^5.0.0",
101
+ "vitest": "^3.0.0"
102
+ },
103
+ "lint-staged": {
104
+ "*.{ts,tsx}": [
105
+ "eslint --max-warnings 0"
106
+ ]
107
+ },
108
+ "optionalDependencies": {
109
+ "undici": "^7.25.0"
110
+ }
111
+ }