@thesight/sdk 0.3.7 → 0.4.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/dist/index.js CHANGED
@@ -5,11 +5,89 @@ import {
5
5
  import {
6
6
  trace as trace3,
7
7
  context as context2,
8
- SpanStatusCode as SpanStatusCode2
8
+ SpanStatusCode as SpanStatusCode3
9
9
  } from "@opentelemetry/api";
10
- import { parseLogs as parseLogs2, IdlResolver as IdlResolver2, enrichTree as enrichTree2, flatAttributions as flatAttributions2 } from "@thesight/core";
11
10
  import { IdlResolver as IdlResolver3 } from "@thesight/core";
12
11
 
12
+ // src/enrichment.ts
13
+ import { SpanStatusCode } from "@opentelemetry/api";
14
+ import { parseLogs, enrichTree, flatAttributions } from "@thesight/core";
15
+ var SOLANA_CU_BUDGET = 2e5;
16
+ var DEFAULT_ENRICHMENT_TIMEOUT_MS = 3e4;
17
+ var DEFAULT_ENRICHMENT_POLL_MS = 500;
18
+ async function pollForTransaction(getTransaction, signature, commitment, deadline, basePollMs) {
19
+ let attempt = 0;
20
+ while (Date.now() < deadline) {
21
+ try {
22
+ const tx = await getTransaction(signature, {
23
+ commitment,
24
+ maxSupportedTransactionVersion: 0
25
+ });
26
+ if (tx) return tx;
27
+ } catch {
28
+ }
29
+ attempt++;
30
+ const waitMs = Math.min(basePollMs * Math.pow(1.5, attempt - 1), 2e3);
31
+ await sleep(waitMs);
32
+ }
33
+ return null;
34
+ }
35
+ function attachTxDetailsToSpan(span, txDetails) {
36
+ span.setAttribute("solana.tx.status", txDetails.meta?.err ? "failed" : "confirmed");
37
+ span.setAttribute("solana.tx.slot", txDetails.slot);
38
+ const fee = txDetails.meta?.fee;
39
+ if (fee !== void 0) span.setAttribute("solana.tx.fee_lamports", fee);
40
+ const cuUsed = txDetails.meta?.computeUnitsConsumed;
41
+ if (cuUsed !== void 0 && cuUsed !== null) {
42
+ span.setAttribute("solana.tx.cu_used", Number(cuUsed));
43
+ span.setAttribute("solana.tx.cu_budget", SOLANA_CU_BUDGET);
44
+ span.setAttribute(
45
+ "solana.tx.cu_utilization",
46
+ parseFloat((Number(cuUsed) / SOLANA_CU_BUDGET * 100).toFixed(1))
47
+ );
48
+ }
49
+ }
50
+ async function attachParsedLogsToSpan(span, logs, resolver) {
51
+ const { cpiTree } = parseLogs({ logs });
52
+ await enrichTree(cpiTree, resolver);
53
+ const attributions = flatAttributions(cpiTree);
54
+ for (const attr of attributions) {
55
+ span.addEvent("cpi.invoke", {
56
+ "cpi.program": attr.programName ?? attr.programId,
57
+ "cpi.instruction": attr.instructionName ?? "unknown",
58
+ "cpi.depth": attr.depth,
59
+ "cpi.cu_consumed": attr.cuConsumed,
60
+ "cpi.cu_self": attr.cuSelf,
61
+ "cpi.percentage": parseFloat(attr.percentage.toFixed(2))
62
+ });
63
+ }
64
+ const root = cpiTree.roots[0];
65
+ if (root) {
66
+ if (root.programName) span.setAttribute("solana.tx.program", root.programName);
67
+ if (root.instructionName) span.setAttribute("solana.tx.instruction", root.instructionName);
68
+ }
69
+ return cpiTree;
70
+ }
71
+ function finalizeSpan(span, txDetails, startTime) {
72
+ if (!txDetails) {
73
+ span.setAttribute("solana.tx.status", "timeout");
74
+ span.setAttribute("solana.tx.enrichment_ms", Date.now() - startTime);
75
+ return;
76
+ }
77
+ span.setAttribute("solana.tx.enrichment_ms", Date.now() - startTime);
78
+ if (txDetails.meta?.err) {
79
+ span.setStatus({ code: SpanStatusCode.ERROR });
80
+ } else {
81
+ span.setStatus({ code: SpanStatusCode.OK });
82
+ }
83
+ }
84
+ function sleep(ms) {
85
+ return new Promise((resolve) => setTimeout(resolve, ms));
86
+ }
87
+
88
+ // src/index.ts
89
+ import { IdlResolver as IdlResolver4 } from "@thesight/core";
90
+
13
91
  // src/init.ts
14
92
  import { trace } from "@opentelemetry/api";
15
93
 
@@ -193,8 +271,9 @@ function initSight(config) {
193
271
  });
194
272
  try {
195
273
  const _require = eval("require");
196
- const { NodeTracerProvider } = _require("@opentelemetry/sdk-trace-node");
197
- const { BatchSpanProcessor } = _require("@opentelemetry/sdk-trace-base");
274
+ const traceBase = _require("@opentelemetry/sdk-trace-base");
275
+ const TracerProvider = traceBase.TracerProvider ?? traceBase.BasicTracerProvider;
276
+ const BatchSpanProcessor = traceBase.BatchSpanProcessor;
198
277
  const otelResources = _require("@opentelemetry/resources");
199
278
  const processor = new BatchSpanProcessor(exporter, {
200
279
  scheduledDelayMillis: config.batchDelayMs ?? 5e3,
@@ -207,11 +286,11 @@ function initSight(config) {
207
286
  };
208
287
  const resource = typeof otelResources.resourceFromAttributes === "function" ? otelResources.resourceFromAttributes(resourceAttrs) : new otelResources.Resource(resourceAttrs);
209
288
  let provider;
210
- if (typeof NodeTracerProvider.prototype.addSpanProcessor === "function") {
211
- provider = new NodeTracerProvider({ resource });
289
+ if (typeof TracerProvider.prototype.addSpanProcessor === "function") {
290
+ provider = new TracerProvider({ resource });
212
291
  provider.addSpanProcessor(processor);
213
292
  } else {
214
- provider = new NodeTracerProvider({ resource, spanProcessors: [processor] });
293
+ provider = new TracerProvider({ resource, spanProcessors: [processor] });
215
294
  }
216
295
  try {
217
296
  provider.register();
@@ -310,68 +389,40 @@ var SightInlineProcessor = class {
310
389
  };
311
390
 
312
391
  // src/track.ts
313
- import { trace as trace2, context, SpanStatusCode } from "@opentelemetry/api";
314
- import { parseLogs, IdlResolver, enrichTree, flatAttributions } from "@thesight/core";
392
+ import { trace as trace2, context, SpanStatusCode as SpanStatusCode2 } from "@opentelemetry/api";
393
+ import { IdlResolver as IdlResolver2 } from "@thesight/core";
315
394
  async function trackSolanaTransaction(opts) {
316
395
  const tracerName = opts.serviceName ?? "@thesight/sdk";
317
396
  const tracer = opts.tracer ?? trace2.getTracer(tracerName);
318
397
  const span = tracer.startSpan("solana.trackTransaction", {}, context.active());
319
398
  span.setAttribute("solana.tx.signature", opts.signature);
320
399
  const start = Date.now();
321
- const deadline = start + (opts.timeoutMs ?? 3e4);
400
+ const deadline = start + (opts.timeoutMs ?? DEFAULT_ENRICHMENT_TIMEOUT_MS);
322
401
  const commitment = opts.commitment ?? "confirmed";
323
- const basePoll = opts.pollIntervalMs ?? 500;
402
+ const basePoll = opts.pollIntervalMs ?? DEFAULT_ENRICHMENT_POLL_MS;
324
403
  const resolver = opts.idlResolver ?? buildResolverFromIdls(opts.idls);
325
404
  try {
326
- const txDetails = await pollGetTransaction(opts.connection, opts.signature, commitment, deadline, basePoll);
405
+ const txDetails = await pollForTransaction(
406
+ (sig, pollOpts) => opts.connection.getTransaction(sig, pollOpts),
407
+ opts.signature,
408
+ commitment,
409
+ deadline,
410
+ basePoll
411
+ );
327
412
  if (!txDetails) {
328
- span.setAttribute("solana.tx.status", "timeout");
329
- span.setAttribute("solana.tx.enrichment_ms", Date.now() - start);
413
+ finalizeSpan(span, null, start);
330
414
  return;
331
415
  }
332
- span.setAttribute("solana.tx.status", txDetails.meta?.err ? "failed" : "confirmed");
333
- span.setAttribute("solana.tx.slot", txDetails.slot);
334
- const fee = txDetails.meta?.fee;
335
- if (fee !== void 0) span.setAttribute("solana.tx.fee_lamports", fee);
336
- const cuUsed = txDetails.meta?.computeUnitsConsumed;
337
- if (cuUsed !== void 0 && cuUsed !== null) {
338
- span.setAttribute("solana.tx.cu_used", Number(cuUsed));
339
- span.setAttribute("solana.tx.cu_budget", 2e5);
340
- span.setAttribute(
341
- "solana.tx.cu_utilization",
342
- parseFloat((Number(cuUsed) / 2e5 * 100).toFixed(1))
343
- );
344
- }
416
+ attachTxDetailsToSpan(span, txDetails);
345
417
  const logs = txDetails.meta?.logMessages ?? [];
346
418
  if (logs.length > 0) {
347
- const { cpiTree } = parseLogs({ logs });
348
- await enrichTree(cpiTree, resolver);
349
- for (const attr of flatAttributions(cpiTree)) {
350
- span.addEvent("cpi.invoke", {
351
- "cpi.program": attr.programName ?? attr.programId,
352
- "cpi.instruction": attr.instructionName ?? "unknown",
353
- "cpi.depth": attr.depth,
354
- "cpi.cu_consumed": attr.cuConsumed,
355
- "cpi.cu_self": attr.cuSelf,
356
- "cpi.percentage": parseFloat(attr.percentage.toFixed(2))
357
- });
358
- }
359
- const root = cpiTree.roots[0];
360
- if (root) {
361
- if (root.programName) span.setAttribute("solana.tx.program", root.programName);
362
- if (root.instructionName) span.setAttribute("solana.tx.instruction", root.instructionName);
363
- }
364
- }
365
- span.setAttribute("solana.tx.enrichment_ms", Date.now() - start);
366
- if (txDetails.meta?.err) {
367
- span.setStatus({ code: SpanStatusCode.ERROR });
368
- } else {
369
- span.setStatus({ code: SpanStatusCode.OK });
419
+ await attachParsedLogsToSpan(span, logs, resolver);
370
420
  }
421
+ finalizeSpan(span, txDetails, start);
371
422
  } catch (err) {
372
423
  span.recordException(err instanceof Error ? err : new Error(String(err)));
373
424
  span.setStatus({
374
- code: SpanStatusCode.ERROR,
425
+ code: SpanStatusCode2.ERROR,
375
426
  message: err instanceof Error ? err.message : String(err)
376
427
  });
377
428
  } finally {
@@ -379,27 +430,10 @@ async function trackSolanaTransaction(opts) {
379
430
  }
380
431
  }
381
432
  function buildResolverFromIdls(idls) {
382
- const resolver = new IdlResolver();
433
+ const resolver = new IdlResolver2();
383
434
  if (idls) resolver.registerMany(idls);
384
435
  return resolver;
385
436
  }
386
- async function pollGetTransaction(connection, signature, commitment, deadline, basePollMs) {
387
- let attempt = 0;
388
- while (Date.now() < deadline) {
389
- try {
390
- const tx = await connection.getTransaction(signature, {
391
- commitment,
392
- maxSupportedTransactionVersion: 0
393
- });
394
- if (tx) return tx;
395
- } catch {
396
- }
397
- attempt++;
398
- const waitMs = Math.min(basePollMs * Math.pow(1.5, attempt - 1), 2e3);
399
- await new Promise((resolve) => setTimeout(resolve, waitMs));
400
- }
401
- return null;
402
- }
403
437
 
404
438
  // src/index.ts
405
439
  var InstrumentedConnection = class extends Connection {
@@ -416,7 +450,9 @@ var InstrumentedConnection = class extends Connection {
416
450
  enrichmentTimeoutMs,
417
451
  enrichmentPollIntervalMs,
418
452
  disableAutoSpan,
419
- commitment,
453
+ // Note: commitment is intentionally NOT destructured out. It must
454
+ // pass through to super() via connectionConfig so the parent
455
+ // Connection uses it for RPC calls (preflight, blockhash, etc.).
420
456
  ...connectionConfig
421
457
  } = config2 ?? {};
422
458
  super(endpoint, connectionConfig);
@@ -425,12 +461,12 @@ var InstrumentedConnection = class extends Connection {
425
461
  idlRpcEndpoint,
426
462
  skipIdlResolution,
427
463
  allowOnChainIdlFetch,
428
- enrichmentTimeoutMs: enrichmentTimeoutMs ?? 3e4,
429
- enrichmentPollIntervalMs: enrichmentPollIntervalMs ?? 500,
464
+ enrichmentTimeoutMs: enrichmentTimeoutMs ?? DEFAULT_ENRICHMENT_TIMEOUT_MS,
465
+ enrichmentPollIntervalMs: enrichmentPollIntervalMs ?? DEFAULT_ENRICHMENT_POLL_MS,
430
466
  disableAutoSpan,
431
- commitment
467
+ commitment: config2?.commitment
432
468
  };
433
- this.idlResolver = new IdlResolver2({
469
+ this.idlResolver = new IdlResolver3({
434
470
  rpcEndpoint: idlRpcEndpoint ?? endpoint,
435
471
  allowOnChainFetch: allowOnChainIdlFetch ?? false
436
472
  });
@@ -478,7 +514,7 @@ var InstrumentedConnection = class extends Connection {
478
514
  span.setAttribute("solana.tx.status", "failed");
479
515
  span.recordException(err instanceof Error ? err : new Error(String(err)));
480
516
  span.setStatus({
481
- code: SpanStatusCode2.ERROR,
517
+ code: SpanStatusCode3.ERROR,
482
518
  message: err instanceof Error ? err.message : String(err)
483
519
  });
484
520
  span.end();
@@ -502,30 +538,30 @@ var InstrumentedConnection = class extends Connection {
502
538
  */
503
539
  async enrichSpanInBackground(span, signature, submitStart) {
504
540
  const enrichStart = Date.now();
505
- const deadline = enrichStart + (this.sightConfig.enrichmentTimeoutMs ?? 3e4);
541
+ const deadline = enrichStart + (this.sightConfig.enrichmentTimeoutMs ?? DEFAULT_ENRICHMENT_TIMEOUT_MS);
506
542
  const commitment = this.sightConfig.commitment ?? "confirmed";
507
- const basePollMs = this.sightConfig.enrichmentPollIntervalMs ?? 500;
543
+ const basePollMs = this.sightConfig.enrichmentPollIntervalMs ?? DEFAULT_ENRICHMENT_POLL_MS;
508
544
  try {
509
- const txDetails = await this.pollForTransaction(signature, commitment, deadline, basePollMs);
545
+ const txDetails = await pollForTransaction(
546
+ (sig, opts) => super.getTransaction(sig, opts),
547
+ signature,
548
+ commitment,
549
+ deadline,
550
+ basePollMs
551
+ );
510
552
  if (!txDetails) {
511
- span.setAttribute("solana.tx.status", "timeout");
512
- span.setAttribute("solana.tx.enrichment_ms", Date.now() - submitStart);
553
+ finalizeSpan(span, null, submitStart);
513
554
  span.end();
514
555
  return;
515
556
  }
516
- this.attachTxDetailsToSpan(span, txDetails);
557
+ attachTxDetailsToSpan(span, txDetails);
517
558
  if (!this.sightConfig.skipIdlResolution) {
518
559
  const logs = txDetails.meta?.logMessages ?? [];
519
560
  if (logs.length > 0) {
520
- await this.attachParsedLogsToSpan(span, logs);
561
+ await attachParsedLogsToSpan(span, logs, this.idlResolver);
521
562
  }
522
563
  }
523
- span.setAttribute("solana.tx.enrichment_ms", Date.now() - submitStart);
524
- if (txDetails.meta?.err) {
525
- span.setStatus({ code: SpanStatusCode2.ERROR });
526
- } else {
527
- span.setStatus({ code: SpanStatusCode2.OK });
528
- }
564
+ finalizeSpan(span, txDetails, submitStart);
529
565
  } catch (err) {
530
566
  span.recordException(err instanceof Error ? err : new Error(String(err)));
531
567
  span.setAttribute(
@@ -536,77 +572,9 @@ var InstrumentedConnection = class extends Connection {
536
572
  span.end();
537
573
  }
538
574
  }
539
- /**
540
- * Poll `getTransaction(signature)` until either the on-chain record is
541
- * returned or the deadline passes. Exponential backoff (1.5x) capped at
542
- * 2 seconds to balance responsiveness against RPC load.
543
- */
544
- async pollForTransaction(signature, commitment, deadline, basePollMs) {
545
- let attempt = 0;
546
- while (Date.now() < deadline) {
547
- try {
548
- const tx = await super.getTransaction(signature, {
549
- commitment,
550
- maxSupportedTransactionVersion: 0
551
- });
552
- if (tx) return tx;
553
- } catch {
554
- }
555
- attempt++;
556
- const waitMs = Math.min(basePollMs * Math.pow(1.5, attempt - 1), 2e3);
557
- await sleep(waitMs);
558
- }
559
- return null;
560
- }
561
- /** Attach the flat fields (slot, fee, CU, status) from a tx response to a span. */
562
- attachTxDetailsToSpan(span, txDetails) {
563
- span.setAttribute("solana.tx.status", txDetails.meta?.err ? "failed" : "confirmed");
564
- span.setAttribute("solana.tx.slot", txDetails.slot);
565
- const fee = txDetails.meta?.fee;
566
- if (fee !== void 0) span.setAttribute("solana.tx.fee_lamports", fee);
567
- const cuUsed = txDetails.meta?.computeUnitsConsumed;
568
- if (cuUsed !== void 0 && cuUsed !== null) {
569
- span.setAttribute("solana.tx.cu_used", Number(cuUsed));
570
- span.setAttribute("solana.tx.cu_budget", 2e5);
571
- span.setAttribute(
572
- "solana.tx.cu_utilization",
573
- parseFloat((Number(cuUsed) / 2e5 * 100).toFixed(1))
574
- );
575
- }
576
- }
577
- /**
578
- * Parse program logs into a CPI tree, enrich with registered IDLs, and
579
- * emit one `cpi.invoke` event per invocation onto the span. Root
580
- * program/instruction names are copied onto span attributes so dashboards
581
- * can filter by them without walking events.
582
- */
583
- async attachParsedLogsToSpan(span, logs) {
584
- const { cpiTree } = parseLogs2({ logs });
585
- await enrichTree2(cpiTree, this.idlResolver);
586
- const attributions = flatAttributions2(cpiTree);
587
- for (const attr of attributions) {
588
- span.addEvent("cpi.invoke", {
589
- "cpi.program": attr.programName ?? attr.programId,
590
- "cpi.instruction": attr.instructionName ?? "unknown",
591
- "cpi.depth": attr.depth,
592
- "cpi.cu_consumed": attr.cuConsumed,
593
- "cpi.cu_self": attr.cuSelf,
594
- "cpi.percentage": parseFloat(attr.percentage.toFixed(2))
595
- });
596
- }
597
- const root = cpiTree.roots[0];
598
- if (root) {
599
- if (root.programName) span.setAttribute("solana.tx.program", root.programName);
600
- if (root.instructionName) span.setAttribute("solana.tx.instruction", root.instructionName);
601
- }
602
- return cpiTree;
603
- }
604
575
  };
605
- function sleep(ms) {
606
- return new Promise((resolve) => setTimeout(resolve, ms));
607
- }
608
576
  export {
609
- IdlResolver3 as IdlResolver,
577
+ IdlResolver4 as IdlResolver,
610
578
  InstrumentedConnection,
611
579
  SightSpanExporter,
612
580
  buildDsn,