@thesight/sdk 0.3.8 → 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
 
@@ -311,68 +389,40 @@ var SightInlineProcessor = class {
311
389
  };
312
390
 
313
391
  // src/track.ts
314
- import { trace as trace2, context, SpanStatusCode } from "@opentelemetry/api";
315
- 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";
316
394
  async function trackSolanaTransaction(opts) {
317
395
  const tracerName = opts.serviceName ?? "@thesight/sdk";
318
396
  const tracer = opts.tracer ?? trace2.getTracer(tracerName);
319
397
  const span = tracer.startSpan("solana.trackTransaction", {}, context.active());
320
398
  span.setAttribute("solana.tx.signature", opts.signature);
321
399
  const start = Date.now();
322
- const deadline = start + (opts.timeoutMs ?? 3e4);
400
+ const deadline = start + (opts.timeoutMs ?? DEFAULT_ENRICHMENT_TIMEOUT_MS);
323
401
  const commitment = opts.commitment ?? "confirmed";
324
- const basePoll = opts.pollIntervalMs ?? 500;
402
+ const basePoll = opts.pollIntervalMs ?? DEFAULT_ENRICHMENT_POLL_MS;
325
403
  const resolver = opts.idlResolver ?? buildResolverFromIdls(opts.idls);
326
404
  try {
327
- 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
+ );
328
412
  if (!txDetails) {
329
- span.setAttribute("solana.tx.status", "timeout");
330
- span.setAttribute("solana.tx.enrichment_ms", Date.now() - start);
413
+ finalizeSpan(span, null, start);
331
414
  return;
332
415
  }
333
- span.setAttribute("solana.tx.status", txDetails.meta?.err ? "failed" : "confirmed");
334
- span.setAttribute("solana.tx.slot", txDetails.slot);
335
- const fee = txDetails.meta?.fee;
336
- if (fee !== void 0) span.setAttribute("solana.tx.fee_lamports", fee);
337
- const cuUsed = txDetails.meta?.computeUnitsConsumed;
338
- if (cuUsed !== void 0 && cuUsed !== null) {
339
- span.setAttribute("solana.tx.cu_used", Number(cuUsed));
340
- span.setAttribute("solana.tx.cu_budget", 2e5);
341
- span.setAttribute(
342
- "solana.tx.cu_utilization",
343
- parseFloat((Number(cuUsed) / 2e5 * 100).toFixed(1))
344
- );
345
- }
416
+ attachTxDetailsToSpan(span, txDetails);
346
417
  const logs = txDetails.meta?.logMessages ?? [];
347
418
  if (logs.length > 0) {
348
- const { cpiTree } = parseLogs({ logs });
349
- await enrichTree(cpiTree, resolver);
350
- for (const attr of flatAttributions(cpiTree)) {
351
- span.addEvent("cpi.invoke", {
352
- "cpi.program": attr.programName ?? attr.programId,
353
- "cpi.instruction": attr.instructionName ?? "unknown",
354
- "cpi.depth": attr.depth,
355
- "cpi.cu_consumed": attr.cuConsumed,
356
- "cpi.cu_self": attr.cuSelf,
357
- "cpi.percentage": parseFloat(attr.percentage.toFixed(2))
358
- });
359
- }
360
- const root = cpiTree.roots[0];
361
- if (root) {
362
- if (root.programName) span.setAttribute("solana.tx.program", root.programName);
363
- if (root.instructionName) span.setAttribute("solana.tx.instruction", root.instructionName);
364
- }
365
- }
366
- span.setAttribute("solana.tx.enrichment_ms", Date.now() - start);
367
- if (txDetails.meta?.err) {
368
- span.setStatus({ code: SpanStatusCode.ERROR });
369
- } else {
370
- span.setStatus({ code: SpanStatusCode.OK });
419
+ await attachParsedLogsToSpan(span, logs, resolver);
371
420
  }
421
+ finalizeSpan(span, txDetails, start);
372
422
  } catch (err) {
373
423
  span.recordException(err instanceof Error ? err : new Error(String(err)));
374
424
  span.setStatus({
375
- code: SpanStatusCode.ERROR,
425
+ code: SpanStatusCode2.ERROR,
376
426
  message: err instanceof Error ? err.message : String(err)
377
427
  });
378
428
  } finally {
@@ -380,27 +430,10 @@ async function trackSolanaTransaction(opts) {
380
430
  }
381
431
  }
382
432
  function buildResolverFromIdls(idls) {
383
- const resolver = new IdlResolver();
433
+ const resolver = new IdlResolver2();
384
434
  if (idls) resolver.registerMany(idls);
385
435
  return resolver;
386
436
  }
387
- async function pollGetTransaction(connection, signature, commitment, deadline, basePollMs) {
388
- let attempt = 0;
389
- while (Date.now() < deadline) {
390
- try {
391
- const tx = await connection.getTransaction(signature, {
392
- commitment,
393
- maxSupportedTransactionVersion: 0
394
- });
395
- if (tx) return tx;
396
- } catch {
397
- }
398
- attempt++;
399
- const waitMs = Math.min(basePollMs * Math.pow(1.5, attempt - 1), 2e3);
400
- await new Promise((resolve) => setTimeout(resolve, waitMs));
401
- }
402
- return null;
403
- }
404
437
 
405
438
  // src/index.ts
406
439
  var InstrumentedConnection = class extends Connection {
@@ -417,7 +450,9 @@ var InstrumentedConnection = class extends Connection {
417
450
  enrichmentTimeoutMs,
418
451
  enrichmentPollIntervalMs,
419
452
  disableAutoSpan,
420
- 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.).
421
456
  ...connectionConfig
422
457
  } = config2 ?? {};
423
458
  super(endpoint, connectionConfig);
@@ -426,12 +461,12 @@ var InstrumentedConnection = class extends Connection {
426
461
  idlRpcEndpoint,
427
462
  skipIdlResolution,
428
463
  allowOnChainIdlFetch,
429
- enrichmentTimeoutMs: enrichmentTimeoutMs ?? 3e4,
430
- enrichmentPollIntervalMs: enrichmentPollIntervalMs ?? 500,
464
+ enrichmentTimeoutMs: enrichmentTimeoutMs ?? DEFAULT_ENRICHMENT_TIMEOUT_MS,
465
+ enrichmentPollIntervalMs: enrichmentPollIntervalMs ?? DEFAULT_ENRICHMENT_POLL_MS,
431
466
  disableAutoSpan,
432
- commitment
467
+ commitment: config2?.commitment
433
468
  };
434
- this.idlResolver = new IdlResolver2({
469
+ this.idlResolver = new IdlResolver3({
435
470
  rpcEndpoint: idlRpcEndpoint ?? endpoint,
436
471
  allowOnChainFetch: allowOnChainIdlFetch ?? false
437
472
  });
@@ -479,7 +514,7 @@ var InstrumentedConnection = class extends Connection {
479
514
  span.setAttribute("solana.tx.status", "failed");
480
515
  span.recordException(err instanceof Error ? err : new Error(String(err)));
481
516
  span.setStatus({
482
- code: SpanStatusCode2.ERROR,
517
+ code: SpanStatusCode3.ERROR,
483
518
  message: err instanceof Error ? err.message : String(err)
484
519
  });
485
520
  span.end();
@@ -503,30 +538,30 @@ var InstrumentedConnection = class extends Connection {
503
538
  */
504
539
  async enrichSpanInBackground(span, signature, submitStart) {
505
540
  const enrichStart = Date.now();
506
- const deadline = enrichStart + (this.sightConfig.enrichmentTimeoutMs ?? 3e4);
541
+ const deadline = enrichStart + (this.sightConfig.enrichmentTimeoutMs ?? DEFAULT_ENRICHMENT_TIMEOUT_MS);
507
542
  const commitment = this.sightConfig.commitment ?? "confirmed";
508
- const basePollMs = this.sightConfig.enrichmentPollIntervalMs ?? 500;
543
+ const basePollMs = this.sightConfig.enrichmentPollIntervalMs ?? DEFAULT_ENRICHMENT_POLL_MS;
509
544
  try {
510
- 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
+ );
511
552
  if (!txDetails) {
512
- span.setAttribute("solana.tx.status", "timeout");
513
- span.setAttribute("solana.tx.enrichment_ms", Date.now() - submitStart);
553
+ finalizeSpan(span, null, submitStart);
514
554
  span.end();
515
555
  return;
516
556
  }
517
- this.attachTxDetailsToSpan(span, txDetails);
557
+ attachTxDetailsToSpan(span, txDetails);
518
558
  if (!this.sightConfig.skipIdlResolution) {
519
559
  const logs = txDetails.meta?.logMessages ?? [];
520
560
  if (logs.length > 0) {
521
- await this.attachParsedLogsToSpan(span, logs);
561
+ await attachParsedLogsToSpan(span, logs, this.idlResolver);
522
562
  }
523
563
  }
524
- span.setAttribute("solana.tx.enrichment_ms", Date.now() - submitStart);
525
- if (txDetails.meta?.err) {
526
- span.setStatus({ code: SpanStatusCode2.ERROR });
527
- } else {
528
- span.setStatus({ code: SpanStatusCode2.OK });
529
- }
564
+ finalizeSpan(span, txDetails, submitStart);
530
565
  } catch (err) {
531
566
  span.recordException(err instanceof Error ? err : new Error(String(err)));
532
567
  span.setAttribute(
@@ -537,77 +572,9 @@ var InstrumentedConnection = class extends Connection {
537
572
  span.end();
538
573
  }
539
574
  }
540
- /**
541
- * Poll `getTransaction(signature)` until either the on-chain record is
542
- * returned or the deadline passes. Exponential backoff (1.5x) capped at
543
- * 2 seconds to balance responsiveness against RPC load.
544
- */
545
- async pollForTransaction(signature, commitment, deadline, basePollMs) {
546
- let attempt = 0;
547
- while (Date.now() < deadline) {
548
- try {
549
- const tx = await super.getTransaction(signature, {
550
- commitment,
551
- maxSupportedTransactionVersion: 0
552
- });
553
- if (tx) return tx;
554
- } catch {
555
- }
556
- attempt++;
557
- const waitMs = Math.min(basePollMs * Math.pow(1.5, attempt - 1), 2e3);
558
- await sleep(waitMs);
559
- }
560
- return null;
561
- }
562
- /** Attach the flat fields (slot, fee, CU, status) from a tx response to a span. */
563
- attachTxDetailsToSpan(span, txDetails) {
564
- span.setAttribute("solana.tx.status", txDetails.meta?.err ? "failed" : "confirmed");
565
- span.setAttribute("solana.tx.slot", txDetails.slot);
566
- const fee = txDetails.meta?.fee;
567
- if (fee !== void 0) span.setAttribute("solana.tx.fee_lamports", fee);
568
- const cuUsed = txDetails.meta?.computeUnitsConsumed;
569
- if (cuUsed !== void 0 && cuUsed !== null) {
570
- span.setAttribute("solana.tx.cu_used", Number(cuUsed));
571
- span.setAttribute("solana.tx.cu_budget", 2e5);
572
- span.setAttribute(
573
- "solana.tx.cu_utilization",
574
- parseFloat((Number(cuUsed) / 2e5 * 100).toFixed(1))
575
- );
576
- }
577
- }
578
- /**
579
- * Parse program logs into a CPI tree, enrich with registered IDLs, and
580
- * emit one `cpi.invoke` event per invocation onto the span. Root
581
- * program/instruction names are copied onto span attributes so dashboards
582
- * can filter by them without walking events.
583
- */
584
- async attachParsedLogsToSpan(span, logs) {
585
- const { cpiTree } = parseLogs2({ logs });
586
- await enrichTree2(cpiTree, this.idlResolver);
587
- const attributions = flatAttributions2(cpiTree);
588
- for (const attr of attributions) {
589
- span.addEvent("cpi.invoke", {
590
- "cpi.program": attr.programName ?? attr.programId,
591
- "cpi.instruction": attr.instructionName ?? "unknown",
592
- "cpi.depth": attr.depth,
593
- "cpi.cu_consumed": attr.cuConsumed,
594
- "cpi.cu_self": attr.cuSelf,
595
- "cpi.percentage": parseFloat(attr.percentage.toFixed(2))
596
- });
597
- }
598
- const root = cpiTree.roots[0];
599
- if (root) {
600
- if (root.programName) span.setAttribute("solana.tx.program", root.programName);
601
- if (root.instructionName) span.setAttribute("solana.tx.instruction", root.instructionName);
602
- }
603
- return cpiTree;
604
- }
605
575
  };
606
- function sleep(ms) {
607
- return new Promise((resolve) => setTimeout(resolve, ms));
608
- }
609
576
  export {
610
- IdlResolver3 as IdlResolver,
577
+ IdlResolver4 as IdlResolver,
611
578
  InstrumentedConnection,
612
579
  SightSpanExporter,
613
580
  buildDsn,