@thesight/sdk 0.1.1 → 0.3.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/README.md CHANGED
@@ -13,12 +13,24 @@ correlation — consumable by the Sight dashboard or any APM backend
13
13
 
14
14
  ```bash
15
15
  pnpm add @thesight/sdk
16
+ # or npm install @thesight/sdk
17
+ # or yarn add @thesight/sdk
16
18
  ```
17
19
 
18
20
  All OpenTelemetry dependencies are bundled transitively — you do **not**
19
21
  need to `pnpm add @opentelemetry/*` separately.
20
22
 
21
- ## Quickstart
23
+ Ships both ESM and CJS builds. Works from modern TypeScript projects,
24
+ Node ESM, legacy CJS via `require()`, bundlers, and serverless runtimes.
25
+
26
+ ## Quickstart — `InstrumentedConnection` (automatic spans)
27
+
28
+ The simplest pattern: swap your `Connection` for `InstrumentedConnection`
29
+ and every transaction you send through it gets a span automatically —
30
+ no matter whether you're calling it directly, going through an Anchor
31
+ `provider.sendAndConfirm`, using web3.js's top-level
32
+ `sendAndConfirmTransaction`, or letting a wallet adapter drive the
33
+ flow.
22
34
 
23
35
  ```ts
24
36
  import { initSight, InstrumentedConnection } from '@thesight/sdk';
@@ -33,17 +45,73 @@ initSight({
33
45
  // Drop-in replacement for @solana/web3.js Connection
34
46
  const connection = new InstrumentedConnection(clusterApiUrl('mainnet'));
35
47
 
36
- // Every confirmed transaction becomes an OTel span routed to Sight ingest
37
- const { signature, cpiTree } = await connection.sendAndConfirmInstrumented(tx);
48
+ // Anywhere a Solana tx goes out, a span goes with it:
49
+ await connection.sendRawTransaction(tx.serialize());
50
+ // or...
51
+ await sendAndConfirmTransaction(connection, tx, signers);
52
+ // or...
53
+ const program = new Program(idl, programId, new AnchorProvider(connection, wallet, {}));
54
+ await program.methods.foo().rpc();
55
+ // or...
56
+ await wallet.sendTransaction(tx, connection);
57
+ ```
58
+
59
+ Under the hood, `InstrumentedConnection` overrides the single method
60
+ every Solana send-path eventually calls — `sendRawTransaction` — so you
61
+ get spans regardless of which layer is driving the transaction.
62
+
63
+ ### What the span does, step by step
64
+
65
+ 1. On the synchronous submit path, a span named `solana.sendRawTransaction`
66
+ starts as a child of whatever OTel context is active.
67
+ 2. `super.sendRawTransaction(rawTx, options)` is called verbatim — **no
68
+ byte mutation, no interception of signing, no private key access**.
69
+ 3. The returned signature is attached to the span and the caller gets
70
+ it back immediately.
71
+ 4. In the background (never blocking the caller), a task polls
72
+ `getTransaction(signature)` with exponential backoff until the
73
+ on-chain record is available, parses the program logs into a CPI
74
+ tree via `@thesight/core`, enriches with registered Anchor IDLs,
75
+ and adds `cpi.invoke` events, per-program CU attribution, and
76
+ decoded error details to the span.
77
+ 5. The span ends and flushes via the Sight exporter configured by
78
+ `initSight`.
79
+
80
+ ## Alternative — `trackSolanaTransaction` (non-wrapping)
81
+
82
+ If you don't want to wrap your `Connection` at all, `trackSolanaTransaction`
83
+ observes by signature alone after you've already sent the transaction
84
+ through *any* connection:
85
+
86
+ ```ts
87
+ import { Connection } from '@solana/web3.js';
88
+ import { initSight, trackSolanaTransaction } from '@thesight/sdk';
89
+
90
+ initSight({ apiKey, serviceName: 'checkout' });
91
+
92
+ // Use your normal Connection, unchanged.
93
+ const connection = new Connection(rpcUrl);
94
+ const signature = await wallet.sendTransaction(tx, connection);
95
+
96
+ // Fire-and-forget — span flushes on its own in the background.
97
+ void trackSolanaTransaction({
98
+ signature,
99
+ connection,
100
+ serviceName: 'checkout',
101
+ idls: { [swapProgramId]: swapIdl },
102
+ });
38
103
  ```
39
104
 
40
- `initSight` registers a `NodeTracerProvider` as the global OpenTelemetry
41
- tracer, installs a batch span processor, and wires a Sight-specific
42
- exporter that POSTs to ingest in the expected format. Any tracer
43
- obtained via `trace.getTracer(...)` (including the one
44
- `InstrumentedConnection` uses internally) routes through the same
45
- exporter so if you add OTel instrumentation elsewhere in your app,
46
- those spans get Sight-correlated for free.
105
+ This helper **never touches the send path**. It only observes the
106
+ transaction after the fact by calling `getTransaction(signature)`.
107
+ Recommended when:
108
+
109
+ - You're security-conscious and don't want any SDK code on the
110
+ critical transaction path
111
+ - Your send path goes through a wallet adapter or a wrapper SDK you
112
+ don't control
113
+ - You want to instrument a specific high-value transaction rather
114
+ than everything a connection sends
47
115
 
48
116
  ## Anchor IDL registration
49
117
 
@@ -73,7 +141,8 @@ being fabricated.
73
141
  ## Self-host the ingest
74
142
 
75
143
  By default spans export to `https://ingest.thesight.dev/ingest`.
76
- Override via `ingestUrl` to point at a self-hosted Sight ingest:
144
+ Override via `ingestUrl` to point at a self-hosted Sight ingest (or a
145
+ local Docker stack for development):
77
146
 
78
147
  ```ts
79
148
  initSight({
@@ -85,24 +154,45 @@ initSight({
85
154
 
86
155
  ## What's on the span
87
156
 
88
- Every `sendAndConfirmInstrumented` call produces an OTel span with the
157
+ Every instrumented transaction produces an OTel span with the
89
158
  following attributes when they're available:
90
159
 
91
160
  - `solana.tx.signature` — base58 signature
92
- - `solana.tx.status` — `confirmed` / `failed` / `timeout`
161
+ - `solana.tx.status` — `submitted` → `confirmed` / `failed` / `timeout`
93
162
  - `solana.tx.slot`
94
163
  - `solana.tx.cu_used` / `solana.tx.cu_budget` / `solana.tx.cu_utilization`
95
164
  - `solana.tx.program` — root program name (from registered IDL or
96
- curated known-programs list)
165
+ the curated known-programs list)
97
166
  - `solana.tx.instruction` — extracted from `Program log: Instruction: …`
98
167
  - `solana.tx.error` / `solana.tx.error_code` / `solana.tx.error_program`
99
168
  — decoded from on-chain return data via the registered IDL's error
100
169
  table or the hardcoded native-error tables
101
170
  - `solana.tx.fee_lamports`
102
- - `solana.tx.submit_ms` / `solana.tx.confirmation_ms` /
103
- `solana.tx.enrichment_ms` — client-observed latencies
104
- - Per-CPI `cpi.invoke` events on the span: program, instruction, depth,
105
- CU consumed, CU self, percentage
171
+ - `solana.tx.submit_ms` / `solana.tx.enrichment_ms` — client-observed
172
+ latencies
173
+ - Per-CPI `cpi.invoke` events on the span: program, instruction,
174
+ depth, CU consumed, CU self, percentage
175
+
176
+ ## Configuration
177
+
178
+ `InstrumentedConnection` accepts these extra options alongside the
179
+ standard web3.js `ConnectionConfig`:
180
+
181
+ ```ts
182
+ new InstrumentedConnection(rpcUrl, {
183
+ // Standard ConnectionConfig fields work as before
184
+ commitment: 'confirmed',
185
+
186
+ // Sight-specific
187
+ tracer: customTracer,
188
+ skipIdlResolution: false, // skip log parsing + IDL decoding
189
+ idls: { [programId]: idl },
190
+ allowOnChainIdlFetch: false, // off by default — never guess
191
+ enrichmentTimeoutMs: 30_000, // background enrichment wall time
192
+ enrichmentPollIntervalMs: 500, // base poll interval with 1.5x backoff
193
+ disableAutoSpan: false, // escape hatch for tests
194
+ });
195
+ ```
106
196
 
107
197
  ## Shutdown
108
198
 
@@ -118,6 +208,33 @@ process.on('SIGTERM', async () => {
118
208
  });
119
209
  ```
120
210
 
211
+ ## Migration from 0.1.x
212
+
213
+ Version 0.2.0 removes the `sendAndConfirmInstrumented()` method that
214
+ earlier versions required you to call explicitly. Spans now fire
215
+ automatically from every call to `sendRawTransaction()` — including
216
+ those made by Anchor's provider, web3.js's top-level helpers, and
217
+ wallet adapters — so explicit wrapping is no longer necessary.
218
+
219
+ **If your 0.1.x code looked like this:**
220
+
221
+ ```ts
222
+ const { signature, cpiTree } = await connection.sendAndConfirmInstrumented(tx);
223
+ ```
224
+
225
+ **Replace it with either:**
226
+
227
+ ```ts
228
+ // 1. Standard web3.js — span fires automatically
229
+ const signature = await sendAndConfirmTransaction(connection, tx, signers);
230
+
231
+ // 2. Or inspect the span attributes via your OTel processor
232
+ ```
233
+
234
+ The `cpiTree` is no longer returned from a direct call. It lives on the
235
+ span as `cpi.invoke` events, accessible via any OTel processor hooked
236
+ into the same tracer provider, or visible in the Sight dashboard.
237
+
121
238
  ## License
122
239
 
123
240
  MIT — see `LICENSE`.