@1sat/cli 0.0.51 → 0.0.53
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 -6
- package/scripts/resubmit-bsv21-discovery.ts +33 -0
- package/src/cli.ts +14 -5
- package/src/commands/config.ts +1 -6
- package/src/commands/identity.ts +1 -8
- package/src/commands/locks.ts +1 -5
- package/src/commands/opns.ts +1 -5
- package/src/commands/ordinals.ts +1 -9
- package/src/commands/remote.ts +1 -11
- package/src/commands/serve-messagebox.ts +233 -0
- package/src/commands/serve.ts +26 -9
- package/src/commands/social.ts +1 -3
- package/src/commands/sweep.ts +1 -4
- package/src/commands/tokens.ts +248 -16
- package/src/commands/tx.ts +1 -3
- package/src/commands/wallet.ts +1 -20
- package/src/config.ts +24 -0
- package/src/help.ts +719 -101
- package/src/types/messagebox-server.d.ts +15 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@1sat/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.53",
|
|
4
4
|
"description": "CLI for 1Sat Ordinals SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/cli.ts",
|
|
@@ -25,11 +25,12 @@
|
|
|
25
25
|
],
|
|
26
26
|
"license": "MIT",
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@1sat/actions": "0.0.
|
|
29
|
-
"@1sat/client": "0.0.
|
|
30
|
-
"@1sat/
|
|
31
|
-
"@1sat/
|
|
32
|
-
"@1sat/wallet-
|
|
28
|
+
"@1sat/actions": "0.0.117",
|
|
29
|
+
"@1sat/client": "0.0.27",
|
|
30
|
+
"@1sat/knex-bun-sqlite": "0.0.1",
|
|
31
|
+
"@1sat/types": "0.0.19",
|
|
32
|
+
"@1sat/wallet-node": "0.0.43",
|
|
33
|
+
"@1sat/wallet-server": "0.0.13",
|
|
33
34
|
"@bsv/sdk": "^2.0.13",
|
|
34
35
|
"@bsv/wallet-toolbox": "npm:@bopen-io/wallet-toolbox@2.1.21-parity-fix.2",
|
|
35
36
|
"chalk": "^5.0.0",
|
|
@@ -38,6 +39,7 @@
|
|
|
38
39
|
"dotenv": "^17.0.0",
|
|
39
40
|
"evlog": "^2.10.0",
|
|
40
41
|
"knex": "^3.1.0",
|
|
42
|
+
"@bopen-io/messagebox-server": "^1.1.5",
|
|
41
43
|
"pg": "^8.11.3"
|
|
42
44
|
},
|
|
43
45
|
"devDependencies": {
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One-off recovery script: re-submit a BSV21 deploy tx to the discovery
|
|
3
|
+
* overlay topic (tm_bsv21).
|
|
4
|
+
*
|
|
5
|
+
* Use when a deploy was broadcast on-chain but didn't reach the overlay
|
|
6
|
+
* (e.g. previous URL bug, network blip, server downtime).
|
|
7
|
+
*
|
|
8
|
+
* Usage: bun run scripts/resubmit-bsv21-discovery.ts <txid>
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { OneSatServices } from '@1sat/client'
|
|
12
|
+
|
|
13
|
+
const txid = process.argv[2]
|
|
14
|
+
if (!txid || !/^[0-9a-f]{64}$/i.test(txid)) {
|
|
15
|
+
console.error(
|
|
16
|
+
'Usage: bun run scripts/resubmit-bsv21-discovery.ts <txid>\n' +
|
|
17
|
+
' txid must be a 64-char hex string',
|
|
18
|
+
)
|
|
19
|
+
process.exit(1)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const services = new OneSatServices('main')
|
|
23
|
+
|
|
24
|
+
console.log(`Fetching BEEF for ${txid}...`)
|
|
25
|
+
const beef = await services.getBeefForTxid(txid)
|
|
26
|
+
console.log(` beef has ${beef.txs.length} txs and ${beef.bumps.length} bumps`)
|
|
27
|
+
|
|
28
|
+
const atomicBeef = beef.toBinaryAtomic(txid)
|
|
29
|
+
console.log(` atomic BEEF size: ${atomicBeef.length} bytes`)
|
|
30
|
+
|
|
31
|
+
console.log('Submitting to tm_bsv21 discovery topic...')
|
|
32
|
+
const result = await services.overlay.submitBsv21Discovery(atomicBeef)
|
|
33
|
+
console.log('Result:', result)
|
package/src/cli.ts
CHANGED
|
@@ -22,7 +22,7 @@ import { handleSweepCommand } from './commands/sweep'
|
|
|
22
22
|
import { handleTokensCommand } from './commands/tokens'
|
|
23
23
|
import { handleTxCommand } from './commands/tx'
|
|
24
24
|
import { handleWalletCommand } from './commands/wallet'
|
|
25
|
-
import { printHelp, printVersion } from './help'
|
|
25
|
+
import { getCommand, printCommandHelp, printHelp, printVersion } from './help'
|
|
26
26
|
import { formatError } from './output'
|
|
27
27
|
|
|
28
28
|
const rawArgs = process.argv.slice(2)
|
|
@@ -37,8 +37,17 @@ async function main(): Promise<void> {
|
|
|
37
37
|
|
|
38
38
|
const [command, ...rest] = flags.rest
|
|
39
39
|
|
|
40
|
-
if (!command
|
|
41
|
-
printHelp()
|
|
40
|
+
if (!command) {
|
|
41
|
+
printHelp(flags.json)
|
|
42
|
+
process.exit(0)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (flags.help) {
|
|
46
|
+
if (getCommand(command)) {
|
|
47
|
+
printCommandHelp(command, flags.json)
|
|
48
|
+
} else {
|
|
49
|
+
printHelp(flags.json)
|
|
50
|
+
}
|
|
42
51
|
process.exit(0)
|
|
43
52
|
}
|
|
44
53
|
|
|
@@ -104,12 +113,12 @@ async function main(): Promise<void> {
|
|
|
104
113
|
break
|
|
105
114
|
|
|
106
115
|
case 'help':
|
|
107
|
-
printHelp()
|
|
116
|
+
printHelp(flags.json)
|
|
108
117
|
break
|
|
109
118
|
|
|
110
119
|
default:
|
|
111
120
|
console.error(formatError(`Unknown command: ${command}`))
|
|
112
|
-
printHelp()
|
|
121
|
+
printHelp(flags.json)
|
|
113
122
|
process.exit(1)
|
|
114
123
|
}
|
|
115
124
|
}
|
package/src/commands/config.ts
CHANGED
|
@@ -42,12 +42,7 @@ export async function handleConfigCommand(
|
|
|
42
42
|
case 'path':
|
|
43
43
|
return configPath(opts)
|
|
44
44
|
default:
|
|
45
|
-
printCommandHelp('config',
|
|
46
|
-
show: 'Display current configuration',
|
|
47
|
-
set: 'Set a config value (e.g. 1sat config set chain test)',
|
|
48
|
-
unset: 'Remove a configuration key (e.g. 1sat config unset chain)',
|
|
49
|
-
path: 'Print config directory path',
|
|
50
|
-
})
|
|
45
|
+
printCommandHelp('config', opts.json)
|
|
51
46
|
if (subcommand && subcommand !== 'help') {
|
|
52
47
|
process.exit(1)
|
|
53
48
|
}
|
package/src/commands/identity.ts
CHANGED
|
@@ -30,14 +30,7 @@ export async function handleIdentityCommand(
|
|
|
30
30
|
case 'verify':
|
|
31
31
|
return identityVerify(rest, opts)
|
|
32
32
|
default:
|
|
33
|
-
printCommandHelp('identity',
|
|
34
|
-
create: 'Create/publish a BAP identity',
|
|
35
|
-
'update-profile': 'Update BAP identity profile (--profile <json>)',
|
|
36
|
-
info: 'Show BAP identity information',
|
|
37
|
-
sign: 'Sign a message with identity key (--message <text> [--encoding <utf8|hex|base64>])',
|
|
38
|
-
verify:
|
|
39
|
-
'Verify a signed message (--message <text> --sig <sig> --address <addr>)',
|
|
40
|
-
})
|
|
33
|
+
printCommandHelp('identity', opts.json)
|
|
41
34
|
if (subcommand && subcommand !== 'help') {
|
|
42
35
|
process.exit(1)
|
|
43
36
|
}
|
package/src/commands/locks.ts
CHANGED
|
@@ -25,11 +25,7 @@ export async function handleLocksCommand(
|
|
|
25
25
|
case 'unlock':
|
|
26
26
|
return locksUnlock(rest, opts)
|
|
27
27
|
default:
|
|
28
|
-
printCommandHelp('locks',
|
|
29
|
-
info: 'Show lock information and maturity status',
|
|
30
|
-
lock: 'Time-lock BSV (--sats <amount> --blocks <n>)',
|
|
31
|
-
unlock: 'Unlock matured BSV locks',
|
|
32
|
-
})
|
|
28
|
+
printCommandHelp('locks', opts.json)
|
|
33
29
|
if (subcommand && subcommand !== 'help') {
|
|
34
30
|
process.exit(1)
|
|
35
31
|
}
|
package/src/commands/opns.ts
CHANGED
|
@@ -32,11 +32,7 @@ export async function handleOpnsCommand(
|
|
|
32
32
|
case 'lookup':
|
|
33
33
|
return opnsLookup(rest, opts)
|
|
34
34
|
default:
|
|
35
|
-
printCommandHelp('opns',
|
|
36
|
-
register: 'Register identity on an OpNS name (--outpoint <op>)',
|
|
37
|
-
deregister: 'Deregister identity from an OpNS name (--outpoint <op>)',
|
|
38
|
-
lookup: 'List OpNS names from wallet',
|
|
39
|
-
})
|
|
35
|
+
printCommandHelp('opns', opts.json)
|
|
40
36
|
if (subcommand && subcommand !== 'help') {
|
|
41
37
|
process.exit(1)
|
|
42
38
|
}
|
package/src/commands/ordinals.ts
CHANGED
|
@@ -46,15 +46,7 @@ export async function handleOrdinalsCommand(
|
|
|
46
46
|
case 'burn':
|
|
47
47
|
return ordinalsBurn(rest, opts)
|
|
48
48
|
default:
|
|
49
|
-
printCommandHelp('ordinals',
|
|
50
|
-
list: 'List owned ordinals/inscriptions',
|
|
51
|
-
mint: 'Mint a new ordinal inscription (--file <path> [--type <mime>] [--map <json>] [--sign-with-bap])',
|
|
52
|
-
transfer: 'Transfer an ordinal (--outpoint <op> --to <addr>)',
|
|
53
|
-
sell: 'List an ordinal for sale (--outpoint <op> --price <sats>)',
|
|
54
|
-
cancel: 'Cancel an ordinal listing (--outpoint <op>)',
|
|
55
|
-
buy: 'Purchase a listed ordinal (--outpoint <op>)',
|
|
56
|
-
burn: 'Burn ordinals permanently (--outpoints <op1,op2,...>)',
|
|
57
|
-
})
|
|
49
|
+
printCommandHelp('ordinals', opts.json)
|
|
58
50
|
if (subcommand && subcommand !== 'help') {
|
|
59
51
|
process.exit(1)
|
|
60
52
|
}
|
package/src/commands/remote.ts
CHANGED
|
@@ -38,17 +38,7 @@ export async function handleRemoteCommand(
|
|
|
38
38
|
case 'topup':
|
|
39
39
|
return remoteTopup(rest, opts)
|
|
40
40
|
default:
|
|
41
|
-
printCommandHelp('remote',
|
|
42
|
-
add: 'Add a remote storage as backup (1sat remote add <url>)',
|
|
43
|
-
list: 'List all configured remotes and their status',
|
|
44
|
-
delete:
|
|
45
|
-
'Remove a remote from the backup list (1sat remote delete <url>)',
|
|
46
|
-
'set-active':
|
|
47
|
-
'Switch active storage (1sat remote set-active <url | local>)',
|
|
48
|
-
status:
|
|
49
|
-
'Fetch GET /account/status from a remote (1sat remote status [url])',
|
|
50
|
-
topup: 'Buy capacity on a remote (1sat remote topup [url] [--units N])',
|
|
51
|
-
})
|
|
41
|
+
printCommandHelp('remote', opts.json)
|
|
52
42
|
if (subcommand && subcommand !== 'help') {
|
|
53
43
|
process.exit(1)
|
|
54
44
|
}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `1sat serve messagebox` — launch the BSV message-box server using the
|
|
3
|
+
* CLI's wallet identity.
|
|
4
|
+
*
|
|
5
|
+
* Storage mirrors the wallet's choice: SQLite via `@1sat/knex-bun-sqlite`
|
|
6
|
+
* when wallet storage is `bun-sqlite`, Postgres when wallet storage is `pg`.
|
|
7
|
+
*
|
|
8
|
+
* messagebox-server boots itself as a side effect of `import` once env vars
|
|
9
|
+
* are populated, so this handler:
|
|
10
|
+
* 1. Reads CLI config + private key
|
|
11
|
+
* 2. Composes env (SERVER_PRIVATE_KEY, PORT, KNEX_DB_*, WALLET_STORAGE_URL, …)
|
|
12
|
+
* 3. Dynamically imports `messagebox-server`
|
|
13
|
+
* 4. Awaits SIGINT/SIGTERM, then closes the HTTP and WebSocket servers
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { join } from 'node:path'
|
|
17
|
+
import { fileURLToPath } from 'node:url'
|
|
18
|
+
import type { PrivateKey } from '@bsv/sdk'
|
|
19
|
+
import type { GlobalFlags } from '../args'
|
|
20
|
+
import {
|
|
21
|
+
type ServerMessageboxConfig,
|
|
22
|
+
type ServerStorageConfig,
|
|
23
|
+
ensureDataDir,
|
|
24
|
+
loadConfig,
|
|
25
|
+
} from '../config'
|
|
26
|
+
import { loadKey } from '../keys'
|
|
27
|
+
import { fatal } from '../output'
|
|
28
|
+
|
|
29
|
+
const DEFAULT_MESSAGEBOX_PORT = 8771
|
|
30
|
+
const DEFAULT_WALLET_HOST = '127.0.0.1'
|
|
31
|
+
const DEFAULT_WALLET_PORT = 8100
|
|
32
|
+
const DEFAULT_PG_SCHEMA = 'messagebox'
|
|
33
|
+
|
|
34
|
+
interface ResolvedMessagebox {
|
|
35
|
+
chain: 'main' | 'test'
|
|
36
|
+
port: number
|
|
37
|
+
websockets: boolean
|
|
38
|
+
walletStorageUrl: string
|
|
39
|
+
knexClient: string
|
|
40
|
+
knexConnection: Record<string, unknown>
|
|
41
|
+
identityHex: string
|
|
42
|
+
identityPub: string
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
interface MessageboxModule {
|
|
46
|
+
http: { close(cb?: (err?: Error) => void): void }
|
|
47
|
+
io: { close(cb?: () => void): void } | null
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface MessageboxStoppable {
|
|
51
|
+
stop(): Promise<void>
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export async function startMessagebox(
|
|
55
|
+
opts: GlobalFlags,
|
|
56
|
+
): Promise<MessageboxStoppable> {
|
|
57
|
+
const resolved = await resolveMessagebox(opts)
|
|
58
|
+
applyEnv(resolved)
|
|
59
|
+
|
|
60
|
+
console.log(`[messagebox] starting on 0.0.0.0:${resolved.port}`)
|
|
61
|
+
console.log(`[messagebox] identity: ${resolved.identityPub.slice(0, 16)}…`)
|
|
62
|
+
console.log(`[messagebox] storage: ${resolved.knexClient}`)
|
|
63
|
+
console.log(`[messagebox] wallet: ${resolved.walletStorageUrl}`)
|
|
64
|
+
console.log(
|
|
65
|
+
`[messagebox] websockets: ${resolved.websockets ? 'enabled' : 'disabled'}`,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
// When the env-driven knexfile resolves to 'sqlite3', swap in our
|
|
69
|
+
// bun:sqlite-backed Knex dialect class and rewrite the migrations
|
|
70
|
+
// directory to an absolute path. ESM singleton semantics mean
|
|
71
|
+
// messagebox-server's app.ts gets the same (mutated) module instance
|
|
72
|
+
// when it imports the knexfile next.
|
|
73
|
+
if (resolved.knexClient === 'sqlite3') {
|
|
74
|
+
const knexfileUrl = import.meta.resolve(
|
|
75
|
+
'@bopen-io/messagebox-server/out/knexfile.js',
|
|
76
|
+
)
|
|
77
|
+
const migrationsDir = fileURLToPath(new URL('src/migrations/', knexfileUrl))
|
|
78
|
+
const [knexfile, dialect] = await Promise.all([
|
|
79
|
+
import('@bopen-io/messagebox-server/out/knexfile.js') as Promise<{
|
|
80
|
+
default: Record<
|
|
81
|
+
string,
|
|
82
|
+
{ client: unknown; migrations?: { directory: string } }
|
|
83
|
+
>
|
|
84
|
+
}>,
|
|
85
|
+
import('@1sat/knex-bun-sqlite'),
|
|
86
|
+
])
|
|
87
|
+
const Client = dialect.default
|
|
88
|
+
for (const env of ['development', 'staging', 'production']) {
|
|
89
|
+
const cfg = knexfile.default[env]
|
|
90
|
+
if (!cfg) continue
|
|
91
|
+
cfg.client = Client
|
|
92
|
+
if (cfg.migrations) cfg.migrations.directory = migrationsDir
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// messagebox-server boots itself when its index module is loaded.
|
|
97
|
+
const mbox = (await import(
|
|
98
|
+
'@bopen-io/messagebox-server'
|
|
99
|
+
)) as unknown as MessageboxModule
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
async stop() {
|
|
103
|
+
await new Promise<void>((resolve) => {
|
|
104
|
+
try {
|
|
105
|
+
mbox.http.close(() => resolve())
|
|
106
|
+
} catch {
|
|
107
|
+
resolve()
|
|
108
|
+
}
|
|
109
|
+
})
|
|
110
|
+
if (mbox.io) {
|
|
111
|
+
await new Promise<void>((resolve) => {
|
|
112
|
+
try {
|
|
113
|
+
mbox.io?.close(() => resolve())
|
|
114
|
+
} catch {
|
|
115
|
+
resolve()
|
|
116
|
+
}
|
|
117
|
+
})
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async function resolveMessagebox(
|
|
124
|
+
opts: GlobalFlags,
|
|
125
|
+
): Promise<ResolvedMessagebox> {
|
|
126
|
+
const config = loadConfig()
|
|
127
|
+
const server = config.server ?? {}
|
|
128
|
+
const messagebox: ServerMessageboxConfig = server.messagebox ?? {}
|
|
129
|
+
|
|
130
|
+
const chain = opts.chain ?? config.chain ?? 'main'
|
|
131
|
+
const port = resolvePort(messagebox.port)
|
|
132
|
+
const websockets = messagebox.websockets !== false
|
|
133
|
+
|
|
134
|
+
let privateKey: PrivateKey
|
|
135
|
+
try {
|
|
136
|
+
privateKey = await loadKey()
|
|
137
|
+
} catch (err) {
|
|
138
|
+
fatal((err as Error).message)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const identityHex = privateKey.toString()
|
|
142
|
+
const identityPub = privateKey.toPublicKey().toString()
|
|
143
|
+
|
|
144
|
+
const walletHost = server.host ?? DEFAULT_WALLET_HOST
|
|
145
|
+
const walletPort = server.port ?? DEFAULT_WALLET_PORT
|
|
146
|
+
const walletStorageUrl =
|
|
147
|
+
messagebox.walletStorageUrl ?? `http://${walletHost}:${walletPort}/`
|
|
148
|
+
|
|
149
|
+
const { knexClient, knexConnection } = resolveStorage(
|
|
150
|
+
server.storage ?? { provider: 'bun-sqlite' },
|
|
151
|
+
messagebox,
|
|
152
|
+
chain,
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
chain,
|
|
157
|
+
port,
|
|
158
|
+
websockets,
|
|
159
|
+
walletStorageUrl,
|
|
160
|
+
knexClient,
|
|
161
|
+
knexConnection,
|
|
162
|
+
identityHex,
|
|
163
|
+
identityPub,
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function resolvePort(configured: number | undefined): number {
|
|
168
|
+
const fromEnv = process.env.ONESAT_MESSAGEBOX_PORT
|
|
169
|
+
if (fromEnv && fromEnv.trim() !== '') {
|
|
170
|
+
const parsed = Number(fromEnv)
|
|
171
|
+
if (!Number.isFinite(parsed) || parsed <= 0 || parsed > 65535) {
|
|
172
|
+
fatal(
|
|
173
|
+
`ONESAT_MESSAGEBOX_PORT must be a valid port number, got: ${fromEnv}`,
|
|
174
|
+
)
|
|
175
|
+
}
|
|
176
|
+
return parsed
|
|
177
|
+
}
|
|
178
|
+
return configured ?? DEFAULT_MESSAGEBOX_PORT
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function resolveStorage(
|
|
182
|
+
storage: ServerStorageConfig,
|
|
183
|
+
messagebox: ServerMessageboxConfig,
|
|
184
|
+
chain: 'main' | 'test',
|
|
185
|
+
): { knexClient: string; knexConnection: Record<string, unknown> } {
|
|
186
|
+
if (storage.provider === 'bun-sqlite') {
|
|
187
|
+
const dataDir = ensureDataDir()
|
|
188
|
+
const filename =
|
|
189
|
+
messagebox.dbPath ?? join(dataDir, `messagebox-${chain}.db`)
|
|
190
|
+
// We pass `sqlite3` to satisfy the env-driven knexfile's alias check;
|
|
191
|
+
// the actual Client class is swapped in via ESM module mutation
|
|
192
|
+
// just before messagebox-server is imported.
|
|
193
|
+
return {
|
|
194
|
+
knexClient: 'sqlite3',
|
|
195
|
+
knexConnection: { filename },
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (storage.provider === 'pg') {
|
|
200
|
+
const schema = messagebox.pgSchema ?? DEFAULT_PG_SCHEMA
|
|
201
|
+
return {
|
|
202
|
+
knexClient: 'pg',
|
|
203
|
+
knexConnection: {
|
|
204
|
+
connectionString: storage.dbUrl,
|
|
205
|
+
searchPath: [schema, 'public'],
|
|
206
|
+
},
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
fatal(
|
|
211
|
+
`server.storage.provider '${(storage as { provider: string }).provider}' is not supported by 'serve messagebox'.`,
|
|
212
|
+
)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function applyEnv(resolved: ResolvedMessagebox): void {
|
|
216
|
+
// messagebox-server reads env at module-load time, so we set everything
|
|
217
|
+
// before the dynamic import. dotenv.config() inside messagebox-server
|
|
218
|
+
// does not overwrite values already set on process.env.
|
|
219
|
+
process.env.SERVER_PRIVATE_KEY = resolved.identityHex
|
|
220
|
+
process.env.BSV_NETWORK = resolved.chain === 'main' ? 'mainnet' : 'testnet'
|
|
221
|
+
process.env.PORT = String(resolved.port)
|
|
222
|
+
// messagebox-server's index.ts forces HTTP_PORT=3000 when NODE_ENV
|
|
223
|
+
// is anything other than 'development', ignoring our PORT entirely.
|
|
224
|
+
// Use 'development' so PORT is honored.
|
|
225
|
+
process.env.NODE_ENV = 'development'
|
|
226
|
+
process.env.ENABLE_WEBSOCKETS = resolved.websockets ? 'true' : 'false'
|
|
227
|
+
process.env.WALLET_STORAGE_URL = resolved.walletStorageUrl
|
|
228
|
+
process.env.KNEX_DB_CLIENT = resolved.knexClient
|
|
229
|
+
process.env.KNEX_DB_CONNECTION = JSON.stringify(resolved.knexConnection)
|
|
230
|
+
if (process.env.ENABLE_FIREBASE === undefined) {
|
|
231
|
+
process.env.ENABLE_FIREBASE = 'false'
|
|
232
|
+
}
|
|
233
|
+
}
|
package/src/commands/serve.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `1sat serve` command — launch wallet server and/or monitor.
|
|
3
3
|
*
|
|
4
|
-
* 1sat serve
|
|
5
|
-
* 1sat serve wallet
|
|
6
|
-
* 1sat serve monitor
|
|
4
|
+
* 1sat serve Wallet server + monitor daemon
|
|
5
|
+
* 1sat serve wallet Wallet server only
|
|
6
|
+
* 1sat serve monitor Monitor daemon only
|
|
7
|
+
* 1sat serve messagebox BSV message-box server
|
|
7
8
|
*
|
|
8
9
|
* The server wraps the same wallet instance the CLI uses. Storage, active
|
|
9
10
|
* remote, and backups all come from `~/.1sat/cli/config.json` via the same
|
|
@@ -13,6 +14,7 @@
|
|
|
13
14
|
* 1sat config set server.port 8100
|
|
14
15
|
* 1sat config set server.host 0.0.0.0
|
|
15
16
|
* 1sat config set server.accounts.enabled true
|
|
17
|
+
* 1sat config set server.messagebox.port 8771
|
|
16
18
|
*/
|
|
17
19
|
|
|
18
20
|
import { join } from 'node:path'
|
|
@@ -23,6 +25,7 @@ import {
|
|
|
23
25
|
} from '@1sat/wallet-node'
|
|
24
26
|
import { createWalletServer } from '@1sat/wallet-server'
|
|
25
27
|
import type { PrivateKey } from '@bsv/sdk'
|
|
28
|
+
import { initLogger } from 'evlog'
|
|
26
29
|
import type { GlobalFlags } from '../args'
|
|
27
30
|
import {
|
|
28
31
|
type ServerAccountsConfig,
|
|
@@ -34,6 +37,7 @@ import { printCommandHelp } from '../help'
|
|
|
34
37
|
import { loadKey } from '../keys'
|
|
35
38
|
import { clearMonitorPid, writeMonitorPid } from '../monitor-lock'
|
|
36
39
|
import { fatal } from '../output'
|
|
40
|
+
import { startMessagebox } from './serve-messagebox'
|
|
37
41
|
|
|
38
42
|
const DEFAULT_HOST = '127.0.0.1'
|
|
39
43
|
const DEFAULT_PORT = 8100
|
|
@@ -44,7 +48,7 @@ const DEFAULT_SATS_PER_UNIT = 1_000_000
|
|
|
44
48
|
const DEFAULT_DURATION_BLOCKS = 4383
|
|
45
49
|
const DEFAULT_STORAGE_IDENTITY_KEY = '1sat-cli-default'
|
|
46
50
|
|
|
47
|
-
type ServeMode = 'all' | 'wallet' | 'monitor'
|
|
51
|
+
type ServeMode = 'all' | 'wallet' | 'monitor' | 'messagebox'
|
|
48
52
|
|
|
49
53
|
interface ResolvedServe {
|
|
50
54
|
chain: 'main' | 'test'
|
|
@@ -78,15 +82,27 @@ export async function handleServeCommand(
|
|
|
78
82
|
const mode = resolveMode(subcommand)
|
|
79
83
|
|
|
80
84
|
if (mode === null) {
|
|
81
|
-
printCommandHelp('serve',
|
|
82
|
-
'(no subcommand)': 'Wallet server plus monitor daemon',
|
|
83
|
-
wallet: 'Wallet server only',
|
|
84
|
-
monitor: 'Monitor daemon only',
|
|
85
|
-
})
|
|
85
|
+
printCommandHelp('serve', opts.json)
|
|
86
86
|
if (subcommand && subcommand !== 'help') process.exit(1)
|
|
87
87
|
return
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
initLogger({ env: { service: `1sat-cli-serve-${mode}` } })
|
|
91
|
+
|
|
92
|
+
if (mode === 'messagebox') {
|
|
93
|
+
const handle = await startMessagebox(opts)
|
|
94
|
+
try {
|
|
95
|
+
await waitForShutdown()
|
|
96
|
+
} finally {
|
|
97
|
+
try {
|
|
98
|
+
await handle.stop()
|
|
99
|
+
} catch (err) {
|
|
100
|
+
console.error(`Error during shutdown: ${(err as Error).message}`)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return
|
|
104
|
+
}
|
|
105
|
+
|
|
90
106
|
const resolved = await resolveServe(opts)
|
|
91
107
|
const handles: Stoppable[] = []
|
|
92
108
|
|
|
@@ -109,6 +125,7 @@ function resolveMode(subcommand: string | undefined): ServeMode | null {
|
|
|
109
125
|
switch (subcommand) {
|
|
110
126
|
case 'wallet':
|
|
111
127
|
case 'monitor':
|
|
128
|
+
case 'messagebox':
|
|
112
129
|
return subcommand
|
|
113
130
|
default:
|
|
114
131
|
return null
|
package/src/commands/social.ts
CHANGED
|
@@ -22,9 +22,7 @@ export async function handleSocialCommand(
|
|
|
22
22
|
case 'post':
|
|
23
23
|
return socialPost(rest, opts)
|
|
24
24
|
default:
|
|
25
|
-
printCommandHelp('social',
|
|
26
|
-
post: 'Create an on-chain social post (--content <text> [--app <name>] [--content-type <text/plain|text/markdown>] [--tags <t1,t2>])',
|
|
27
|
-
})
|
|
25
|
+
printCommandHelp('social', opts.json)
|
|
28
26
|
if (subcommand && subcommand !== 'help') {
|
|
29
27
|
process.exit(1)
|
|
30
28
|
}
|
package/src/commands/sweep.ts
CHANGED
|
@@ -32,10 +32,7 @@ export async function handleSweepCommand(
|
|
|
32
32
|
case 'import':
|
|
33
33
|
return sweepImport(rest, opts)
|
|
34
34
|
default:
|
|
35
|
-
printCommandHelp('sweep',
|
|
36
|
-
scan: 'Scan an address for UTXOs (--wif <key>)',
|
|
37
|
-
import: 'Import UTXOs into wallet (--wif <key>)',
|
|
38
|
-
})
|
|
35
|
+
printCommandHelp('sweep', opts.json)
|
|
39
36
|
if (subcommand && subcommand !== 'help') {
|
|
40
37
|
process.exit(1)
|
|
41
38
|
}
|