npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@miden-sdk/telemetry-otel

v0.17.3

Published

Opt-in OpenTelemetry binding for Miden SDK observations

Readme

@miden-sdk/telemetry-otel

Opt-in OpenTelemetry binding for Miden SDK observations.

@miden-sdk/miden-sdk emits one observation per client operation — name, outcome, duration — and never transports one. It has no telemetry dependency and no egress primitive in that path. This package is the adapter that turns those observations into spans on a tracer you already own, without the core gaining anything.

Installation

pnpm add @miden-sdk/telemetry-otel

OpenTelemetry itself is not a dependency of this package, not even a peer. The binding is defined against the startSpan shape rather than an @opentelemetry/api import, so you own your OTel version, your provider, and your exporters. That matters more here than for most vendors: a second @opentelemetry/api resolved in one tree carries its own global provider registration, and spans start disappearing into whichever copy lost.

Usage

import { trace } from "@opentelemetry/api";
import { MidenClient } from "@miden-sdk/miden-sdk";
import { createOtelObserver } from "@miden-sdk/telemetry-otel";

const client = await MidenClient.create({
  rpcUrl: "testnet",
  feeFaucetId: FEE_FAUCET,
  observer: createOtelObserver({ tracer: trace.getTracer("my-app") }),
});

Pass anything with a startSpan(name, { startTime }) method that returns an object with setAttribute, setStatus, and end: a real tracer, a wrapper of your own, or a test double. Getting the tracer — and registering the provider that backs it — stays your call, in your entry point.

Options

tracer

  • Type: TracerLike — an object with a startSpan method
  • Required. createOtelObserver throws a TypeError at wiring time if it is missing or cannot start a span. That is the one thing this package reports by throwing, and it throws from the factory rather than the observer: an observer cannot report its own misconfiguration, so one built around a missing tracer would discard every observation forever and look exactly like a working one.

includeSensitive

  • Type: boolean
  • Default: false

See below. Only a literal true enables it.

Recorded shape

One span per observation, recorded synchronously, with nothing scheduled afterwards:

| | | |---|---| | span name | miden.<op>, e.g. miden.proveTransaction | | miden.duration_ms | wall time the caller waited | | miden.outcome | "ok" or "error" | | status | ERROR (code 2) on failure; left UNSET on success |

Retroactive spans

The SDK reports an operation once it has finished, so there is never a live span to wrap around the work. The span is reconstructed instead: it ends at the instant the observation arrived and is backdated by the reported duration, so it occupies the interval the operation really ran in. Both timestamps are passed explicitly, which keeps the span's own interval and its miden.duration_ms attribute in agreement — an implicit end time would drift by however long recording the attributes took.

One consequence worth knowing when you read a trace: these spans have no parent and are not nested inside whatever your application was doing at the time. They are a record of a completed operation, not a live instrumentation of one.

A duration that is not a finite, non-negative number cannot describe an interval. Rather than hand the tracer a garbage timestamp, the operation is recorded as an instant at the moment it was reported, with no miden.duration_ms attribute at all.

Sensitive detail

An observation's sensitive channel carries verbatim error text, and the account identifier where the SDK supplies one. It is opt-in at both ends: observeSensitive: true when you construct the client, and includeSensitive: true here. Either one left alone and nothing from that channel reaches your tracer.

When enabled, three attributes may be added, each only if the SDK populated the field:

| | | |---|---| | miden.error_message | verbatim error message | | miden.error_stack | verbatim error stack | | miden.account_id | account the operation acted on |

miden.account_id will not appear in practice yet: the SDK declares sensitive.accountId on the type but does not currently populate it, so the guard for that attribute never fires. It is read defensively here so the attribute starts appearing on its own if a later SDK version fills the field in — do not build a dashboard that assumes it is there today.

By default the SDK omits the sensitive key from an observation entirely, and this binding records nothing in its place — no placeholder, no inferred value, and no empty-valued attributes for a UI to render as blank rows. An observation without the key is still recorded; only its detail is absent. The three fields are read by name rather than enumerated, so a field a later SDK version adds to the channel cannot start flowing to your backend before you have decided it should.

Do not enable either flag in an application with confidentiality obligations to its users. A wallet, for example, must never enable it.

Failure behaviour

The observer never throws. A tracer that is unconfigured, detached, or throwing takes its own span with it and nothing else — the client operation being recorded still succeeds, and the next observation is still recorded. The SDK guards observer invocation too, but this binding is usable outside that guard, so it does not rely on it.

License

MIT