@1sat/cli 0.0.89 → 0.0.91
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/package.json +8 -8
- package/src/beef.ts +48 -0
- package/src/commands/authfetch.ts +187 -0
- package/src/commands/locks.ts +57 -44
- package/src/commands/messagebox.ts +59 -0
- package/src/commands/opns.ts +144 -143
- package/src/commands/ordinals.ts +100 -161
- package/src/commands/tokens.ts +10 -8
- package/src/help.ts +146 -37
- package/src/main.ts +13 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@1sat/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.91",
|
|
4
4
|
"description": "CLI for 1Sat Ordinals SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/cli.ts",
|
|
@@ -26,13 +26,13 @@
|
|
|
26
26
|
],
|
|
27
27
|
"license": "MIT",
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@1sat/actions": "0.0.
|
|
30
|
-
"@1sat/client": "0.0.
|
|
31
|
-
"@1sat/types": "0.0.
|
|
32
|
-
"@1sat/wallet-node": "0.0.
|
|
33
|
-
"@1sat/wallet-server": "0.0.
|
|
34
|
-
"@bsv/sdk": "^2.1.
|
|
35
|
-
"@bsv/wallet-toolbox": "2.
|
|
29
|
+
"@1sat/actions": "0.0.191",
|
|
30
|
+
"@1sat/client": "0.0.46",
|
|
31
|
+
"@1sat/types": "0.0.37",
|
|
32
|
+
"@1sat/wallet-node": "0.0.63",
|
|
33
|
+
"@1sat/wallet-server": "0.0.37",
|
|
34
|
+
"@bsv/sdk": "^2.1.9",
|
|
35
|
+
"@bsv/wallet-toolbox": "2.4.3",
|
|
36
36
|
"chalk": "^5.0.0",
|
|
37
37
|
"@clack/prompts": "^0.8.0",
|
|
38
38
|
"bitcoin-backup": "^0.0.11",
|
package/src/beef.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse --beef from file path, hex, or base64.
|
|
3
|
+
*/
|
|
4
|
+
import { readFileSync } from 'node:fs'
|
|
5
|
+
import { Utils } from '@bsv/sdk'
|
|
6
|
+
import { fatal } from './output'
|
|
7
|
+
|
|
8
|
+
export function parseBeefFlag(value: string | undefined): number[] | undefined {
|
|
9
|
+
if (!value) return undefined
|
|
10
|
+
try {
|
|
11
|
+
if (!value.includes('\n') && !value.includes(' ') && value.length < 4096) {
|
|
12
|
+
try {
|
|
13
|
+
const buf = readFileSync(value)
|
|
14
|
+
return Array.from(buf)
|
|
15
|
+
} catch {
|
|
16
|
+
// not a readable path — treat as hex/base64
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
const hex = value.replace(/^0x/i, '')
|
|
20
|
+
if (/^[0-9a-fA-F]+$/.test(hex) && hex.length % 2 === 0) {
|
|
21
|
+
return Utils.toArray(hex, 'hex')
|
|
22
|
+
}
|
|
23
|
+
return Utils.toArray(value, 'base64')
|
|
24
|
+
} catch (e) {
|
|
25
|
+
fatal(`Invalid --beef: ${e instanceof Error ? e.message : String(e)}`)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Bare id from tags (strips id: prefix). */
|
|
30
|
+
export function idFromTags(tags: string[] | undefined): string | undefined {
|
|
31
|
+
const t = tags?.find((x) => x.startsWith('id:'))
|
|
32
|
+
return t ? t.slice(3) : undefined
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Parse --to as P2PKH address or identity pubkey hex.
|
|
37
|
+
* Identity keys: 66 hex chars starting with 02/03.
|
|
38
|
+
*/
|
|
39
|
+
export function parseToFlag(to: string): {
|
|
40
|
+
address?: string
|
|
41
|
+
counterparty?: string
|
|
42
|
+
} {
|
|
43
|
+
const trimmed = to.trim()
|
|
44
|
+
if (/^0[23][0-9a-fA-F]{64}$/.test(trimmed)) {
|
|
45
|
+
return { counterparty: trimmed }
|
|
46
|
+
}
|
|
47
|
+
return { address: trimmed }
|
|
48
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authenticated HTTP client using CLI wallet keys (BRC-104 AuthFetch).
|
|
3
|
+
*
|
|
4
|
+
* 1sat authfetch <method> <url> [--body <json|@file>] [--header 'K: V']...
|
|
5
|
+
*
|
|
6
|
+
* Always authenticates. On 402 Payment Required, prompts unless --yes, then
|
|
7
|
+
* AuthFetch pays and retries.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { readFileSync } from 'node:fs'
|
|
11
|
+
import { AuthFetch } from '@bsv/sdk'
|
|
12
|
+
import { confirm, isCancel } from '@clack/prompts'
|
|
13
|
+
import type { GlobalFlags } from '../args'
|
|
14
|
+
import { loadContext } from '../context'
|
|
15
|
+
import { printCommandHelp } from '../help'
|
|
16
|
+
import { loadKey } from '../keys'
|
|
17
|
+
import { fatal, output } from '../output'
|
|
18
|
+
|
|
19
|
+
const METHODS = new Set([
|
|
20
|
+
'GET',
|
|
21
|
+
'POST',
|
|
22
|
+
'PUT',
|
|
23
|
+
'PATCH',
|
|
24
|
+
'DELETE',
|
|
25
|
+
'HEAD',
|
|
26
|
+
'OPTIONS',
|
|
27
|
+
])
|
|
28
|
+
|
|
29
|
+
export async function handleAuthfetchCommand(
|
|
30
|
+
args: string[],
|
|
31
|
+
opts: GlobalFlags,
|
|
32
|
+
): Promise<void> {
|
|
33
|
+
if (
|
|
34
|
+
!args[0] ||
|
|
35
|
+
args[0] === 'help' ||
|
|
36
|
+
args.includes('--help') ||
|
|
37
|
+
args.includes('-h')
|
|
38
|
+
) {
|
|
39
|
+
printCommandHelp('authfetch', opts.json)
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let method: string | undefined
|
|
44
|
+
let url: string | undefined
|
|
45
|
+
let bodyRaw: string | undefined
|
|
46
|
+
const headerArgs: string[] = []
|
|
47
|
+
|
|
48
|
+
for (let i = 0; i < args.length; i++) {
|
|
49
|
+
const a = args[i]
|
|
50
|
+
if (a === '--body') {
|
|
51
|
+
bodyRaw = args[++i]
|
|
52
|
+
if (bodyRaw === undefined) fatal('--body requires a value')
|
|
53
|
+
continue
|
|
54
|
+
}
|
|
55
|
+
if (a === '--header') {
|
|
56
|
+
const h = args[++i]
|
|
57
|
+
if (h === undefined) fatal('--header requires a value')
|
|
58
|
+
headerArgs.push(h)
|
|
59
|
+
continue
|
|
60
|
+
}
|
|
61
|
+
if (a.startsWith('--')) {
|
|
62
|
+
fatal(`Unknown flag: ${a}`)
|
|
63
|
+
}
|
|
64
|
+
if (!method) {
|
|
65
|
+
method = a.toUpperCase()
|
|
66
|
+
continue
|
|
67
|
+
}
|
|
68
|
+
if (!url) {
|
|
69
|
+
url = a
|
|
70
|
+
continue
|
|
71
|
+
}
|
|
72
|
+
fatal(`Unexpected argument: ${a}`)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (!method || !METHODS.has(method)) {
|
|
76
|
+
fatal(
|
|
77
|
+
`Usage: 1sat authfetch <method> <url> [--body …] [--header 'K: V']…\nUnknown or missing method: ${method ?? ''}`,
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
if (!url) fatal('Missing URL')
|
|
81
|
+
try {
|
|
82
|
+
new URL(url)
|
|
83
|
+
} catch {
|
|
84
|
+
fatal(`Invalid URL: ${url}`)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const headers: Record<string, string> = {}
|
|
88
|
+
for (const h of headerArgs) {
|
|
89
|
+
const i = h.indexOf(':')
|
|
90
|
+
if (i <= 0) fatal(`Invalid --header (want 'Name: value'): ${h}`)
|
|
91
|
+
headers[h.slice(0, i).trim()] = h.slice(i + 1).trim()
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
let body: string | undefined
|
|
95
|
+
if (bodyRaw !== undefined) {
|
|
96
|
+
body = bodyRaw.startsWith('@')
|
|
97
|
+
? readFileSync(bodyRaw.slice(1), 'utf8')
|
|
98
|
+
: bodyRaw
|
|
99
|
+
if (!headers['Content-Type'] && !headers['content-type']) {
|
|
100
|
+
headers['Content-Type'] = 'application/json'
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const privateKey = await loadKey()
|
|
105
|
+
const { walletResult, destroy } = await loadContext(privateKey, {
|
|
106
|
+
chain: opts.chain,
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
const auth = new AuthFetch(walletResult.wallet)
|
|
111
|
+
const init = {
|
|
112
|
+
method,
|
|
113
|
+
headers,
|
|
114
|
+
...(body !== undefined ? { body } : {}),
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
let res: Response
|
|
118
|
+
try {
|
|
119
|
+
// Authenticate but do not auto-pay on first try (so we can confirm).
|
|
120
|
+
res = await auth.fetch(url, {
|
|
121
|
+
...init,
|
|
122
|
+
paymentRetryAttempts: 0,
|
|
123
|
+
})
|
|
124
|
+
} catch (err) {
|
|
125
|
+
// Public routes may return 200 without BSV auth headers; AuthFetch rejects those.
|
|
126
|
+
const msg = err instanceof Error ? err.message : String(err)
|
|
127
|
+
if (/without valid BSV authentication/i.test(msg)) {
|
|
128
|
+
res = await fetch(url, init)
|
|
129
|
+
} else {
|
|
130
|
+
throw err
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (res.status === 402) {
|
|
135
|
+
const satsHeader = res.headers.get('x-bsv-payment-satoshis-required')
|
|
136
|
+
const sats = satsHeader ? Number(satsHeader) : undefined
|
|
137
|
+
const payMsg =
|
|
138
|
+
sats != null && Number.isFinite(sats)
|
|
139
|
+
? `Pay ${sats} sats for ${method} ${url}?`
|
|
140
|
+
: `Server requires payment (402) for ${method} ${url}. Continue?`
|
|
141
|
+
|
|
142
|
+
if (!opts.yes) {
|
|
143
|
+
const ok = await confirm({ message: payMsg })
|
|
144
|
+
if (isCancel(ok) || !ok) fatal('Payment cancelled.')
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
res = await auth.fetch(url, init)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const text = await res.text()
|
|
151
|
+
let parsed: unknown = text
|
|
152
|
+
const ct = res.headers.get('content-type') ?? ''
|
|
153
|
+
if (ct.includes('application/json') && text.length > 0) {
|
|
154
|
+
try {
|
|
155
|
+
parsed = JSON.parse(text)
|
|
156
|
+
} catch {
|
|
157
|
+
/* keep raw */
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (opts.json) {
|
|
162
|
+
output(
|
|
163
|
+
{
|
|
164
|
+
status: res.status,
|
|
165
|
+
ok: res.ok,
|
|
166
|
+
headers: Object.fromEntries(res.headers.entries()),
|
|
167
|
+
body: parsed,
|
|
168
|
+
},
|
|
169
|
+
opts,
|
|
170
|
+
)
|
|
171
|
+
if (!res.ok) process.exit(1)
|
|
172
|
+
return
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (!opts.quiet) {
|
|
176
|
+
console.log(`${res.status} ${res.statusText || ''}`.trim())
|
|
177
|
+
}
|
|
178
|
+
if (text.length > 0) {
|
|
179
|
+
console.log(
|
|
180
|
+
typeof parsed === 'string' ? parsed : JSON.stringify(parsed, null, 2),
|
|
181
|
+
)
|
|
182
|
+
}
|
|
183
|
+
if (!res.ok) process.exit(1)
|
|
184
|
+
} finally {
|
|
185
|
+
await destroy()
|
|
186
|
+
}
|
|
187
|
+
}
|
package/src/commands/locks.ts
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Lock commands
|
|
2
|
+
* Lock commands — list, bsv (lock), unlock.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { listLocks, lockBsv, unlockBsv } from '@1sat/actions'
|
|
6
6
|
import { confirm, isCancel } from '@clack/prompts'
|
|
7
7
|
import type { GlobalFlags } from '../args'
|
|
8
8
|
import { extractFlag } from '../args'
|
|
9
|
+
import { idFromTags } from '../beef'
|
|
9
10
|
import { loadContext } from '../context'
|
|
10
11
|
import { printCommandHelp } from '../help'
|
|
11
12
|
import { loadKey } from '../keys'
|
|
12
|
-
import { fatal,
|
|
13
|
+
import { fatal, formatLabel, formatValue, output } from '../output'
|
|
13
14
|
|
|
14
15
|
export async function handleLocksCommand(
|
|
15
16
|
args: string[],
|
|
@@ -18,10 +19,12 @@ export async function handleLocksCommand(
|
|
|
18
19
|
const [subcommand, ...rest] = args
|
|
19
20
|
|
|
20
21
|
switch (subcommand) {
|
|
21
|
-
case '
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
case 'list':
|
|
23
|
+
case 'info': // deprecated alias — still summary-friendly
|
|
24
|
+
return locksList(rest, opts)
|
|
25
|
+
case 'bsv':
|
|
26
|
+
case 'lock': // deprecated alias
|
|
27
|
+
return locksBsv(rest, opts)
|
|
25
28
|
case 'unlock':
|
|
26
29
|
return locksUnlock(rest, opts)
|
|
27
30
|
default:
|
|
@@ -32,89 +35,99 @@ export async function handleLocksCommand(
|
|
|
32
35
|
}
|
|
33
36
|
}
|
|
34
37
|
|
|
35
|
-
async function
|
|
38
|
+
async function locksList(_args: string[], opts: GlobalFlags): Promise<void> {
|
|
36
39
|
const privateKey = await loadKey()
|
|
37
|
-
const { ctx, destroy } = await loadContext(privateKey, {
|
|
38
|
-
chain: opts.chain,
|
|
39
|
-
})
|
|
40
|
+
const { ctx, destroy } = await loadContext(privateKey, { chain: opts.chain })
|
|
40
41
|
|
|
41
42
|
try {
|
|
42
|
-
const
|
|
43
|
+
const result = await listLocks.execute(ctx, {})
|
|
43
44
|
|
|
44
45
|
if (opts.json) {
|
|
45
|
-
output(
|
|
46
|
+
output(result.outputs, opts)
|
|
46
47
|
return
|
|
47
48
|
}
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
'
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
if (result.outputs.length === 0) {
|
|
51
|
+
output('No locks found.', opts)
|
|
52
|
+
return
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
let total = 0
|
|
56
|
+
for (const o of result.outputs) {
|
|
57
|
+
const id = idFromTags(o.tags) ?? ''
|
|
58
|
+
const until = o.tags?.find((t) => t.startsWith('until:'))?.slice(6) ?? '?'
|
|
59
|
+
total += o.satoshis
|
|
60
|
+
console.log(
|
|
61
|
+
` ${formatValue(id)} ${formatValue(String(o.satoshis))} sats until ${formatLabel(until)} ${formatValue(o.outpoint)}`,
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
console.log(`\n ${result.outputs.length} lock(s), ${total} sats total.`)
|
|
54
65
|
} finally {
|
|
55
66
|
await destroy()
|
|
56
67
|
}
|
|
57
68
|
}
|
|
58
69
|
|
|
59
|
-
async function
|
|
70
|
+
async function locksBsv(args: string[], opts: GlobalFlags): Promise<void> {
|
|
60
71
|
const satsStr = extractFlag(args, '--sats')
|
|
61
|
-
const
|
|
72
|
+
const untilStr = extractFlag(args, '--until') ?? extractFlag(args, '--blocks')
|
|
62
73
|
|
|
63
74
|
if (!satsStr) fatal('Missing --sats <amount>')
|
|
64
|
-
if (!
|
|
75
|
+
if (!untilStr) fatal('Missing --until <block-height>')
|
|
65
76
|
|
|
66
77
|
const satoshis = Number(satsStr)
|
|
67
78
|
if (!Number.isFinite(satoshis) || satoshis <= 0) {
|
|
68
79
|
fatal('--sats must be a positive number')
|
|
69
80
|
}
|
|
70
81
|
|
|
71
|
-
const until = Number(
|
|
82
|
+
const until = Number(untilStr)
|
|
72
83
|
if (!Number.isFinite(until) || until <= 0) {
|
|
73
|
-
fatal('--
|
|
84
|
+
fatal('--until must be a positive block height')
|
|
74
85
|
}
|
|
75
86
|
|
|
76
87
|
if (!opts.yes) {
|
|
77
88
|
const ok = await confirm({
|
|
78
89
|
message: `Lock ${satoshis} satoshis until block ${until}?`,
|
|
79
90
|
})
|
|
80
|
-
if (isCancel(ok) || !ok)
|
|
81
|
-
fatal('Lock cancelled.')
|
|
82
|
-
}
|
|
91
|
+
if (isCancel(ok) || !ok) fatal('Lock cancelled.')
|
|
83
92
|
}
|
|
84
93
|
|
|
85
94
|
const privateKey = await loadKey()
|
|
86
|
-
const { ctx, destroy } = await loadContext(privateKey, {
|
|
87
|
-
chain: opts.chain,
|
|
88
|
-
})
|
|
95
|
+
const { ctx, destroy } = await loadContext(privateKey, { chain: opts.chain })
|
|
89
96
|
|
|
90
97
|
try {
|
|
91
98
|
const result = await lockBsv.execute(ctx, {
|
|
92
99
|
requests: [{ satoshis, until }],
|
|
93
100
|
})
|
|
94
|
-
|
|
95
|
-
if (result.error) {
|
|
96
|
-
fatal(result.error)
|
|
97
|
-
}
|
|
98
|
-
|
|
101
|
+
if (result.error) fatal(result.error)
|
|
99
102
|
output(opts.json ? result : { txid: result.txid }, opts)
|
|
100
103
|
} finally {
|
|
101
104
|
await destroy()
|
|
102
105
|
}
|
|
103
106
|
}
|
|
104
107
|
|
|
105
|
-
async function locksUnlock(
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
108
|
+
async function locksUnlock(args: string[], opts: GlobalFlags): Promise<void> {
|
|
109
|
+
const ids = extractFlag(args, '--ids')
|
|
110
|
+
?.split(',')
|
|
111
|
+
.map((s) => s.trim())
|
|
112
|
+
.filter(Boolean)
|
|
110
113
|
|
|
111
|
-
|
|
112
|
-
const
|
|
114
|
+
if (!opts.yes) {
|
|
115
|
+
const ok = await confirm({
|
|
116
|
+
message: ids?.length
|
|
117
|
+
? `Unlock ${ids.length} lock(s)?`
|
|
118
|
+
: 'Unlock all matured locks?',
|
|
119
|
+
})
|
|
120
|
+
if (isCancel(ok) || !ok) fatal('Unlock cancelled.')
|
|
121
|
+
}
|
|
113
122
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
123
|
+
const privateKey = await loadKey()
|
|
124
|
+
const { ctx, destroy } = await loadContext(privateKey, { chain: opts.chain })
|
|
117
125
|
|
|
126
|
+
try {
|
|
127
|
+
const result = await unlockBsv.execute(ctx, {
|
|
128
|
+
...(ids?.length ? { ids } : {}),
|
|
129
|
+
})
|
|
130
|
+
if (result.error) fatal(result.error)
|
|
118
131
|
output(opts.json ? result : { txid: result.txid }, opts)
|
|
119
132
|
} finally {
|
|
120
133
|
await destroy()
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MessageBox commands — pull paymail / P2P inbox into the wallet.
|
|
3
|
+
*
|
|
4
|
+
* 1sat messagebox sync [--url <host>] [--box <name>]
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { syncMessages } from '@1sat/actions'
|
|
8
|
+
import type { GlobalFlags } from '../args'
|
|
9
|
+
import { extractFlag } from '../args'
|
|
10
|
+
import { loadContext } from '../context'
|
|
11
|
+
import { printCommandHelp } from '../help'
|
|
12
|
+
import { loadKey } from '../keys'
|
|
13
|
+
import { output } from '../output'
|
|
14
|
+
|
|
15
|
+
export async function handleMessageboxCommand(
|
|
16
|
+
args: string[],
|
|
17
|
+
opts: GlobalFlags,
|
|
18
|
+
): Promise<void> {
|
|
19
|
+
const [subcommand, ...rest] = args
|
|
20
|
+
|
|
21
|
+
switch (subcommand) {
|
|
22
|
+
case 'sync':
|
|
23
|
+
return messageboxSync(rest, opts)
|
|
24
|
+
default:
|
|
25
|
+
printCommandHelp('messagebox', opts.json)
|
|
26
|
+
if (subcommand && subcommand !== 'help') {
|
|
27
|
+
process.exit(1)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function messageboxSync(
|
|
33
|
+
args: string[],
|
|
34
|
+
opts: GlobalFlags,
|
|
35
|
+
): Promise<void> {
|
|
36
|
+
const url = extractFlag(args, '--url')
|
|
37
|
+
const box = extractFlag(args, '--box')
|
|
38
|
+
|
|
39
|
+
const privateKey = await loadKey()
|
|
40
|
+
const { ctx, destroy } = await loadContext(privateKey, {
|
|
41
|
+
chain: opts.chain,
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
const result = await syncMessages.execute(ctx, {
|
|
46
|
+
...(url ? { messageboxUrl: url } : {}),
|
|
47
|
+
...(box ? { messageBox: box } : {}),
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
if (opts.json) {
|
|
51
|
+
output(result, opts)
|
|
52
|
+
return
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
console.log(`\nprocessed: ${result.processed} failed: ${result.failed}\n`)
|
|
56
|
+
} finally {
|
|
57
|
+
await destroy()
|
|
58
|
+
}
|
|
59
|
+
}
|