bip-321 0.0.2 → 0.0.3

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/AGENTS.md ADDED
@@ -0,0 +1,261 @@
1
+ # BIP-321 Parser - Agent Development Guide
2
+
3
+ This document provides guidance for AI agents and developers working on the BIP-321 Bitcoin URI parser library.
4
+
5
+ ## Project Overview
6
+
7
+ A TypeScript/JavaScript library for parsing BIP-321 Bitcoin URIs with support for multiple payment methods (on-chain, Lightning, BOLT12, Silent Payments). Works natively in Node.js, browsers, and React Native without build tools.
8
+
9
+ ## Tech Stack
10
+
11
+ ### Runtime
12
+ - **Bun** - Primary development runtime
13
+ - Use `bun test` instead of `jest` or `vitest`
14
+ - Use `bun <file>` instead of `node <file>` or `ts-node <file>`
15
+ - Use `bun install` for package management
16
+
17
+ ### Key Dependencies
18
+
19
+ **Why These Specific Dependencies:**
20
+
21
+ 1. **`@scure/base`** (^2.0.0)
22
+ - Pure JavaScript base58, bech32, and bech32m encoding
23
+ - Works natively in all environments (Node.js, browser, React Native)
24
+ - No browserify or build tools needed
25
+ - Used for Base58 address decoding and bech32/bech32m validation
26
+
27
+ 2. **`@noble/hashes`** (^2.0.1)
28
+ - Pure JavaScript cryptographic hashing (SHA-256)
29
+ - Properly exports all modules (no import warnings)
30
+ - Used for Base58Check checksum validation
31
+ - Import path: `@noble/hashes/sha2.js` (with .js extension)
32
+
33
+ 3. **`bitcoinjs-lib`** (^7.0.0)
34
+ - Standard Bitcoin library for address validation
35
+ - Note: Taproot addresses require manual bech32m validation (ECC lib not initialized)
36
+ - Fallback to `@scure/base` for taproot validation
37
+
38
+ 4. **`light-bolt11-decoder`** (^3.2.0)
39
+ - Lightweight Lightning BOLT11 invoice parser
40
+ - No heavy dependencies
41
+
42
+ ### What We AVOID
43
+
44
+ - ❌ `bs58` - Requires browserify for browsers
45
+ - ❌ `bs58check` - Has module export warnings with `@noble/hashes`
46
+ - ❌ `express` or heavy server frameworks
47
+ - ❌ Build tools (webpack, browserify, rollup)
48
+
49
+ ## Development Commands
50
+
51
+ ```bash
52
+ # Run tests
53
+ bun test
54
+
55
+ # Run TypeScript type check
56
+ bun run check
57
+ # or
58
+ bunx tsc --noEmit
59
+
60
+ # Run examples
61
+ bun example.ts
62
+
63
+ # Run linter
64
+ bun run lint
65
+ ```
66
+
67
+ ## Project Structure
68
+
69
+ ```
70
+ bip-321/
71
+ ├── index.ts # Main parser implementation
72
+ ├── index.test.ts # Comprehensive test suite (39 tests)
73
+ ├── example.ts # Usage examples
74
+ ├── README.md # User documentation
75
+ ├── CLAUDE.md # Bun-specific development rules
76
+ ├── AGENTS.md # This file
77
+ ├── package.json # Dependencies and scripts
78
+ └── tsconfig.json # TypeScript configuration
79
+ ```
80
+
81
+ ## Key Design Decisions
82
+
83
+ ### 1. Network Detection Strategy
84
+
85
+ ```typescript
86
+ // Order matters for Lightning invoices!
87
+ // Check "lnbcrt" before "lnbc" to avoid false positives
88
+ if (lowerInvoice.startsWith("lnbcrt")) return "regtest";
89
+ else if (lowerInvoice.startsWith("lnbc")) return "mainnet";
90
+ else if (lowerInvoice.startsWith("lntbs")) return "signet";
91
+ else if (lowerInvoice.startsWith("lntb")) return "testnet";
92
+ ```
93
+
94
+ ### 2. Taproot Address Validation
95
+
96
+ bitcoinjs-lib requires ECC library initialization for taproot validation, so we use manual bech32m validation:
97
+
98
+ ```typescript
99
+ // Fallback to manual bech32/bech32m validation for taproot
100
+ const decoded = lowerAddress.startsWith("bc1p")
101
+ ? bech32m.decode(address as `${string}1${string}`, 90)
102
+ : bech32.decode(address as `${string}1${string}`, 90);
103
+ ```
104
+
105
+ ### 3. Base58Check Validation
106
+
107
+ Manual implementation using `@scure/base` + `@noble/hashes` to avoid dependencies with browser compatibility issues:
108
+
109
+ ```typescript
110
+ const decoded = base58.decode(address);
111
+ const payload = decoded.slice(0, -4);
112
+ const checksum = decoded.slice(-4);
113
+ const hash = sha256(sha256(payload)); // Double SHA-256
114
+ // Verify checksum matches
115
+ ```
116
+
117
+ ### 4. Query Parameter Parsing
118
+
119
+ Manual parsing instead of `URLSearchParams` to preserve encoded values for `pop` parameter:
120
+
121
+ ```typescript
122
+ // Parse manually to preserve encoded values for pop parameter
123
+ const paramPairs = queryString.split("&");
124
+ // Keep pop value encoded as per BIP-321 spec
125
+ ```
126
+
127
+ ## Supported Payment Methods
128
+
129
+ | Type | Parameter | Validation | Notes |
130
+ |------|-----------|------------|-------|
131
+ | On-chain | `address`, `bc`, `tb`, `bcrt` | Full validation with network check | P2PKH, P2SH, Segwit, Taproot |
132
+ | Lightning | `lightning` | BOLT11 decode + network detection | Mainnet, testnet, regtest, signet |
133
+ | BOLT12 | `lno` | Accept any value | Offers (minimal validation) |
134
+ | Silent Payments | `sp` | Prefix check (`sp1`) | BIP-352 addresses |
135
+
136
+ **Removed:** BIP-351 Private Payments (`pay` parameter) - Unused spec, nobody knows what it is
137
+
138
+ ## Testing Guidelines
139
+
140
+ ### Test Structure
141
+ - 39 tests covering all functionality
142
+ - Use `test()` and `expect()` from `bun:test`
143
+ - Group related tests with `describe()`
144
+ - Use non-null assertions (`!`) where values are guaranteed to exist
145
+
146
+ ### Example Test Pattern
147
+ ```typescript
148
+ test("parses mainnet address", () => {
149
+ const result = parseBIP321("bitcoin:1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa");
150
+ expect(result.valid).toBe(true);
151
+ expect(result.network).toBe("mainnet");
152
+ expect(result.paymentMethods[0]!.type).toBe("onchain");
153
+ });
154
+ ```
155
+
156
+ ## TypeScript Type Safety
157
+
158
+ All code must pass strict TypeScript checking with zero errors:
159
+
160
+ ```bash
161
+ bunx tsc --noEmit # Must pass with 0 errors
162
+ ```
163
+
164
+ ### Common Type Patterns
165
+
166
+ ```typescript
167
+ // Use non-null assertions for array access where guaranteed
168
+ result.paymentMethods[0]!.type
169
+
170
+ // Use optional chaining for potentially undefined values
171
+ result.paymentMethods[0]?.network
172
+
173
+ // Use nullish coalescing for fallbacks
174
+ byNetwork.mainnet?.length || 0
175
+ ```
176
+
177
+ ## BIP-321 Compliance Rules
178
+
179
+ 1. ✅ URI must start with `bitcoin:` (case-insensitive)
180
+ 2. ✅ `label`, `message`, `amount`, `pop` cannot appear multiple times
181
+ 3. ✅ `pop` and `req-pop` cannot both be present
182
+ 4. ✅ Required parameters (`req-*`) must be understood or URI is invalid
183
+ 5. ✅ Network-specific parameters must match address network
184
+ 6. ✅ `pop` scheme must not be forbidden (http, https, file, javascript, mailto)
185
+ 7. ✅ `amount` must be decimal BTC (no commas)
186
+ 8. ✅ At least one valid payment method required
187
+
188
+ ## Common Pitfalls
189
+
190
+ ### ❌ Don't Do This
191
+ ```typescript
192
+ // Wrong: Using .js imports breaks TypeScript
193
+ import { sha256 } from "@noble/hashes/sha2";
194
+
195
+ // Wrong: bs58 requires browserify
196
+ import bs58 from "bs58";
197
+
198
+ // Wrong: Checking lnbc before lnbcrt
199
+ if (invoice.startsWith("lnbc")) return "mainnet";
200
+ ```
201
+
202
+ ### ✅ Do This
203
+ ```typescript
204
+ // Correct: Use .js extension for @noble/hashes
205
+ import { sha256 } from "@noble/hashes/sha2.js";
206
+
207
+ // Correct: Use @scure/base (works everywhere)
208
+ import { base58 } from "@scure/base";
209
+
210
+ // Correct: Check longer prefix first
211
+ if (invoice.startsWith("lnbcrt")) return "regtest";
212
+ else if (invoice.startsWith("lnbc")) return "mainnet";
213
+ ```
214
+
215
+ ## Adding New Payment Methods
216
+
217
+ 1. Add to `PaymentMethod` type union
218
+ 2. Add parameter parsing in `parseBIP321()`
219
+ 3. Implement validation function if needed
220
+ 4. Add network detection if applicable
221
+ 5. Write tests for new method
222
+ 6. Update README documentation
223
+ 7. Add example usage
224
+
225
+ ## Browser Compatibility
226
+
227
+ All dependencies work natively in browsers via ES modules:
228
+
229
+ ```html
230
+ <script type="module">
231
+ import { parseBIP321 } from './index.js';
232
+ // No build tools needed!
233
+ </script>
234
+ ```
235
+
236
+ **No browserify, webpack, rollup, or any build tools required.**
237
+
238
+ ## Performance Considerations
239
+
240
+ - Address validation is synchronous and fast
241
+ - Lightning invoice decoding is the slowest operation
242
+ - No async operations in the entire codebase
243
+ - Manual Base58 validation is faster than external libraries
244
+
245
+ ## Contributing Guidelines
246
+
247
+ 1. All changes must pass TypeScript type check (`bun run check`)
248
+ 2. All tests must pass (`bun test`)
249
+ 3. Add tests for new functionality
250
+ 4. Update README for API changes
251
+ 5. Keep dependencies minimal and browser-compatible
252
+ 6. No build tools or polyfills
253
+ 7. Maintain cross-platform compatibility (Node.js, browser, React Native)
254
+
255
+ ## Resources
256
+
257
+ - [BIP-321 Specification](https://bips.dev/321/)
258
+ - [BIP-21 (Original)](https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki)
259
+ - [BIP-352 Silent Payments](https://github.com/bitcoin/bips/blob/master/bip-0352.mediawiki)
260
+ - [@scure/base Documentation](https://github.com/paulmillr/scure-base)
261
+ - [@noble/hashes Documentation](https://github.com/paulmillr/noble-hashes)
package/README.md CHANGED
@@ -5,30 +5,23 @@ A TypeScript/JavaScript library for parsing BIP-321 Bitcoin URI scheme. This lib
5
5
  ## Features
6
6
 
7
7
  - ✅ **Complete BIP-321 compliance** - Implements the full BIP-321 specification
8
- - ✅ **Multiple payment methods** - Supports on-chain, Lightning (BOLT11), BOLT12 offers, silent payments, and private payments
8
+ - ✅ **Multiple payment methods** - Supports on-chain, Lightning (BOLT11), BOLT12 offers, and silent payments
9
9
  - ✅ **Network detection** - Automatically detects mainnet, testnet, regtest, and signet networks
10
10
  - ✅ **Address validation** - Validates Bitcoin addresses (P2PKH, P2SH, Segwit v0, Taproot)
11
11
  - ✅ **Lightning invoice validation** - Validates BOLT11 Lightning invoices
12
- - ✅ **Cross-platform** - Works in Node.js, browsers, and React Native
13
- - ✅ **TypeScript support** - Fully typed with TypeScript definitions
14
- - ✅ **Proof of payment** - Supports pop/req-pop parameters for payment callbacks
15
- - ✅ **Comprehensive error handling** - Clear error messages for invalid URIs
16
12
 
17
13
  ```typescript
18
14
  import { parseBIP321, type BIP321ParseResult, type PaymentMethod } from "bip-321";
19
15
 
20
- // Fully typed result with autocomplete support
21
16
  const result: BIP321ParseResult = parseBIP321("bitcoin:...");
22
17
 
23
- // TypeScript knows all available properties
24
18
  result.valid; // boolean
25
19
  result.network; // "mainnet" | "testnet" | "regtest" | "signet" | undefined
26
20
  result.paymentMethods; // PaymentMethod[]
27
21
  result.errors; // string[]
28
22
 
29
- // Payment methods are also fully typed
30
23
  result.paymentMethods.forEach((method: PaymentMethod) => {
31
- method.type; // "onchain" | "lightning" | "lno" | "silent-payment" | "private-payment" | "other"
24
+ method.type; // "onchain" | "lightning" | "lno" | "silent-payment" | "other"
32
25
  method.network; // "mainnet" | "testnet" | "regtest" | "signet" | undefined
33
26
  method.valid; // boolean
34
27
  });
@@ -46,16 +39,6 @@ Or with npm:
46
39
  npm install bip-321
47
40
  ```
48
41
 
49
- ### Note on Dependencies
50
-
51
- This library uses modern, browser-native dependencies:
52
- - **`@scure/base`** - Pure JavaScript base58, bech32, and bech32m encoding (no browserify needed)
53
- - **`@noble/hashes`** - Pure JavaScript cryptographic hashing
54
- - **`bitcoinjs-lib`** - Bitcoin address validation
55
- - **`light-bolt11-decoder`** - Lightning invoice parsing
56
-
57
- All dependencies work natively in Node.js, browsers, and React Native without any build tools or polyfills required.
58
-
59
42
  ## Quick Start
60
43
 
61
44
  ```typescript
@@ -198,7 +181,7 @@ interface BIP321ParseResult {
198
181
 
199
182
  ```typescript
200
183
  interface PaymentMethod {
201
- type: "onchain" | "lightning" | "lno" | "silent-payment" | "private-payment" | "other";
184
+ type: "onchain" | "lightning" | "lno" | "silent-payment" | "other";
202
185
  value: string; // The actual address/invoice value
203
186
  network?: "mainnet" | "testnet" | "regtest" | "signet";
204
187
  valid: boolean; // Whether this payment method is valid
@@ -250,7 +233,6 @@ console.log(summary);
250
233
  | Lightning | `lightning` | BOLT11 Lightning invoices |
251
234
  | BOLT12 | `lno` | Lightning BOLT12 offers |
252
235
  | Silent Payments | `sp` | BIP352 Silent Payment addresses |
253
- | Private Payments | `pay` | BIP351 Private Payment addresses |
254
236
 
255
237
  ## Network Detection
256
238
 
package/index.test.ts CHANGED
@@ -186,12 +186,6 @@ describe("BIP-321 Parser", () => {
186
186
  expect(result.valid).toBe(true);
187
187
  expect(result.paymentMethods.length).toBe(2);
188
188
  });
189
-
190
- test("parses private payment address", () => {
191
- const result = parseBIP321("bitcoin:?pay=bip351address");
192
- expect(result.valid).toBe(true);
193
- expect(result.paymentMethods[0]!.type).toBe("private-payment");
194
- });
195
189
  });
196
190
 
197
191
  describe("Network-specific Parameters", () => {
package/index.ts CHANGED
@@ -4,13 +4,7 @@ import { sha256 } from "@noble/hashes/sha2.js";
4
4
  import { base58, bech32, bech32m } from "@scure/base";
5
5
 
6
6
  export interface PaymentMethod {
7
- type:
8
- | "onchain"
9
- | "lightning"
10
- | "lno"
11
- | "silent-payment"
12
- | "private-payment"
13
- | "other";
7
+ type: "onchain" | "lightning" | "lno" | "silent-payment" | "other";
14
8
  value: string;
15
9
  network?: "mainnet" | "testnet" | "regtest" | "signet";
16
10
  valid: boolean;
@@ -353,13 +347,6 @@ export function parseBIP321(uri: string): BIP321ParseResult {
353
347
  if (!isSilentPayment) {
354
348
  result.errors.push("Invalid silent payment address format");
355
349
  }
356
- } else if (lowerKey === "pay") {
357
- const decodedValue = decodeURIComponent(value);
358
- result.paymentMethods.push({
359
- type: "private-payment",
360
- value: decodedValue,
361
- valid: true,
362
- });
363
350
  } else if (
364
351
  lowerKey === "bc" ||
365
352
  lowerKey === "tb" ||
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bip-321",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "A TypeScript/JavaScript library for parsing BIP-321 Bitcoin URI scheme with support for multiple payment methods",
5
5
  "type": "module",
6
6
  "main": "./index.ts",
package/CLAUDE.md DELETED
@@ -1,107 +0,0 @@
1
- ---
2
-
3
- Default to using Bun instead of Node.js.
4
-
5
- - Use `bun <file>` instead of `node <file>` or `ts-node <file>`
6
- - Use `bun test` instead of `jest` or `vitest`
7
- - Use `bun build <file.html|file.ts|file.css>` instead of `webpack` or `esbuild`
8
- - Use `bun install` instead of `npm install` or `yarn install` or `pnpm install`
9
- - Use `bun run <script>` instead of `npm run <script>` or `yarn run <script>` or `pnpm run <script>`
10
- - Bun automatically loads .env, so don't use dotenv.
11
-
12
- ## APIs
13
-
14
- - `Bun.serve()` supports WebSockets, HTTPS, and routes. Don't use `express`.
15
- - `bun:sqlite` for SQLite. Don't use `better-sqlite3`.
16
- - `Bun.redis` for Redis. Don't use `ioredis`.
17
- - `Bun.sql` for Postgres. Don't use `pg` or `postgres.js`.
18
- - `WebSocket` is built-in. Don't use `ws`.
19
- - Prefer `Bun.file` over `node:fs`'s readFile/writeFile
20
- - Bun.$`ls` instead of execa.
21
-
22
- ## Testing
23
-
24
- Use `bun test` to run tests.
25
-
26
- ```ts#index.test.ts
27
- import { test, expect } from "bun:test";
28
-
29
- test("hello world", () => {
30
- expect(1).toBe(1);
31
- });
32
- ```
33
-
34
- ## Frontend
35
-
36
- Use HTML imports with `Bun.serve()`. Don't use `vite`. HTML imports fully support React, CSS, Tailwind.
37
-
38
- Server:
39
-
40
- ```ts#index.ts
41
- import index from "./index.html"
42
-
43
- Bun.serve({
44
- routes: {
45
- "/": index,
46
- "/api/users/:id": {
47
- GET: (req) => {
48
- return new Response(JSON.stringify({ id: req.params.id }));
49
- },
50
- },
51
- },
52
- // optional websocket support
53
- websocket: {
54
- open: (ws) => {
55
- ws.send("Hello, world!");
56
- },
57
- message: (ws, message) => {
58
- ws.send(message);
59
- },
60
- close: (ws) => {
61
- // handle close
62
- }
63
- },
64
- development: {
65
- hmr: true,
66
- console: true,
67
- }
68
- })
69
- ```
70
-
71
- HTML files can import .tsx, .jsx or .js files directly and Bun's bundler will transpile & bundle automatically. `<link>` tags can point to stylesheets and Bun's CSS bundler will bundle.
72
-
73
- ```html#index.html
74
- <html>
75
- <body>
76
- <h1>Hello, world!</h1>
77
- <script type="module" src="./frontend.tsx"></script>
78
- </body>
79
- </html>
80
- ```
81
-
82
- With the following `frontend.tsx`:
83
-
84
- ```tsx#frontend.tsx
85
- import React from "react";
86
-
87
- // import .css files directly and it works
88
- import './index.css';
89
-
90
- import { createRoot } from "react-dom/client";
91
-
92
- const root = createRoot(document.body);
93
-
94
- export default function Frontend() {
95
- return <h1>Hello, world!</h1>;
96
- }
97
-
98
- root.render(<Frontend />);
99
- ```
100
-
101
- Then, run index.ts
102
-
103
- ```sh
104
- bun --hot ./index.ts
105
- ```
106
-
107
- For more information, read the Bun API docs in `node_modules/bun-types/docs/**.md`.