viem 2.18.1 → 2.18.4

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 (50) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/_cjs/chains/definitions/gravity.js +28 -0
  3. package/_cjs/chains/definitions/gravity.js.map +1 -0
  4. package/_cjs/chains/index.js +7 -5
  5. package/_cjs/chains/index.js.map +1 -1
  6. package/_cjs/clients/transports/webSocket.js +5 -2
  7. package/_cjs/clients/transports/webSocket.js.map +1 -1
  8. package/_cjs/errors/base.js +27 -27
  9. package/_cjs/errors/base.js.map +1 -1
  10. package/_cjs/errors/version.js +1 -1
  11. package/_cjs/utils/rpc/socket.js +27 -6
  12. package/_cjs/utils/rpc/socket.js.map +1 -1
  13. package/_cjs/utils/rpc/webSocket.js +22 -5
  14. package/_cjs/utils/rpc/webSocket.js.map +1 -1
  15. package/_esm/chains/definitions/gravity.js +25 -0
  16. package/_esm/chains/definitions/gravity.js.map +1 -0
  17. package/_esm/chains/index.js +1 -0
  18. package/_esm/chains/index.js.map +1 -1
  19. package/_esm/clients/transports/webSocket.js +5 -2
  20. package/_esm/clients/transports/webSocket.js.map +1 -1
  21. package/_esm/errors/base.js +27 -27
  22. package/_esm/errors/base.js.map +1 -1
  23. package/_esm/errors/version.js +1 -1
  24. package/_esm/utils/rpc/socket.js +29 -6
  25. package/_esm/utils/rpc/socket.js.map +1 -1
  26. package/_esm/utils/rpc/webSocket.js +22 -5
  27. package/_esm/utils/rpc/webSocket.js.map +1 -1
  28. package/_types/chains/definitions/gravity.d.ts +34 -0
  29. package/_types/chains/definitions/gravity.d.ts.map +1 -0
  30. package/_types/chains/index.d.ts +1 -0
  31. package/_types/chains/index.d.ts.map +1 -1
  32. package/_types/clients/transports/webSocket.d.ts +5 -0
  33. package/_types/clients/transports/webSocket.d.ts.map +1 -1
  34. package/_types/errors/base.d.ts +1 -1
  35. package/_types/errors/base.d.ts.map +1 -1
  36. package/_types/errors/version.d.ts +1 -1
  37. package/_types/utils/rpc/compat.d.ts +1 -0
  38. package/_types/utils/rpc/compat.d.ts.map +1 -1
  39. package/_types/utils/rpc/socket.d.ts +16 -2
  40. package/_types/utils/rpc/socket.d.ts.map +1 -1
  41. package/_types/utils/rpc/webSocket.d.ts +1 -1
  42. package/_types/utils/rpc/webSocket.d.ts.map +1 -1
  43. package/chains/definitions/gravity.ts +25 -0
  44. package/chains/index.ts +1 -0
  45. package/clients/transports/webSocket.ts +10 -1
  46. package/errors/base.ts +7 -6
  47. package/errors/version.ts +1 -1
  48. package/package.json +1 -1
  49. package/utils/rpc/socket.ts +59 -11
  50. package/utils/rpc/webSocket.ts +25 -6
package/errors/base.ts CHANGED
@@ -15,13 +15,11 @@ export class BaseError extends Error {
15
15
  docsPath?: string | undefined
16
16
  metaMessages?: string[] | undefined
17
17
  shortMessage: string
18
+ version: string
18
19
 
19
20
  override name = 'ViemError'
20
- version = getVersion()
21
21
 
22
22
  constructor(shortMessage: string, args: BaseErrorParameters = {}) {
23
- super()
24
-
25
23
  const details =
26
24
  args.cause instanceof BaseError
27
25
  ? args.cause.details
@@ -32,8 +30,9 @@ export class BaseError extends Error {
32
30
  args.cause instanceof BaseError
33
31
  ? args.cause.docsPath || args.docsPath
34
32
  : args.docsPath
33
+ const version = getVersion()
35
34
 
36
- this.message = [
35
+ const message = [
37
36
  shortMessage || 'An error occurred.',
38
37
  '',
39
38
  ...(args.metaMessages ? [...args.metaMessages, ''] : []),
@@ -45,14 +44,16 @@ export class BaseError extends Error {
45
44
  ]
46
45
  : []),
47
46
  ...(details ? [`Details: ${details}`] : []),
48
- `Version: ${this.version}`,
47
+ `Version: ${version}`,
49
48
  ].join('\n')
50
49
 
51
- if (args.cause) this.cause = args.cause
50
+ super(message, args.cause ? { cause: args.cause } : undefined)
51
+
52
52
  this.details = details
53
53
  this.docsPath = docsPath
54
54
  this.metaMessages = args.metaMessages
55
55
  this.shortMessage = shortMessage
56
+ this.version = version
56
57
  }
57
58
 
58
59
  walk(): Error
package/errors/version.ts CHANGED
@@ -1 +1 @@
1
- export const version = '2.18.1'
1
+ export const version = '2.18.4'
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "viem",
3
3
  "description": "TypeScript Interface for Ethereum",
4
- "version": "2.18.1",
4
+ "version": "2.18.4",
5
5
  "main": "./_cjs/index.js",
6
6
  "module": "./_esm/index.js",
7
7
  "types": "./_types/index.d.ts",
@@ -16,6 +16,7 @@ type CallbackFn = {
16
16
  type CallbackMap = Map<Id, CallbackFn>
17
17
 
18
18
  export type GetSocketParameters = {
19
+ onClose: () => void
19
20
  onError: (error?: Error | Event | undefined) => void
20
21
  onOpen: () => void
21
22
  onResponse: (data: RpcResponse) => void
@@ -23,9 +24,8 @@ export type GetSocketParameters = {
23
24
 
24
25
  export type Socket<socket extends {}> = socket & {
25
26
  close(): void
26
- request(params: {
27
- body: RpcRequest
28
- }): void
27
+ ping?: (() => void) | undefined
28
+ request(params: { body: RpcRequest }): void
29
29
  }
30
30
 
31
31
  export type SocketRpcClient<socket extends {}> = {
@@ -47,9 +47,23 @@ export type SocketRpcClient<socket extends {}> = {
47
47
 
48
48
  export type GetSocketRpcClientParameters<socket extends {} = {}> = {
49
49
  getSocket(params: GetSocketParameters): Promise<Socket<socket>>
50
+ /**
51
+ * Whether or not to send keep-alive messages.
52
+ * @default true
53
+ */
54
+ keepAlive?:
55
+ | boolean
56
+ | {
57
+ /**
58
+ * The interval (in ms) to send keep-alive messages.
59
+ * @default 30_000
60
+ */
61
+ interval?: number | undefined
62
+ }
63
+ | undefined
50
64
  key?: string
51
65
  /**
52
- * Whether or not to attempt to reconnect on socket failure.
66
+ * Whether or not to attempt to reconnect on socket failure or closure.
53
67
  * @default true
54
68
  */
55
69
  reconnect?:
@@ -80,9 +94,17 @@ export const socketClientCache = /*#__PURE__*/ new Map<
80
94
  >()
81
95
 
82
96
  export async function getSocketRpcClient<socket extends {}>(
83
- params: GetSocketRpcClientParameters<socket>,
97
+ parameters: GetSocketRpcClientParameters<socket>,
84
98
  ): Promise<SocketRpcClient<socket>> {
85
- const { getSocket, key = 'socket', reconnect = true, url } = params
99
+ const {
100
+ getSocket,
101
+ keepAlive = true,
102
+ key = 'socket',
103
+ reconnect = true,
104
+ url,
105
+ } = parameters
106
+ const { interval: keepAliveInterval = 30_000 } =
107
+ typeof keepAlive === 'object' ? keepAlive : {}
86
108
  const { attempts = 5, delay = 2_000 } =
87
109
  typeof reconnect === 'object' ? reconnect : {}
88
110
 
@@ -105,10 +127,24 @@ export async function getSocketRpcClient<socket extends {}>(
105
127
  const subscriptions = new Map<Id, CallbackFn>()
106
128
 
107
129
  let error: Error | Event | undefined
108
- let socket: Socket<any>
130
+ let socket: Socket<{}>
131
+ let keepAliveTimer: Timer | undefined
132
+
109
133
  // Set up socket implementation.
110
134
  async function setup() {
111
- return getSocket({
135
+ const result = await getSocket({
136
+ onClose() {
137
+ // Clear all requests and subscriptions.
138
+ requests.clear()
139
+ subscriptions.clear()
140
+
141
+ // Attempt to reconnect.
142
+ if (reconnect && reconnectCount < attempts)
143
+ setTimeout(async () => {
144
+ reconnectCount++
145
+ await setup().catch(console.error)
146
+ }, delay)
147
+ },
112
148
  onError(error_) {
113
149
  error = error_
114
150
 
@@ -125,7 +161,7 @@ export async function getSocketRpcClient<socket extends {}>(
125
161
  if (reconnect && reconnectCount < attempts)
126
162
  setTimeout(async () => {
127
163
  reconnectCount++
128
- socket = await setup().catch(console.error)
164
+ await setup().catch(console.error)
129
165
  }, delay)
130
166
  },
131
167
  onOpen() {
@@ -141,17 +177,29 @@ export async function getSocketRpcClient<socket extends {}>(
141
177
  if (!isSubscription) cache.delete(id)
142
178
  },
143
179
  })
180
+
181
+ socket = result
182
+
183
+ if (keepAlive) {
184
+ if (keepAliveTimer) clearInterval(keepAliveTimer)
185
+ keepAliveTimer = setInterval(() => socket.ping?.(), keepAliveInterval)
186
+ }
187
+
188
+ return result
144
189
  }
145
- socket = await setup()
190
+ await setup()
146
191
  error = undefined
147
192
 
148
193
  // Create a new socket instance.
149
194
  socketClient = {
150
195
  close() {
196
+ keepAliveTimer && clearInterval(keepAliveTimer)
151
197
  socket.close()
152
198
  socketClientCache.delete(`${key}:${url}`)
153
199
  },
154
- socket,
200
+ get socket() {
201
+ return socket
202
+ },
155
203
  request({ body, onError, onResponse }) {
156
204
  if (error && onError) onError(error)
157
205
 
@@ -10,22 +10,23 @@ import {
10
10
 
11
11
  export type GetWebSocketRpcClientOptions = Pick<
12
12
  GetSocketRpcClientParameters,
13
- 'reconnect'
13
+ 'keepAlive' | 'reconnect'
14
14
  >
15
15
 
16
16
  export async function getWebSocketRpcClient(
17
17
  url: string,
18
18
  options: GetWebSocketRpcClientOptions | undefined = {},
19
19
  ): Promise<SocketRpcClient<WebSocket>> {
20
- const { reconnect } = options
20
+ const { keepAlive, reconnect } = options
21
21
 
22
22
  return getSocketRpcClient({
23
- async getSocket({ onError, onOpen, onResponse }) {
23
+ async getSocket({ onClose, onError, onOpen, onResponse }) {
24
24
  const WebSocket = await import('isows').then((module) => module.WebSocket)
25
25
  const socket = new WebSocket(url)
26
26
 
27
- function onClose() {
28
- socket.removeEventListener('close', onClose)
27
+ function onClose_() {
28
+ onClose()
29
+ socket.removeEventListener('close', onClose_)
29
30
  socket.removeEventListener('message', onMessage)
30
31
  socket.removeEventListener('error', onError)
31
32
  socket.removeEventListener('open', onOpen)
@@ -35,7 +36,7 @@ export async function getWebSocketRpcClient(
35
36
  }
36
37
 
37
38
  // Setup event listeners for RPC & subscription responses.
38
- socket.addEventListener('close', onClose)
39
+ socket.addEventListener('close', onClose_)
39
40
  socket.addEventListener('message', onMessage)
40
41
  socket.addEventListener('error', onError)
41
42
  socket.addEventListener('open', onOpen)
@@ -56,6 +57,23 @@ export async function getWebSocketRpcClient(
56
57
  close_.bind(socket)()
57
58
  onClose()
58
59
  },
60
+ ping() {
61
+ try {
62
+ if (
63
+ socket.readyState === socket.CLOSED ||
64
+ socket.readyState === socket.CLOSING
65
+ )
66
+ throw new WebSocketRequestError({
67
+ body: {},
68
+ url: socket.url,
69
+ details: 'Socket is closed.',
70
+ })
71
+
72
+ socket.send('ping')
73
+ } catch (error) {
74
+ onError(error as Error)
75
+ }
76
+ },
59
77
  request({ body }) {
60
78
  if (
61
79
  socket.readyState === socket.CLOSED ||
@@ -71,6 +89,7 @@ export async function getWebSocketRpcClient(
71
89
  },
72
90
  } as Socket<WebSocket>)
73
91
  },
92
+ keepAlive,
74
93
  reconnect,
75
94
  url,
76
95
  })