txo_parser 0.0.1

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.
Files changed (5) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +131 -0
  3. package/cli.js +79 -0
  4. package/index.js +152 -0
  5. package/package.json +31 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 sandy-mount
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,131 @@
1
+ # TXO URI Parser
2
+
3
+ A pure JavaScript ES module for parsing and formatting TXO URIs according to the [TXO URI Specification v0.1](txo_uri.md).
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install txo_parser
9
+ ```
10
+
11
+ For global installation (to use the CLI):
12
+
13
+ ```bash
14
+ npm install -g txo_parser
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ### As a Module
20
+
21
+ ```javascript
22
+ import { parseTxoUri, isValidTxoUri, formatTxoUri } from 'txo_parser'
23
+
24
+ // Parse a TXO URI
25
+ const uri =
26
+ 'txo:btc:4e9c1ef9ba5fa3b0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0:0?amount=0.75'
27
+ const parsed = parseTxoUri(uri)
28
+ console.log(parsed)
29
+ // Output:
30
+ // {
31
+ // network: 'btc',
32
+ // txid: '4e9c1ef9ba5fa3b0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0',
33
+ // output: 0,
34
+ // amount: 0.75
35
+ // }
36
+
37
+ // Check if a URI is valid
38
+ console.log(isValidTxoUri(uri)) // true
39
+
40
+ // Format a JSON object into a TXO URI
41
+ const data = {
42
+ network: 'btc',
43
+ txid: '4e9c1ef9ba5fa3b0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0',
44
+ output: 0,
45
+ amount: 0.75,
46
+ script_type: 'p2tr'
47
+ }
48
+ const formattedUri = formatTxoUri(data)
49
+ console.log(formattedUri)
50
+ // Output: txo:btc:4e9c1ef9ba5fa3b0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0:0?amount=0.75&script_type=p2tr
51
+ ```
52
+
53
+ ### Using the CLI
54
+
55
+ The package includes a command-line tool that allows you to parse TXO URIs directly from the terminal:
56
+
57
+ ```bash
58
+ # Parse a TXO URI and output the full JSON
59
+ txo-parser "txo:btc:4e9c1ef9ba5fa3b0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0:0?amount=0.75"
60
+
61
+ # Extract just the txid
62
+ txo-parser "txo:btc:4e9c1ef9ba5fa3b0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0:0" --txid
63
+
64
+ # Extract the network
65
+ txo-parser "txo:btc:4e9c1ef9ba5fa3b0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0:0" --network
66
+
67
+ # Get help
68
+ txo-parser --help
69
+ ```
70
+
71
+ If you haven't installed the package globally, you can use `npx`:
72
+
73
+ ```bash
74
+ npx txo-parser "txo:btc:4e9c1ef9ba5fa3b0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0:0"
75
+ ```
76
+
77
+ ## API
78
+
79
+ ### `parseTxoUri(uri)`
80
+
81
+ Parses a TXO URI string and returns a JSON object.
82
+
83
+ - **Parameters:**
84
+ - `uri` (string): The TXO URI to parse
85
+ - **Returns:** Object with parsed components
86
+ - **Throws:** Error if URI format is invalid
87
+
88
+ ### `isValidTxoUri(uri)`
89
+
90
+ Checks if a string is a valid TXO URI.
91
+
92
+ - **Parameters:**
93
+ - `uri` (string): The URI to validate
94
+ - **Returns:** Boolean indicating validity
95
+
96
+ ### `formatTxoUri(data)`
97
+
98
+ Formats a JSON object into a TXO URI string.
99
+
100
+ - **Parameters:**
101
+ - `data` (object): The data to format (must include network, txid, and output)
102
+ - **Returns:** Formatted TXO URI string
103
+ - **Throws:** Error if required fields are missing or invalid
104
+
105
+ ## Testing
106
+
107
+ Run tests with:
108
+
109
+ ```bash
110
+ npm test
111
+ ```
112
+
113
+ ## Using in Node.js Projects
114
+
115
+ If you're using this in a Node.js project, make sure your package.json includes:
116
+
117
+ ```json
118
+ {
119
+ "type": "module"
120
+ }
121
+ ```
122
+
123
+ Or when importing in a CommonJS project:
124
+
125
+ ```javascript
126
+ import { parseTxoUri } from 'txo_parser/index.js'
127
+ ```
128
+
129
+ ## License
130
+
131
+ MIT
package/cli.js ADDED
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * TXO URI Parser CLI
5
+ *
6
+ * A command-line interface for the TXO URI parser
7
+ * Usage: txo-parser <uri> [options]
8
+ *
9
+ * Options:
10
+ * --<field> Output only the specified field (e.g., --txid, --network, --output)
11
+ * --help Show help
12
+ */
13
+
14
+ import { parseTxoUri, isValidTxoUri } from './index.js';
15
+
16
+ const args = process.argv.slice(2);
17
+
18
+ // Help message
19
+ function showHelp () {
20
+ console.log(`
21
+ TXO URI Parser CLI
22
+
23
+ Parse TXO URIs from the command line and output JSON or specific fields.
24
+
25
+ Usage:
26
+ txo-parser <uri> [options]
27
+
28
+ Options:
29
+ --<field> Output only the specified field (e.g., --txid, --network, --output)
30
+ --help Show this help message
31
+
32
+ Examples:
33
+ txo-parser "txo:btc:4e9c1ef9ba5fa3b0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabb:0"
34
+ txo-parser "txo:btc:4e9c1ef9ba5fa3b0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabb:0?amount=0.75" --txid
35
+ txo-parser "txo:btc:4e9c1ef9ba5fa3b0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabb:0" --network
36
+ `);
37
+ }
38
+
39
+ // Check for help
40
+ if (args.includes('--help') || args.length === 0) {
41
+ showHelp();
42
+ process.exit(0);
43
+ }
44
+
45
+ // Get the URI and options
46
+ const uri = args[0];
47
+ const options = args.slice(1);
48
+
49
+ try {
50
+ // Parse the URI
51
+ if (!isValidTxoUri(uri)) {
52
+ console.error('Error: Invalid TXO URI');
53
+ process.exit(1);
54
+ }
55
+
56
+ const parsed = parseTxoUri(uri);
57
+
58
+ // Check if a specific field was requested
59
+ if (options.length > 0) {
60
+ for (const option of options) {
61
+ if (option.startsWith('--')) {
62
+ const field = option.substring(2);
63
+ if (parsed[field] !== undefined) {
64
+ console.log(parsed[field]);
65
+ process.exit(0);
66
+ } else {
67
+ console.error(`Error: Field "${field}" not found in parsed URI`);
68
+ process.exit(1);
69
+ }
70
+ }
71
+ }
72
+ } else {
73
+ // Output the full JSON
74
+ console.log(JSON.stringify(parsed, null, 2));
75
+ }
76
+ } catch (error) {
77
+ console.error(`Error: ${error.message}`);
78
+ process.exit(1);
79
+ }
package/index.js ADDED
@@ -0,0 +1,152 @@
1
+ /**
2
+ * TXO URI Parser
3
+ * Implementation of the TXO URI Specification (v0.1)
4
+ *
5
+ * Format: txo:<network>:<txid>:<output>?key=value&key=value...
6
+ */
7
+
8
+ /**
9
+ * Parse a TXO URI and return a JSON object
10
+ * @param {string} uri - The TXO URI to parse
11
+ * @returns {object} - Parsed result as JSON
12
+ * @throws {Error} - If URI format is invalid
13
+ */
14
+ export function parseTxoUri (uri) {
15
+ if (!uri || typeof uri !== 'string') {
16
+ throw new Error('Invalid URI: URI must be a non-empty string');
17
+ }
18
+
19
+ // Split the URI into its components
20
+ const [scheme, network, txid, outputAndRest] = uri.split(':');
21
+
22
+ // Validate scheme
23
+ if (scheme !== 'txo') {
24
+ throw new Error('Invalid URI: Scheme must be "txo"');
25
+ }
26
+
27
+ // Validate network (allow lowercase letters and digits, 3-10 chars)
28
+ // Updated to match the specification - at least one letter and can include numbers
29
+ if (!network || !/^[a-z][a-z0-9]{2,9}$/.test(network)) {
30
+ throw new Error('Invalid URI: Network must be 3-10 characters (lowercase letters and digits), starting with a letter');
31
+ }
32
+
33
+ // Validate txid
34
+ if (!txid || !/^[0-9a-f]{64}$/.test(txid)) {
35
+ throw new Error('Invalid URI: TXID must be a 64-character lowercase hexadecimal');
36
+ }
37
+
38
+ if (!outputAndRest) {
39
+ throw new Error('Invalid URI: Missing output index');
40
+ }
41
+
42
+ // Split the output and query string
43
+ let output, queryString;
44
+ if (outputAndRest.includes('?')) {
45
+ [output, queryString] = outputAndRest.split('?');
46
+ } else {
47
+ output = outputAndRest;
48
+ queryString = '';
49
+ }
50
+
51
+ // Validate output
52
+ const outputNum = parseInt(output, 10);
53
+ if (isNaN(outputNum) || outputNum < 0 || outputNum > 4294967295 || !/^\d+$/.test(output)) {
54
+ throw new Error('Invalid URI: Output must be a non-negative integer (0-4294967295)');
55
+ }
56
+
57
+ // Parse query string
58
+ const queryParams = {};
59
+ if (queryString) {
60
+ const params = queryString.split('&');
61
+ params.forEach(param => {
62
+ if (param.includes('=')) {
63
+ const [key, value] = param.split('=');
64
+ // Convert key to lowercase for case-insensitivity
65
+ const normalizedKey = key.toLowerCase();
66
+
67
+ // Process specific key types
68
+ if (normalizedKey === 'amount') {
69
+ // Parse amount as a number
70
+ const amount = parseFloat(value);
71
+ if (!isNaN(amount)) {
72
+ queryParams[normalizedKey] = amount;
73
+ } else {
74
+ queryParams[normalizedKey] = value;
75
+ }
76
+ } else {
77
+ queryParams[normalizedKey] = value;
78
+ }
79
+ }
80
+ });
81
+ }
82
+
83
+ // Build the result object
84
+ const result = {
85
+ network,
86
+ txid,
87
+ output: outputNum,
88
+ ...queryParams
89
+ };
90
+
91
+ return result;
92
+ }
93
+
94
+ /**
95
+ * Validates if a string is a valid TXO URI
96
+ * @param {string} uri - The URI to validate
97
+ * @returns {boolean} - True if valid, false otherwise
98
+ */
99
+ export function isValidTxoUri (uri) {
100
+ try {
101
+ parseTxoUri(uri);
102
+ return true;
103
+ } catch (error) {
104
+ return false;
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Formats a JSON object into a TXO URI
110
+ * @param {object} data - The data to format
111
+ * @returns {string} - The formatted TXO URI
112
+ * @throws {Error} - If required fields are missing or invalid
113
+ */
114
+ export function formatTxoUri (data) {
115
+ // Validate required fields
116
+ if (!data.network || !data.txid || data.output === undefined) {
117
+ throw new Error('Missing required fields: network, txid, and output are required');
118
+ }
119
+
120
+ // Validate network (allow lowercase letters and digits, 3-10 chars)
121
+ if (!data.network || !/^[a-z][a-z0-9]{2,9}$/.test(data.network)) {
122
+ throw new Error('Invalid network: must be 3-10 characters (lowercase letters and digits), starting with a letter');
123
+ }
124
+
125
+ // Validate txid
126
+ if (!/^[0-9a-f]{64}$/.test(data.txid)) {
127
+ throw new Error('Invalid txid: must be a 64-character lowercase hexadecimal');
128
+ }
129
+
130
+ // Validate output
131
+ const output = parseInt(data.output, 10);
132
+ if (isNaN(output) || output < 0 || output > 4294967295) {
133
+ throw new Error('Invalid output: must be a non-negative integer (0-4294967295)');
134
+ }
135
+
136
+ // Build the base URI
137
+ let uri = `txo:${data.network}:${data.txid}:${output}`;
138
+
139
+ // Add query parameters
140
+ const queryParams = [];
141
+ Object.entries(data).forEach(([key, value]) => {
142
+ if (!['network', 'txid', 'output'].includes(key) && value !== undefined) {
143
+ queryParams.push(`${key.toLowerCase()}=${encodeURIComponent(value)}`);
144
+ }
145
+ });
146
+
147
+ if (queryParams.length > 0) {
148
+ uri += `?${queryParams.join('&')}`;
149
+ }
150
+
151
+ return uri;
152
+ }
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "txo_parser",
3
+ "version": "0.0.1",
4
+ "description": "Parser for TXO URI Specification (v0.1)",
5
+ "type": "module",
6
+ "main": "index.js",
7
+ "bin": {
8
+ "txo-parser": "./cli.js"
9
+ },
10
+ "scripts": {
11
+ "test": "node test.js"
12
+ },
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/sandy-mount/txo_parser.git"
16
+ },
17
+ "keywords": [
18
+ "txo",
19
+ "uri",
20
+ "parser",
21
+ "bitcoin",
22
+ "blockchain",
23
+ "cli"
24
+ ],
25
+ "author": "Melvin Carvalho",
26
+ "license": "MIT",
27
+ "bugs": {
28
+ "url": "https://github.com/sandy-mount/txo_parser/issues"
29
+ },
30
+ "homepage": "https://github.com/sandy-mount/txo_parser#readme"
31
+ }