nuxt-error-tracker 0.1.18 → 0.1.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -185,6 +185,9 @@ per environment (staging vs. production) without touching code.
185
185
  | `captureConsole` | `boolean` | `true` | Patch `console.error` to capture logged-but-not-thrown errors. |
186
186
  | `captureInputs` | `boolean` | `false` | Record form input values as breadcrumbs (on change/blur). Sensitive fields masked. **Opt-in** — captures user-entered data. |
187
187
  | `flushDelay` | `number` | `2000` | Debounce (ms) before a queued batch is sent. |
188
+ | `minFlushInterval` | `number` | `0` | Floor (ms) between consecutive flushes — throttles request rate during an error storm. `0` = off. |
189
+ | `sampleRate` | `number` | `1` | Fraction (0..1) of captured errors actually sent; the rest are dropped at capture. `0.3` ≈ keep 30%. Thins volume before the server rate limit. |
190
+ | `maxPerMinute` | `number` | `0` | Client-side cap on errors queued per rolling minute (fixed window); excess dropped. Mirrors the server per-project rate limit. `0` = unlimited. |
188
191
  | `maxPerSession` | `number` | `5` | Max occurrences of the *same* error captured per session. |
189
192
  | `maxBatch` | `number` | `20` | Max errors per request (clamped to server hard cap of 20). |
190
193
  | `maxBreadcrumbs` | `number` | `30` | Breadcrumbs kept in the ring buffer / sent per error (clamped to 50). |
package/README.uk.md CHANGED
@@ -185,6 +185,9 @@ export default defineNuxtConfig({
185
185
  | `captureConsole` | `boolean` | `true` | Патчить `console.error`, щоб ловити залоговані-але-не-кинуті помилки. |
186
186
  | `captureInputs` | `boolean` | `false` | Записує значення полів форм як breadcrumbs (на change/blur). Чутливі поля маскуються. **Opt-in** — захоплює введені користувачем дані. |
187
187
  | `flushDelay` | `number` | `2000` | Debounce (мс) перед відправкою черги-батча. |
188
+ | `minFlushInterval` | `number` | `0` | Мін. пауза (мс) між флашами — throttle частоти запитів під час шторму помилок. `0` = вимкнено. |
189
+ | `sampleRate` | `number` | `1` | Частка (0..1) захоплених помилок, що реально шлються; решта дропається при capture. `0.3` ≈ 30%. Ріже обʼєм до серверного rate limit. |
190
+ | `maxPerMinute` | `number` | `0` | Клієнтський ліміт помилок у чергу за rolling-хвилину (fixed window); понад — дроп. Дзеркалить серверний per-project rate limit. `0` = без ліміту. |
188
191
  | `maxPerSession` | `number` | `5` | Макс. кількість occurrences *тієї самої* помилки за сесію. |
189
192
  | `maxBatch` | `number` | `20` | Макс. помилок на запит (обрізається серверним лімітом 20). |
190
193
  | `maxBreadcrumbs` | `number` | `30` | Breadcrumbs у ring buffer / на помилку (обрізається до 50). |
package/dist/module.d.mts CHANGED
@@ -21,8 +21,34 @@ interface ModuleOptions {
21
21
  * masked. Default false — opt in, since it can capture user-entered data.
22
22
  */
23
23
  captureInputs?: boolean;
24
- /** Debounce before a batch is flushed, in ms. Default 2000. */
24
+ /**
25
+ * How often batches leave the browser (debounce before a flush), in ms.
26
+ * A flush is scheduled `flushDelay` after the first queued error; more errors
27
+ * arriving in that window ride the same batch. Default 2000.
28
+ */
25
29
  flushDelay?: number;
30
+ /**
31
+ * Floor on the spacing between consecutive flushes, in ms. Unlike `flushDelay`
32
+ * (a per-batch debounce), this throttles the *rate* of network requests during
33
+ * a sustained error storm: a flush never fires sooner than `minFlushInterval`
34
+ * after the previous one. Default 0 (off — `flushDelay` alone governs cadence).
35
+ */
36
+ minFlushInterval?: number;
37
+ /**
38
+ * Client-side sampling: fraction (0..1) of captured errors to actually send;
39
+ * the rest are dropped before they ever queue. 1 = send everything (default),
40
+ * 0.3 = keep ~30%. Thins volume at the source so a high-traffic app doesn't
41
+ * flood the per-project server rate limit. Applied per occurrence, before the
42
+ * per-session dedup — so with a low rate even a rare error may be dropped.
43
+ */
44
+ sampleRate?: number;
45
+ /**
46
+ * Client-side hard cap on errors *queued* per rolling minute (fixed window);
47
+ * anything over is dropped. Mirrors the server's per-project rate limit so the
48
+ * browser stops emitting instead of shipping batches that get rejected.
49
+ * Default 0 (off — unlimited).
50
+ */
51
+ maxPerMinute?: number;
26
52
  /** Max occurrences of the same error captured per session. Default 5. */
27
53
  maxPerSession?: number;
28
54
  /** Max errors per flushed batch. Default 20 (server also caps at 20). */
package/dist/module.d.ts CHANGED
@@ -21,8 +21,34 @@ interface ModuleOptions {
21
21
  * masked. Default false — opt in, since it can capture user-entered data.
22
22
  */
23
23
  captureInputs?: boolean;
24
- /** Debounce before a batch is flushed, in ms. Default 2000. */
24
+ /**
25
+ * How often batches leave the browser (debounce before a flush), in ms.
26
+ * A flush is scheduled `flushDelay` after the first queued error; more errors
27
+ * arriving in that window ride the same batch. Default 2000.
28
+ */
25
29
  flushDelay?: number;
30
+ /**
31
+ * Floor on the spacing between consecutive flushes, in ms. Unlike `flushDelay`
32
+ * (a per-batch debounce), this throttles the *rate* of network requests during
33
+ * a sustained error storm: a flush never fires sooner than `minFlushInterval`
34
+ * after the previous one. Default 0 (off — `flushDelay` alone governs cadence).
35
+ */
36
+ minFlushInterval?: number;
37
+ /**
38
+ * Client-side sampling: fraction (0..1) of captured errors to actually send;
39
+ * the rest are dropped before they ever queue. 1 = send everything (default),
40
+ * 0.3 = keep ~30%. Thins volume at the source so a high-traffic app doesn't
41
+ * flood the per-project server rate limit. Applied per occurrence, before the
42
+ * per-session dedup — so with a low rate even a rare error may be dropped.
43
+ */
44
+ sampleRate?: number;
45
+ /**
46
+ * Client-side hard cap on errors *queued* per rolling minute (fixed window);
47
+ * anything over is dropped. Mirrors the server's per-project rate limit so the
48
+ * browser stops emitting instead of shipping batches that get rejected.
49
+ * Default 0 (off — unlimited).
50
+ */
51
+ maxPerMinute?: number;
26
52
  /** Max occurrences of the same error captured per session. Default 5. */
27
53
  maxPerSession?: number;
28
54
  /** Max errors per flushed batch. Default 20 (server also caps at 20). */
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nuxt-error-tracker",
3
3
  "configKey": "errorTracker",
4
- "version": "0.1.18",
4
+ "version": "0.1.19",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "0.8.4",
7
7
  "unbuild": "2.0.0"
package/dist/module.mjs CHANGED
@@ -4,6 +4,14 @@ function posInt(value, fallback) {
4
4
  const n = Number(value);
5
5
  return Number.isFinite(n) && n > 0 ? Math.floor(n) : fallback;
6
6
  }
7
+ function clamp01(value, fallback) {
8
+ const n = Number(value);
9
+ return Number.isFinite(n) ? Math.min(Math.max(n, 0), 1) : fallback;
10
+ }
11
+ function nonNegInt(value, fallback) {
12
+ const n = Number(value);
13
+ return Number.isFinite(n) && n >= 0 ? Math.floor(n) : fallback;
14
+ }
7
15
  const module = defineNuxtModule({
8
16
  meta: {
9
17
  name: "nuxt-error-tracker",
@@ -19,6 +27,9 @@ const module = defineNuxtModule({
19
27
  captureConsole: true,
20
28
  captureInputs: false,
21
29
  flushDelay: 2e3,
30
+ minFlushInterval: 0,
31
+ sampleRate: 1,
32
+ maxPerMinute: 0,
22
33
  maxPerSession: 5,
23
34
  maxBatch: 20,
24
35
  maxBreadcrumbs: 30
@@ -35,6 +46,9 @@ const module = defineNuxtModule({
35
46
  captureConsole: options.captureConsole !== false,
36
47
  captureInputs: options.captureInputs === true,
37
48
  flushDelay: posInt(options.flushDelay, 2e3),
49
+ minFlushInterval: nonNegInt(options.minFlushInterval, 0),
50
+ sampleRate: clamp01(options.sampleRate, 1),
51
+ maxPerMinute: nonNegInt(options.maxPerMinute, 0),
38
52
  maxPerSession: posInt(options.maxPerSession, 5),
39
53
  // Server hard-caps batches at 20 — never emit larger, even if misconfigured.
40
54
  maxBatch: Math.min(posInt(options.maxBatch, 20), 20),
@@ -11,12 +11,29 @@ export default defineNuxtPlugin((nuxtApp) => {
11
11
  if (!config || !config.endpoint || !config.publicKey) return;
12
12
  const route = useRoute();
13
13
  const FLUSH_DELAY = config.flushDelay ?? 2e3;
14
+ const MIN_FLUSH_INTERVAL = config.minFlushInterval ?? 0;
15
+ const SAMPLE_RATE = config.sampleRate ?? 1;
16
+ const MAX_PER_MINUTE = config.maxPerMinute ?? 0;
14
17
  const MAX_PER_SESSION = config.maxPerSession ?? 5;
15
18
  const MAX_BATCH = config.maxBatch ?? 20;
16
19
  const MAX_CRUMBS = config.maxBreadcrumbs ?? 30;
17
20
  const queue = [];
18
21
  const sessionCounts = /* @__PURE__ */ new Map();
19
22
  let flushTimer = null;
23
+ let lastFlushAt = 0;
24
+ let rateWindowStart = 0;
25
+ let rateWindowCount = 0;
26
+ function rateLimited() {
27
+ if (!MAX_PER_MINUTE) return false;
28
+ const now = Date.now();
29
+ if (now - rateWindowStart >= 6e4) {
30
+ rateWindowStart = now;
31
+ rateWindowCount = 0;
32
+ }
33
+ if (rateWindowCount >= MAX_PER_MINUTE) return true;
34
+ rateWindowCount++;
35
+ return false;
36
+ }
20
37
  const crumbs = [];
21
38
  function addCrumb(c) {
22
39
  crumbs.push({ ...c, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
@@ -43,6 +60,7 @@ export default defineNuxtPlugin((nuxtApp) => {
43
60
  const MAX_QUEUE = 200;
44
61
  function flush(useBeacon = false) {
45
62
  if (!queue.length) return;
63
+ lastFlushAt = Date.now();
46
64
  try {
47
65
  const batch = queue.splice(0, MAX_BATCH);
48
66
  const body = {
@@ -78,18 +96,22 @@ export default defineNuxtPlugin((nuxtApp) => {
78
96
  }
79
97
  function scheduleFlush() {
80
98
  if (flushTimer) return;
99
+ const sinceLast = Date.now() - lastFlushAt;
100
+ const wait = Math.max(FLUSH_DELAY, MIN_FLUSH_INTERVAL - sinceLast);
81
101
  flushTimer = setTimeout(() => {
82
102
  flushTimer = null;
83
103
  flush();
84
- }, FLUSH_DELAY);
104
+ }, wait);
85
105
  }
86
106
  function capture(err, source, level = "error") {
87
107
  try {
88
108
  const error = err instanceof Error ? err : new Error(String(err));
89
109
  if (error.message === "Script error.") return;
110
+ if (SAMPLE_RATE < 1 && Math.random() >= SAMPLE_RATE) return;
90
111
  const key = sessionKey(error.message, error.stack ?? "");
91
112
  const count = sessionCounts.get(key) ?? 0;
92
113
  if (count >= MAX_PER_SESSION) return;
114
+ if (rateLimited()) return;
93
115
  sessionCounts.set(key, count + 1);
94
116
  queue.push({
95
117
  message: error.message.slice(0, 1e3),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-error-tracker",
3
- "version": "0.1.18",
3
+ "version": "0.1.19",
4
4
  "type": "module",
5
5
  "license": "PolyForm-Shield-1.0.0",
6
6
  "exports": {