@1sat/cli 0.0.124 → 0.0.126

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/dist/cli.js CHANGED
@@ -1486,15 +1486,15 @@ var init_help = __esm(() => {
1486
1486
  {
1487
1487
  group: "Server",
1488
1488
  name: "serve",
1489
- description: "Run unified host server (storage + accounts + paymail + messagebox) and/or monitor (config under server.* in config.json)",
1489
+ description: "Run unified host server (accounts + paymail + messagebox), wallet storage server and/or monitor (config under server.* in config.json)",
1490
1490
  subcommands: [
1491
1491
  {
1492
1492
  name: "(no subcommand)",
1493
1493
  description: "Host server + monitor daemon"
1494
1494
  },
1495
1495
  {
1496
- name: "wallet",
1497
- description: "Wallet storage server only (BRC-100 HTTP)"
1496
+ name: "storage",
1497
+ description: "Wallet storage server only (wallet-toolbox StorageServer, BRC-100 HTTP)"
1498
1498
  },
1499
1499
  { name: "monitor", description: "Monitor daemon only" },
1500
1500
  {
@@ -3615,7 +3615,9 @@ async function remoteAdd(args, opts) {
3615
3615
  });
3616
3616
  const config = loadConfig();
3617
3617
  try {
3618
- const client = new StorageClient(walletResult.wallet, url);
3618
+ const client = new StorageClient(walletResult.wallet, url, {
3619
+ binaryRequests: true
3620
+ });
3619
3621
  await walletResult.storage.addWalletStorageProvider(client);
3620
3622
  if (!walletResult.storage.isActiveEnabled) {
3621
3623
  const localKey = config.storageIdentityKey ?? "1sat-cli-default";
@@ -4183,8 +4185,9 @@ import {
4183
4185
  KnexHandleCertStore,
4184
4186
  KnexPendingStore,
4185
4187
  createHostServer,
4186
- createWalletServer
4188
+ createStorageServer
4187
4189
  } from "@1sat/wallet-server";
4190
+ import { StorageProvider } from "@bsv/wallet-toolbox";
4188
4191
  import { initLogger as initLogger2 } from "evlog";
4189
4192
  import knexLib from "knex";
4190
4193
  async function handleServeCommand(args, opts) {
@@ -4216,7 +4219,7 @@ function resolveMode(subcommand) {
4216
4219
  if (!subcommand)
4217
4220
  return "all";
4218
4221
  switch (subcommand) {
4219
- case "wallet":
4222
+ case "storage":
4220
4223
  case "monitor":
4221
4224
  case "wallet-api":
4222
4225
  return subcommand;
@@ -4321,9 +4324,18 @@ async function runWithStorage(resolved, mode) {
4321
4324
  }
4322
4325
  };
4323
4326
  }
4327
+ if (mode === "storage") {
4328
+ const server = startStorageServer(resolved, walletResult);
4329
+ return {
4330
+ stop: async () => {
4331
+ await server.close();
4332
+ await walletResult.destroy();
4333
+ }
4334
+ };
4335
+ }
4324
4336
  const runMonitor = mode === "monitor" || mode === "all" && resolved.monitorEnabled;
4325
4337
  const accounts = mode === "monitor" ? undefined : await buildAccountsForServer(resolved, walletResult);
4326
- const serverHandle = mode === "monitor" ? undefined : await startWalletServer(resolved, walletResult, accounts, mode);
4338
+ const serverHandle = mode === "monitor" ? undefined : await startWalletServer(resolved, walletResult, accounts);
4327
4339
  if (runMonitor) {
4328
4340
  const r = resolved.repricer;
4329
4341
  const targets = [];
@@ -4376,29 +4388,29 @@ async function runWithStorage(resolved, mode) {
4376
4388
  }
4377
4389
  };
4378
4390
  }
4379
- async function startWalletServer(resolved, walletResult, accounts, mode) {
4380
- const config = loadConfig();
4381
- const sessionStoreCfg = config.server?.sessionStore;
4382
- const sessionStore = sessionStoreCfg?.redisUrl ? {
4383
- redisUrl: sessionStoreCfg.redisUrl,
4384
- ttlSeconds: sessionStoreCfg.ttlSeconds
4385
- } : undefined;
4386
- if (mode === "wallet") {
4387
- const handle2 = createWalletServer({
4388
- wallet: walletResult.wallet,
4389
- storage: walletResult.getActiveStorage(),
4390
- serverIdentityKey: walletResult.wallet.identityKey,
4391
- listen: { port: resolved.port, host: resolved.host },
4392
- publicPath: "/",
4393
- internalPath: null,
4394
- accounts: accounts?.walletServerAccounts,
4395
- sessionStore
4396
- });
4397
- const port2 = await handle2.start();
4398
- const notes2 = [resolved.accounts.enabled ? "accounts: on" : ""].filter(Boolean).join(", ");
4399
- console.log(`[wallet] listening on ${resolved.host}:${port2}${notes2 ? ` (${notes2})` : ""}`);
4400
- return { stop: () => handle2.stop() };
4391
+ function resolveSessionStore(config) {
4392
+ const sessionStore = config.server?.sessionStore;
4393
+ return sessionStore?.redisUrl ? { redisUrl: sessionStore.redisUrl, ttlSeconds: sessionStore.ttlSeconds } : undefined;
4394
+ }
4395
+ function startStorageServer(resolved, walletResult) {
4396
+ const storage = walletResult.getActiveStorage();
4397
+ if (!(storage instanceof StorageProvider)) {
4398
+ fatal("serve storage needs local storage active; activeRemote is set.");
4401
4399
  }
4400
+ const config = loadConfig();
4401
+ const server = createStorageServer({
4402
+ storage,
4403
+ wallet: walletResult.wallet,
4404
+ listen: { port: resolved.port, host: resolved.host },
4405
+ sessionStore: resolveSessionStore(config),
4406
+ trustProxy: config.server?.trustProxy
4407
+ });
4408
+ server.start();
4409
+ return server;
4410
+ }
4411
+ async function startWalletServer(resolved, walletResult, accounts) {
4412
+ const config = loadConfig();
4413
+ const sessionStore = resolveSessionStore(config);
4402
4414
  const serverCfg = config.server ?? {};
4403
4415
  const paymailCfg = serverCfg.paymail;
4404
4416
  const messageboxCfg = serverCfg.messagebox;
@@ -4596,7 +4608,7 @@ var init_social = __esm(() => {
4596
4608
  // src/commands/storage.ts
4597
4609
  import { join as join7 } from "node:path";
4598
4610
  import { StorageBunSqlite, nominateInvalidReqs } from "@1sat/wallet-node";
4599
- import { StorageProvider } from "@bsv/wallet-toolbox";
4611
+ import { StorageProvider as StorageProvider2 } from "@bsv/wallet-toolbox";
4600
4612
  async function handleStorageCommand(args, opts) {
4601
4613
  const [subcommand, ...rest] = args;
4602
4614
  switch (subcommand) {
@@ -4653,14 +4665,14 @@ async function openServeStorage(opts) {
4653
4665
  const config = loadConfig();
4654
4666
  const chain = opts.chain ?? config.chain ?? "main";
4655
4667
  const storageConfig = config.server?.storage ?? { provider: "bun-sqlite" };
4656
- const baseOptions = StorageProvider.createStorageBaseOptions(chain);
4668
+ const baseOptions = StorageProvider2.createStorageBaseOptions(chain);
4657
4669
  let storage;
4658
4670
  if (storageConfig.provider === "pg") {
4659
4671
  if (!storageConfig.dbUrl) {
4660
4672
  fatal("server.storage.provider is pg but server.storage.dbUrl is not set.");
4661
4673
  }
4662
- const { StoragePg } = await import("@1sat/wallet-node");
4663
- storage = new StoragePg({ ...baseOptions, dbUrl: storageConfig.dbUrl });
4674
+ const { StorageKnexPg } = await import("@1sat/wallet-node");
4675
+ storage = new StorageKnexPg({ ...baseOptions, dbUrl: storageConfig.dbUrl });
4664
4676
  } else {
4665
4677
  storage = new StorageBunSqlite({
4666
4678
  ...baseOptions,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@1sat/cli",
3
- "version": "0.0.124",
3
+ "version": "0.0.126",
4
4
  "description": "CLI for 1Sat Ordinals SDK",
5
5
  "type": "module",
6
6
  "main": "./dist/cli.js",
@@ -27,15 +27,15 @@
27
27
  ],
28
28
  "license": "MIT",
29
29
  "dependencies": {
30
- "@1sat/actions": "0.0.228",
31
- "@1sat/client": "0.0.57",
30
+ "@1sat/actions": "0.0.229",
31
+ "@1sat/client": "0.0.58",
32
32
  "@1sat/types": "0.0.49",
33
- "@1sat/wallet": "0.0.114",
34
- "@1sat/wallet-node": "0.0.81",
35
- "@1sat/wallet-server": "0.0.58",
33
+ "@1sat/wallet": "0.0.115",
34
+ "@1sat/wallet-node": "0.0.82",
35
+ "@1sat/wallet-server": "0.0.60",
36
36
  "@bopen-io/messagebox-server": "^1.3.2",
37
37
  "@bsv/sdk": "^2.6.0",
38
- "@bsv/wallet-toolbox": "^2.14.4",
38
+ "@bsv/wallet-toolbox": "npm:@bopen-io/wallet-toolbox@2.14.5",
39
39
  "@clack/prompts": "^0.8.0",
40
40
  "bitcoin-backup": "^0.0.11",
41
41
  "chalk": "^5.0.0",
@@ -84,7 +84,9 @@ async function remoteAdd(args: string[], opts: GlobalFlags): Promise<void> {
84
84
  const config = loadConfig()
85
85
 
86
86
  try {
87
- const client = new StorageClient(walletResult.wallet, url)
87
+ const client = new StorageClient(walletResult.wallet, url, {
88
+ binaryRequests: true,
89
+ })
88
90
  await walletResult.storage.addWalletStorageProvider(client)
89
91
 
90
92
  // When adding a backup, the remote may report itself as "active" which
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * `1sat serve` command — launch the unified host server and/or monitor.
3
3
  *
4
- * 1sat serve Host server (storage + accounts + paymail + messagebox) + monitor
5
- * 1sat serve wallet Wallet storage server only
4
+ * 1sat serve Host server (accounts + paymail + messagebox) + monitor
5
+ * 1sat serve storage Wallet storage server only (wallet-toolbox StorageServer)
6
6
  * 1sat serve monitor Monitor daemon only
7
7
  * 1sat serve wallet-api App-facing BRC-100 endpoint (headless; grants come from `1sat permissions`)
8
8
  *
@@ -29,14 +29,17 @@ import {
29
29
  KnexAccountStore,
30
30
  KnexHandleCertStore,
31
31
  KnexPendingStore,
32
+ type WalletServerAccounts,
32
33
  createHostServer,
33
- createWalletServer,
34
+ createStorageServer,
34
35
  } from '@1sat/wallet-server'
35
36
  import type { PrivateKey } from '@bsv/sdk'
37
+ import { StorageProvider } from '@bsv/wallet-toolbox'
36
38
  import { initLogger } from 'evlog'
37
39
  import knexLib from 'knex'
38
40
  import type { GlobalFlags } from '../args.js'
39
41
  import {
42
+ type OneSatCliConfig,
40
43
  type RepricerConfig,
41
44
  type ServerAccountsConfig,
42
45
  type ServerMessageboxConfig,
@@ -68,7 +71,7 @@ const DEFAULT_SATS_PER_UNIT = 1_000_000
68
71
  const DEFAULT_DURATION_BLOCKS = 4383
69
72
  const DEFAULT_STORAGE_IDENTITY_KEY = '1sat-cli-default'
70
73
 
71
- type ServeMode = 'all' | 'wallet' | 'monitor' | 'wallet-api'
74
+ type ServeMode = 'all' | 'storage' | 'monitor' | 'wallet-api'
72
75
 
73
76
  interface ResolvedServe {
74
77
  chain: 'main' | 'test'
@@ -132,7 +135,7 @@ export async function handleServeCommand(
132
135
  function resolveMode(subcommand: string | undefined): ServeMode | null {
133
136
  if (!subcommand) return 'all'
134
137
  switch (subcommand) {
135
- case 'wallet':
138
+ case 'storage':
136
139
  case 'monitor':
137
140
  case 'wallet-api':
138
141
  return subcommand
@@ -286,9 +289,21 @@ async function runWithStorage(
286
289
  }
287
290
  }
288
291
 
289
- // One active monitor per deployment: wallet mode never runs it, monitor
290
- // mode always does, all mode runs it unless server.monitor.enabled=false
291
- // (set on redundant host instances that share a dedicated serve monitor).
292
+ // storage serves only the wallet-toolbox StorageServer: no accounts, no
293
+ // monitor.
294
+ if (mode === 'storage') {
295
+ const server = startStorageServer(resolved, walletResult)
296
+ return {
297
+ stop: async () => {
298
+ await server.close()
299
+ await walletResult.destroy()
300
+ },
301
+ }
302
+ }
303
+
304
+ // One active monitor per deployment: monitor mode always runs it, all mode
305
+ // runs it unless server.monitor.enabled=false (set on redundant host
306
+ // instances that share a dedicated serve monitor).
292
307
  const runMonitor =
293
308
  mode === 'monitor' || (mode === 'all' && resolved.monitorEnabled)
294
309
 
@@ -300,7 +315,7 @@ async function runWithStorage(
300
315
  const serverHandle =
301
316
  mode === 'monitor'
302
317
  ? undefined
303
- : await startWalletServer(resolved, walletResult, accounts, mode)
318
+ : await startWalletServer(resolved, walletResult, accounts)
304
319
 
305
320
  if (runMonitor) {
306
321
  const r = resolved.repricer
@@ -370,44 +385,49 @@ async function runWithStorage(
370
385
  }
371
386
  }
372
387
 
388
+ /**
389
+ * BRC-104 sessions in Redis when server.sessionStore.redisUrl is set (several
390
+ * instances behind one load balancer); in memory otherwise.
391
+ */
392
+ function resolveSessionStore(
393
+ config: OneSatCliConfig,
394
+ ): { redisUrl: string; ttlSeconds?: number } | undefined {
395
+ const sessionStore = config.server?.sessionStore
396
+ return sessionStore?.redisUrl
397
+ ? { redisUrl: sessionStore.redisUrl, ttlSeconds: sessionStore.ttlSeconds }
398
+ : undefined
399
+ }
400
+
401
+ /** The wallet's own storage, served to remote wallets by the toolbox StorageServer. */
402
+ function startStorageServer(
403
+ resolved: ResolvedServe,
404
+ walletResult: NodeWalletResult,
405
+ ): ReturnType<typeof createStorageServer> {
406
+ const storage = walletResult.getActiveStorage()
407
+ if (!(storage instanceof StorageProvider)) {
408
+ fatal('serve storage needs local storage active; activeRemote is set.')
409
+ }
410
+ const config = loadConfig()
411
+ const server = createStorageServer({
412
+ storage,
413
+ wallet: walletResult.wallet,
414
+ listen: { port: resolved.port, host: resolved.host },
415
+ sessionStore: resolveSessionStore(config),
416
+ trustProxy: config.server?.trustProxy,
417
+ })
418
+ server.start()
419
+ return server
420
+ }
421
+
373
422
  async function startWalletServer(
374
423
  resolved: ResolvedServe,
375
424
  walletResult: NodeWalletResult,
376
425
  accounts: AccountsRuntime | undefined,
377
- mode: ServeMode,
378
426
  ): Promise<{ stop(): Promise<void> }> {
379
427
  const config = loadConfig()
428
+ const sessionStore = resolveSessionStore(config)
380
429
 
381
- const sessionStoreCfg = config.server?.sessionStore
382
- const sessionStore = sessionStoreCfg?.redisUrl
383
- ? {
384
- redisUrl: sessionStoreCfg.redisUrl,
385
- ttlSeconds: sessionStoreCfg.ttlSeconds,
386
- }
387
- : undefined
388
-
389
- if (mode === 'wallet') {
390
- const handle = createWalletServer({
391
- wallet: walletResult.wallet,
392
- storage: walletResult.getActiveStorage(),
393
- serverIdentityKey: walletResult.wallet.identityKey,
394
- listen: { port: resolved.port, host: resolved.host },
395
- publicPath: '/',
396
- internalPath: null,
397
- accounts: accounts?.walletServerAccounts,
398
- sessionStore,
399
- })
400
- const port = await handle.start()
401
- const notes = [resolved.accounts.enabled ? 'accounts: on' : '']
402
- .filter(Boolean)
403
- .join(', ')
404
- console.log(
405
- `[wallet] listening on ${resolved.host}:${port}${notes ? ` (${notes})` : ''}`,
406
- )
407
- return { stop: () => handle.stop() }
408
- }
409
-
410
- // Unified host: storage + accounts + paymail + messagebox. The account
430
+ // Unified host: accounts + paymail + messagebox. The account
411
431
  // registry is always on: it is the paymail user-domain backend and the
412
432
  // entitlement gate for paymail resolution and messagebox delivery.
413
433
  const serverCfg = config.server ?? {}
@@ -508,9 +528,7 @@ function createMessageboxKnex(
508
528
  }
509
529
 
510
530
  interface AccountsRuntime {
511
- walletServerAccounts: NonNullable<
512
- Parameters<typeof createWalletServer>[0]['accounts']
513
- >
531
+ walletServerAccounts: WalletServerAccounts
514
532
  }
515
533
 
516
534
  async function buildAccountsForServer(
@@ -102,8 +102,8 @@ async function openServeStorage(opts: GlobalFlags): Promise<StorageProvider> {
102
102
  'server.storage.provider is pg but server.storage.dbUrl is not set.',
103
103
  )
104
104
  }
105
- const { StoragePg } = await import('@1sat/wallet-node')
106
- storage = new StoragePg({ ...baseOptions, dbUrl: storageConfig.dbUrl })
105
+ const { StorageKnexPg } = await import('@1sat/wallet-node')
106
+ storage = new StorageKnexPg({ ...baseOptions, dbUrl: storageConfig.dbUrl })
107
107
  } else {
108
108
  storage = new StorageBunSqlite({
109
109
  ...baseOptions,
package/src/config.ts CHANGED
@@ -181,6 +181,12 @@ export interface ServerConfig {
181
181
  * run behind one load balancer; unset keeps sessions in-memory.
182
182
  */
183
183
  sessionStore?: ServerSessionStoreConfig
184
+ /**
185
+ * Express `trust proxy` for `serve storage`, whose IP rate limit keys on
186
+ * the client address: a hop count, or an address/subnet list such as
187
+ * `"loopback"`. Set it behind a reverse proxy. Unset = the socket address.
188
+ */
189
+ trustProxy?: number | string | string[]
184
190
  /** Background monitor task loop. Defaults to enabled. */
185
191
  monitor?: ServerMonitorConfig
186
192
  }
package/src/help.ts CHANGED
@@ -743,15 +743,16 @@ export const COMMANDS: CommandSpec[] = [
743
743
  group: 'Server',
744
744
  name: 'serve',
745
745
  description:
746
- 'Run unified host server (storage + accounts + paymail + messagebox) and/or monitor (config under server.* in config.json)',
746
+ 'Run unified host server (accounts + paymail + messagebox), wallet storage server and/or monitor (config under server.* in config.json)',
747
747
  subcommands: [
748
748
  {
749
749
  name: '(no subcommand)',
750
750
  description: 'Host server + monitor daemon',
751
751
  },
752
752
  {
753
- name: 'wallet',
754
- description: 'Wallet storage server only (BRC-100 HTTP)',
753
+ name: 'storage',
754
+ description:
755
+ 'Wallet storage server only (wallet-toolbox StorageServer, BRC-100 HTTP)',
755
756
  },
756
757
  { name: 'monitor', description: 'Monitor daemon only' },
757
758
  {
@@ -64,7 +64,7 @@ const adminPermissionModules = Object.fromEntries(
64
64
  * Metadata encryption is left at the toolbox default (on), the same as
65
65
  * the served endpoint: the CLI writes encrypted descriptions and custom
66
66
  * instructions and reads them back decrypted. Nothing downstream loses by
67
- * that. `1sat serve wallet` is the wallet-toolbox *storage* interface, not
67
+ * that. `1sat serve storage` is the wallet-toolbox *storage* interface, not
68
68
  * a BRC-100 API — it moves opaque records and never interprets a
69
69
  * description — and the wallet at the far end (wallet-desktop, the
70
70
  * browser wallet, a remote CLI) runs its own permissions manager, which