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 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
+ }