Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,20 @@ Contributors: add user-facing changes under **[Unreleased]** in your PR to `deve

---

## [1.22.11] - 2026-10-20

### Added

- **Missing-event alerts page** — new marketing page at `/features/missing-event-alerts` describing business heartbeat rules (one named event per condition, 1–24 hour window, checks about every 5 minutes, no recovery notification yet), linking to `/docs/alerts` and `/docs/checkins`; added to the sitemap and `llms.txt` ([#842](https://github.com/Telemetry-Tracker/telemetry-tracker/pull/842))
- **README** — XERJ Corpus Hub contributor badge in the README and its German, Spanish and French versions ([#840](https://github.com/Telemetry-Tracker/telemetry-tracker/pull/840))

### Changed

- **Heartbeat rule editor** — a "No events" condition now asks explicitly whether to watch all events in the project or a specific event; "A specific event" requires a name. Existing rules without an event name open as "All events" and behave as before. No API change ([#844](https://github.com/Telemetry-Tracker/telemetry-tracker/pull/844))
- **Docs** — example sender in the email setup docs is now `Telemetry Tracker <info@telemetry-tracker.com>` instead of `noreply@tacko.io` ([#845](https://github.com/Telemetry-Tracker/telemetry-tracker/pull/845))

---

## [1.22.10] - 2026-10-20

### Added
Expand Down
1 change: 1 addition & 0 deletions README.de.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
![TypeScript](https://img.shields.io/badge/TypeScript-3178C6?style=flat&logo=typescript&logoColor=white)
[![npm version](https://img.shields.io/npm/v/@telemetry-tracker/core)](https://www.npmjs.com/package/@telemetry-tracker/core)
[![npm downloads](https://img.shields.io/npm/dm/@telemetry-tracker/core)](https://www.npmjs.com/package/@telemetry-tracker/core)
[![XERJ Corpus Hub contributor](https://hub.xerj.org/contributors/unjica/badge.svg)](https://hub.xerj.org/contributors/unjica.html)

<p align="center">
<strong>Open-source Fehlerverfolgung, Produktanalyse, und Sitzungstelemetrie.</strong>
Expand Down
1 change: 1 addition & 0 deletions README.es.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
![TypeScript](https://img.shields.io/badge/TypeScript-3178C6?style=flat&logo=typescript&logoColor=white)
[![npm version](https://img.shields.io/npm/v/@telemetry-tracker/core)](https://www.npmjs.com/package/@telemetry-tracker/core)
[![npm downloads](https://img.shields.io/npm/dm/@telemetry-tracker/core)](https://www.npmjs.com/package/@telemetry-tracker/core)
[![XERJ Corpus Hub contributor](https://hub.xerj.org/contributors/unjica/badge.svg)](https://hub.xerj.org/contributors/unjica.html)

<p align="center">
<strong>Seguimiento de errores, análisis de productos y telemetría de sesiones open-source.</strong>
Expand Down
1 change: 1 addition & 0 deletions README.fr.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
![TypeScript](https://img.shields.io/badge/TypeScript-3178C6?style=flat&logo=typescript&logoColor=white)
[![npm version](https://img.shields.io/npm/v/@telemetry-tracker/core)](https://www.npmjs.com/package/@telemetry-tracker/core)
[![npm downloads](https://img.shields.io/npm/dm/@telemetry-tracker/core)](https://www.npmjs.com/package/@telemetry-tracker/core)
[![XERJ Corpus Hub contributor](https://hub.xerj.org/contributors/unjica/badge.svg)](https://hub.xerj.org/contributors/unjica.html)

<p align="center">
<strong>Suivi d'erreurs open-source, analytics produit et télémétrie de session.</strong>
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
![TypeScript](https://img.shields.io/badge/TypeScript-3178C6?style=flat&logo=typescript&logoColor=white)
[![npm version](https://img.shields.io/npm/v/@telemetry-tracker/core)](https://www.npmjs.com/package/@telemetry-tracker/core)
[![npm downloads](https://img.shields.io/npm/dm/@telemetry-tracker/core)](https://www.npmjs.com/package/@telemetry-tracker/core)
[![XERJ Corpus Hub contributor](https://hub.xerj.org/contributors/unjica/badge.svg)](https://hub.xerj.org/contributors/unjica.html)

<p align="center">
<strong>Open-source error tracking, product analytics, and session telemetry.</strong>
Expand Down
2 changes: 1 addition & 1 deletion apps/api/scripts/send-release-email.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ async function main() {
if (isResendDomainVerificationError(result.error)) {
console.error(
"Resend rejected the sender domain. Set TELEMETRY_EMAIL_FROM to an address on a verified domain " +
"(hosted cloud: Telemetry Tracker <noreply@tacko.io>). See docs/BILLING.md#production-setup-hosted-cloud."
"(hosted cloud: Telemetry Tracker <info@telemetry-tracker.com>). See docs/BILLING.md#production-setup-hosted-cloud."
);
process.exit(1);
}
Expand Down
2 changes: 1 addition & 1 deletion apps/api/src/generated/api-version.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
/** Generated at build time from CHANGELOG (CHANGELOG.md). Do not edit manually. */
export const API_VERSION = "1.22.10";
export const API_VERSION = "1.22.11";
2 changes: 1 addition & 1 deletion apps/api/src/routes/contact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ function contactDeliveryError(result: { status?: number; error?: string }): stri
) {
return (
`Email delivery is blocked by Resend: verify tacko.io (or your sending domain) in the Resend dashboard ` +
`and set TELEMETRY_EMAIL_FROM to an address on that domain (e.g. Telemetry <noreply@tacko.io>). ` +
`and set TELEMETRY_EMAIL_FROM to an address on that domain (e.g. Telemetry <info@telemetry-tracker.com>). ` +
`Until then, email ${CONTACT_INBOX} directly.`
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ export function GuideCta({
body = "No credit card. Create a project, install the SDK, and the first error shows up in Issues.",
secondaryHref = "/docs/hosted-cloud",
secondaryLabel = "Hosted cloud guide",
primaryLabel = "Start free",
}: {
heading?: string;
body?: string;
secondaryHref?: string;
secondaryLabel?: string;
primaryLabel?: string;
}) {
return (
<section className="not-prose mt-14 rounded-2xl border border-border-strong bg-surface/50 p-6 sm:p-8">
Expand All @@ -22,7 +24,7 @@ export function GuideCta({
pendingLabel="Loading…"
className="inline-flex items-center gap-1.5 rounded-full bg-primary px-5 py-2.5 text-sm font-medium text-primary-foreground transition-transform hover:scale-[1.02]"
>
Start free
{primaryLabel}
<svg
viewBox="0 0 16 16"
className="h-3.5 w-3.5"
Expand Down
58 changes: 56 additions & 2 deletions apps/dashboard/app/dashboard/alerts/AlertRuleEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,41 @@ export function AlertRuleEditor({
</div>
{condition.type === "NO_EVENTS" ? (
<>
<fieldset className="mb-3 flex flex-col gap-1.5 text-[12px] text-muted-foreground">
<legend className="mb-1">Watch</legend>
<div className="flex flex-wrap gap-4">
<label className="flex items-center gap-1.5 text-[13px] text-foreground">
<input
type="radio"
name={`condition-${condition.key}-event-scope`}
value="all"
checked={condition.eventScope === "all"}
disabled={pending}
onChange={() =>
updateCondition(index, { eventScope: "all" })
}
aria-label={`Condition ${index + 1} all events`}
/>
All events in the project
</label>
<label className="flex items-center gap-1.5 text-[13px] text-foreground">
<input
type="radio"
name={`condition-${condition.key}-event-scope`}
value="specific"
checked={condition.eventScope === "specific"}
disabled={pending}
onChange={() =>
updateCondition(index, { eventScope: "specific" })
}
aria-label={`Condition ${index + 1} specific event`}
/>
A specific event
</label>
</div>
</fieldset>
<div className="flex flex-wrap gap-3">
{condition.eventScope === "specific" ? (
<label className="flex min-w-[12rem] flex-1 flex-col gap-1 text-[12px] text-muted-foreground">
Event name
<input
Expand All @@ -181,8 +215,16 @@ export function AlertRuleEditor({
maxLength={MAX_ALERT_RULE_EVENT_NAME_LENGTH}
className={`${inputClass} font-mono`}
aria-label={`Condition ${index + 1} event name`}
aria-invalid={!condition.eventName.trim()}
required
/>
{!condition.eventName.trim() ? (
<span className="text-destructive" role="status">
Enter the event name, or choose &quot;All events&quot;.
</span>
) : null}
</label>
) : null}
<label className="flex flex-col gap-1 text-[12px] text-muted-foreground">
No event for (hours)
<input
Expand Down Expand Up @@ -219,8 +261,14 @@ export function AlertRuleEditor({
</label>
</div>
<p className="mt-2 text-[12px] text-muted-foreground">
Exact name as sent with <code>trackEvent()</code>; leave empty
for any event. Pick a window comfortably longer than the usual
{condition.eventScope === "specific" ? (
<>
Exact name as sent with <code>trackEvent()</code>.{" "}
</>
) : (
<>Alerts when no event of any name arrives. </>
)}
Pick a window comfortably longer than the usual
gap between these events (max {MAX_NO_EVENTS_WINDOW_HOURS}h) —
quiet apps can go hours without a signup. While the event stays
missing the alert repeats every cooldown; there is no recovery
Expand Down Expand Up @@ -414,6 +462,12 @@ export function AlertRuleEditor({
pending ||
!draft.name.trim() ||
draft.conditions.length === 0 ||
draft.conditions.some(
(c) =>
c.type === "NO_EVENTS" &&
c.eventScope === "specific" &&
!c.eventName.trim()
) ||
draft.destinationIds.length === 0
}
onClick={onSubmit}
Expand Down
5 changes: 3 additions & 2 deletions apps/dashboard/app/docs/alerts/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,12 @@ export default function DocsAlertsPage() {
<code>ERROR_RATE</code> between error ingests
</li>
</ul>
<h2>Business heartbeats</h2>
<h2 id="business-heartbeats">Business heartbeats</h2>
<p>
Some failures throw nothing: a verification email is never sent, a webhook returns 200 but
skips the work, a nightly job never runs. Track an event when the flow succeeds, then alert
when that event has not arrived for a number of hours.
when that event has not arrived for a number of hours. Examples and limits are on{" "}
<Link href="/features/missing-event-alerts">missing-event alerts</Link>.
</p>
<pre><code>{`trackEvent("signup_verified"); // user confirmed their email
trackEvent("stripe_webhook_processed"); // webhook handler finished the work
Expand Down
Loading
Loading