nuxt-error-tracker

English · **Українська**
4,042
Install
npm install nuxt-error-tracker
Latest Version:0.1.22
Vue:3
License:PolyForm-Shield-1.0.0
Last Updated:Aug 9, 2026
Links: npm
Maintainer: ray_of_goodness_

nuxt-error-tracker

English · Українська

Легкий трекер frontend-помилок для Nuxt 3 / 4. Перехоплює неопрацьовані помилки, невдалі запити та ланцюжок дій користувача (breadcrumbs), після чого відправляє їх на ваш власний Observer ingest-endpoint. Працює лише на клієнті, батчами, і збудований так, щоб ніколи не ламати застосунок-хост — якщо його не налаштовано, він не робить нічого.

Ви даєте URL і публічний ключ; пакет робить перехоплення. Усе відправлене потрапляє під ваш проєкт у вашому Observer-дашборді, де ви самі переглядаєте, шукаєте та керуєте логами.


Зміст


Як це працює (складові)

Складових три. Цей пакет — лише перша.

Складова Що це За що відповідає
Цей пакет (nuxt-error-tracker) Nuxt-модуль, який ви ставите у застосунок Підключається до браузера, перехоплює помилки + breadcrumbs, батчить їх і POSTить на ваш endpoint. Працює лише на клієнті.
Ваш ingest-endpoint (.../v1/ingest) Observer API, який ви хостите (або маєте доступ) Автентифікує запит за публічним ключем + origin, валідує та rate-лімітує, дедуплікує помилки за fingerprint і зберігає.
Ваш дашборд Консоль Observer Де ви переглядаєте, шукаєте та керуєте логами — стек-трейси, occurrences, breadcrumb-ланцюжки, retention.

Пакет ніколи не вирішує, куди йдуть дані — вирішуєте ви, вказавши endpoint на свій хост. Дефолтного URL немає. Змініть хост — логи підуть за ним. Це і є «bring your own backend»: той самий пакет працює проти localhost під час розробки та проти вашого прод-Observer у релізі, лише зміною endpoint.

Усередині самого пакета:

  • module.ts — Nuxt-модуль. Читає ваші опції та реєструє плагін перехоплення лише коли enabled + endpoint + publicKey присутні всі. Немає будь-чого → плагін не додається, застосунок працює недоторканим. Також нормалізує опції (обрізає maxBatch ≤ 20, maxBreadcrumbs ≤ 50 під серверні ліміти) і додає TypeScript-типи для хелперів.
  • plugin.client.ts — власне рушій перехоплення (лише браузер). Слухає помилки, обгортає fetch, патчить console.error, пише breadcrumbs і керує чергою відправки.
  • plugin.server.ts — маленька SSR-заглушка. Дає no-op $trackError / $addBreadcrumb, щоб виклик під час серверного рендеру ніколи не кидав помилку.
  • ingest.codec.ts — саморобний protobuf-енкодер (без залежностей), що перетворює батч на бінарний формат, який очікує API.

Встановлення

npm i nuxt-error-tracker
# або: bun add nuxt-error-tracker

Отримати endpoint і ключ

Модулю потрібні рівно дві речі, щоб почати звітувати: ingest-endpoint (ваш URL) і публічний ключ (якому проєкту належать помилки). Обидва беруться з вашого Observer-дашборда.

  1. Відкрийте дашборд за адресою https://<ваш-observer-хост>/dashboard.
  2. Створіть акаунт — введіть email і пароль (мін. 8 символів), надішліть. Ви лишаєтесь залогіненим через захищений httpOnly-cookie.
  3. Натисніть New project, дайте назву (напр. my-app) і за бажанням перелічіть origins, на яких працює ваш сайт (через кому, напр. https://my-app.com, http://localhost:3000). Порожньо = приймати будь-який origin. Це серверний allowlist — запити з інших origins відхиляються.
  4. Проєкт тепер показує публічний ключ (pk_…) і готовий сніпет nuxt.config. Використайте Copy key / Copy config.
  5. Endpoint — це ваш хост + /v1/ingest, тобто https://<ваш-observer-хост>/v1/ingest.

Що насправді роблять ці два значення

  • endpoint — куди відправляти. Це ваш URL. Вказуйте на будь-який хост, де крутиться Observer API. Хостованого дефолту немає; ви завжди шлете на свій бекенд.
  • publicKey — чий проєкт помилки. На кожному запиті API шукає проєкт за цим ключем (заголовок X-Public-Key або query ?key= для beacon-шляху), потім застосовує allowlist origins і rate-ліміт цього проєкту. Це публічне значення — безпечно класти у клієнтські бандли. Воно дає лише запис (ingest) в один проєкт; воно не дає нікому читати ваші логи. Читання вимагає логіну в дашборд.

Origins важливі. Якщо ви задали allowlist, він мусить містити кожен origin, з якого віддається застосунок — прод-домени та http://localhost:3000 для локальної розробки — інакше запити браузера отримають 401. Лишіть порожнім під час експериментів, звузьте для продакшену.

Після налаштування (нижче) і деплою перехоплені помилки з'являються під цим проєктом у дашборді. Відкрийте Logs на проєкті, щоб їх переглянути.


Налаштування

Додайте модуль і вкажіть йому ingest-endpoint з публічним ключем вашого проєкту:

// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['nuxt-error-tracker'],
  errorTracker: {
    endpoint: 'https://<ваш-observer-хост>/v1/ingest',
    publicKey: 'pk_xxxxxxxxxxxxxxxxxxxxxxxx',
  },
})

Це мінімум. Усе решта має розумні дефолти.

Немає ключів? Не проблема

Якщо endpoint чи publicKey порожні (або enabled: false), плагін не реєструється, і застосунок працює недоторканим. Тому модуль можна лишати встановленим, підключаючи ключі по-середовищах — dev-збірки без ключа просто не трекають. Ні падіння, ні шуму в консолі, ні мережевого виклику.


Конфігурація через змінні середовища

Кожну опцію можна задати зі змінних середовища замість хардкоду, за конвенцією публічних env у Nuxt runtimeConfig:

NUXT_PUBLIC_ERROR_TRACKER_ENDPOINT=https://<ваш-observer-хост>/v1/ingest
NUXT_PUBLIC_ERROR_TRACKER_PUBLIC_KEY=pk_xxxxxxxxxxxxxxxxxxxxxxxx
NUXT_PUBLIC_ERROR_TRACKER_APP_VERSION=1.4.2

Підключіть їх у nuxt.config.ts:

export default defineNuxtConfig({
  modules: ['nuxt-error-tracker'],
  runtimeConfig: {
    public: {
      errorTracker: {
        endpoint: process.env.NUXT_PUBLIC_ERROR_TRACKER_ENDPOINT,
        publicKey: process.env.NUXT_PUBLIC_ERROR_TRACKER_PUBLIC_KEY,
        appVersion: process.env.NUXT_PUBLIC_ERROR_TRACKER_APP_VERSION,
      },
    },
  },
})

Це рекомендований спосіб націлити ту саму збірку на різний endpoint за середовищем (staging vs. production) без правки коду.


Опції

Опція Тип Дефолт Опис
endpoint string '' Ingest URL (.../v1/ingest). Обовʼязково — ваш хост.
publicKey string '' Публічний ключ вашого проєкту (pk_…). Обовʼязково.
appVersion string 'unknown' Тегує кожен батч релізом/версією для фільтрації.
enabled boolean true Головний вимикач. false = повністю вимкнено, плагін не реєструється.
captureFetch boolean true Обгортає fetch, щоб breadcrumbʼити запити і звітувати про збої / 5xx.
captureFetchDetails boolean true Додає повну деталь запиту/відповіді (метод, статус, тайминг, заголовки, тіло запиту, тіло відповіді) до кожного fetch-breadcrumb. Чутливі заголовки редагуються, тіла обрізаються до 2 КБ. false — лишити fetch-крихти лише-повідомленням (не захоплювати payload / PII).
captureConsole boolean true Патчить console.error, щоб ловити залоговані-але-не-кинуті помилки.
captureInDev boolean false Реєструвати плагін і під nuxt dev. Вимкнено за замовчуванням: dev-сервер зазвичай успадковує прод-.env і слав би помилки в той самий проєкт, що й реальні користувачі. Вмикати лише проти тестового проєкту.
captureInputs boolean false Записує значення полів форм як breadcrumbs (на change/blur). Чутливі поля маскуються. Opt-in — захоплює введені користувачем дані.
flushDelay number 2000 Debounce (мс) перед відправкою черги-батча.
minFlushInterval number 0 Мін. пауза (мс) між флашами — throttle частоти запитів під час шторму помилок. 0 = вимкнено.
sampleRate number 1 Частка (0..1) захоплених помилок, що реально шлються; решта дропається при capture. 0.3 ≈ 30%. Ріже обʼєм до серверного rate limit.
maxPerMinute number 0 Клієнтський ліміт помилок у чергу за rolling-хвилину (fixed window); понад — дроп. Дзеркалить серверний per-project rate limit. 0 = без ліміту.
dedupeWindowMs number 0 Схлопує повтори тієї самої помилки (однакові message + source) у межах N мс в один occurrence. Для клієнтських retry-циклів: повторний запит летить через мілісекунди, має той самий fingerprint і подвоює лічильник для одного видимого користувачу збою. 0 = вимкнено.
maxPerSession number 5 Макс. кількість occurrences тієї самої помилки за сесію.
maxBatch number 20 Макс. помилок на запит (обрізається серверним лімітом 20).
maxBreadcrumbs number 30 Breadcrumbs у ring buffer / на помилку (обрізається до 50).

Runtime-хелпери

Плагін інʼєктить два хелпери для ручного використання:

const { $trackError, $addBreadcrumb } = useNuxtApp()

// Звітувати про опрацьовану помилку самому — опційний рівень серйозності
// ('fatal' | 'error' | 'warning' | 'info' | 'debug', дефолт 'error')
try {
  await mayFail()
} catch (e) {
  $trackError(e, 'warning')
}

// Додати власний breadcrumb у ланцюжок
$addBreadcrumb({
  type: 'custom',
  category: 'checkout',
  message: 'user clicked pay',
  level: 'info',
})

Обидва хелпери завжди викликаються. Реальне перехоплення — лише на клієнті; на сервері (SSR — напр. верхньорівневий <script setup>) це безпечні no-opʼи, тож виклик ніколи не кидає помилку.

$trackError і $addBreadcrumb повністю типізовані — модуль постачає augmentation для NuxtApp і Vue ComponentCustomProperties, тож і useNuxtApp(), і використання в шаблоні бачать їх як функції (без unknown / TS18046). Ручний .d.ts не потрібен.


Що відправляється на API

Нічого не відправляється, доки не станеться помилка. Пакет тримає в памʼяті ring buffer breadcrumbs, поки користувач взаємодіє; при перехопленні помилки він знімає снапшот цього ланцюжка, ставить помилку в чергу і (після debounce) POSTить батч.

Батч має дві частини: meta (раз на батч, застосовується до всіх помилок у ньому) і errors (масив перехоплених помилок).

meta (раз на батч)

Поле Тип Джерело Нотатки
device object navigator / window userAgent, language, platform, screen (ШxВ), viewport (ШxВ), online (bool), memory (deviceMemory, ГБ або null), connection (effectiveType або null). Сервер обрізає JSON до 2 КБ.
userId string | null cookie user_id Читається з cookie user_id, якщо є, інакше null. Пакет ніколи не вигадує id. Макс. 100 символів.
appVersion string ваша опція appVersion Дефолт 'unknown'. Макс. 50 символів.

errors[] (на кожну перехоплену помилку)

Поле Тип Опис Ліміт
message string Повідомлення помилки. ≤ 1000 симв.
stack string Стек-трейс. ≤ 8000 симв.
source string Звідки: vue, window, promise, fetch чи console. ≤ 20 симв.
level string Серйозність: fatal | error | warning | info | debug. одне зі списку
url string window.location.href на момент перехоплення. ≤ 2000 симв.
route string Nuxt-route fullPath. ≤ 500 симв.
occurredAt string ISO-8601 timestamp. ISO-8601
breadcrumbs Breadcrumb[] Ланцюжок, що привів до помилки (нижче). ≤ 50 елементів

Кожен Breadcrumb:

Поле Тип Опис Ліміт
type string click, input, navigation, fetch, console чи ваш кастомний тип. ≤ 30 симв.
category string напр. ui.click, ui.input, navigation, http, console. ≤ 60 симв.
message string Людиночитний рядок, напр. POST /api/pay → 500. ≤ 500 симв.
level string info | error | … ≤ 20 симв.
timestamp string ISO-8601. ISO-8601
data object Опційний структурований payload (деталі fetch: метод, статус, тайминг, заголовки, тіла запиту/відповіді). JSON

Ліміти батча: щонайбільше 20 помилок на запит; клієнт також повертає в чергу невдалі батчі (обмежено 200 у памʼяті) і дедуплікує ту саму помилку до maxPerSession (5) occurrences за сесію, тож одна повторювана помилка не затопить вашу квоту.


Формат передачі та типи даних

Payloadʼи кодуються у protobuf (proto3) і POSTяться як application/x-protobuf. Енкодер саморобний і без залежностей — жодного protobufjs, тож споживачам не потрібні ні Vite optimizeDeps, ні CJS-interop-конфіг.

Схема (номери полів визначальні — вони мусять збігатися з декодером API):

message Breadcrumb {
  string type      = 1;
  string category  = 2;
  string message   = 3;
  string level     = 4;
  string timestamp = 5;
  string data      = 6;  // обʼєкт у вигляді JSON-рядка
}

message Error {
  string message           = 1;
  string stack             = 2;
  string source            = 3;
  string url               = 4;
  string route             = 5;
  string userId            = 6;  // per-error override (цим клієнтом не використовується)
  string appVersion        = 7;  // per-error override (цим клієнтом не використовується)
  string device            = 8;  // per-error override (цим клієнтом не використовується)
  string occurredAt        = 9;
  repeated Breadcrumb breadcrumbs = 10;
  string level             = 11;
}

message Meta  { string device = 1; string userId = 2; string appVersion = 3; }
message Batch { Meta meta = 1; repeated Error errors = 2; }

device і breadcrumb data — обʼєкти, тож їдуть як JSON-рядки всередині protobuf. Порожні рядки опускаються (дефолт proto3). Бінарне обрамлення лише тримає мережеву панель охайною — це не шифрування; схема публічна, тож будь-хто з нею може декодувати payload.

Як передається

  • Звичайний шлях: fetch(endpoint, { method: 'POST', headers: { 'Content-Type': 'application/x-protobuf', 'X-Public-Key': <ключ> }, body: <bytes>, keepalive: true }).
  • Шлях page-hide: черга примусово скидається через `navigator.sendBeacon(endpoint
    • '?key=<ключ>', Blob)— оскільки beacon не може ставити заголовки, ключ їде в query-параметрі?key=. Відкат до fetch(..., { keepalive: true }), якщо sendBeacon` недоступний чи відмовив.

API також приймає звичайний JSON на тому самому endpoint (та сама валідація), що зручно для скриптових тестових POSTів, але SDK завжди шле protobuf.


Перегляд і контроль ваших логів

Сенс власного endpoint: після відправки пакетом ви володієте даними і керуєте ними повністю зі свого дашборда — без сторонньої консолі.

  • Перегляд — відкрийте Logs на проєкті, щоб побачити групи помилок, кожну з повідомленням, лічильником, first/last seen, зачепленими routes і стек-трейсом + breadcrumb-ланцюжком на кожну occurrence (включно з захопленими fetch payload/response, коли captureFetchDetails увімкнено).
  • Дедуплікація — API групує occurrences за fingerprint (хеш нормалізованого повідомлення + верхні стек-фрейми), тож повторювана помилка — це один рядок із лічильником, а не тисячі дублікатів.
  • Rate-ліміт і origins — кожен проєкт має власний per-minute rate-ліміт і allowlist origins. Звузьте origins, щоб відкидати сторонній трафік; самого ключа недостатньо, щоб дані зайшли з неперелічeного origin.
  • Retention — occurrences видаляються після вікна retention (за замовчуванням 7 днів на сервері), тож сховище лишається обмеженим без жодних дій з вашого боку.

Оскільки ключ — лише на запис, а читання під логіном, публікація ключа у клієнтському бандлі не відкриває жодних збережених даних.


Приватність

Click-breadcrumbs записують елемент (tag / id / class / короткий текст / data-* атрибути) — ніколи значення полів. Нічого не захоплюється, доки не станеться помилка; breadcrumbs живуть лише в памʼяті і їдуть прикріпленими до помилки.

Значення полів захоплюються лише коли ви явно вмикаєте captureInputs: true. Навіть тоді чутливі поля маскуються (зберігаються як [masked, N chars], ніколи у відкритому вигляді): будь-який type="password", а також поля, чиї name / id / autocomplete збігаються з pass, secret, token, otp, cvv, card, iban, ssn, pin, auth тощо. Нечутливі значення обрізаються до 100 символів.

Захоплення деталей fetch (captureFetchDetails, увімкнено за замовчуванням) редагує чутливі заголовки запиту/відповіді (authorization, cookie, x-api-key, CSRF-токени, …) і обрізає тіла до 2 КБ. Поставте false, якщо не хочете, щоб payloadʼи запитів чи тіла відповідей взагалі покидали браузер.


Ліцензія

PolyForm Shield 1.0.0 — source-available. Безкоштовно ставити й використовувати для будь-якої мети, окрім створення продукту, що конкурує з цим ПЗ або з тим, що ліцензіар надає з його допомогою. Не можна форкнути у конкурента. Повні умови у LICENSE; авторські права лишаються за автором.

Version History

Version Released Vue License
0.1.22 ^3.0 PolyForm-Shield-1.0.0
0.1.20 ^3.0 PolyForm-Shield-1.0.0
0.1.19 ^3.0 PolyForm-Shield-1.0.0
0.1.18 ^3.0 PolyForm-Shield-1.0.0
0.1.17 ^3.0