@psalomo/jsonrpc-client 0.4.0 → 1.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/index.js CHANGED
@@ -27,27 +27,44 @@ __export(index_exports, {
27
27
  NearRpcClient: () => NearRpcClient,
28
28
  NearRpcError: () => NearRpcError,
29
29
  RPC_METHODS: () => import_jsonrpc_types3.RPC_METHODS,
30
- default: () => NearRpcClient
30
+ block: () => block,
31
+ broadcastTxAsync: () => broadcastTxAsync,
32
+ broadcastTxCommit: () => broadcastTxCommit,
33
+ changes: () => changes,
34
+ chunk: () => chunk,
35
+ clientConfig: () => clientConfig,
36
+ default: () => NearRpcClient,
37
+ defaultClient: () => defaultClient,
38
+ enableValidation: () => enableValidation,
39
+ experimentalChanges: () => experimentalChanges,
40
+ experimentalChangesInBlock: () => experimentalChangesInBlock,
41
+ experimentalCongestionLevel: () => experimentalCongestionLevel,
42
+ experimentalGenesisConfig: () => experimentalGenesisConfig,
43
+ experimentalLightClientBlockProof: () => experimentalLightClientBlockProof,
44
+ experimentalLightClientProof: () => experimentalLightClientProof,
45
+ experimentalMaintenanceWindows: () => experimentalMaintenanceWindows,
46
+ experimentalProtocolConfig: () => experimentalProtocolConfig,
47
+ experimentalReceipt: () => experimentalReceipt,
48
+ experimentalSplitStorageInfo: () => experimentalSplitStorageInfo,
49
+ experimentalTxStatus: () => experimentalTxStatus,
50
+ experimentalValidatorsOrdered: () => experimentalValidatorsOrdered,
51
+ gasPrice: () => gasPrice,
52
+ health: () => health,
53
+ lightClientProof: () => lightClientProof,
54
+ networkInfo: () => networkInfo,
55
+ nextLightClientBlock: () => nextLightClientBlock,
56
+ query: () => query,
57
+ sendTx: () => sendTx,
58
+ status: () => status,
59
+ tx: () => tx,
60
+ validators: () => validators,
61
+ viewAccessKey: () => viewAccessKey,
62
+ viewAccount: () => viewAccount,
63
+ viewFunction: () => viewFunction
31
64
  });
32
65
  module.exports = __toCommonJS(index_exports);
33
66
 
34
67
  // src/client.ts
35
- var import_jsonrpc_types = require("@psalomo/jsonrpc-types");
36
- var JsonRpcClientError = class extends Error {
37
- constructor(message, code, data) {
38
- super(message);
39
- this.code = code;
40
- this.data = data;
41
- this.name = "JsonRpcClientError";
42
- }
43
- };
44
- var JsonRpcNetworkError = class extends Error {
45
- constructor(message, originalError) {
46
- super(message);
47
- this.originalError = originalError;
48
- this.name = "JsonRpcNetworkError";
49
- }
50
- };
51
68
  function camelToSnake(str) {
52
69
  return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
53
70
  }
@@ -82,60 +99,61 @@ function convertKeysToCamelCase(obj) {
82
99
  }
83
100
  return converted;
84
101
  }
85
- var NearRpcClient = class {
102
+ var REQUEST_ID = "dontcare";
103
+ var JsonRpcClientError = class extends Error {
104
+ constructor(message, code, data) {
105
+ super(message);
106
+ this.code = code;
107
+ this.data = data;
108
+ this.name = "JsonRpcClientError";
109
+ }
110
+ };
111
+ var JsonRpcNetworkError = class extends Error {
112
+ constructor(message, originalError) {
113
+ super(message);
114
+ this.originalError = originalError;
115
+ this.name = "JsonRpcNetworkError";
116
+ }
117
+ };
118
+ var NearRpcClient = class _NearRpcClient {
86
119
  endpoint;
87
120
  headers;
88
121
  timeout;
89
122
  retries;
90
- validateResponses;
91
- requestIdCounter = 0;
123
+ validation;
92
124
  constructor(config) {
93
125
  if (typeof config === "string") {
94
126
  this.endpoint = config;
95
- this.headers = {
96
- "Content-Type": "application/json"
97
- };
127
+ this.headers = {};
98
128
  this.timeout = 3e4;
99
129
  this.retries = 3;
100
- this.validateResponses = true;
101
130
  } else {
102
131
  this.endpoint = config.endpoint;
103
- this.headers = {
104
- "Content-Type": "application/json",
105
- ...config.headers
106
- };
132
+ this.headers = config.headers || {};
107
133
  this.timeout = config.timeout || 3e4;
108
134
  this.retries = config.retries || 3;
109
- this.validateResponses = config.validateResponses ?? true;
135
+ if (config.validation) {
136
+ this.validation = config.validation;
137
+ }
110
138
  }
111
139
  }
112
140
  /**
113
- * Generate a unique request ID
141
+ * Make a raw JSON-RPC request
142
+ * This is used internally by the standalone RPC functions
114
143
  */
115
- generateRequestId() {
116
- return `near-rpc-${Date.now()}-${++this.requestIdCounter}`;
117
- }
118
- /**
119
- * Make a raw JSON-RPC call
120
- * This method is public to allow dynamic calls to any RPC method
121
- */
122
- async call(method, params) {
123
- const requestId = this.generateRequestId();
124
- const snakeCaseParams = params ? convertKeysToSnakeCase(params) : void 0;
144
+ async makeRequest(method, params) {
145
+ const snakeCaseParams = params ? convertKeysToSnakeCase(params) : params;
125
146
  const request = {
126
147
  jsonrpc: "2.0",
127
- id: requestId,
148
+ id: REQUEST_ID,
128
149
  method,
129
150
  params: snakeCaseParams
130
151
  };
131
- if (this.validateResponses) {
132
- try {
133
- import_jsonrpc_types.JsonRpcRequestSchema.parse(request);
134
- } catch (error) {
135
- throw new JsonRpcNetworkError(
136
- `Invalid request format: ${error instanceof Error ? error.message : "Unknown error"}`,
137
- error
138
- );
152
+ if (this.validation) {
153
+ if ("validateMethodRequest" in this.validation) {
154
+ this.validation.validateMethodRequest(method, request);
155
+ } else {
156
+ this.validation.validateRequest(request);
139
157
  }
140
158
  }
141
159
  let lastError = null;
@@ -145,84 +163,81 @@ var NearRpcClient = class {
145
163
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
146
164
  const response = await fetch(this.endpoint, {
147
165
  method: "POST",
148
- headers: this.headers,
166
+ headers: {
167
+ "Content-Type": "application/json",
168
+ ...this.headers
169
+ },
149
170
  body: JSON.stringify(request),
150
171
  signal: controller.signal
151
172
  });
152
173
  clearTimeout(timeoutId);
153
- const jsonResponse = await response.json();
154
- if (this.validateResponses) {
155
- try {
156
- import_jsonrpc_types.JsonRpcResponseSchema.parse(jsonResponse);
157
- } catch (error) {
158
- throw new JsonRpcClientError(
159
- `Invalid response format: ${error instanceof Error ? error.message : "Unknown error"}`
160
- );
161
- }
174
+ if (!response.ok) {
175
+ throw new JsonRpcNetworkError(
176
+ `HTTP error! status: ${response.status}`
177
+ );
178
+ }
179
+ let jsonResponse;
180
+ try {
181
+ jsonResponse = await response.json();
182
+ } catch (parseError) {
183
+ throw new JsonRpcNetworkError(
184
+ "Failed to parse JSON response",
185
+ parseError
186
+ );
162
187
  }
163
- const rpcResponse = jsonResponse;
164
- if (rpcResponse.error) {
188
+ if (this.validation) {
189
+ this.validation.validateResponse(jsonResponse);
190
+ }
191
+ if (jsonResponse.error) {
165
192
  throw new JsonRpcClientError(
166
- rpcResponse.error.message,
167
- rpcResponse.error.code,
168
- rpcResponse.error.data
193
+ jsonResponse.error.message,
194
+ jsonResponse.error.code,
195
+ jsonResponse.error.data
169
196
  );
170
197
  }
171
- if (!response.ok) {
172
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
198
+ const camelCaseResult = jsonResponse.result ? convertKeysToCamelCase(jsonResponse.result) : jsonResponse.result;
199
+ if (this.validation && "validateMethodResponse" in this.validation) {
200
+ const camelCaseResponse = {
201
+ ...jsonResponse,
202
+ result: camelCaseResult
203
+ };
204
+ this.validation.validateMethodResponse(method, camelCaseResponse);
173
205
  }
174
- const camelCaseResult = rpcResponse.result ? convertKeysToCamelCase(rpcResponse.result) : rpcResponse.result;
175
206
  return camelCaseResult;
176
207
  } catch (error) {
177
208
  lastError = error;
178
209
  if (error instanceof JsonRpcClientError) {
179
210
  throw error;
180
211
  }
181
- if (attempt < this.retries) {
182
- const delay = Math.min(1e3 * Math.pow(2, attempt), 1e4);
183
- await new Promise((resolve) => setTimeout(resolve, delay));
184
- continue;
212
+ if (attempt === this.retries) {
213
+ break;
185
214
  }
215
+ await new Promise(
216
+ (resolve) => setTimeout(resolve, Math.pow(2, attempt) * 1e3)
217
+ );
186
218
  }
187
219
  }
188
220
  throw new JsonRpcNetworkError(
189
- `Failed to make RPC call after ${this.retries + 1} attempts: ${lastError?.message}`,
190
- lastError
221
+ lastError?.message || "Request failed after all retries",
222
+ lastError || void 0
191
223
  );
192
224
  }
193
- };
194
- import_jsonrpc_types.RPC_METHODS.forEach((method) => {
195
- let methodName = method;
196
- if (methodName.startsWith("EXPERIMENTAL_")) {
197
- methodName = "experimental" + methodName.substring(13).replace(/_([a-z])/g, (_, letter) => letter.toUpperCase()).replace(/^([a-z])/, (_, letter) => letter.toUpperCase());
198
- } else {
199
- methodName = methodName.replace(
200
- /_([a-z])/g,
201
- (_, letter) => letter.toUpperCase()
202
- );
225
+ /**
226
+ * Create a new client with modified configuration
227
+ */
228
+ withConfig(config) {
229
+ return new _NearRpcClient({
230
+ endpoint: config.endpoint ?? this.endpoint,
231
+ headers: config.headers ?? this.headers,
232
+ timeout: config.timeout ?? this.timeout,
233
+ retries: config.retries ?? this.retries,
234
+ ...config.validation !== void 0 ? { validation: config.validation } : this.validation !== void 0 ? { validation: this.validation } : {}
235
+ });
203
236
  }
204
- NearRpcClient.prototype[methodName] = function(params) {
205
- return this.call(method, params);
206
- };
207
- });
208
- NearRpcClient.prototype.viewAccount = function(params) {
209
- return this.query({
210
- requestType: "view_account",
211
- ...params
212
- });
213
- };
214
- NearRpcClient.prototype.viewFunction = function(params) {
215
- return this.query({
216
- requestType: "call_function",
217
- ...params
218
- });
219
- };
220
- NearRpcClient.prototype.viewAccessKey = function(params) {
221
- return this.query({
222
- requestType: "view_access_key",
223
- ...params
224
- });
225
237
  };
238
+ var defaultClient = new NearRpcClient({
239
+ endpoint: "https://rpc.mainnet.near.org"
240
+ });
226
241
 
227
242
  // src/types.ts
228
243
  var NearRpcError = class extends Error {
@@ -237,6 +252,188 @@ var NearRpcError = class extends Error {
237
252
  // src/index.ts
238
253
  var import_jsonrpc_types2 = require("@psalomo/jsonrpc-types");
239
254
  var import_jsonrpc_types3 = require("@psalomo/jsonrpc-types");
255
+
256
+ // src/generated-types.ts
257
+ async function experimentalChanges(client, params) {
258
+ return client.makeRequest("EXPERIMENTAL_changes", params);
259
+ }
260
+ async function experimentalChangesInBlock(client, params) {
261
+ return client.makeRequest("EXPERIMENTAL_changes_in_block", params);
262
+ }
263
+ async function experimentalCongestionLevel(client, params) {
264
+ return client.makeRequest("EXPERIMENTAL_congestion_level", params);
265
+ }
266
+ async function experimentalGenesisConfig(client, params) {
267
+ return client.makeRequest("EXPERIMENTAL_genesis_config", params);
268
+ }
269
+ async function experimentalLightClientBlockProof(client, params) {
270
+ return client.makeRequest("EXPERIMENTAL_light_client_block_proof", params);
271
+ }
272
+ async function experimentalLightClientProof(client, params) {
273
+ return client.makeRequest("EXPERIMENTAL_light_client_proof", params);
274
+ }
275
+ async function experimentalMaintenanceWindows(client, params) {
276
+ return client.makeRequest("EXPERIMENTAL_maintenance_windows", params);
277
+ }
278
+ async function experimentalProtocolConfig(client, params) {
279
+ return client.makeRequest("EXPERIMENTAL_protocol_config", params);
280
+ }
281
+ async function experimentalReceipt(client, params) {
282
+ return client.makeRequest("EXPERIMENTAL_receipt", params);
283
+ }
284
+ async function experimentalSplitStorageInfo(client, params) {
285
+ return client.makeRequest("EXPERIMENTAL_split_storage_info", params);
286
+ }
287
+ async function experimentalTxStatus(client, params) {
288
+ return client.makeRequest("EXPERIMENTAL_tx_status", params);
289
+ }
290
+ async function experimentalValidatorsOrdered(client, params) {
291
+ return client.makeRequest("EXPERIMENTAL_validators_ordered", params);
292
+ }
293
+ async function block(client, params) {
294
+ return client.makeRequest("block", params);
295
+ }
296
+ async function broadcastTxAsync(client, params) {
297
+ return client.makeRequest("broadcast_tx_async", params);
298
+ }
299
+ async function broadcastTxCommit(client, params) {
300
+ return client.makeRequest("broadcast_tx_commit", params);
301
+ }
302
+ async function changes(client, params) {
303
+ return client.makeRequest("changes", params);
304
+ }
305
+ async function chunk(client, params) {
306
+ return client.makeRequest("chunk", params);
307
+ }
308
+ async function clientConfig(client, params) {
309
+ return client.makeRequest("client_config", params);
310
+ }
311
+ async function gasPrice(client, params) {
312
+ return client.makeRequest("gas_price", params);
313
+ }
314
+ async function health(client, params) {
315
+ return client.makeRequest("health", params);
316
+ }
317
+ async function lightClientProof(client, params) {
318
+ return client.makeRequest("light_client_proof", params);
319
+ }
320
+ async function networkInfo(client, params) {
321
+ return client.makeRequest("network_info", params);
322
+ }
323
+ async function nextLightClientBlock(client, params) {
324
+ return client.makeRequest("next_light_client_block", params);
325
+ }
326
+ async function query(client, params) {
327
+ return client.makeRequest("query", params);
328
+ }
329
+ async function sendTx(client, params) {
330
+ return client.makeRequest("send_tx", params);
331
+ }
332
+ async function status(client, params) {
333
+ return client.makeRequest("status", params);
334
+ }
335
+ async function tx(client, params) {
336
+ return client.makeRequest("tx", params);
337
+ }
338
+ async function validators(client, params) {
339
+ return client.makeRequest("validators", params);
340
+ }
341
+
342
+ // src/convenience.ts
343
+ async function viewAccount(client, params) {
344
+ const queryParams = params.blockId ? {
345
+ requestType: "view_account",
346
+ accountId: params.accountId,
347
+ blockId: params.blockId
348
+ } : {
349
+ requestType: "view_account",
350
+ accountId: params.accountId,
351
+ finality: params.finality || "final"
352
+ };
353
+ return query(client, queryParams);
354
+ }
355
+ async function viewFunction(client, params) {
356
+ const baseParams = {
357
+ requestType: "call_function",
358
+ accountId: params.accountId,
359
+ methodName: params.methodName,
360
+ argsBase64: params.argsBase64 ?? ""
361
+ // Default to empty string if no arguments
362
+ };
363
+ const queryParams = params.blockId ? { ...baseParams, blockId: params.blockId } : { ...baseParams, finality: params.finality || "final" };
364
+ return query(client, queryParams);
365
+ }
366
+ async function viewAccessKey(client, params) {
367
+ const queryParams = params.blockId ? {
368
+ requestType: "view_access_key",
369
+ accountId: params.accountId,
370
+ publicKey: params.publicKey,
371
+ blockId: params.blockId
372
+ } : {
373
+ requestType: "view_access_key",
374
+ accountId: params.accountId,
375
+ publicKey: params.publicKey,
376
+ finality: params.finality || "final"
377
+ };
378
+ return query(client, queryParams);
379
+ }
380
+
381
+ // src/validation.ts
382
+ var import_jsonrpc_types = require("@psalomo/jsonrpc-types");
383
+ function enableValidation() {
384
+ const requestSchema = (0, import_jsonrpc_types.JsonRpcRequestSchema)();
385
+ const responseSchema = (0, import_jsonrpc_types.JsonRpcResponseSchema)();
386
+ return {
387
+ validateRequest: (request) => {
388
+ try {
389
+ requestSchema.parse(request);
390
+ } catch (error) {
391
+ throw new JsonRpcNetworkError(
392
+ `Invalid request format: ${error instanceof Error ? error.message : "Unknown error"}`,
393
+ error
394
+ );
395
+ }
396
+ },
397
+ validateResponse: (response) => {
398
+ try {
399
+ responseSchema.parse(response);
400
+ } catch (error) {
401
+ throw new JsonRpcClientError(
402
+ `Invalid response format: ${error instanceof Error ? error.message : "Unknown error"}`
403
+ );
404
+ }
405
+ },
406
+ validateMethodRequest: (method, request) => {
407
+ try {
408
+ requestSchema.parse(request);
409
+ const methodSchemas = import_jsonrpc_types.VALIDATION_SCHEMA_MAP[method];
410
+ if (methodSchemas?.requestSchema) {
411
+ const methodRequestSchema = methodSchemas.requestSchema();
412
+ methodRequestSchema.parse(request);
413
+ }
414
+ } catch (error) {
415
+ throw new JsonRpcNetworkError(
416
+ `Invalid ${method} request: ${error instanceof Error ? error.message : "Unknown error"}`,
417
+ error
418
+ );
419
+ }
420
+ },
421
+ validateMethodResponse: (method, response) => {
422
+ try {
423
+ responseSchema.parse(response);
424
+ const methodSchemas = import_jsonrpc_types.VALIDATION_SCHEMA_MAP[method];
425
+ if (methodSchemas?.responseSchema) {
426
+ const methodResponseSchema = methodSchemas.responseSchema();
427
+ methodResponseSchema.parse(response);
428
+ }
429
+ } catch (error) {
430
+ throw new JsonRpcClientError(
431
+ `Invalid ${method} response: ${error instanceof Error ? error.message : "Unknown error"}`
432
+ );
433
+ }
434
+ }
435
+ };
436
+ }
240
437
  // Annotate the CommonJS export names for ESM import in node:
241
438
  0 && (module.exports = {
242
439
  JsonRpcClientError,
@@ -245,5 +442,38 @@ var import_jsonrpc_types3 = require("@psalomo/jsonrpc-types");
245
442
  JsonRpcResponseSchema,
246
443
  NearRpcClient,
247
444
  NearRpcError,
248
- RPC_METHODS
445
+ RPC_METHODS,
446
+ block,
447
+ broadcastTxAsync,
448
+ broadcastTxCommit,
449
+ changes,
450
+ chunk,
451
+ clientConfig,
452
+ defaultClient,
453
+ enableValidation,
454
+ experimentalChanges,
455
+ experimentalChangesInBlock,
456
+ experimentalCongestionLevel,
457
+ experimentalGenesisConfig,
458
+ experimentalLightClientBlockProof,
459
+ experimentalLightClientProof,
460
+ experimentalMaintenanceWindows,
461
+ experimentalProtocolConfig,
462
+ experimentalReceipt,
463
+ experimentalSplitStorageInfo,
464
+ experimentalTxStatus,
465
+ experimentalValidatorsOrdered,
466
+ gasPrice,
467
+ health,
468
+ lightClientProof,
469
+ networkInfo,
470
+ nextLightClientBlock,
471
+ query,
472
+ sendTx,
473
+ status,
474
+ tx,
475
+ validators,
476
+ viewAccessKey,
477
+ viewAccount,
478
+ viewFunction
249
479
  });