@direct.dev/sdk 1.0.0 → 1.0.2

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/README.md CHANGED
@@ -13,7 +13,7 @@
13
13
  </p>
14
14
  </div>
15
15
 
16
- A drop-in `fetch` wrapper for [Direct.dev](https://direct.dev/) RPC endpoints. Your existing code keeps working — Direct.dev quietly takes over JSON-RPC calls to its own URLs and serves them faster, with caching, sync, and failover built in. Everything else passes through to native `fetch` untouched.
16
+ A drop-in `fetch` wrapper for [Direct.dev](https://direct.dev/) RPC endpoints. Your existing code keeps working — Direct.dev quietly takes over JSON-RPC requests to its own URLs and serves them faster, with caching, sync, and failover built in.
17
17
 
18
18
  ## Highlights
19
19
 
@@ -21,13 +21,13 @@ A drop-in `fetch` wrapper for [Direct.dev](https://direct.dev/) RPC endpoints. Y
21
21
  Popular requests are answered from a local cache; the rest are routed through the Direct.dev edge.
22
22
 
23
23
  **Less bandwidth**<br />
24
- Direct Sync streams only what changed since your last call, instead of resending the full payload every time.
24
+ Direct Sync streams only what changed since your last request, instead of resending the full payload every time.
25
25
 
26
26
  **Compact wire format**<br />
27
27
  Direct Wire is a binary protocol tuned for Web3 traffic — smaller frames and faster decode than JSON-RPC.
28
28
 
29
29
  **Built-in failover**<br />
30
- Calls reroute through a healthy path automatically when an upstream is unavailable. No retry logic to write.
30
+ Requests reroute through a healthy path automatically when an upstream is unavailable. No retry logic to write.
31
31
 
32
32
  **Drop-in**<br />
33
33
  Plugs into native `fetch`, so viem, ethers, and your own code work unchanged. Only Direct.dev URLs are intercepted.
@@ -40,14 +40,14 @@ npm install @direct.dev/sdk
40
40
 
41
41
  ## Quick start
42
42
 
43
- Call `install()` once at app startup and you're done:
43
+ Run `install()` once at app startup and you're done:
44
44
 
45
45
  ```ts
46
46
  import { install } from "@direct.dev/sdk";
47
47
 
48
48
  install();
49
49
 
50
- const res = await fetch("https://rpc.direct.dev/v1/<projectId>.<token>/ethereum", {
50
+ const res = await fetch("https://rpc.direct.dev/v1/<project>.<token>/ethereum", {
51
51
  method: "POST",
52
52
  headers: { "Content-Type": "application/json" },
53
53
  body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_blockNumber", params: [] }),
@@ -57,7 +57,7 @@ const { result } = await res.json();
57
57
  // "0x134a1c0"
58
58
  ```
59
59
 
60
- That's it. Every call to a Direct.dev RPC URL now goes through the SDK; everything else still hits native `fetch`.
60
+ That's it. Every request to a Direct.dev RPC URL now goes through the SDK.
61
61
 
62
62
  ### With options
63
63
 
@@ -78,7 +78,7 @@ const directFetch = createFetch({
78
78
  logging: { client: "info" },
79
79
  });
80
80
 
81
- const res = await directFetch("https://rpc.direct.dev/v1/<projectId>.<token>/ethereum", {
81
+ const res = await directFetch("https://rpc.direct.dev/v1/<project>.<token>/ethereum", {
82
82
  method: "POST",
83
83
  headers: { "Content-Type": "application/json" },
84
84
  body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_blockNumber", params: [] }),
@@ -102,7 +102,7 @@ install();
102
102
 
103
103
  const client = createPublicClient({
104
104
  chain: mainnet,
105
- transport: http("https://rpc.direct.dev/v1/<projectId>.<token>/ethereum"),
105
+ transport: http("https://rpc.direct.dev/v1/<project>.<token>/ethereum"),
106
106
  });
107
107
 
108
108
  await client.getBlockNumber();
@@ -119,7 +119,7 @@ const directFetch = createFetch({ logging: { client: "info" } });
119
119
 
120
120
  const client = createPublicClient({
121
121
  chain: mainnet,
122
- transport: http("https://rpc.direct.dev/v1/<projectId>.<token>/ethereum", {
122
+ transport: http("https://rpc.direct.dev/v1/<project>.<token>/ethereum", {
123
123
  fetch: directFetch,
124
124
  }),
125
125
  });
@@ -136,7 +136,7 @@ In the browser, prefer an HTML preload link. It lets the browser start fetching
136
136
  rel="preload"
137
137
  as="fetch"
138
138
  crossorigin="anonymous"
139
- href="https://rpc.direct.dev/v1/<projectId>.<token>/ethereum"
139
+ href="https://rpc.direct.dev/v1/<project>.<token>/ethereum"
140
140
  />
141
141
  ```
142
142
 
@@ -145,8 +145,8 @@ On the server, or in environments without preload links, pass `preload` to `inst
145
145
  ```ts
146
146
  install({
147
147
  preload: [
148
- "https://rpc.direct.dev/v1/<projectId>.<token>/ethereum",
149
- "https://rpc.direct.dev/v1/<projectId>.<token>/sonic",
148
+ "https://rpc.direct.dev/v1/<project>.<token>/ethereum",
149
+ "https://rpc.direct.dev/v1/<project>.<token>/sonic",
150
150
  ],
151
151
  });
152
152
  ```
@@ -157,14 +157,14 @@ install({
157
157
  | --- | --- | --- | --- |
158
158
  | `logging.client` | `"silent" \| "error" \| "warn" \| "info" \| "debug"` | `"warn"` | Operational / lifecycle log verbosity. |
159
159
  | `logging.requests` | `"off" \| "summary" \| "debug"` | `"off"` | Per-request tracing. |
160
- | `logging.onEvent` | `(event) => void` | — | Structured event sink. Replaces console output when set. |
160
+ | `logging.onEvent` | `(event: LogEvent) => void` | — | Structured event sink. Replaces console output when set. |
161
161
  | `fetch` | `typeof fetch` | `globalThis.fetch` | Underlying fetch to wrap. |
162
162
  | `createWebSocket` | `(url) => WebSocket` | `globalThis.WebSocket` | WebSocket factory for Direct Wire sync. |
163
163
  | `preload` | `string[]` | auto from `<link rel="preload">` | Endpoint URLs to warm at startup. In the browser, the SDK already picks up `<link rel="preload">` tags automatically — use this option for SSR / non-browser runtimes, or to add endpoints not declared in the HTML. |
164
164
 
165
165
  ### `fetch`
166
166
 
167
- Wrap a specific implementation instead of `globalThis.fetch`. Useful in tests, polyfilled environments, or when you want a `createFetch()` instance that bypasses an existing `install()`:
167
+ Wrap a specific implementation instead of `globalThis.fetch`. Useful in tests, custom runtimes, or when you need a `createFetch()` instance that bypasses an existing `install()`:
168
168
 
169
169
  ```ts
170
170
  const directFetch = createFetch({
@@ -199,7 +199,7 @@ The `logging` option covers three independent concerns:
199
199
  | `silent` | Nothing. |
200
200
  | `error` | Errors only. `[direct:ERROR] Batch contains duplicate request IDs { ids: [1, 1] }` |
201
201
  | `warn` | Errors + warnings. `[direct:WARN] Request failed { input: ..., err: ... }` |
202
- | `info` | Reserved for sparse operational summaries. No default emissions yet. |
202
+ | `info` | Sparse operational summaries, including live sync connection state. |
203
203
  | `debug` | Full lifecycle: preload, sync, client phases. |
204
204
 
205
205
  Example debug output:
@@ -215,6 +215,27 @@ Example debug output:
215
215
  client_instance_id: "client_ethereum_f47ac10b_1",
216
216
  network_id: "ethereum"
217
217
  }
218
+ [direct:INFO] sync.connection {
219
+ client_instance_id: "client_ethereum_f47ac10b_1",
220
+ network_id: "ethereum",
221
+ connected: true,
222
+ transport: "wire_socket",
223
+ reason: "started"
224
+ }
225
+ [direct:INFO] sync.ready {
226
+ client_instance_id: "client_ethereum_f47ac10b_1",
227
+ network_id: "ethereum",
228
+ ready: true,
229
+ transport: "wire_socket",
230
+ reason: "block_state_available",
231
+ current_block_height: "0x134a1c0"
232
+ }
233
+ [direct:INFO] block.advanced {
234
+ client_instance_id: "client_ethereum_f47ac10b_1",
235
+ network_id: "ethereum",
236
+ source: "wire_socket",
237
+ current_block_height: "0x134a1c1"
238
+ }
218
239
  ```
219
240
 
220
241
  ### `logging.requests`
@@ -257,13 +278,17 @@ Debug example (a single request):
257
278
  Get events as structured objects — useful for dashboards, telemetry, or piping into your own observability stack:
258
279
 
259
280
  ```ts
281
+ import { install, type LogEvent } from "@direct.dev/sdk";
282
+
283
+ const onDirectEvent = (event: LogEvent) => {
284
+ dashboard.push(event);
285
+ };
286
+
260
287
  install({
261
288
  logging: {
262
289
  client: "debug",
263
290
  requests: "debug",
264
- onEvent(event) {
265
- dashboard.push(event);
266
- },
291
+ onEvent: onDirectEvent,
267
292
  },
268
293
  });
269
294
  ```
@@ -271,7 +296,7 @@ install({
271
296
  Event shape:
272
297
 
273
298
  ```ts
274
- type DirectLogEvent = {
299
+ type LogEvent = {
275
300
  level: "debug" | "info" | "warn" | "error";
276
301
  name: string;
277
302
  value: Record<string, unknown>;
@@ -285,6 +310,9 @@ type DirectLogEvent = {
285
310
  - `preload.phase`
286
311
  - `preload.clock_sync`
287
312
  - `sync.rebuild`
313
+ - `sync.connection`
314
+ - `sync.ready`
315
+ - `block.advanced`
288
316
  - `client.phase`
289
317
 
290
318
  **Debug-only diagnostics** — only emitted when the relevant log level is active:
@@ -293,14 +321,14 @@ type DirectLogEvent = {
293
321
  - `request_handled`
294
322
  - `block.state_probe`
295
323
 
296
- Typed helper unions live in `@direct.dev/client`: `KnownDirectLogEvent`, `StableDirectLogEvent`, `DebugDirectLogEvent`.
324
+ The SDK exports `LogEvent`, `LoggingOptions`, and `CreateFetchOptions` for typed integrations.
297
325
 
298
326
  ## Inspecting the live client
299
327
 
300
328
  The SDK intercepts a special JSON-RPC method, `direct_client_status`, and answers it locally without touching the network. Useful for debugging your integration:
301
329
 
302
330
  ```ts
303
- const res = await fetch("https://rpc.direct.dev/v1/<projectId>.<token>/ethereum", {
331
+ const res = await fetch("https://rpc.direct.dev/v1/<project>.<token>/ethereum", {
304
332
  method: "POST",
305
333
  headers: { "Content-Type": "application/json" },
306
334
  body: JSON.stringify({
@@ -326,11 +354,9 @@ const { result } = await res.json();
326
354
 
327
355
  The SDK only takes over POST requests whose body is JSON-RPC and whose URL matches a Direct.dev RPC endpoint:
328
356
 
329
- - `https://rpc.direct.dev/v1/<projectId>.<token>/<networkId>`
330
- - `https://staging.rpc.direct.dev/v1/<projectId>.<token>/<networkId>`
331
- - `https://prod.rpc.direct.dev/v1/<projectId>.<token>/<networkId>`
332
-
333
- Everything else — REST APIs, image loads, third-party APIs — passes straight through to native `fetch`.
357
+ - `https://rpc.direct.dev/v1/<project>.<token>/<network>`
358
+ - `https://staging.rpc.direct.dev/v1/<project>.<token>/<network>`
359
+ - `https://prod.rpc.direct.dev/v1/<project>.<token>/<network>`
334
360
 
335
361
  ## License
336
362