]> git.codecow.com Git - libnemo.git/commitdiff
Refactor RPC class to reference psuedo-namespaced environment variables and utilize...
authorChris Duncan <chris@codecow.com>
Tue, 4 Aug 2026 17:27:12 +0000 (10:27 -0700)
committerChris Duncan <chris@codecow.com>
Tue, 4 Aug 2026 17:27:12 +0000 (10:27 -0700)
README.md
sample.env
sample.env.mjs
src/lib/rpc/index.ts
test/GLOBALS.mjs
test/test.refresh-accounts.mjs
test/test.tools.mjs

index 6ca67b2671ad9d3f101500a24460eb2e30eef164..17baf08d13ba9f1ab3725389691b14a72b075ae5 100644 (file)
--- a/README.md
+++ b/README.md
@@ -240,8 +240,10 @@ try {
 
 #### Requesting proof-of-work from an online service
 
+Instantiating Rpc object with API key included for `Authorization` header
+
 ```javascript
-const node = new Rpc("https://nano-node.example.com/");
+const node = new Rpc("https://nano-node.example.com/", 'api-key-example-123456789');
 try {
   await block.pow("https://nano-node.example.com/");
 } catch (err) {
@@ -251,8 +253,16 @@ try {
 
 #### Processing a block on the network
 
+Using process environment to set `Authorization` header
+
+```console
+#!/usr/env/bash
+
+export LIBNEMO_RPC_AUTHORIZATION = 'api-key-example-123456789'
+```
+
 ```javascript
-const node = new Rpc("https://nano-node.example.com", "nodes-api-key");
+const node = new Rpc("https://nano-node.example.com");
 try {
   const hash = await block.process("https://nano-node.example.com/");
 } catch (err) {
index f2fd965a7866fd7d3f5b807459bb657f5d58e2fa..b1f6ab24831b19c2c11cd6c5da9ea71e27e547c8 100644 (file)
@@ -2,6 +2,5 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 
 # Save this file as `.env` and replace the following with real values
-NODE_URL="https://rpc.example.com"
-API_KEY_NAME="api_key"
-LIBNEMO_RPC_API_KEY="fedcba9876543210fedcba9876543210"
+LIBNEMO_RPC_URL="https://rpc.example.com"
+LIBNEMO_RPC_AUTHORIZATION="fedcba9876543210fedcba9876543210"
index 5e5284e730e5eaef613690b7975171c013895857..1b61f5f2243f2b8354fd74d125642fc3017feaeb 100644 (file)
@@ -5,7 +5,6 @@
 
 // Save this file as `env.mjs` and replace the following with real values
 export const env = {
-       NODE_URL: "https://rpc.example.com",
-       API_KEY_NAME: "api_key",
-       LIBNEMO_RPC_API_KEY: "fedcba9876543210fedcba9876543210"
+       LIBNEMO_RPC_URL: "https://rpc.example.com",
+       LIBNEMO_RPC_AUTHORIZATION: "fedcba9876543210fedcba9876543210"
 }
index c79e663788d598e0832c94f6f74a7900967538da..38c295b1becb556cce4337ca67782172db8512a3 100644 (file)
@@ -6,23 +6,25 @@ export { Schema }
 
 /**
  * Represents a Nano network node. It primarily consists of a URL which will
- * accept RPC calls, and an optional API key header construction can be passed if
- * required by the node. Once instantiated, the Rpc object can be used to call
- * any action supported by the Nano protocol. The URL protocol must be HTTPS; any
- * other value will be changed automatically.
+ * accept RPC calls; an optional authentication header name can be passed if an
+ * API key is required by the node. Once instantiated, the Rpc object can be
+ * used to call any action supported by the Nano protocol.
+ *
+ * The URL protocol must be HTTPS; any other protocol will be changed to
+ * `https:` automatically.
  */
 export class Rpc {
-       #u: URL
-       #n?: string
+       #url: URL
+       #auth?: string
 
        /**
-        * @param {(string|URL)} url
-        * @param {string} [apiKeyName]
+        * @param {(string|URL)} url Nano network node
+        * @param {string} [auth] optional API key
         */
-       constructor (url: string | URL, apiKeyName?: string) {
-               this.#u = new URL(url)
-               this.#u.protocol = 'https:'
-               this.#n = apiKeyName
+       constructor (url: string | URL, auth?: string) {
+               this.#url = new URL(url)
+               this.#url.protocol = 'https:'
+               this.#auth = auth
        }
 
        /**
@@ -36,10 +38,12 @@ export class Rpc {
        async post (action: unknown, data: unknown): Promise<unknown> {
                const env = typeof process !== 'undefined' && 'env' in process ? process.env : null
                this.#validate(action)
-               const headers: Record<string, string> = {}
-               headers['Content-Type'] = 'application/json'
-               if (this.#n && env?.LIBNEMO_RPC_API_KEY) {
-                       headers[this.#n] = env.LIBNEMO_RPC_API_KEY
+               const headers: Record<string, string> = {
+                       'Content-Type': 'application/json'
+               }
+               const auth = this.#auth ?? env?.LIBNEMO_RPC_AUTHORIZATION
+               if (auth) {
+                       headers['Authorization'] = auth
                }
                if (data !== undefined && typeof data !== 'object') {
                        throw new TypeError('Invalid RPC post data')
@@ -51,7 +55,7 @@ export class Rpc {
                reqBody.action = action.toLowerCase()
 
                const aborter = new AbortController()
-               const req = new Request(this.#u, {
+               const req = new Request(this.#url, {
                        signal: aborter.signal,
                        method: 'POST',
                        headers,
@@ -63,17 +67,13 @@ export class Rpc {
                }, 10000)
                try {
                        const res = await fetch(req)
+                       const { status, statusText } = res
                        const resBody = await res.json()
-                       if (res.status !== 200) {
-                               throw new Error(`${res.status} ${res.statusText}`, { cause: resBody })
-                       }
-                       if (resBody.error != null) {
-                               const msg = resBody.message == null
-                                       ? resBody.error
-                                       : `${resBody.error} ${resBody.message}`
-                               throw new Error(msg)
+                       const { error, message } = resBody
+                       if (status !== 200 || error != null) {
+                               throw new Error(`${status} ${statusText}`, { cause: { error, message } })
                        }
-                       return resBody
+                       return message
                } catch (err) {
                        console.error(err)
                        throw new Error(`RPC ${action} request failed`, { cause: err })
index b6159e220ab8f567238a335a0cd91cb5bea0897b..c5fdc8b51a63976c75cf119d2b03cf94073ef9f6 100644 (file)
@@ -2,7 +2,12 @@
 //! SPDX-License-Identifier: GPL-3.0-or-later
 
 //@ts-nocheck
-export { env } from '../env.mjs'
+import { Rpc } from 'libnemo'
+import { env } from '../env.mjs'
+
+export { env }
+export const isNode = globalThis !== globalThis.window
+export const rpc = new Rpc(env?.LIBNEMO_RPC_URL ?? '', env.LIBNEMO_RPC_AUTHORIZATION)
 
 if (globalThis.sessionStorage == null) {
        let _sessionStorage = {}
@@ -55,8 +60,6 @@ const queue = {
        }
 }
 
-export const isNode = globalThis !== globalThis.window
-
 let NodeTestSuite, NodeTestTest
 if (isNode) {
        ({ suite: NodeTestSuite, test: NodeTestTest } = await import('node:test'))
index 387ea1573e55cc7500c7441dbf36f5570d0df4d7..a4f55ce993f3c72add46d4f8b510bc376c2d1a93 100644 (file)
@@ -4,13 +4,12 @@
 'use strict'
 
 import { Account, Rpc, Wallet } from 'libnemo'
-import { assert, env, suite, test } from './GLOBALS.mjs'
+import { assert, rpc, suite, test } from './GLOBALS.mjs'
 import { NANO_TEST_VECTORS, TEST_PASSWORD } from './VECTORS.mjs'
 
-const rpc = new Rpc(env.NODE_URL ?? '', env.API_KEY_NAME)
-
 await Promise.all([
        suite('Refreshing account info', { skip: false }, async () => {
+
                await test('fetch balance, frontier, and representative', async () => {
                        const wallet = await Wallet.load('BIP-44', TEST_PASSWORD, NANO_TEST_VECTORS.BIP39_SEED)
                        await wallet.unlock(TEST_PASSWORD)
index 8ce86c5d5c9060736a28711eb0e095071ebd4cce..5f6a307069f76286363b616e50ff9675484b9dae 100644 (file)
@@ -3,12 +3,10 @@
 \r
 'use strict'\r
 \r
-import { Rpc, Tools, Wallet } from 'libnemo'\r
-import { assert, click, env, suite, test } from './GLOBALS.mjs'\r
+import { Tools, Wallet } from 'libnemo'\r
+import { assert, click, rpc, suite, test } from './GLOBALS.mjs'\r
 import { MAX_RAW, MAX_SUPPLY, NANO_TEST_VECTORS, TEST_PASSWORD } from './VECTORS.mjs'\r
 \r
-const rpc = new Rpc(env?.NODE_URL ?? '', env?.API_KEY_NAME)\r
-\r
 await Promise.all([\r
        suite('Tools unit conversion tests', async () => {\r
 \r