nostr-bray 2.3.0 → 3.0.0

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/zap/tools.js CHANGED
@@ -1,23 +1,23 @@
1
1
  import { z } from 'zod';
2
- import { handleZapReceipts, handleZapDecode, handleZapSend, handleZapBalance, handleZapMakeInvoice, handleZapLookupInvoice, handleZapListTransactions, resolveNwcUri, loadWallets, saveWallets, parseNwcUri, } from './handlers.js';
2
+ import { handleZapReceipts, handleZapDecode, handleZapSend, handleZapBalance, handleZapMakeInvoice, handleZapLookupInvoice, handleZapListTransactions, resolveNwcUri, loadWallets, saveWallets, } from './handlers.js';
3
+ import { normaliseNwcUriFile } from './nwc-file.js';
3
4
  /** Resolve the NWC URI for the active identity, with per-identity and global fallback */
4
5
  function getNwcUri(deps) {
5
6
  return resolveNwcUri(deps.ctx, deps.walletsFile, deps.nwcUri);
6
7
  }
7
8
  export function registerZapTools(server, deps) {
8
9
  server.registerTool('zap-wallet-set', {
9
- description: 'Set the NWC wallet URI for the active identity. Each persona can have its own Lightning wallet.',
10
+ description: 'Set the private local file containing the NWC wallet URI for the active identity. The bearer URI never crosses MCP.',
10
11
  inputSchema: {
11
- nwcUri: z.string().describe('nostr+walletconnect:// URI for this identity'),
12
+ nwcUriFile: z.string().describe('Path to a local 0600 file containing the nostr+walletconnect:// URI'),
12
13
  },
13
- annotations: { readOnlyHint: false },
14
- }, async ({ nwcUri }) => {
15
- // Validate URI format
16
- parseNwcUri(nwcUri);
14
+ annotations: { readOnlyHint: false, destructiveHint: true },
15
+ }, async ({ nwcUriFile }) => {
16
+ const secretFile = normaliseNwcUriFile(nwcUriFile);
17
17
  const pubkey = deps.ctx.activePublicKeyHex;
18
18
  const npub = deps.ctx.activeNpub;
19
19
  const wallets = loadWallets(deps.walletsFile);
20
- wallets[pubkey] = nwcUri;
20
+ wallets[pubkey] = secretFile;
21
21
  saveWallets(deps.walletsFile, wallets);
22
22
  return {
23
23
  content: [{ type: 'text', text: JSON.stringify({
@@ -28,7 +28,7 @@ export function registerZapTools(server, deps) {
28
28
  };
29
29
  });
30
30
  server.registerTool('zap-wallet-clear', {
31
- description: 'Remove the NWC wallet for the active identity. Falls back to the global NWC_URI if set.',
31
+ description: 'Remove the NWC wallet file reference for the active identity. Falls back to global NWC_URI_FILE configuration.',
32
32
  annotations: { readOnlyHint: false },
33
33
  }, async () => {
34
34
  const pubkey = deps.ctx.activePublicKeyHex;
@@ -56,6 +56,10 @@ export function registerZapTools(server, deps) {
56
56
  }, async ({ invoice, confirm }) => {
57
57
  // Always decode first so the caller sees what they're paying
58
58
  const decoded = handleZapDecode(invoice);
59
+ if (decoded.expiry === undefined)
60
+ throw new Error('Invalid BOLT-11 invoice');
61
+ if (decoded.amountMsats === undefined)
62
+ throw new Error('Amountless BOLT-11 invoices are not supported');
59
63
  if (!confirm) {
60
64
  return {
61
65
  content: [{ type: 'text', text: JSON.stringify({
@@ -70,9 +74,10 @@ export function registerZapTools(server, deps) {
70
74
  return {
71
75
  content: [{ type: 'text', text: JSON.stringify({
72
76
  paid: true,
77
+ verified: result.verified,
73
78
  amountMsats: decoded.amountMsats,
74
- id: result.event.id,
75
- publish: result.publish,
79
+ paymentHash: result.paymentHash,
80
+ feesPaidMsats: result.fees_paid,
76
81
  }, null, 2) }],
77
82
  };
78
83
  });
@@ -82,7 +87,7 @@ export function registerZapTools(server, deps) {
82
87
  }, async () => {
83
88
  const result = await handleZapBalance(deps.ctx, deps.pool, { nwcUri: getNwcUri(deps) });
84
89
  return {
85
- content: [{ type: 'text', text: JSON.stringify({ id: result.event.id, publish: result.publish }, null, 2) }],
90
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
86
91
  };
87
92
  });
88
93
  server.registerTool('zap-make-invoice', {
@@ -97,7 +102,7 @@ export function registerZapTools(server, deps) {
97
102
  amountMsats, description, nwcUri: getNwcUri(deps),
98
103
  });
99
104
  return {
100
- content: [{ type: 'text', text: JSON.stringify({ id: result.event.id, publish: result.publish }, null, 2) }],
105
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
101
106
  };
102
107
  });
103
108
  server.registerTool('zap-lookup-invoice', {
@@ -112,7 +117,7 @@ export function registerZapTools(server, deps) {
112
117
  paymentHash, invoice, nwcUri: getNwcUri(deps),
113
118
  });
114
119
  return {
115
- content: [{ type: 'text', text: JSON.stringify({ id: result.event.id, publish: result.publish }, null, 2) }],
120
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
116
121
  };
117
122
  });
118
123
  server.registerTool('zap-list-transactions', {
@@ -127,7 +132,7 @@ export function registerZapTools(server, deps) {
127
132
  limit, offset, nwcUri: getNwcUri(deps),
128
133
  });
129
134
  return {
130
- content: [{ type: 'text', text: JSON.stringify({ id: result.event.id, publish: result.publish }, null, 2) }],
135
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
131
136
  };
132
137
  });
133
138
  server.registerTool('zap-receipts', {
package/llms-full.txt CHANGED
@@ -18,8 +18,7 @@ Single-process MCP server (stdio or HTTP transport) with 253 tools in 28 groups.
18
18
  | NOSTR_SECRET_KEY_FILE | Tier 3* | Path to file containing the secret key |
19
19
  | NOSTR_SECRET_KEY | Tier 4* | nsec bech32, 64-char hex, or BIP-39 mnemonic |
20
20
  | NOSTR_RELAYS | Yes | Comma-separated relay WebSocket URLs |
21
- | NWC_URI | No | Nostr Wallet Connect URI for zap operations |
22
- | NWC_URI_FILE | No | Path to file containing NWC URI |
21
+ | NWC_URI_FILE | No | Path to a private 0600 file containing the NWC URI |
23
22
  | TOR_PROXY | No | SOCKS5h proxy URL (e.g. socks5h://127.0.0.1:9050) |
24
23
  | ALLOW_CLEARNET_WITH_TOR | No | Set to "1" to allow clearnet relays with Tor |
25
24
  | NIP04_ENABLED | No | Set to "1" to enable legacy NIP-04 DMs |
@@ -608,11 +607,11 @@ Recommend relays for your use case. Strategies: balanced, privacy, performance,
608
607
  ### Zap Tools (9)
609
608
 
610
609
  #### zap-wallet-set
611
- Set the NWC wallet URI for the active identity. Each persona can have its own Lightning wallet.
612
- - Input: nwcUri (nostr+walletconnect:// URI)
610
+ Set the private local file containing the NWC wallet URI for the active identity. The bearer URI never crosses MCP.
611
+ - Input: nwcUriFile (path to a regular 0600 secret file)
613
612
 
614
613
  #### zap-wallet-clear
615
- Remove the NWC wallet for the active identity. Falls back to global NWC_URI.
614
+ Remove the NWC wallet file reference for the active identity. Falls back to global NWC_URI_FILE configuration.
616
615
  - No inputs
617
616
 
618
617
  #### zap-send
@@ -1130,7 +1129,9 @@ Execute an action found via search-actions.
1130
1129
  - Private keys never appear in tool responses
1131
1130
  - LRU cache with cryptographic zeroing on eviction (active entry never evicted)
1132
1131
  - Secrets deleted from process.env after parsing, references cleared after startup
1133
- - NWC secret buffers zeroised in try/finally after each operation
1132
+ - NWC uses @forgesworn/nwc-kit with NIP-44 v2 and authenticated wallet events
1133
+ - Returned payment preimages are verified against the challenged BOLT-11 invoice with farrier-kit
1134
+ - Caller-owned NWC URI strings cannot be erased; library-owned key byte arrays are zeroised in try/finally after each operation
1134
1135
  - NIP-04 disabled by default (requires explicit opt-in)
1135
1136
  - Tor proxy support via SOCKS5h with clearnet blocking enforced on runtime relay additions
1136
1137
  - Per-identity relay separation to prevent linking
package/llms.txt CHANGED
@@ -136,7 +136,7 @@ search-actions, execute-action
136
136
  - **Master/derived**: The master key derives child identities via nsec-tree. Children can be zeroised independently.
137
137
  - **NIP-65 relay chasing**: When messaging someone, bray fetches their NIP-65 relay list and writes to their preferred relays.
138
138
  - **NIP-17 default**: DMs use gift-wrapped NIP-17 by default. NIP-04 requires explicit opt-in.
139
- - **NWC wallet**: Per-persona Lightning wallets via Nostr Wallet Connect (NIP-47).
139
+ - **NWC wallet**: Per-persona Lightning wallets via Nostr Wallet Connect (NIP-47). Bearer URIs are accepted only from private local files, never MCP arguments or raw environment values.
140
140
  - **Dispatch protocol**: AI-to-AI task collaboration over encrypted NIP-17 DMs with NIP-89 capability discovery.
141
141
  - **CANARY groups**: Multi-member verification with time-rotating spoken words and silent duress signalling.
142
142
  - **Marketplace**: Discover, compare, and consume L402/x402 paid APIs announced via kind 31402.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nostr-bray",
3
- "version": "2.3.0",
3
+ "version": "3.0.0",
4
4
  "mcpName": "dev.forgesworn/bray",
5
5
  "description": "Trust-aware Nostr for AI and humans. Three dimensions of trust -- verification, proximity, and access -- woven into every interaction.",
6
6
  "type": "module",
@@ -115,10 +115,13 @@
115
115
  "build": "tsc && node scripts/build-widgets.mjs && node scripts/export-tool-schemas.mjs",
116
116
  "update:kind-registry": "node scripts/update-kind-registry.mjs",
117
117
  "test": "vitest run",
118
+ "test:release": "npm run check:publish-dependencies && npm test",
119
+ "check:publish-dependencies": "node scripts/check-publish-dependencies.mjs",
118
120
  "test:coverage": "vitest run --coverage",
119
121
  "test:watch": "vitest",
120
122
  "lint": "tsc --noEmit",
121
- "start": "node dist/index.js"
123
+ "start": "node dist/index.js",
124
+ "prepublishOnly": "npm run check:publish-dependencies && npm run build && npm test"
122
125
  },
123
126
  "keywords": [
124
127
  "nostr",
@@ -149,9 +152,10 @@
149
152
  "homepage": "https://github.com/forgesworn/bray#readme",
150
153
  "license": "MIT",
151
154
  "engines": {
152
- "node": ">=22.19.0"
155
+ "node": ">=24"
153
156
  },
154
157
  "dependencies": {
158
+ "@forgesworn/nwc-kit": "0.1.1",
155
159
  "@forgesworn/range-proof": "^2.0.1",
156
160
  "@forgesworn/ring-sig": "^3.0.0",
157
161
  "@forgesworn/shamir-words": "^1.0.4",
@@ -159,6 +163,7 @@
159
163
  "@modelcontextprotocol/sdk": "^1.27.1",
160
164
  "canary-kit": "^2.6.2",
161
165
  "dominion-protocol": "^1.0.0",
166
+ "farrier-kit": "1.1.2",
162
167
  "nostr-attestations": "^2.5.4",
163
168
  "nostr-tools": "^2.23.3",
164
169
  "nostr-veil": "^0.30.0",