dingding-browser 1.3.8
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 +39 -0
- package/bin/ddb.cjs +15 -0
- package/package.json +27 -0
- package/src/cli.cjs +340 -0
package/README.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# dingding-browser
|
|
2
|
+
|
|
3
|
+
DingDing Browser CLI for the local Launch API.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g dingding-browser
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Aliases:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
dingding-browser
|
|
15
|
+
dingding
|
|
16
|
+
ddb
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Examples
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
ddb status
|
|
23
|
+
ddb list-profiles
|
|
24
|
+
ddb open BUYER_001
|
|
25
|
+
ddb open 550e8400-e29b-41d4-a716-446655440000 --by profile-id
|
|
26
|
+
ddb runtime-session BUYER_001 --timeout-ms 45000
|
|
27
|
+
ddb close BUYER_001
|
|
28
|
+
ddb list-proxies
|
|
29
|
+
ddb create-proxy '{"proxyName":"US-1","proxyConfig":"http://127.0.0.1:8080"}'
|
|
30
|
+
ddb list-scripts
|
|
31
|
+
ddb run-script '{"scriptId":"news-query-txt","selector":{"code":"BUYER_001"},"params":{"keyword":"OpenAI"}}'
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Connection:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
ddb status --port 19876 --api-key "$DDB_API_KEY"
|
|
38
|
+
ddb status --base-url http://127.0.0.1:19876
|
|
39
|
+
```
|
package/bin/ddb.cjs
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
const { run } = require('../src/cli.cjs')
|
|
5
|
+
|
|
6
|
+
run(process.argv.slice(2)).catch((err) => {
|
|
7
|
+
const payload = {
|
|
8
|
+
ok: false,
|
|
9
|
+
error: err && err.message ? err.message : String(err),
|
|
10
|
+
}
|
|
11
|
+
if (err && err.status) payload.status = err.status
|
|
12
|
+
if (err && err.payload !== undefined) payload.payload = err.payload
|
|
13
|
+
process.stderr.write(`${JSON.stringify(payload, null, 2)}\n`)
|
|
14
|
+
process.exitCode = 1
|
|
15
|
+
})
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dingding-browser",
|
|
3
|
+
"version": "1.3.8",
|
|
4
|
+
"description": "DingDing Browser local automation CLI.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"main": "src/cli.cjs",
|
|
7
|
+
"bin": {
|
|
8
|
+
"dingding-browser": "bin/ddb.cjs",
|
|
9
|
+
"dingding": "bin/ddb.cjs",
|
|
10
|
+
"ddb": "bin/ddb.cjs"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"bin",
|
|
14
|
+
"src",
|
|
15
|
+
"README.md"
|
|
16
|
+
],
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"dingding-local-api-core": "1.3.8"
|
|
19
|
+
},
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=18"
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"test": "node --test test/*.test.cjs",
|
|
25
|
+
"check": "node --check bin/ddb.cjs && node --check src/cli.cjs"
|
|
26
|
+
}
|
|
27
|
+
}
|
package/src/cli.cjs
ADDED
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const core = loadCore()
|
|
4
|
+
const {
|
|
5
|
+
createClient,
|
|
6
|
+
parseJSONArg,
|
|
7
|
+
parseValueOrJSON,
|
|
8
|
+
selectorBodyFromValue,
|
|
9
|
+
trim,
|
|
10
|
+
} = core
|
|
11
|
+
|
|
12
|
+
const VERSION = '1.3.8'
|
|
13
|
+
|
|
14
|
+
async function run(argv = process.argv.slice(2), io = process) {
|
|
15
|
+
const parsed = parseArgs(argv)
|
|
16
|
+
if (parsed.help || !parsed.command) {
|
|
17
|
+
write(io.stdout, helpText())
|
|
18
|
+
return
|
|
19
|
+
}
|
|
20
|
+
if (parsed.command === 'version' || parsed.command === '--version' || parsed.command === '-v') {
|
|
21
|
+
write(io.stdout, `${VERSION}\n`)
|
|
22
|
+
return
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const client = createClient(parsed.options)
|
|
26
|
+
const result = await executeCommand(client, parsed.command, parsed.args, parsed.options)
|
|
27
|
+
if (parsed.options.raw) {
|
|
28
|
+
write(io.stdout, typeof result === 'string' ? `${result}\n` : `${JSON.stringify(result)}\n`)
|
|
29
|
+
} else {
|
|
30
|
+
write(io.stdout, `${JSON.stringify(result, null, 2)}\n`)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function executeCommand(client, command, args, options = {}) {
|
|
35
|
+
switch (normalizeCommand(command)) {
|
|
36
|
+
case 'status':
|
|
37
|
+
return client.health()
|
|
38
|
+
case 'list-profiles':
|
|
39
|
+
return client.listProfiles()
|
|
40
|
+
case 'get-profile':
|
|
41
|
+
return client.getProfile(requiredArg(args, 0, 'profileId'))
|
|
42
|
+
case 'create-profile':
|
|
43
|
+
return client.createProfile(parseJSONArg(requiredArg(args, 0, 'request JSON'), 'create profile request'))
|
|
44
|
+
case 'update-profile': {
|
|
45
|
+
const first = requiredArg(args, 0, 'profileId or request JSON')
|
|
46
|
+
if (looksJSON(first)) {
|
|
47
|
+
const input = parseJSONArg(first, 'update profile request')
|
|
48
|
+
const profileId = input.profileId
|
|
49
|
+
delete input.profileId
|
|
50
|
+
return client.updateProfile(profileId, input)
|
|
51
|
+
}
|
|
52
|
+
return client.updateProfile(first, parseJSONArg(requiredArg(args, 1, 'request JSON'), 'update profile request'))
|
|
53
|
+
}
|
|
54
|
+
case 'delete-profile':
|
|
55
|
+
return client.deleteProfile(requiredArg(args, 0, 'profileId'))
|
|
56
|
+
case 'open-browser':
|
|
57
|
+
return client.launch(buildSelectorRequest(args, options))
|
|
58
|
+
case 'open-browser-by-code':
|
|
59
|
+
return client.launchByCode(requiredArg(args, 0, 'code'))
|
|
60
|
+
case 'runtime-active':
|
|
61
|
+
return client.runtimeActive()
|
|
62
|
+
case 'runtime-session':
|
|
63
|
+
return client.runtimeSession(buildSelectorRequest(args, options))
|
|
64
|
+
case 'runtime-status':
|
|
65
|
+
return client.runtimeStatus(buildSelectorRequest(args, options))
|
|
66
|
+
case 'close-browser':
|
|
67
|
+
return client.runtimeStop(buildSelectorRequest(args, options))
|
|
68
|
+
case 'launch-logs':
|
|
69
|
+
return client.launchLogs(args[0] || options.limit)
|
|
70
|
+
case 'list-scripts':
|
|
71
|
+
return client.listAutomationScripts()
|
|
72
|
+
case 'get-script':
|
|
73
|
+
return client.getAutomationScript(requiredArg(args, 0, 'scriptId'))
|
|
74
|
+
case 'run-script':
|
|
75
|
+
return client.runAutomationScript(buildRunScriptRequest(args))
|
|
76
|
+
case 'list-runs':
|
|
77
|
+
return client.listAutomationRuns(args[0] || options.limit)
|
|
78
|
+
case 'list-groups':
|
|
79
|
+
return client.listGroups()
|
|
80
|
+
case 'create-group':
|
|
81
|
+
return client.createGroup(parseJSONArg(requiredArg(args, 0, 'request JSON'), 'create group request'))
|
|
82
|
+
case 'update-group':
|
|
83
|
+
return client.updateGroup(requiredArg(args, 0, 'groupId'), parseJSONArg(requiredArg(args, 1, 'request JSON'), 'update group request'))
|
|
84
|
+
case 'delete-group':
|
|
85
|
+
return client.deleteGroup(requiredArg(args, 0, 'groupId'))
|
|
86
|
+
case 'move-profiles':
|
|
87
|
+
return client.moveProfilesToGroup(requiredArg(args, 0, 'groupId'), parseJSONArg(requiredArg(args, 1, 'profileIds JSON array'), 'profileIds'))
|
|
88
|
+
case 'list-proxies':
|
|
89
|
+
return client.listProxies(options.group || options.groupName || args[0])
|
|
90
|
+
case 'list-proxy-groups':
|
|
91
|
+
return client.listProxyGroups()
|
|
92
|
+
case 'get-proxy':
|
|
93
|
+
return client.getProxy(requiredArg(args, 0, 'proxyId'))
|
|
94
|
+
case 'create-proxy':
|
|
95
|
+
return client.createProxy(parseJSONArg(requiredArg(args, 0, 'proxy JSON or JSON array'), 'create proxy request'))
|
|
96
|
+
case 'save-proxies':
|
|
97
|
+
return client.saveProxies(parseJSONArg(requiredArg(args, 0, 'proxy list JSON'), 'save proxies request'))
|
|
98
|
+
case 'update-proxy':
|
|
99
|
+
return client.updateProxy(requiredArg(args, 0, 'proxyId'), parseJSONArg(requiredArg(args, 1, 'proxy JSON'), 'update proxy request'))
|
|
100
|
+
case 'delete-proxy':
|
|
101
|
+
return client.deleteProxy(requiredArg(args, 0, 'proxyId'))
|
|
102
|
+
case 'list-tags':
|
|
103
|
+
return client.listTags()
|
|
104
|
+
case 'rename-tag':
|
|
105
|
+
return client.renameTag(requiredArg(args, 0, 'oldName'), requiredArg(args, 1, 'newName'))
|
|
106
|
+
case 'set-tags':
|
|
107
|
+
return client.setTags(parseJSONArg(requiredArg(args, 0, 'profileIds JSON array'), 'profileIds'), parseJSONArg(requiredArg(args, 1, 'tags JSON array'), 'tags'), Boolean(options.replace))
|
|
108
|
+
case 'remove-tags':
|
|
109
|
+
return client.removeTags(parseJSONArg(requiredArg(args, 0, 'profileIds JSON array'), 'profileIds'), parseJSONArg(requiredArg(args, 1, 'tags JSON array'), 'tags'))
|
|
110
|
+
case 'list-cores':
|
|
111
|
+
return client.listCores()
|
|
112
|
+
default:
|
|
113
|
+
throw new Error(`unknown command: ${command}`)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function buildSelectorRequest(args, options) {
|
|
118
|
+
const first = requiredArg(args, 0, 'selector value or JSON')
|
|
119
|
+
const parsed = parseValueOrJSON(first)
|
|
120
|
+
const body = selectorBodyFromValue(parsed, options)
|
|
121
|
+
if (options.matchMode && !body.matchMode) body.matchMode = options.matchMode
|
|
122
|
+
if (options.startUrl) body.startUrls = Array.isArray(options.startUrl) ? options.startUrl : [options.startUrl]
|
|
123
|
+
if (options.skipDefaultStartUrls) body.skipDefaultStartUrls = true
|
|
124
|
+
if (options.timeoutMs) body.timeoutMs = Number(options.timeoutMs)
|
|
125
|
+
return body
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function buildRunScriptRequest(args) {
|
|
129
|
+
const first = requiredArg(args, 0, 'scriptId or request JSON')
|
|
130
|
+
if (looksJSON(first)) return parseJSONArg(first, 'run script request')
|
|
131
|
+
const req = { scriptId: first }
|
|
132
|
+
if (args[1]) req.params = parseJSONArg(args[1], 'script params')
|
|
133
|
+
if (args[2]) req.selector = parseJSONArg(args[2], 'script selector')
|
|
134
|
+
return req
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function parseArgs(argv) {
|
|
138
|
+
const options = {}
|
|
139
|
+
const args = []
|
|
140
|
+
let command = ''
|
|
141
|
+
let help = false
|
|
142
|
+
|
|
143
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
144
|
+
const token = argv[i]
|
|
145
|
+
if (token === '-h' || token === '--help') {
|
|
146
|
+
help = true
|
|
147
|
+
continue
|
|
148
|
+
}
|
|
149
|
+
if (token === '--raw') {
|
|
150
|
+
options.raw = true
|
|
151
|
+
continue
|
|
152
|
+
}
|
|
153
|
+
if (token === '--replace') {
|
|
154
|
+
options.replace = true
|
|
155
|
+
continue
|
|
156
|
+
}
|
|
157
|
+
if (token === '--skip-default-start-urls') {
|
|
158
|
+
options.skipDefaultStartUrls = true
|
|
159
|
+
continue
|
|
160
|
+
}
|
|
161
|
+
if (token === '-p' || token === '--port') {
|
|
162
|
+
options.port = requiredNext(argv, ++i, token)
|
|
163
|
+
continue
|
|
164
|
+
}
|
|
165
|
+
if (token === '-b' || token === '--base-url') {
|
|
166
|
+
options.baseUrl = requiredNext(argv, ++i, token)
|
|
167
|
+
continue
|
|
168
|
+
}
|
|
169
|
+
if (token === '-k' || token === '--api-key') {
|
|
170
|
+
options.apiKey = requiredNext(argv, ++i, token)
|
|
171
|
+
continue
|
|
172
|
+
}
|
|
173
|
+
if (token === '--auth-header') {
|
|
174
|
+
options.authHeader = requiredNext(argv, ++i, token)
|
|
175
|
+
continue
|
|
176
|
+
}
|
|
177
|
+
if (token === '--by') {
|
|
178
|
+
options.by = requiredNext(argv, ++i, token)
|
|
179
|
+
continue
|
|
180
|
+
}
|
|
181
|
+
if (token === '--match-mode') {
|
|
182
|
+
options.matchMode = requiredNext(argv, ++i, token)
|
|
183
|
+
continue
|
|
184
|
+
}
|
|
185
|
+
if (token === '--start-url') {
|
|
186
|
+
options.startUrl = appendOption(options.startUrl, requiredNext(argv, ++i, token))
|
|
187
|
+
continue
|
|
188
|
+
}
|
|
189
|
+
if (token === '--timeout-ms') {
|
|
190
|
+
options.timeoutMs = requiredNext(argv, ++i, token)
|
|
191
|
+
continue
|
|
192
|
+
}
|
|
193
|
+
if (token === '--group' || token === '--group-name') {
|
|
194
|
+
options.groupName = requiredNext(argv, ++i, token)
|
|
195
|
+
continue
|
|
196
|
+
}
|
|
197
|
+
if (!command) {
|
|
198
|
+
command = token
|
|
199
|
+
} else {
|
|
200
|
+
args.push(token)
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return { command, args, options, help }
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function normalizeCommand(command) {
|
|
208
|
+
switch (command) {
|
|
209
|
+
case 'check-status':
|
|
210
|
+
return 'status'
|
|
211
|
+
case 'profiles':
|
|
212
|
+
case 'get-browser-list':
|
|
213
|
+
case 'list-browser':
|
|
214
|
+
case 'list-browsers':
|
|
215
|
+
return 'list-profiles'
|
|
216
|
+
case 'get-browser':
|
|
217
|
+
return 'get-profile'
|
|
218
|
+
case 'create-browser':
|
|
219
|
+
return 'create-profile'
|
|
220
|
+
case 'update-browser':
|
|
221
|
+
return 'update-profile'
|
|
222
|
+
case 'delete-browser':
|
|
223
|
+
return 'delete-profile'
|
|
224
|
+
case 'open':
|
|
225
|
+
case 'launch':
|
|
226
|
+
return 'open-browser'
|
|
227
|
+
case 'launch-code':
|
|
228
|
+
return 'open-browser-by-code'
|
|
229
|
+
case 'active':
|
|
230
|
+
return 'runtime-active'
|
|
231
|
+
case 'session':
|
|
232
|
+
return 'runtime-session'
|
|
233
|
+
case 'runtime':
|
|
234
|
+
return 'runtime-session'
|
|
235
|
+
case 'profile-status':
|
|
236
|
+
case 'get-browser-active':
|
|
237
|
+
return 'runtime-status'
|
|
238
|
+
case 'close':
|
|
239
|
+
case 'stop':
|
|
240
|
+
case 'close-browser':
|
|
241
|
+
return 'close-browser'
|
|
242
|
+
case 'scripts':
|
|
243
|
+
return 'list-scripts'
|
|
244
|
+
case 'runs':
|
|
245
|
+
return 'list-runs'
|
|
246
|
+
case 'groups':
|
|
247
|
+
case 'get-group-list':
|
|
248
|
+
return 'list-groups'
|
|
249
|
+
case 'proxies':
|
|
250
|
+
case 'get-proxy-list':
|
|
251
|
+
return 'list-proxies'
|
|
252
|
+
case 'proxy-groups':
|
|
253
|
+
return 'list-proxy-groups'
|
|
254
|
+
case 'tags':
|
|
255
|
+
case 'get-tag-list':
|
|
256
|
+
return 'list-tags'
|
|
257
|
+
case 'cores':
|
|
258
|
+
case 'get-kernel-list':
|
|
259
|
+
return 'list-cores'
|
|
260
|
+
default:
|
|
261
|
+
return command
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function helpText() {
|
|
266
|
+
return `DingDing Browser CLI ${VERSION}
|
|
267
|
+
|
|
268
|
+
Usage:
|
|
269
|
+
ddb <command> [arg] [--port 19876] [--api-key KEY]
|
|
270
|
+
|
|
271
|
+
Core:
|
|
272
|
+
ddb status
|
|
273
|
+
ddb list-profiles
|
|
274
|
+
ddb open BUYER_001
|
|
275
|
+
ddb open 550e8400-e29b-41d4-a716-446655440000 --by profile-id
|
|
276
|
+
ddb close BUYER_001
|
|
277
|
+
ddb runtime-session BUYER_001 --timeout-ms 45000
|
|
278
|
+
|
|
279
|
+
Profiles:
|
|
280
|
+
ddb get-profile <profileId>
|
|
281
|
+
ddb create-profile '{"profile":{"profileName":"buyer-001"},"launchCode":"BUYER_001"}'
|
|
282
|
+
ddb update-profile <profileId> '{"profile":{"profileName":"buyer-001"}}'
|
|
283
|
+
ddb delete-profile <profileId>
|
|
284
|
+
|
|
285
|
+
Groups / Proxies / Tags / Cores:
|
|
286
|
+
ddb list-groups
|
|
287
|
+
ddb create-group '{"groupName":"Team A"}'
|
|
288
|
+
ddb list-proxies [groupName]
|
|
289
|
+
ddb create-proxy '{"proxyName":"US-1","proxyConfig":"http://127.0.0.1:8080"}'
|
|
290
|
+
ddb list-tags
|
|
291
|
+
ddb list-cores
|
|
292
|
+
|
|
293
|
+
Automation:
|
|
294
|
+
ddb list-scripts
|
|
295
|
+
ddb run-script '{"scriptId":"news-query-txt","selector":{"code":"BUYER_001"},"params":{"keyword":"OpenAI"}}'
|
|
296
|
+
`
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function requiredArg(args, index, label) {
|
|
300
|
+
const value = trim(args[index])
|
|
301
|
+
if (!value) throw new Error(`${label} is required`)
|
|
302
|
+
return value
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function requiredNext(argv, index, flag) {
|
|
306
|
+
const value = trim(argv[index])
|
|
307
|
+
if (!value) throw new Error(`${flag} requires a value`)
|
|
308
|
+
return value
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function appendOption(current, value) {
|
|
312
|
+
if (!current) return value
|
|
313
|
+
if (Array.isArray(current)) return [...current, value]
|
|
314
|
+
return [current, value]
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function looksJSON(value) {
|
|
318
|
+
const text = trim(value)
|
|
319
|
+
return text.startsWith('{') || text.startsWith('[')
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function write(stream, text) {
|
|
323
|
+
if (stream && typeof stream.write === 'function') stream.write(text)
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function loadCore() {
|
|
327
|
+
try {
|
|
328
|
+
return require('dingding-local-api-core')
|
|
329
|
+
} catch {
|
|
330
|
+
return require('../../dingding-local-api-core/src/index.cjs')
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
module.exports = {
|
|
335
|
+
executeCommand,
|
|
336
|
+
helpText,
|
|
337
|
+
normalizeCommand,
|
|
338
|
+
parseArgs,
|
|
339
|
+
run,
|
|
340
|
+
}
|