viem 2.4.1 → 2.5.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.
Files changed (97) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/_cjs/clients/transports/http.js +8 -5
  3. package/_cjs/clients/transports/http.js.map +1 -1
  4. package/_cjs/clients/transports/ipc.js +77 -0
  5. package/_cjs/clients/transports/ipc.js.map +1 -0
  6. package/_cjs/clients/transports/webSocket.js +11 -7
  7. package/_cjs/clients/transports/webSocket.js.map +1 -1
  8. package/_cjs/errors/version.js +1 -1
  9. package/_cjs/node/index.js +8 -0
  10. package/_cjs/node/index.js.map +1 -0
  11. package/_cjs/utils/index.js +13 -6
  12. package/_cjs/utils/index.js.map +1 -1
  13. package/_cjs/utils/rpc/compat.js +35 -0
  14. package/_cjs/utils/rpc/compat.js.map +1 -0
  15. package/_cjs/utils/rpc/http.js +74 -0
  16. package/_cjs/utils/rpc/http.js.map +1 -0
  17. package/_cjs/utils/rpc/id.js +17 -0
  18. package/_cjs/utils/rpc/id.js.map +1 -0
  19. package/_cjs/utils/rpc/ipc.js +75 -0
  20. package/_cjs/utils/rpc/ipc.js.map +1 -0
  21. package/_cjs/utils/rpc/socket.js +85 -0
  22. package/_cjs/utils/rpc/socket.js.map +1 -0
  23. package/_cjs/utils/rpc/webSocket.js +50 -0
  24. package/_cjs/utils/rpc/webSocket.js.map +1 -0
  25. package/_esm/clients/transports/http.js +8 -5
  26. package/_esm/clients/transports/http.js.map +1 -1
  27. package/_esm/clients/transports/ipc.js +77 -0
  28. package/_esm/clients/transports/ipc.js.map +1 -0
  29. package/_esm/clients/transports/webSocket.js +10 -6
  30. package/_esm/clients/transports/webSocket.js.map +1 -1
  31. package/_esm/errors/version.js +1 -1
  32. package/_esm/node/index.js +3 -0
  33. package/_esm/node/index.js.map +1 -0
  34. package/_esm/utils/index.js +4 -1
  35. package/_esm/utils/index.js.map +1 -1
  36. package/_esm/utils/rpc/compat.js +86 -0
  37. package/_esm/utils/rpc/compat.js.map +1 -0
  38. package/_esm/utils/rpc/http.js +70 -0
  39. package/_esm/utils/rpc/http.js.map +1 -0
  40. package/_esm/utils/rpc/id.js +13 -0
  41. package/_esm/utils/rpc/id.js.map +1 -0
  42. package/_esm/utils/rpc/ipc.js +71 -0
  43. package/_esm/utils/rpc/ipc.js.map +1 -0
  44. package/_esm/utils/rpc/socket.js +90 -0
  45. package/_esm/utils/rpc/socket.js.map +1 -0
  46. package/_esm/utils/rpc/webSocket.js +48 -0
  47. package/_esm/utils/rpc/webSocket.js.map +1 -0
  48. package/_types/clients/transports/http.d.ts +2 -2
  49. package/_types/clients/transports/http.d.ts.map +1 -1
  50. package/_types/clients/transports/ipc.d.ts +46 -0
  51. package/_types/clients/transports/ipc.d.ts.map +1 -0
  52. package/_types/clients/transports/webSocket.d.ts +6 -1
  53. package/_types/clients/transports/webSocket.d.ts.map +1 -1
  54. package/_types/errors/version.d.ts +1 -1
  55. package/_types/node/index.d.ts +3 -0
  56. package/_types/node/index.d.ts.map +1 -0
  57. package/_types/types/rpc.d.ts +35 -0
  58. package/_types/types/rpc.d.ts.map +1 -1
  59. package/_types/utils/buildRequest.d.ts +2 -2
  60. package/_types/utils/buildRequest.d.ts.map +1 -1
  61. package/_types/utils/index.d.ts +4 -1
  62. package/_types/utils/index.d.ts.map +1 -1
  63. package/_types/utils/rpc/compat.d.ts +78 -0
  64. package/_types/utils/rpc/compat.d.ts.map +1 -0
  65. package/_types/utils/rpc/http.d.ts +20 -0
  66. package/_types/utils/rpc/http.d.ts.map +1 -0
  67. package/_types/utils/rpc/id.d.ts +11 -0
  68. package/_types/utils/rpc/id.d.ts.map +1 -0
  69. package/_types/utils/rpc/ipc.d.ts +8 -0
  70. package/_types/utils/rpc/ipc.d.ts.map +1 -0
  71. package/_types/utils/rpc/socket.d.ts +45 -0
  72. package/_types/utils/rpc/socket.d.ts.map +1 -0
  73. package/_types/utils/rpc/webSocket.d.ts +3 -0
  74. package/_types/utils/rpc/webSocket.d.ts.map +1 -0
  75. package/clients/transports/http.ts +15 -6
  76. package/clients/transports/ipc.ts +144 -0
  77. package/clients/transports/webSocket.ts +16 -6
  78. package/errors/version.ts +1 -1
  79. package/node/index.ts +11 -0
  80. package/node/package.json +6 -0
  81. package/package.json +9 -1
  82. package/types/rpc.ts +44 -0
  83. package/utils/buildRequest.ts +2 -2
  84. package/utils/index.ts +19 -8
  85. package/utils/rpc/compat.ts +117 -0
  86. package/utils/rpc/http.ts +132 -0
  87. package/utils/rpc/id.ts +13 -0
  88. package/utils/rpc/ipc.ts +89 -0
  89. package/utils/rpc/socket.ts +162 -0
  90. package/utils/rpc/webSocket.ts +63 -0
  91. package/_cjs/utils/rpc.js +0 -154
  92. package/_cjs/utils/rpc.js.map +0 -1
  93. package/_esm/utils/rpc.js +0 -160
  94. package/_esm/utils/rpc.js.map +0 -1
  95. package/_types/utils/rpc.d.ts +0 -80
  96. package/_types/utils/rpc.d.ts.map +0 -1
  97. package/utils/rpc.ts +0 -318
@@ -4,8 +4,12 @@ import {
4
4
  type UrlRequiredErrorType,
5
5
  } from '../../errors/transport.js'
6
6
  import type { ErrorType } from '../../errors/utils.js'
7
+ import type { RpcRequest } from '../../types/rpc.js'
7
8
  import { createBatchScheduler } from '../../utils/promise/createBatchScheduler.js'
8
- import { type HttpOptions, type RpcRequest, rpc } from '../../utils/rpc.js'
9
+ import {
10
+ type HttpRpcClientOptions,
11
+ getHttpRpcClient,
12
+ } from '../../utils/rpc/http.js'
9
13
 
10
14
  import {
11
15
  type CreateTransportErrorType,
@@ -31,7 +35,7 @@ export type HttpTransportConfig = {
31
35
  * Request configuration to pass to `fetch`.
32
36
  * @link https://developer.mozilla.org/en-US/docs/Web/API/fetch
33
37
  */
34
- fetchOptions?: HttpOptions['fetchOptions']
38
+ fetchOptions?: HttpRpcClientOptions['fetchOptions']
35
39
  /** The key of the HTTP transport. */
36
40
  key?: TransportConfig['key']
37
41
  /** The name of the HTTP transport. */
@@ -79,6 +83,9 @@ export function http(
79
83
  const timeout = timeout_ ?? config.timeout ?? 10_000
80
84
  const url_ = url || chain?.rpcUrls.default.http[0]
81
85
  if (!url_) throw new UrlRequiredError()
86
+
87
+ const rpcClient = getHttpRpcClient(url_, { fetchOptions, timeout })
88
+
82
89
  return createTransport(
83
90
  {
84
91
  key,
@@ -93,10 +100,8 @@ export function http(
93
100
  return requests.length > batchSize
94
101
  },
95
102
  fn: (body: RpcRequest[]) =>
96
- rpc.http(url_, {
103
+ rpcClient.request({
97
104
  body,
98
- fetchOptions,
99
- timeout,
100
105
  }),
101
106
  sort: (a, b) => a.id - b.id,
102
107
  })
@@ -104,7 +109,11 @@ export function http(
104
109
  const fn = async (body: RpcRequest) =>
105
110
  batch
106
111
  ? schedule(body)
107
- : [await rpc.http(url_, { body, fetchOptions, timeout })]
112
+ : [
113
+ await rpcClient.request({
114
+ body,
115
+ }),
116
+ ]
108
117
 
109
118
  const [{ error, result }] = await fn(body)
110
119
  if (error)
@@ -0,0 +1,144 @@
1
+ import { RpcRequestError } from '../../errors/request.js'
2
+ import { type UrlRequiredErrorType } from '../../errors/transport.js'
3
+ import type { ErrorType } from '../../errors/utils.js'
4
+ import type { Hash } from '../../types/misc.js'
5
+ import type { RpcResponse } from '../../types/rpc.js'
6
+ import { type IpcRpcClient, getIpcRpcClient } from '../../utils/rpc/ipc.js'
7
+ import {
8
+ type CreateTransportErrorType,
9
+ type Transport,
10
+ type TransportConfig,
11
+ createTransport,
12
+ } from './createTransport.js'
13
+
14
+ type IpcTransportSubscribeParameters = {
15
+ onData: (data: RpcResponse) => void
16
+ onError?: (error: any) => void
17
+ }
18
+
19
+ type IpcTransportSubscribeReturnType = {
20
+ subscriptionId: Hash
21
+ unsubscribe: () => Promise<RpcResponse<boolean>>
22
+ }
23
+
24
+ type IpcTransportSubscribe = {
25
+ subscribe(
26
+ args: IpcTransportSubscribeParameters & {
27
+ /**
28
+ * @description Add information about compiled contracts
29
+ * @link https://hardhat.org/hardhat-network/docs/reference#hardhat_addcompilationresult
30
+ */
31
+ params: ['newHeads']
32
+ },
33
+ ): Promise<IpcTransportSubscribeReturnType>
34
+ }
35
+
36
+ export type IpcTransportConfig = {
37
+ /** The key of the Ipc transport. */
38
+ key?: TransportConfig['key']
39
+ /** The name of the Ipc transport. */
40
+ name?: TransportConfig['name']
41
+ /** The max number of times to retry. */
42
+ retryCount?: TransportConfig['retryCount']
43
+ /** The base delay (in ms) between retries. */
44
+ retryDelay?: TransportConfig['retryDelay']
45
+ /** The timeout (in ms) for async Ipc requests. Default: 10_000 */
46
+ timeout?: TransportConfig['timeout']
47
+ }
48
+
49
+ export type IpcTransport = Transport<
50
+ 'ipc',
51
+ {
52
+ getRpcClient(): Promise<IpcRpcClient>
53
+ subscribe: IpcTransportSubscribe['subscribe']
54
+ }
55
+ >
56
+
57
+ export type IpcTransportErrorType =
58
+ | CreateTransportErrorType
59
+ | UrlRequiredErrorType
60
+ | ErrorType
61
+
62
+ /**
63
+ * @description Creates an IPC transport that connects to a JSON-RPC API.
64
+ */
65
+ export function ipc(
66
+ path: string,
67
+ config: IpcTransportConfig = {},
68
+ ): IpcTransport {
69
+ const { key = 'ipc', name = 'IPC JSON-RPC', retryDelay } = config
70
+ return ({ retryCount: retryCount_, timeout: timeout_ }) => {
71
+ const retryCount = config.retryCount ?? retryCount_
72
+ const timeout = timeout_ ?? config.timeout ?? 10_000
73
+ return createTransport(
74
+ {
75
+ key,
76
+ name,
77
+ async request({ method, params }) {
78
+ const body = { method, params }
79
+ const rpcClient = await getIpcRpcClient(path)
80
+ const { error, result } = await rpcClient.requestAsync({
81
+ body,
82
+ timeout,
83
+ })
84
+ if (error)
85
+ throw new RpcRequestError({
86
+ body,
87
+ error,
88
+ url: path,
89
+ })
90
+ return result
91
+ },
92
+ retryCount,
93
+ retryDelay,
94
+ timeout,
95
+ type: 'ipc',
96
+ },
97
+ {
98
+ getRpcClient() {
99
+ return getIpcRpcClient(path)
100
+ },
101
+ async subscribe({ params, onData, onError }: any) {
102
+ const rpcClient = await getIpcRpcClient(path)
103
+ const { result: subscriptionId } = await new Promise<any>(
104
+ (resolve, reject) =>
105
+ rpcClient.request({
106
+ body: {
107
+ method: 'eth_subscribe',
108
+ params,
109
+ },
110
+ onResponse(response) {
111
+ if (response.error) {
112
+ reject(response.error)
113
+ onError?.(response.error)
114
+ return
115
+ }
116
+
117
+ if (typeof response.id === 'number') {
118
+ resolve(response)
119
+ return
120
+ }
121
+ if (response.method !== 'eth_subscription') return
122
+ onData(response.params)
123
+ },
124
+ }),
125
+ )
126
+ return {
127
+ subscriptionId,
128
+ async unsubscribe() {
129
+ return new Promise<any>((resolve) =>
130
+ rpcClient.request({
131
+ body: {
132
+ method: 'eth_unsubscribe',
133
+ params: [subscriptionId],
134
+ },
135
+ onResponse: resolve,
136
+ }),
137
+ )
138
+ },
139
+ }
140
+ },
141
+ },
142
+ )
143
+ }
144
+ }
@@ -5,7 +5,10 @@ import {
5
5
  } from '../../errors/transport.js'
6
6
  import type { ErrorType } from '../../errors/utils.js'
7
7
  import type { Hash } from '../../types/misc.js'
8
- import { type RpcResponse, getSocket, rpc } from '../../utils/rpc.js'
8
+ import type { RpcResponse } from '../../types/rpc.js'
9
+ import { getSocket } from '../../utils/rpc/compat.js'
10
+ import type { SocketRpcClient } from '../../utils/rpc/socket.js'
11
+ import { getWebSocketRpcClient } from '../../utils/rpc/webSocket.js'
9
12
  import {
10
13
  type CreateTransportErrorType,
11
14
  type Transport,
@@ -51,7 +54,11 @@ export type WebSocketTransportConfig = {
51
54
  export type WebSocketTransport = Transport<
52
55
  'webSocket',
53
56
  {
57
+ /**
58
+ * @deprecated use `getRpcClient` instead.
59
+ */
54
60
  getSocket(): Promise<WebSocket>
61
+ getRpcClient(): Promise<SocketRpcClient<WebSocket>>
55
62
  subscribe: WebSocketTransportSubscribe['subscribe']
56
63
  }
57
64
  >
@@ -81,8 +88,8 @@ export function webSocket(
81
88
  name,
82
89
  async request({ method, params }) {
83
90
  const body = { method, params }
84
- const socket = await getSocket(url_)
85
- const { error, result } = await rpc.webSocketAsync(socket, {
91
+ const rpcClient = await getWebSocketRpcClient(url_)
92
+ const { error, result } = await rpcClient.requestAsync({
86
93
  body,
87
94
  timeout,
88
95
  })
@@ -103,11 +110,14 @@ export function webSocket(
103
110
  getSocket() {
104
111
  return getSocket(url_)
105
112
  },
113
+ getRpcClient() {
114
+ return getWebSocketRpcClient(url_)
115
+ },
106
116
  async subscribe({ params, onData, onError }: any) {
107
- const socket = await getSocket(url_)
117
+ const rpcClient = await getWebSocketRpcClient(url_)
108
118
  const { result: subscriptionId } = await new Promise<any>(
109
119
  (resolve, reject) =>
110
- rpc.webSocket(socket, {
120
+ rpcClient.request({
111
121
  body: {
112
122
  method: 'eth_subscribe',
113
123
  params,
@@ -132,7 +142,7 @@ export function webSocket(
132
142
  subscriptionId,
133
143
  async unsubscribe() {
134
144
  return new Promise<any>((resolve) =>
135
- rpc.webSocket(socket, {
145
+ rpcClient.request({
136
146
  body: {
137
147
  method: 'eth_unsubscribe',
138
148
  params: [subscriptionId],
package/errors/version.ts CHANGED
@@ -1 +1 @@
1
- export const version = '2.4.1'
1
+ export const version = '2.5.0'
package/node/index.ts ADDED
@@ -0,0 +1,11 @@
1
+ export {
2
+ type IpcTransport,
3
+ type IpcTransportConfig,
4
+ type IpcTransportErrorType,
5
+ ipc,
6
+ } from '../clients/transports/ipc.js'
7
+
8
+ export {
9
+ type IpcRpcClient,
10
+ getIpcRpcClient,
11
+ } from '../utils/rpc/ipc.js'
@@ -0,0 +1,6 @@
1
+ {
2
+ "type": "module",
3
+ "types": "../_types/node/index.d.ts",
4
+ "module": "../_esm/node/index.js",
5
+ "main": "../_cjs/node/index.js"
6
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "viem",
3
3
  "description": "TypeScript Interface for Ethereum",
4
- "version": "2.4.1",
4
+ "version": "2.5.0",
5
5
  "main": "./_cjs/index.js",
6
6
  "module": "./_esm/index.js",
7
7
  "types": "./_types/index.d.ts",
@@ -52,6 +52,11 @@
52
52
  "import": "./_esm/ens/index.js",
53
53
  "default": "./_cjs/ens/index.js"
54
54
  },
55
+ "./node": {
56
+ "types": "./_types/node/index.d.ts",
57
+ "import": "./_esm/node/index.js",
58
+ "default": "./_cjs/node/index.js"
59
+ },
55
60
  "./op-stack": {
56
61
  "types": "./_types/chains/opStack/index.d.ts",
57
62
  "import": "./_esm/chains/opStack/index.js",
@@ -94,6 +99,9 @@
94
99
  "ens": [
95
100
  "./_types/ens/index.d.ts"
96
101
  ],
102
+ "node": [
103
+ "./_types/node/index.d.ts"
104
+ ],
97
105
  "op-stack": [
98
106
  "./_types/chains/opStack/index.d.ts"
99
107
  ],
package/types/rpc.ts CHANGED
@@ -57,3 +57,47 @@ export type RpcTransaction<TPending extends boolean = boolean> = UnionOmit<
57
57
  >,
58
58
  'typeHex'
59
59
  >
60
+
61
+ type SuccessResult<T> = {
62
+ method?: never
63
+ result: T
64
+ error?: never
65
+ }
66
+ type ErrorResult<T> = {
67
+ method?: never
68
+ result?: never
69
+ error: T
70
+ }
71
+ type Subscription<TResult, TError> = {
72
+ method: 'eth_subscription'
73
+ error?: never
74
+ result?: never
75
+ params: {
76
+ subscription: string
77
+ } & (
78
+ | {
79
+ result: TResult
80
+ error?: never
81
+ }
82
+ | {
83
+ result?: never
84
+ error: TError
85
+ }
86
+ )
87
+ }
88
+
89
+ export type RpcRequest = {
90
+ jsonrpc?: '2.0'
91
+ method: string
92
+ params?: any
93
+ id?: number
94
+ }
95
+
96
+ export type RpcResponse<TResult = any, TError = any> = {
97
+ jsonrpc: `${number}`
98
+ id: number
99
+ } & (
100
+ | SuccessResult<TResult>
101
+ | ErrorResult<TError>
102
+ | Subscription<TResult, TError>
103
+ )
@@ -57,7 +57,7 @@ import type {
57
57
  } from '../types/eip1193.js'
58
58
  import type { CreateBatchSchedulerErrorType } from './promise/createBatchScheduler.js'
59
59
  import { type WithRetryErrorType, withRetry } from './promise/withRetry.js'
60
- import type { GetSocketErrorType } from './rpc.js'
60
+ import type { GetSocketRpcClientErrorType } from './rpc/socket.js'
61
61
 
62
62
  export type RequestErrorType =
63
63
  | ChainDisconnectedErrorType
@@ -67,7 +67,7 @@ export type RequestErrorType =
67
67
  | InvalidInputRpcErrorType
68
68
  | InvalidParamsRpcErrorType
69
69
  | InvalidRequestRpcErrorType
70
- | GetSocketErrorType
70
+ | GetSocketRpcClientErrorType
71
71
  | JsonRpcVersionUnsupportedErrorType
72
72
  | LimitExceededRpcErrorType
73
73
  | MethodNotFoundRpcErrorType
package/utils/index.ts CHANGED
@@ -32,13 +32,6 @@ export {
32
32
  export { arrayRegex, bytesRegex, integerRegex } from './regex.js'
33
33
 
34
34
  export {
35
- type GetSocketErrorType,
36
- type HttpErrorType,
37
- type HttpOptions,
38
- type HttpReturnType,
39
- type RpcRequest,
40
- type RpcResponse,
41
- type Socket,
42
35
  type WebSocketAsyncErrorType,
43
36
  type WebSocketAsyncOptions,
44
37
  type WebSocketAsyncReturnType,
@@ -47,7 +40,25 @@ export {
47
40
  type WebSocketReturnType,
48
41
  getSocket,
49
42
  rpc,
50
- } from './rpc.js'
43
+ } from './rpc/compat.js'
44
+ export {
45
+ type HttpRpcClient,
46
+ type HttpRpcClientOptions,
47
+ type HttpRequestErrorType,
48
+ type HttpRequestParameters,
49
+ type HttpRequestReturnType,
50
+ getHttpRpcClient,
51
+ } from './rpc/http.js'
52
+ export {
53
+ type GetSocketRpcClientErrorType,
54
+ type GetSocketRpcClientParameters,
55
+ type GetSocketParameters,
56
+ type Socket,
57
+ type SocketRpcClient,
58
+ getSocketRpcClient,
59
+ socketClientCache,
60
+ } from './rpc/socket.js'
61
+ export { getWebSocketRpcClient } from './rpc/webSocket.js'
51
62
  export { type StringifyErrorType, stringify } from './stringify.js'
52
63
  export {
53
64
  type DomainSeparatorErrorType,
@@ -0,0 +1,117 @@
1
+ // TODO(v3): This file is here for backwards compatibility, and to prevent breaking changes.
2
+ // These APIs will be removed in v3.
3
+
4
+ /* c8 ignore start */
5
+ import {
6
+ type TimeoutErrorType,
7
+ WebSocketRequestError,
8
+ } from '../../errors/request.js'
9
+ import type { ErrorType } from '../../errors/utils.js'
10
+ import type { RpcResponse } from '../../types/rpc.js'
11
+ import { type WithTimeoutErrorType } from '../promise/withTimeout.js'
12
+ import { type HttpRequestParameters, getHttpRpcClient } from './http.js'
13
+ import { type SocketRpcClient } from './socket.js'
14
+ import { getWebSocketRpcClient } from './webSocket.js'
15
+
16
+ export type WebSocketOptions = Parameters<
17
+ SocketRpcClient<WebSocket>['request']
18
+ >[0]
19
+ export type WebSocketReturnType = SocketRpcClient<WebSocket>
20
+ export type WebSocketErrorType = WebSocketRequestError | ErrorType
21
+
22
+ function webSocket(
23
+ socketClient: SocketRpcClient<WebSocket>,
24
+ { body, onError, onResponse }: WebSocketOptions,
25
+ ): WebSocketReturnType {
26
+ socketClient.request({
27
+ body,
28
+ onError,
29
+ onResponse,
30
+ })
31
+ return socketClient
32
+ }
33
+
34
+ export type WebSocketAsyncOptions = Parameters<
35
+ SocketRpcClient<WebSocket>['requestAsync']
36
+ >[0]
37
+ export type WebSocketAsyncReturnType = RpcResponse
38
+ export type WebSocketAsyncErrorType =
39
+ | WebSocketErrorType
40
+ | TimeoutErrorType
41
+ | WithTimeoutErrorType
42
+ | ErrorType
43
+
44
+ async function webSocketAsync(
45
+ socketClient: SocketRpcClient<WebSocket>,
46
+ { body, timeout = 10_000 }: WebSocketAsyncOptions,
47
+ ): Promise<WebSocketAsyncReturnType> {
48
+ return socketClient.requestAsync({
49
+ body,
50
+ timeout,
51
+ })
52
+ }
53
+
54
+ /**
55
+ * @deprecated use `getSocketClient` instead.
56
+ *
57
+ * ```diff
58
+ * -import { getSocket } from 'viem/utils'
59
+ * +import { getSocketClient } from 'viem/utils'
60
+ *
61
+ * -const socket = await getSocket(url)
62
+ * +const socketClient = await getSocketClient(url)
63
+ * +const socket = socketClient.socket
64
+ * ```
65
+ */
66
+ export async function getSocket(url: string) {
67
+ const client = await getWebSocketRpcClient(url)
68
+ return Object.assign(client.socket, {
69
+ requests: client.requests,
70
+ subscriptions: client.subscriptions,
71
+ })
72
+ }
73
+
74
+ export const rpc = {
75
+ /**
76
+ * @deprecated use `getHttpRpcClient` instead.
77
+ *
78
+ * ```diff
79
+ * -import { rpc } from 'viem/utils'
80
+ * +import { getHttpRpcClient } from 'viem/utils'
81
+ *
82
+ * -rpc.http(url, params)
83
+ * +const httpClient = getHttpRpcClient(url)
84
+ * +httpClient.request(params)
85
+ * ```
86
+ */
87
+ http(url: string, params: HttpRequestParameters) {
88
+ return getHttpRpcClient(url).request(params)
89
+ },
90
+ /**
91
+ * @deprecated use `getWebSocketRpcClient` instead.
92
+ *
93
+ * ```diff
94
+ * -import { rpc } from 'viem/utils'
95
+ * +import { getWebSocketRpcClient } from 'viem/utils'
96
+ *
97
+ * -rpc.webSocket(url, params)
98
+ * +const webSocketClient = getWebSocketRpcClient(url)
99
+ * +webSocketClient.request(params)
100
+ * ```
101
+ */
102
+ webSocket,
103
+ /**
104
+ * @deprecated use `getWebSocketRpcClient` instead.
105
+ *
106
+ * ```diff
107
+ * -import { rpc } from 'viem/utils'
108
+ * +import { getWebSocketRpcClient } from 'viem/utils'
109
+ *
110
+ * -const response = await rpc.webSocketAsync(url, params)
111
+ * +const webSocketClient = getWebSocketRpcClient(url)
112
+ * +const response = await webSocketClient.requestAsync(params)
113
+ * ```
114
+ */
115
+ webSocketAsync,
116
+ }
117
+ /* c8 ignore end */
@@ -0,0 +1,132 @@
1
+ import {
2
+ HttpRequestError,
3
+ type HttpRequestErrorType as HttpRequestErrorType_,
4
+ TimeoutError,
5
+ type TimeoutErrorType,
6
+ } from '../../errors/request.js'
7
+ import type { ErrorType } from '../../errors/utils.js'
8
+ import type { RpcRequest, RpcResponse } from '../../types/rpc.js'
9
+ import {
10
+ type WithTimeoutErrorType,
11
+ withTimeout,
12
+ } from '../promise/withTimeout.js'
13
+ import { stringify } from '../stringify.js'
14
+ import { idCache } from './id.js'
15
+
16
+ export type HttpRpcClientOptions = {
17
+ // Request configuration to pass to `fetch`.
18
+ fetchOptions?: Omit<RequestInit, 'body'>
19
+ // The timeout (in ms) for the request.
20
+ timeout?: number
21
+ }
22
+
23
+ export type HttpRequestParameters<
24
+ TBody extends RpcRequest | RpcRequest[] = RpcRequest,
25
+ > = {
26
+ // The RPC request body.
27
+ body: TBody
28
+ // Request configuration to pass to `fetch`.
29
+ fetchOptions?: HttpRpcClientOptions['fetchOptions']
30
+ // The timeout (in ms) for the request.
31
+ timeout?: HttpRpcClientOptions['timeout']
32
+ }
33
+
34
+ export type HttpRequestReturnType<
35
+ TBody extends RpcRequest | RpcRequest[] = RpcRequest,
36
+ > = TBody extends RpcRequest[] ? RpcResponse[] : RpcResponse
37
+
38
+ export type HttpRequestErrorType =
39
+ | HttpRequestErrorType_
40
+ | TimeoutErrorType
41
+ | WithTimeoutErrorType
42
+ | ErrorType
43
+
44
+ export type HttpRpcClient = {
45
+ request<TBody extends RpcRequest | RpcRequest[]>(
46
+ params: HttpRequestParameters<TBody>,
47
+ ): Promise<HttpRequestReturnType<TBody>>
48
+ }
49
+
50
+ export function getHttpRpcClient(
51
+ url: string,
52
+ options: HttpRpcClientOptions = {},
53
+ ): HttpRpcClient {
54
+ return {
55
+ async request(params) {
56
+ const {
57
+ body,
58
+ fetchOptions = {},
59
+ timeout = options.timeout ?? 10_000,
60
+ } = params
61
+ const {
62
+ headers,
63
+ method,
64
+ signal: signal_,
65
+ } = { ...options.fetchOptions, ...fetchOptions }
66
+
67
+ try {
68
+ const response = await withTimeout(
69
+ async ({ signal }) => {
70
+ const response = await fetch(url, {
71
+ ...fetchOptions,
72
+ body: Array.isArray(body)
73
+ ? stringify(
74
+ body.map((body) => ({
75
+ jsonrpc: '2.0',
76
+ id: body.id ?? idCache.take(),
77
+ ...body,
78
+ })),
79
+ )
80
+ : stringify({
81
+ jsonrpc: '2.0',
82
+ id: body.id ?? idCache.take(),
83
+ ...body,
84
+ }),
85
+ headers: {
86
+ ...headers,
87
+ 'Content-Type': 'application/json',
88
+ },
89
+ method: method || 'POST',
90
+ signal: signal_ || (timeout > 0 ? signal : undefined),
91
+ })
92
+ return response
93
+ },
94
+ {
95
+ errorInstance: new TimeoutError({ body, url }),
96
+ timeout,
97
+ signal: true,
98
+ },
99
+ )
100
+
101
+ let data: any
102
+ if (
103
+ response.headers.get('Content-Type')?.startsWith('application/json')
104
+ ) {
105
+ data = await response.json()
106
+ } else {
107
+ data = await response.text()
108
+ }
109
+
110
+ if (!response.ok) {
111
+ throw new HttpRequestError({
112
+ body,
113
+ details: stringify(data.error) || response.statusText,
114
+ headers: response.headers,
115
+ status: response.status,
116
+ url,
117
+ })
118
+ }
119
+
120
+ return data
121
+ } catch (err) {
122
+ if (err instanceof HttpRequestError) throw err
123
+ if (err instanceof TimeoutError) throw err
124
+ throw new HttpRequestError({
125
+ body,
126
+ details: (err as Error).message,
127
+ url,
128
+ })
129
+ }
130
+ },
131
+ }
132
+ }
@@ -0,0 +1,13 @@
1
+ export function createIdStore() {
2
+ return {
3
+ current: 0,
4
+ take() {
5
+ return this.current++
6
+ },
7
+ reset() {
8
+ this.current = 0
9
+ },
10
+ }
11
+ }
12
+
13
+ export const idCache = /*#__PURE__*/ createIdStore()