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

@openbarclay/telltale-client

v0.1.2

Published

Send in-app bug reports to a Telltale ingest Worker, which opens or comments on a GitHub issue in the project's own repo. Zero dependencies; works in browsers, React Native, Expo, Node and Deno.

Readme

@openbarclay/telltale-client

Send in-app bug reports to a Telltale ingest Worker, which scrubs them, deduplicates by fingerprint, and opens or comments on a GitHub issue in that project's own repository.

  • Zero dependencies. Browsers, React Native, Expo, Node 18+, Deno — same package, no polyfill, no native module, no per-platform install step.
  • Ships ESM and CommonJS. import and require both work, so Jest and other CJS tooling load it without any transformIgnorePatterns surgery in your project.
  • ~4 kB. One createTelltale() call and one report().
  • Implements every sender obligation in spec §8.1 so you don't re-derive them per app.

Crashes do not go here. They go Sentry → Sentry's native GitHub integration, with no Telltale code involved. This package is for user-typed bug reports only.

Install

npm install @openbarclay/telltale-client

Use

import { createTelltale, PUBLIC_POSTING_NOTICE } from '@openbarclay/telltale-client'

const telltale = createTelltale({
  project: 'tenzy',                                    // your registry slug
  secret: process.env.EXPO_PUBLIC_TELLTALE_SECRET!,    // YOUR project's secret, only
  endpoint: 'https://telltale.openbarclay.workers.dev',
  release: { version: '1.4.2', surface: 'android' },   // optional
})

// Fire-and-forget: never blocks, never throws.
await telltale.report({
  title: 'Save button does nothing on the guide screen',
  body: 'Tapped save, nothing happened, no error.',
})

report() resolves to { ok: true, issue, url } or { ok: false, error, status } and never rejects. Ignore the promise entirely if you don't need the issue number.

You must show the notice

Spec §4.3 requires a submit-time notice, and this package cannot enforce it — only your UI can place it:

<Text style={styles.notice}>{PUBLIC_POSTING_NOTICE}</Text>
<Button title="Send report" onPress={submit} disabled={!title.trim()} />

The server-side scrub is pattern-based. It catches well-formed emails and phone numbers, not alex at example dot com. The notice is the user's only real warning.

The notice deliberately does not say who can read the issue. §4.3 was written assuming public repositories, but every repo in the registry is currently private — so "anyone can read this" would be false. It cannot claim the reverse either: repository visibility is an operator setting, and flipping a repo to public exposes every historical report retroactively, with no notice to the people who filed them. The wording asserts only what holds under both: the report is filed, durable, and should not carry personal details.

React Native / Expo

Pass AsyncStorage so the anon_id survives app restarts. Without it the id is session-scoped, which still works — it just stops grouping one user's repeat reports.

import AsyncStorage from '@react-native-async-storage/async-storage'

const telltale = createTelltale({
  project: 'tenzy',
  secret: process.env.EXPO_PUBLIC_TELLTALE_SECRET!,
  endpoint: 'https://telltale.openbarclay.workers.dev',
  storage: AsyncStorage,   // satisfies the interface as-is, no adapter
})

No crypto polyfill is needed. React Native ships no SubtleCrypto — Hermes has no WebCrypto, and expo-crypto exposes digests rather than HMAC — so this package carries its own SHA-256/HMAC and uses it automatically when WebCrypto is absent. Both paths are asserted byte-identical to the Worker's own verifier in the test suite; that cross-check is the reason you can trust the fallback.

Use 0.1.2 or later on React Native. 0.1.0 and 0.1.1 never delivered a report from iOS or Android. React Native replaces the global AbortSignal with a polyfill that has no static timeout, so the request deadline threw before fetch ran. Every native report then came back network_error, 2 seconds late, while web builds worked. 0.1.2 falls back to an AbortController plus a timer when AbortSignal.timeout is missing. npm run verify:client now sends a report through each built half with both AbortSignal.timeout and WebCrypto removed, as on Hermes.

Browser

Nothing extra. localStorage and crypto.subtle are picked up automatically.

About the secret

The secret ships inside your client and is extractable. This is a known, accepted position (spec §4.1, §10.1), not an oversight. HMAC here does two things:

  1. Raises abuse from a one-line curl to reverse-engineering a specific app.
  2. Makes abuse attributable to one project, so the response is rotating exactly one secret.

It is not a confidentiality boundary. Give each app only its own secret — never the whole TELLTALE_SENDER_SECRETS blob — because X-Telltale-Project is the sole authority for which repo gets written to, and a shared secret would let the weakest client publish into any repo in the registry.

API

createTelltale(options)

| Option | Required | Notes | |---|---|---| | project | ✓ | Registry slug. Must exist in the Worker's src/registry.ts. | | secret | ✓ | This project's HMAC secret. | | endpoint | ✓ | Worker origin; a full /v1/events URL also works. | | release | | { version, surface }, surface ∈ ios\|android\|web\|desktop. Default for every report. | | context | | { platform, os_version, locale } — a bounded set; other keys are dropped server-side. | | storage | | Defaults to localStorage, else memory. Pass AsyncStorage on RN. | | fetch / now | | Injectable for tests. | | retryDelayMs | | Defaults to 2000. §8.3 mandates this; lowering it deviates from spec. | | onError | | Transport failures. Without it, the only signal is the Worker's /v1/stats. |

report(report)

{ title, body?, release?, context?, occurredAt?, diagnostics? }. title is trimmed and truncated to 120 chars; body is truncated server-side at 8000. Neither is ever rejected for length.

Attaching logs — diagnostics

GitHub has no API for issue attachments, so a log tail is rendered inline instead: the Worker puts it in a collapsed <details> block after the user's own text, under its own 4000-char budget so it cannot truncate the part a human wrote.

await telltale.report({
  title,
  body,
  diagnostics: recentLogLines.join('\n'),   // a curated tail, not raw console
})

It gets the body-scope scrub plus home-path redaction — C:\Users\alex\… becomes C:\Users\[redacted:user]\…, preserving the path shape for triage while dropping the account name. That rule exists because a home path is by far the most common identifier in machine-generated text, and neither the email nor the phone pattern catches it.

Show the user what you are attaching, before it is sent. They can self-censor what they type; they cannot review what your app attaches, and the issue is durable. The scrub is pattern-based — it will not catch API tokens, session ids, or file names someone chose. Send a curated log tail, never raw console output.

anonId()

The install-scoped, per-project anonymous id, generated and persisted on first use. Client-controlled and regenerable — explicitly never a security boundary (§4.2).

Errors you can get back

| error | Meaning | |---|---| | empty_title | Caught locally before any request. | | bad_signature | Wrong secret, or the body was re-encoded after signing. | | clock_skew | Device clock is >10 min out and the single re-sign retry also failed. | | unregistered_project | The slug is not in the Worker's registry — usually a typo. | | rate_limited | §4.2 caps. Dropped, not queued. | | ignored | Matched an issue marked not_planned or telltale:muted. Working as intended. | | github_error | GitHub unreachable — or a PAT that is unset or expired. | | labels_dropped | The issue was created but its labels were not. Breaks dedup; operator must look. | | network_error | Both attempts failed to reach the Worker. |

Retry behaviour

One retry, total. Spec §8.3 allows a single retry after 2s, then the report is dropped — there is no persistent outbox, because that means durable on-device storage of user-typed text.

The clock-skew re-sign is that retry, not an extra one. On a 401 carrying X-Telltale-Server-Time the client re-signs with the server's clock and retries immediately; on a 5xx it waits (honouring a sane Retry-After, capped at 30s) and retries once. A 400, 404 or 429 is never retried.

Adding a new project

  1. Add an explicit entry to the Worker's src/registry.ts — there is no slug-to-repo inference, because a wrong guess writes a user's bug report into a stranger's repository.
  2. Generate an HMAC secret, add it to TELLTALE_SENDER_SECRETS, redeploy the Worker.
  3. Give the app that one secret and call createTelltale.

License

MIT