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

@mizchi/utels

v0.1.0

Published

Sentry alternative for browser and Node.js error tracking with source maps, issue grouping, alerts, and AI-ready debugging context.

Readme

UTELS

ブラウザ / Node.js 向けの軽量エラートラッキング基盤。

v0 では Sentry 代替の error tracking を主導線にし、OpenTelemetry の命名と一部 semantic conventions は補助的に取り入れる。ブラウザ側 SDK は独自の最小実装にする。

Product Positioning

UTELS は browser / Node.js error tracking を主導線にした、self-host 可能な Sentry 代替の最小基盤。raw stack を送って server-side stack parsing と source map 復元を行い、同じ原因の例外を issue として集計する。UX 指標、breadcrumb、AI 向け context bundle、Playwright investigation は error 調査を補助する機能として扱う。BI / product analytics は主導線に混ぜず、必要な契約だけを src/bi/ に隔離する。

v0 の方針

  • モダンブラウザ前提
  • ブラウザ側は最小スクリプト
  • Node.js は bearer token 付きの trusted ingest として扱う
  • 送信は navigator.sendBeacon() 優先
  • サーバー側は Cloudflare Workers
  • UI 計測は data-utels による opt-in
  • エラーは raw stack を送り、server-side parser / symbolication で復元する
  • Web Vitals は一通り送信
  • source map 復元はサーバー側
  • センシティブデータは収集しない
  • sampling rate を設定可能にする

主導線

ブラウザ:

import { createBrowserErrorTracker } from "@mizchi/utels/browser";

const tracker = createBrowserErrorTracker({
  endpoint: "https://utels.dev/__utels?v=1",
  projectId: "proj-example",
  release: "2026.04.11",
  buildId: "build-123",
  sample: {
    session: 1,
    error: 1,
    vital: 1,
    ui: 0.1,
    feature: 0.01,
  },
});

tracker.captureException(new Error("manual error"));

Node.js:

import { createNodeErrorTracker } from "@mizchi/utels/node";

const tracker = createNodeErrorTracker({
  endpoint: "https://utels.dev/__utels?v=1",
  projectId: "proj-example",
  release: "2026.04.11",
  buildId: "build-123",
  token: process.env.UTELS_INGEST_TOKEN,
  sample: {
    session: 1,
    error: 1,
    vital: 0,
    ui: 0,
    feature: 0,
  },
});

tracker.captureException(new Error("manual error"));

src/client は低レベルの browser telemetry client として残し、利用者向けの入口は package subpath の @mizchi/utels/browser@mizchi/utels/node に寄せる。root の @mizchi/utels は両方を re-export する。BI / product analytics は主導線から外し、追加する場合は src/bi/ 配下に隔離する。 BI layer の v1 境界と session / identity / funnel / retention の判断は src/bi/README.mdBI_LAYER_CONTRACT_V1 に固定する。

v0 の主要イベント

  • exception
  • browser.web_vital
  • ui.component.mount
  • ui.component.expose
  • ui.component.click
  • ui.component.unmount
  • ui.screen.view
  • feature.use
  • http.client
  • app.jank

error.enrich は過去 client-side parser との互換イベントとして Worker 側に残すが、v0 の主経路では送らない。

exception には直近 breadcrumb を添付できる。client は ui.screen.viewfeature.useui.component.click、失敗した http.client から breadcrumb を自動生成し、console は v0 では自動収集しない。

詳細は docs/telemetry-spec.md を参照。 今後の製品方針は docs/product-direction.md を参照。 Sentry 相当の機能整理は docs/sentry-parity.md を参照。 server-side noise filter の既定ルールは docs/noise-filter.md を参照。

Cloudflare 側の resource 構成は docs/cloudflare-infra.md を参照。 Dashboard / issue context API の JSON Schema は docs/api-schema.json を参照。 OTel export 用の metric mapping は docs/otel-metric-mapping.md を参照。 Grafana / Prometheus 向けの sample dashboard は docs/grafana-utels-dashboard.json を参照。

正式リリース前の security review、token rotation、retention、production smoke、rollback は docs/release-gates.md を gate として扱う。 GitHub Actions の例は docs/github-actions.md を参照。 workers.dev への初期リリース手順は docs/release-workers-dev.md を参照。 今後の実装タスクは TODO.md を参照。 初期状態では UTELS_BOOTSTRAP_TOKEN で route 全体を閉じられる。

自分自身への dogfood は Node tracker から synthetic error を送る。

pnpm dogfood:self -- \
  --endpoint https://utels.dev \
  --token "$UTELS_INGEST_TOKEN" \
  --release "$(node -p 'require("./package.json").version')" \
  --build-id "$(git rev-parse --short HEAD)"

OTLP metrics export は D1 aggregate から batch job として実行する。

pnpm export:otlp -- \
  --project-id utels-self-host \
  --endpoint https://otel.example.com/v1/metrics \
  --database ANALYTICS_DB

OpenObserve へ試す場合は preset で endpoint と header を組み立てられる。

pnpm export:otlp -- \
  --project-id utels-self-host \
  --preset openobserve \
  --openobserve-url https://api.openobserve.ai \
  --openobserve-org org_name \
  --openobserve-stream utels_metrics \
  --openobserve-username [email protected] \
  --openobserve-password "$OPENOBSERVE_PASSWORD"

Issue Debug Context API

AI triage や bug tracking automation から、対象 issue の調査材料が揃っているかを問い合わせられる。

GET /api/projects/:publicHash/issues/:issueId/debug-context?v=1

レスポンスは utels.issue-debug-context.v1 contract の JSON で、readiness.ok / score / missing / warnings / recommendedActions を返す。元データは issue detail snapshot なので、sourcemap 復元、release/runtime、browser/OS/node version、route/screen、occurrence timeline の不足を同じ API で確認できる。

AI に調査材料一式を渡す場合は context bundle API を使う。

GET /api/projects/:publicHash/issues/:issueId/context?v=1

レスポンスは utels.issue-context.v1 contract の JSON で、issue detail、debug context、occurrence timeline、breakdowns、environment、route/screen、source pointer、source snippet、representative raw samples、release artifact metadata / content hash をまとめて返す。source snippet は sourcemap の sourcesContent から添付し、取得できない場合は limitations に明示する。

AI/agent に Playwright 調査を任せる場合は investigation job API を使う。

GET /api/projects/:publicHash/issues/:issueId/investigation?v=1

レスポンスは utels.issue-investigation.v1 contract の JSON で、context/debug-context API、候補 URL、Chromium / Firefox / WebKit の実行対象、収集すべき evidence を返す。ローカルまたは CI の runner から実行する場合は:

pnpm investigate:issue -- \
  --endpoint http://127.0.0.1:8787 \
  --public-hash uph_xxx \
  --issue-id iss_xxx

調査結果を Worker 側に保存する場合は --upload と bootstrap token を付ける。

pnpm investigate:issue -- \
  --endpoint http://127.0.0.1:8787 \
  --public-hash uph_xxx \
  --issue-id iss_xxx \
  --upload \
  --bootstrap-token "$UTELS_BOOTSTRAP_TOKEN"

保存済み report は issue 単位で取得できる。

GET /api/projects/:publicHash/issues/:issueId/investigation-reports?v=1
GET /api/projects/:publicHash/issues/:issueId/investigation-reports?v=1&include=body
x-utels-bootstrap-token: <UTELS_BOOTSTRAP_TOKEN>

component expose / click の trend は component / screen / event で絞り込める。

GET /api/projects/:publicHash/component-trends?v=1&event=ui.component.click&componentId=2550221387&screenId=3474889267&limit=24

session / pageview 単位の直近統計は raw archive から組み立てる。高 cardinality な永続 BI 集計ではなく、debug 用の短期 API として扱う。

GET /api/projects/:publicHash/pageviews?v=1&sessionId=s1&pageViewId=p1&limit=20&archiveLimit=20

sampling config は project ごとに取得でき、更新は bootstrap token が必要。

GET /api/projects/:publicHash/sampling-config?v=1
PATCH /api/projects/:publicHash/sampling-config?v=1
x-utels-bootstrap-token: <UTELS_BOOTSTRAP_TOKEN>

issue 一覧は status / text / release / runtime / browser などで絞り込める。queryq の alias としても受け付ける。sort=count|last_seen|first_seenorder=desc|asclimitoffset で stream 表示を制御する。未定義の query parameter は typo 防止のため 400 にする。

GET /api/projects/:publicHash/issues?v=1&status=open&query=TypeError&release=2026.05.07&sort=count&order=desc

dashboard API は snapshot.contractx-utels-contract header で schema を versioning する。project dashboard は utels.project-dashboard.v1、UX dashboard は utels.project-ux-dashboard.v1、component trend は utels.component-trend.v1、pageview stats は utels.pageview-stats.v1、sampling config は utels.sampling-config.v1、issue detail は utels.issue-detail.v1、issue search は utels.issue-search.v1

issue search は status=all を指定すると resolved / ignored も含めて検索する。

issue の lifecycle は bootstrap token 付き API で更新できる。

PATCH /api/projects/:publicHash/issues/:issueId/status?v=1
x-utels-bootstrap-token: <UTELS_BOOTSTRAP_TOKEN>

{
  "v": 1,
  "status": "resolved"
}

statusopen / resolved / ignoredresolved issue に同じ canonical fingerprint の error が再発した場合は open に戻る。ignored は自動 reopen しない。

誤って分かれた issue は bootstrap token 付き API で merge / split できる。

POST /api/projects/:publicHash/issues/:targetIssueId/merge?v=1
POST /api/projects/:publicHash/issues/:targetIssueId/split?v=1
x-utels-bootstrap-token: <UTELS_BOOTSTRAP_TOKEN>

{
  "v": 1,
  "sourceIssueIds": ["iss_source"]
}

merge は source issue の occurrence / breakdown を target issue に加算し、split 用 snapshot を issue_group_merge に保存する。split は snapshot の分だけ target から減算して source issue を復元する。

canonical fingerprint の override rule は project 単位に保存できる。

POST /api/projects/:publicHash/fingerprint-rules?v=1
GET /api/projects/:publicHash/fingerprint-rules?v=1
x-utels-bootstrap-token: <UTELS_BOOTSTRAP_TOKEN>

{
  "v": 1,
  "name": "Checkout hook grouping",
  "priority": 10,
  "match": {
    "field": "top_source",
    "contains": "useCheckout.ts"
  },
  "fingerprint": "override:checkout-hook"
}

fieldcanonical_fingerprint / raw_fingerprint / error_type / error_message / top_source / top_function。最初に match した enabled rule が queue consumer と raw backfill の issue grouping に使われる。既存 aggregate に反映するには raw backfill を実行する。

Alert Rules API

alert rule は project 単位に保存できる。new_issue / regression / spike は queue consumer が generic webhook へ utels.alert.v1 payload を送る。

POST /api/projects/:publicHash/alert-rules?v=1
x-utels-bootstrap-token: <UTELS_BOOTSTRAP_TOKEN>

{
  "v": 1,
  "name": "New issue webhook",
  "trigger": "new_issue",
  "action": {
    "type": "webhook",
    "target": "https://hooks.example.com/utels"
  }
}
GET /api/projects/:publicHash/alert-rules?v=1
x-utels-bootstrap-token: <UTELS_BOOTSTRAP_TOKEN>

action.typewebhook / slackwebhookutels.alert.v1 をそのまま POST し、slack は Slack incoming webhook 向けの text / blocks payload に変換して送る。

action.targethttp / https のみ受け付ける。SSRF 防止のため credentials 付き URL、localhost、private / link-local / reserved IP、metadata host は作成時と送信直前の両方で拒否する。

triggernew_issue / regression / spike / rate_limitedspikethreshold.countthreshold.windowSec を使い、issue の window 内 occurrence が threshold 以上になったときに送る。regressionresolved issue が再発して open に戻るときに送る。rate_limited は ingest が 429 になったときに送る。

dashboard API は releaseRegressions に release 間の増加も返す。error_issue_breakdown_hourlyrelease dimension から issue ごとに最新 release と直前 release を比較し、最新 release の occurrence が増えた open issue を deltaCount 順に表示する。これは resolved issue の再発 alert とは別に、release 後に悪化した issue を一覧化するための検出である。

初期プリセットは以下を推奨する。

  • new_issue: 新しい原因の error を即時通知
  • regression: resolved issue の再発を即時通知
  • spike: threshold.count = 10, threshold.windowSec = 3600
  • rate_limited: ingest の 429 を通知

Slack へ送る場合は上の rule の action.typeslackaction.target を Slack incoming webhook URL にする。

webhook payload:

{
  "v": 1,
  "contract": "utels.alert.v1",
  "trigger": "new_issue",
  "rule": {
    "ruleId": "arule_xxx",
    "name": "New issue webhook"
  },
  "project": {
    "projectId": "proj-example"
  },
  "issue": {
    "issueId": "iss_xxx",
    "canonicalFingerprint": "TypeError|src/app.ts:10:render",
    "errorType": "TypeError",
    "errorMessage": "boom"
  },
  "spike": {
    "count": 12,
    "bucketStart": 1778144400,
    "windowStart": 1778144400,
    "threshold": {
      "count": 10,
      "windowSec": 3600
    }
  },
  "regression": {
    "previousStatus": "resolved",
    "previousRelease": "2026.05.06",
    "currentRelease": "2026.05.07"
  },
  "occurredAt": 1778147803853
}

spike は spike alert のときだけ、regression は regression alert のときだけ入る。

delivery は alert_delivery に記録し、rule_id + dedupe_key で同じ issue への重複送信を避ける。失敗した delivery は bootstrap token 付き API で再送できる。

delivery history:

GET /api/projects/:publicHash/alert-deliveries?v=1&status=failed&include=payload
x-utels-bootstrap-token: <UTELS_BOOTSTRAP_TOKEN>

statusall / pending / delivered / failedinclude=payload を付けたときだけ保存済み utels.alert.v1 payload を返す。

POST /__utels/alerts/retry?v=1
x-utels-bootstrap-token: <UTELS_BOOTSTRAP_TOKEN>

{
  "v": 1,
  "projectId": "proj-example",
  "limit": 20
}

Ingest Guardrails

Worker 側で既知ノイズを queue 前に落とす。対象は ResizeObserver loop limit exceeded、extension stack、stack 無し Script error. など。

INGEST_RATE_LIMIT_FREE_PER_MINUTE / INGEST_RATE_LIMIT_PAID_PER_MINUTE を設定すると、project の plan_tier ごとに 1 分 window の rate limit を分けられる。判定は project 全体と project + origin/token 単位の両方で行う。旧 INGEST_RATE_LIMIT_PER_MINUTE は tier 別 limit が未設定のときの fallback。超過時は 429Retry-After を返す。

ingest_metric_hourly には accepted / invalid_payload / rate_limited / noise_droppedoutcome dimension として集計する。queue consumer 側は queue_outcome dimension に invalid_message / raw_archived / raw_archive_failed / aggregate_persisted / aggregate_failed / dead_letter_archived / dead_letter_archive_failed を記録する。DLQ 到達後は再集計せず、R2 の dead/project=<projectId>/...*.jsonl.br に退避する。

Retention / Privacy

retention policy は docs/retention-privacy.mdsrc/shared/privacy.tsutels.retention-privacy-policy.v1 contract で固定する。

  • raw .jsonl.br archive: 30 days
  • D1 error aggregate / ingest metric: 400 days
  • alert delivery / investigation report: 90 days
  • release manifest / sourcemap artifact: manual release GC

PII は SDK と Worker の両方で scrub する。対象は exception.message / exception.stacktrace / rawFingerprint で、secret key-value、Authorization header、JWT、URL credentials、email address を queue / raw archive 前に除去する。full DOM replay、input value、cookie、storage、request body は収集しない。

Raw Backfill

sourcemap を後から upload した場合は、R2 の raw .jsonl.br archive から project の error aggregate を再構築できる。

POST /__utels/backfill/raw?v=1
x-utels-bootstrap-token: <UTELS_BOOTSTRAP_TOKEN>

{
  "v": 1,
  "projectId": "proj-example",
  "resetProjectErrors": true
}

実行時は raw/project=<projectId>/ 配下の .jsonl.br を列挙し、現在の sourcemap / release manifest で error issue、occurrence、breakdown だけを作り直す。Web Vitals / UI / feature aggregate は二重加算を避けるため replay 対象にしない。確認だけなら "dryRun": true を使う。

Release Artifact Upload

release manifest と sourcemap は CLI で UTELS_ARTIFACTS 用 R2 bucket に upload する。

Project の作成

第三者向けに使わせる前に、project を登録する。

pnpm create:project -- \
  --display-name "Example App" \
  --plan free

既存 project の一覧:

pnpm list:projects

Domain の検証タグを発行する

GA と同じように、最初は verification 用の埋め込みタグでサイト管理者であることを確認する。

pnpm create:domain -- \
  --project-id proj-example \
  --origin https://example.com \
  --endpoint https://utels.dev

返り値には verification token と、サイトへ貼る <script> tag が含まれる。

一覧確認:

pnpm list:domains -- \
  --project-id proj-example

verified_at が入った origin だけが browser ingest の許可対象になる。

Upload Token の発行

第三者向け CI upload の前に、運用者が project ごとの upload token を発行する。

pnpm create:upload-token -- \
  --project-id proj-example \
  --label "GitHub Actions"

このコマンドは artifact_upload_token に hash だけを書き込み、平文 token は標準出力に 1 回だけ出す。CI ではその値を UTELS_UPLOAD_TOKEN として secret に保存する。

発行済み token の一覧:

pnpm list:upload-tokens -- \
  --project-id proj-example

token の失効:

pnpm revoke:upload-token -- \
  --token-id utok_xxx \
  --project-id proj-example

Ingest Token の発行

Node.js など trusted runtime から Authorization: Bearer で送る場合は、upload token ではなく ingest token を使う。

pnpm create:ingest-token -- \
  --project-id proj-example \
  --label "Node production"

このコマンドは ingest_token に hash だけを書き込み、平文 token は標準出力に 1 回だけ出す。Node.js SDK ではその値を token に渡す。

pnpm list:ingest-tokens -- \
  --project-id proj-example

pnpm revoke:ingest-token -- \
  --token-id itok_xxx \
  --project-id proj-example

release 時に sourcemap がまだ無い場合は、先に manifest だけ upload できる。

pnpm upload:release -- \
  --dir dist \
  --project-id proj-example \
  --release 2026.04.11 \
  --build-id build-123 \
  --asset-base-url https://cdn.example.com/assets/ \
  --manifest-only \
  --manifest-out dist/utels-manifest.json

sourcemap を後から追加するときは、保存しておいた manifest を参照して sourcemap だけ upload する。

pnpm upload:release -- \
  --dir dist \
  --project-id proj-example \
  --release 2026.04.11 \
  --build-id build-123 \
  --manifest dist/utels-manifest.json \
  --sourcemaps-only

Vite build 時に upload する

Vite project では plugin で build 後に manifest と sourcemap を upload できる。

// vite.config.ts
import { defineConfig } from "vite";
import { utelsVitePlugin } from "@mizchi/utels/vite";

export default defineConfig({
  build: {
    sourcemap: true,
  },
  plugins: [
    utelsVitePlugin({
      projectId: process.env.UTELS_PROJECT_ID,
      release: process.env.UTELS_RELEASE,
      buildId: process.env.UTELS_BUILD_ID,
      assetBaseUrl: process.env.UTELS_ASSET_BASE_URL,
      endpoint: process.env.UTELS_ENDPOINT,
      token: process.env.UTELS_UPLOAD_TOKEN,
    }),
  ],
});

manifest の各 asset には contentHash: "sha256:<hex>" が入り、upload された sourcemap と build artifact を照合できる。

第三者向けの CI では、wrangler の代わりに bearer token 付き HTTP upload を使える。

pnpm upload:release -- \
  --dir dist \
  --project-id proj-example \
  --release 2026.04.11 \
  --build-id build-123 \
  --asset-base-url https://cdn.example.com/assets/ \
  --endpoint https://utels.dev \
  --token "$UTELS_UPLOAD_TOKEN"

UTELS_PROJECT_ID UTELS_ENDPOINT UTELS_UPLOAD_TOKEN UTELS_RELEASE UTELS_BUILD_ID UTELS_ASSET_BASE_URL を環境変数で渡せば、CI では pnpm upload:release -- --dir dist だけでも動く。utel / UTEL_* 互換 alias は提供しない。

artifact は project 単位の key に保存され、公開 read endpoint は持たない。source map は worker 内の symbolication からだけ参照される。

browser ingest は Origin / Refererverified_domain と照合して許可する。public browser path は CORS preflight を避けるため、text/plain の simple request 前提で送る。Node.js ingest は Authorization: Bearer <token> を使う。

注意:

  • 後付けした sourcemap は以後の symbolication に使われる
  • すでに集計済みの過去 raw event を再解決する backfill job はまだ未実装
  • upload token は project ごとに分ける
  • upload token の平文は再表示できない前提で扱う
  • revoke は revoked_at を立てるだけで物理削除しない

dry run:

pnpm upload:release -- \
  --dir dist \
  --project-id proj-example \
  --release 2026.04.11 \
  --build-id build-123 \
  --asset-base-url https://cdn.example.com/assets/ \
  --dry-run

hello サンプルの aggregate を確認するときは:

pnpm inspect:hello

ブラウザの dashboard は:

https://utels.dev/projects/<publicHash>/dashboard
https://utels.dev/projects/<publicHash>/ux

publicHashpnpm create:project の返り値、または pnpm list:projects の出力に含まれる。dashboard は最新 1 件ではなく、component / feature / web vital / error の集計値を表示する。web vital は histogram 由来の p75 / p90 / p99 upper bound を表示する。error は open issue 数と occurrence count を分け、issue list は total_count の多い順に表示する。

UX dashboard は route / screen ごとに views、UI event、HTTP failure、jank blocking をまとめ、Web Vitals は route ごとの percentile として表示する。

異なる browser で同じ原因の error が出た場合は、sourcemap 解決後の exception.type + original source + line + function を canonical fingerprint にして同じ issue に寄せる。sourcemap が無い場合は raw stack 由来の fallback fingerprint を使う。

同じ集計値は JSON API でも取れる。

https://utels.dev/api/projects/<publicHash>/dashboard?v=1
https://utels.dev/api/projects/<publicHash>/ux?v=1
https://utels.dev/api/projects/<publicHash>/component-trends?v=1&event=all
https://utels.dev/api/projects/<publicHash>/pageviews?v=1&archiveLimit=20
https://utels.dev/api/projects/<publicHash>/sampling-config?v=1