@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 +135 -18
- package/dist/index.cjs +297 -121
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +225 -58
- package/dist/index.d.ts +225 -58
- package/dist/index.js +298 -121
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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
|
-
|
|
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
|
-
//
|
|
37
|
-
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
|
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.
|
|
103
|
-
|
|
104
|
-
- Per-CPI `cpi.invoke` events on the span: program, instruction,
|
|
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`.
|