@victor-studio/monitor 0.1.0 → 0.2.0

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/dist/index.cjs CHANGED
@@ -1,23 +1,73 @@
1
1
  'use strict';
2
2
 
3
3
  // src/core/transport.ts
4
- async function sendBatch(config, events) {
4
+ var DEFAULT_TIMEOUT = 1e4;
5
+ var DEFAULT_MAX_RETRIES = 3;
6
+ var MAX_PAYLOAD_BYTES = 6e4;
7
+ async function sendBatch(config, events, logger, options) {
5
8
  if (events.length === 0) return true;
6
- try {
7
- const response = await fetch(config.endpoint, {
8
- method: "POST",
9
- headers: { "Content-Type": "application/json" },
10
- body: JSON.stringify({
11
- apiKey: config.apiKey,
12
- events
13
- }),
14
- // Usar keepalive pra garantir envio mesmo quando a página fecha
15
- keepalive: true
16
- });
17
- return response.ok;
18
- } catch {
19
- return false;
9
+ const payload = JSON.stringify({ events });
10
+ if (options?.useBeacon && typeof navigator !== "undefined" && navigator.sendBeacon) {
11
+ const beaconPayload = JSON.stringify({ apiKey: config.apiKey, events });
12
+ const beaconBlob = new Blob([beaconPayload], { type: "application/json" });
13
+ const sent = navigator.sendBeacon(config.endpoint, beaconBlob);
14
+ logger.debug("sendBeacon", sent ? "queued" : "failed", `${events.length} events`);
15
+ return sent;
16
+ }
17
+ const payloadSize = new Blob([payload]).size;
18
+ if (payloadSize > MAX_PAYLOAD_BYTES && events.length > 1) {
19
+ const mid = Math.floor(events.length / 2);
20
+ const [first, second] = await Promise.all([
21
+ sendBatch(config, events.slice(0, mid), logger),
22
+ sendBatch(config, events.slice(mid), logger)
23
+ ]);
24
+ return first && second;
25
+ }
26
+ return sendWithRetry(config, payload, logger);
27
+ }
28
+ async function sendWithRetry(config, payload, logger) {
29
+ const maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;
30
+ const timeout = config.timeout ?? DEFAULT_TIMEOUT;
31
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
32
+ try {
33
+ const controller = new AbortController();
34
+ const timer = setTimeout(() => controller.abort(), timeout);
35
+ const response = await fetch(config.endpoint, {
36
+ method: "POST",
37
+ headers: {
38
+ "Content-Type": "application/json",
39
+ "Authorization": `Bearer ${config.apiKey}`
40
+ },
41
+ body: payload,
42
+ signal: controller.signal,
43
+ keepalive: attempt === 0
44
+ // keepalive só na primeira tentativa
45
+ });
46
+ clearTimeout(timer);
47
+ if (response.ok) {
48
+ logger.debug("sent", `attempt ${attempt + 1}`, response.status);
49
+ return true;
50
+ }
51
+ if (response.status >= 400 && response.status < 500) {
52
+ logger.warn("client error", response.status, "\u2014 no retry");
53
+ return false;
54
+ }
55
+ logger.warn("server error", response.status, `attempt ${attempt + 1}/${maxRetries + 1}`);
56
+ } catch (err) {
57
+ const message = err instanceof Error ? err.message : "unknown error";
58
+ logger.warn("network error", message, `attempt ${attempt + 1}/${maxRetries + 1}`);
59
+ }
60
+ if (attempt < maxRetries) {
61
+ const delay = Math.min(1e3 * Math.pow(2, attempt), 16e3);
62
+ const jitter = Math.random() * 1e3;
63
+ await sleep(delay + jitter);
64
+ }
20
65
  }
66
+ logger.error("all retries exhausted, dropping batch");
67
+ return false;
68
+ }
69
+ function sleep(ms) {
70
+ return new Promise((resolve) => setTimeout(resolve, ms));
21
71
  }
22
72
 
23
73
  // src/core/collector.ts
@@ -28,9 +78,16 @@ var Collector = class {
28
78
  timer = null;
29
79
  config;
30
80
  flushInterval;
31
- constructor(config, flushInterval = DEFAULT_FLUSH_INTERVAL) {
81
+ logger;
82
+ beforeSend;
83
+ sampleRate;
84
+ visibilityHandler = null;
85
+ constructor(config, logger, options) {
32
86
  this.config = config;
33
- this.flushInterval = flushInterval;
87
+ this.logger = logger;
88
+ this.flushInterval = options?.flushInterval ?? DEFAULT_FLUSH_INTERVAL;
89
+ this.beforeSend = options?.beforeSend;
90
+ this.sampleRate = options?.sampleRate ?? 1;
34
91
  }
35
92
  start() {
36
93
  if (this.timer) return;
@@ -38,11 +95,12 @@ var Collector = class {
38
95
  this.flush();
39
96
  }, this.flushInterval);
40
97
  if (typeof window !== "undefined") {
41
- window.addEventListener("visibilitychange", () => {
98
+ this.visibilityHandler = () => {
42
99
  if (document.visibilityState === "hidden") {
43
- this.flush();
100
+ this.flush(true);
44
101
  }
45
- });
102
+ };
103
+ window.addEventListener("visibilitychange", this.visibilityHandler);
46
104
  }
47
105
  }
48
106
  stop() {
@@ -50,55 +108,132 @@ var Collector = class {
50
108
  clearInterval(this.timer);
51
109
  this.timer = null;
52
110
  }
111
+ if (this.visibilityHandler && typeof window !== "undefined") {
112
+ window.removeEventListener("visibilitychange", this.visibilityHandler);
113
+ this.visibilityHandler = null;
114
+ }
53
115
  this.flush();
54
116
  }
55
- push(event) {
56
- this.buffer.push({
57
- ...event,
117
+ push(input) {
118
+ if (input.type !== "heartbeat" && this.sampleRate < 1) {
119
+ if (Math.random() >= this.sampleRate) {
120
+ this.logger.debug("sampled out", input.type);
121
+ return;
122
+ }
123
+ }
124
+ const event = {
125
+ ...input,
58
126
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
59
- });
127
+ };
128
+ if (this.beforeSend) {
129
+ const result = this.beforeSend(event);
130
+ if (result === null) {
131
+ this.logger.debug("dropped by beforeSend", event.type);
132
+ return;
133
+ }
134
+ this.buffer.push(result);
135
+ } else {
136
+ this.buffer.push(event);
137
+ }
138
+ this.logger.debug("buffered", event.type, `(${this.buffer.length}/${MAX_BUFFER_SIZE})`);
60
139
  if (this.buffer.length >= MAX_BUFFER_SIZE) {
61
140
  this.flush();
62
141
  }
63
142
  }
64
- flush() {
143
+ /** Flush manual — exposto via MonitorClient.flush() */
144
+ flush(useBeacon = false) {
65
145
  if (this.buffer.length === 0) return;
66
146
  const events = [...this.buffer];
67
147
  this.buffer = [];
68
- sendBatch(this.config, events).catch(() => {
148
+ this.logger.debug("flushing", events.length, "events", useBeacon ? "(beacon)" : "");
149
+ sendBatch(this.config, events, this.logger, { useBeacon }).catch(() => {
69
150
  });
70
151
  }
152
+ /** Número de eventos no buffer (para debug/testes) */
153
+ get pending() {
154
+ return this.buffer.length;
155
+ }
71
156
  };
72
157
 
158
+ // src/core/env.ts
159
+ var LOCAL_HOSTNAMES = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "0.0.0.0", "[::1]"]);
160
+ function isDev() {
161
+ if (typeof process !== "undefined" && process.env?.NODE_ENV === "development") return true;
162
+ if (typeof process !== "undefined" && process.env?.NODE_ENV === "test") return true;
163
+ if (typeof window !== "undefined" && LOCAL_HOSTNAMES.has(window.location?.hostname)) return true;
164
+ return false;
165
+ }
166
+
167
+ // src/core/logger.ts
168
+ var PREFIX = "[monitor]";
169
+ function createLogger(debug) {
170
+ if (!debug) {
171
+ return { debug: noop, warn: noop, error: noop };
172
+ }
173
+ return {
174
+ debug: (...args) => console.debug(PREFIX, ...args),
175
+ warn: (...args) => console.warn(PREFIX, ...args),
176
+ error: (...args) => console.error(PREFIX, ...args)
177
+ };
178
+ }
179
+ function noop() {
180
+ }
181
+
73
182
  // src/core/client.ts
74
183
  var MonitorClient = class {
75
184
  config;
76
185
  collector;
186
+ logger;
77
187
  heartbeatTimer = null;
78
188
  active = false;
79
189
  constructor(config) {
80
190
  this.config = config;
191
+ this.logger = createLogger(config.debug ?? false);
81
192
  this.collector = new Collector(
82
- { endpoint: config.endpoint, apiKey: config.apiKey },
83
- config.flushInterval
193
+ {
194
+ endpoint: config.endpoint,
195
+ apiKey: config.apiKey,
196
+ timeout: config.timeout,
197
+ maxRetries: config.maxRetries
198
+ },
199
+ this.logger,
200
+ {
201
+ flushInterval: config.flushInterval,
202
+ beforeSend: config.beforeSend,
203
+ sampleRate: config.sampleRate
204
+ }
84
205
  );
85
206
  }
86
207
  /** Inicia o monitoring (heartbeat + collector) */
87
208
  start() {
88
- if (this.config.disableInDev !== false && this.isDev()) return;
209
+ if (this.config.disableInDev !== false && isDev()) {
210
+ this.logger.debug("disabled in dev \u2014 call start() with disableInDev: false to override");
211
+ return;
212
+ }
89
213
  if (this.active) return;
90
214
  this.active = true;
91
215
  this.collector.start();
92
216
  this.startHeartbeat();
217
+ this.logger.debug("started", `endpoint=${this.config.endpoint}`);
93
218
  }
94
219
  /** Para o monitoring */
95
220
  stop() {
221
+ if (!this.active) return;
96
222
  this.active = false;
97
223
  this.collector.stop();
98
224
  if (this.heartbeatTimer) {
99
225
  clearInterval(this.heartbeatTimer);
100
226
  this.heartbeatTimer = null;
101
227
  }
228
+ this.logger.debug("stopped");
229
+ }
230
+ /** Força um flush imediato do buffer */
231
+ flush() {
232
+ this.collector.flush();
233
+ }
234
+ /** Verifica se o monitoring está ativo */
235
+ get isActive() {
236
+ return this.active;
102
237
  }
103
238
  /** Registra um evento de request HTTP (usado pelo middleware) */
104
239
  trackRequest(data) {
@@ -110,6 +245,22 @@ var MonitorClient = class {
110
245
  if (!this.active) return;
111
246
  this.collector.push({ type: "vital", data });
112
247
  }
248
+ /** Registra um evento de adapter (DB, cache, AI, queue, email) */
249
+ trackAdapter(data) {
250
+ if (!this.active) return;
251
+ this.collector.push({ type: "adapter", data });
252
+ }
253
+ /** Registra um erro capturado */
254
+ captureError(data) {
255
+ if (!this.active) return;
256
+ this.collector.push({ type: "error", data });
257
+ }
258
+ /** Registra um evento de deploy */
259
+ trackDeploy(data) {
260
+ if (!this.active) return;
261
+ this.collector.push({ type: "deploy", data });
262
+ }
263
+ // ─── Private ────────────────────────────────────────
113
264
  startHeartbeat() {
114
265
  const interval = this.config.heartbeatInterval ?? 6e4;
115
266
  this.sendHeartbeat();
@@ -136,18 +287,12 @@ var MonitorClient = class {
136
287
  this.collector.push({
137
288
  type: "heartbeat",
138
289
  data: {
139
- status: "online",
140
- // O app está rodando, mesmo que o endpoint falhe
290
+ status: "offline",
141
291
  latencyMs: Math.round(performance.now() - start)
142
292
  }
143
293
  });
144
294
  }
145
295
  }
146
- isDev() {
147
- if (typeof process !== "undefined" && process.env?.NODE_ENV === "development") return true;
148
- if (typeof window !== "undefined" && window.location?.hostname === "localhost") return true;
149
- return false;
150
- }
151
296
  };
152
297
 
153
298
  // src/index.ts
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/transport.ts","../src/core/collector.ts","../src/core/client.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["// Transport — envia batch de eventos pro backend Nuvio\n\nexport interface MonitorEvent {\n type: 'heartbeat' | 'request' | 'vital'\n data: Record<string, unknown>\n timestamp: string\n}\n\nexport interface TransportConfig {\n endpoint: string\n apiKey: string\n}\n\nexport async function sendBatch(\n config: TransportConfig,\n events: MonitorEvent[],\n): Promise<boolean> {\n if (events.length === 0) return true\n\n try {\n const response = await fetch(config.endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n apiKey: config.apiKey,\n events,\n }),\n // Usar keepalive pra garantir envio mesmo quando a página fecha\n keepalive: true,\n })\n\n return response.ok\n } catch {\n // Falha silenciosa — monitoring não pode quebrar o app do cliente\n return false\n }\n}\n","// Collector — acumula eventos em buffer e envia em batch\n\nimport { sendBatch, type MonitorEvent, type TransportConfig } from './transport'\n\nconst DEFAULT_FLUSH_INTERVAL = 30_000 // 30 segundos\nconst MAX_BUFFER_SIZE = 50\n\nexport class Collector {\n private buffer: MonitorEvent[] = []\n private timer: ReturnType<typeof setInterval> | null = null\n private config: TransportConfig\n private flushInterval: number\n\n constructor(config: TransportConfig, flushInterval = DEFAULT_FLUSH_INTERVAL) {\n this.config = config\n this.flushInterval = flushInterval\n }\n\n start() {\n if (this.timer) return\n\n this.timer = setInterval(() => {\n this.flush()\n }, this.flushInterval)\n\n // Flush quando a página for fechada (browser)\n if (typeof window !== 'undefined') {\n window.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'hidden') {\n this.flush()\n }\n })\n }\n }\n\n stop() {\n if (this.timer) {\n clearInterval(this.timer)\n this.timer = null\n }\n // Flush final\n this.flush()\n }\n\n push(event: Omit<MonitorEvent, 'timestamp'>) {\n this.buffer.push({\n ...event,\n timestamp: new Date().toISOString(),\n })\n\n // Se buffer cheio, flush imediato\n if (this.buffer.length >= MAX_BUFFER_SIZE) {\n this.flush()\n }\n }\n\n private flush() {\n if (this.buffer.length === 0) return\n\n const events = [...this.buffer]\n this.buffer = []\n\n // Fire-and-forget — não bloqueia o app\n sendBatch(this.config, events).catch(() => {\n // Silencioso — eventos perdidos são aceitáveis\n })\n }\n}\n","// MonitorClient — instância principal do SDK\n\nimport { Collector } from './collector'\n\nexport interface MonitorConfig {\n /** ID do projeto no Nuvio */\n projectId: string\n /** API key gerada no Nuvio */\n apiKey: string\n /** URL do endpoint de ingest (ex: https://app.nuvio.com/api/monitor/ingest) */\n endpoint: string\n /** Intervalo do heartbeat em ms (default: 60000) */\n heartbeatInterval?: number\n /** Intervalo do flush do buffer em ms (default: 30000) */\n flushInterval?: number\n /** Desabilitar em desenvolvimento (default: true) */\n disableInDev?: boolean\n}\n\nexport class MonitorClient {\n readonly config: MonitorConfig\n readonly collector: Collector\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null\n private active = false\n\n constructor(config: MonitorConfig) {\n this.config = config\n this.collector = new Collector(\n { endpoint: config.endpoint, apiKey: config.apiKey },\n config.flushInterval,\n )\n }\n\n /** Inicia o monitoring (heartbeat + collector) */\n start() {\n // Não roda em dev por padrão\n if (this.config.disableInDev !== false && this.isDev()) return\n if (this.active) return\n\n this.active = true\n this.collector.start()\n this.startHeartbeat()\n }\n\n /** Para o monitoring */\n stop() {\n this.active = false\n this.collector.stop()\n\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer)\n this.heartbeatTimer = null\n }\n }\n\n /** Registra um evento de request HTTP (usado pelo middleware) */\n trackRequest(data: {\n method: string\n route: string\n statusCode: number\n responseTimeMs: number\n userAgent?: string\n region?: string\n }) {\n if (!this.active) return\n this.collector.push({ type: 'request', data })\n }\n\n /** Registra um Web Vital (usado pelo MonitorScript) */\n trackVital(data: {\n name: 'LCP' | 'INP' | 'CLS' | 'FCP' | 'TTFB'\n value: number\n rating: 'good' | 'needs-improvement' | 'poor'\n page?: string\n deviceType?: string\n browser?: string\n }) {\n if (!this.active) return\n this.collector.push({ type: 'vital', data })\n }\n\n private startHeartbeat() {\n const interval = this.config.heartbeatInterval ?? 60_000\n\n // Primeiro heartbeat imediato\n this.sendHeartbeat()\n\n this.heartbeatTimer = setInterval(() => {\n this.sendHeartbeat()\n }, interval)\n }\n\n private async sendHeartbeat() {\n const start = performance.now()\n\n try {\n // Ping pro endpoint pra medir latência\n const response = await fetch(this.config.endpoint, {\n method: 'HEAD',\n cache: 'no-store',\n })\n\n const latencyMs = Math.round(performance.now() - start)\n\n this.collector.push({\n type: 'heartbeat',\n data: {\n status: response.ok ? 'online' : 'offline',\n latencyMs,\n },\n })\n } catch {\n this.collector.push({\n type: 'heartbeat',\n data: {\n status: 'online', // O app está rodando, mesmo que o endpoint falhe\n latencyMs: Math.round(performance.now() - start),\n },\n })\n }\n }\n\n private isDev(): boolean {\n if (typeof process !== 'undefined' && process.env?.NODE_ENV === 'development') return true\n if (typeof window !== 'undefined' && window.location?.hostname === 'localhost') return true\n return false\n }\n}\n","// @victor-studio/monitor — SDK de monitoramento\n\nimport { MonitorClient, type MonitorConfig } from './core/client'\n\nexport { MonitorClient, type MonitorConfig } from './core/client'\n\n/**\n * Cria e inicia uma instância do monitor.\n *\n * @example\n * ```ts\n * import { createMonitor } from '@victor-studio/monitor'\n *\n * export const monitor = createMonitor({\n * projectId: 'uuid-do-projeto',\n * apiKey: 'nuvio_mon_xxxxxxxx',\n * endpoint: 'https://app.nuvio.com/api/monitor/ingest',\n * })\n * ```\n */\nexport function createMonitor(config: MonitorConfig): MonitorClient {\n const client = new MonitorClient(config)\n client.start()\n return client\n}\n"]}
1
+ {"version":3,"sources":["../src/core/transport.ts","../src/core/collector.ts","../src/core/env.ts","../src/core/logger.ts","../src/core/client.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["// Transport — envia batch de eventos pro backend Nuvio\n\nimport type { MonitorEvent } from '../types'\nimport type { Logger } from './logger'\n\nexport interface TransportConfig {\n endpoint: string\n apiKey: string\n /** Timeout do fetch em ms (default: 10000) */\n timeout?: number\n /** Max tentativas de retry (default: 3) */\n maxRetries?: number\n}\n\ninterface SendOptions {\n /** Usar sendBeacon em vez de fetch (para page unload) */\n useBeacon?: boolean\n}\n\nconst DEFAULT_TIMEOUT = 10_000\nconst DEFAULT_MAX_RETRIES = 3\nconst MAX_PAYLOAD_BYTES = 60_000 // 60KB — abaixo do limite de 64KB do keepalive\n\n/**\n * Envia um batch de eventos para o endpoint.\n * Usa Authorization header, retry com backoff, e sendBeacon como fallback.\n */\nexport async function sendBatch(\n config: TransportConfig,\n events: MonitorEvent[],\n logger: Logger,\n options?: SendOptions,\n): Promise<boolean> {\n if (events.length === 0) return true\n\n const payload = JSON.stringify({ events })\n\n // Se é unload, usa sendBeacon (mais confiável que fetch no page close)\n if (options?.useBeacon && typeof navigator !== 'undefined' && navigator.sendBeacon) {\n // sendBeacon não suporta headers customizados — inclui apiKey no body\n const beaconPayload = JSON.stringify({ apiKey: config.apiKey, events })\n const beaconBlob = new Blob([beaconPayload], { type: 'application/json' })\n const sent = navigator.sendBeacon(config.endpoint, beaconBlob)\n logger.debug('sendBeacon', sent ? 'queued' : 'failed', `${events.length} events`)\n return sent\n }\n\n // Dividir em batches menores se payload é muito grande\n const payloadSize = new Blob([payload]).size\n if (payloadSize > MAX_PAYLOAD_BYTES && events.length > 1) {\n const mid = Math.floor(events.length / 2)\n const [first, second] = await Promise.all([\n sendBatch(config, events.slice(0, mid), logger),\n sendBatch(config, events.slice(mid), logger),\n ])\n return first && second\n }\n\n return sendWithRetry(config, payload, logger)\n}\n\nasync function sendWithRetry(\n config: TransportConfig,\n payload: string,\n logger: Logger,\n): Promise<boolean> {\n const maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES\n const timeout = config.timeout ?? DEFAULT_TIMEOUT\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), timeout)\n\n const response = await fetch(config.endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${config.apiKey}`,\n },\n body: payload,\n signal: controller.signal,\n keepalive: attempt === 0, // keepalive só na primeira tentativa\n })\n\n clearTimeout(timer)\n\n if (response.ok) {\n logger.debug('sent', `attempt ${attempt + 1}`, response.status)\n return true\n }\n\n // 4xx — erro do cliente, não faz retry (apiKey inválida, payload mal formado, etc.)\n if (response.status >= 400 && response.status < 500) {\n logger.warn('client error', response.status, '— no retry')\n return false\n }\n\n // 5xx — erro do servidor, faz retry\n logger.warn('server error', response.status, `attempt ${attempt + 1}/${maxRetries + 1}`)\n } catch (err) {\n // Network error ou timeout — faz retry\n const message = err instanceof Error ? err.message : 'unknown error'\n logger.warn('network error', message, `attempt ${attempt + 1}/${maxRetries + 1}`)\n }\n\n // Esperar antes do retry (exponential backoff com jitter)\n if (attempt < maxRetries) {\n const delay = Math.min(1000 * Math.pow(2, attempt), 16_000)\n const jitter = Math.random() * 1000\n await sleep(delay + jitter)\n }\n }\n\n logger.error('all retries exhausted, dropping batch')\n return false\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n","// Collector — acumula eventos em buffer e envia em batch\n\nimport type { MonitorEvent, MonitorEventInput, BeforeSendHook } from '../types'\nimport { sendBatch, type TransportConfig } from './transport'\nimport type { Logger } from './logger'\n\nconst DEFAULT_FLUSH_INTERVAL = 30_000 // 30 segundos\nconst MAX_BUFFER_SIZE = 50\n\nexport class Collector {\n private buffer: MonitorEvent[] = []\n private timer: ReturnType<typeof setInterval> | null = null\n private config: TransportConfig\n private flushInterval: number\n private logger: Logger\n private beforeSend: BeforeSendHook | undefined\n private sampleRate: number\n private visibilityHandler: (() => void) | null = null\n\n constructor(\n config: TransportConfig,\n logger: Logger,\n options?: {\n flushInterval?: number\n beforeSend?: BeforeSendHook\n sampleRate?: number\n },\n ) {\n this.config = config\n this.logger = logger\n this.flushInterval = options?.flushInterval ?? DEFAULT_FLUSH_INTERVAL\n this.beforeSend = options?.beforeSend\n this.sampleRate = options?.sampleRate ?? 1.0\n }\n\n start() {\n if (this.timer) return\n\n this.timer = setInterval(() => {\n this.flush()\n }, this.flushInterval)\n\n // Flush quando a página for fechada (browser) — usa sendBeacon\n if (typeof window !== 'undefined') {\n this.visibilityHandler = () => {\n if (document.visibilityState === 'hidden') {\n this.flush(true)\n }\n }\n window.addEventListener('visibilitychange', this.visibilityHandler)\n }\n }\n\n stop() {\n if (this.timer) {\n clearInterval(this.timer)\n this.timer = null\n }\n\n // Remover listener para evitar memory leak\n if (this.visibilityHandler && typeof window !== 'undefined') {\n window.removeEventListener('visibilitychange', this.visibilityHandler)\n this.visibilityHandler = null\n }\n\n // Flush final\n this.flush()\n }\n\n push(input: MonitorEventInput) {\n // Sampling — heartbeats nunca são amostrados\n if (input.type !== 'heartbeat' && this.sampleRate < 1.0) {\n if (Math.random() >= this.sampleRate) {\n this.logger.debug('sampled out', input.type)\n return\n }\n }\n\n const event: MonitorEvent = {\n ...input,\n timestamp: new Date().toISOString(),\n } as MonitorEvent\n\n // beforeSend hook — permite filtrar ou modificar eventos\n if (this.beforeSend) {\n const result = this.beforeSend(event)\n if (result === null) {\n this.logger.debug('dropped by beforeSend', event.type)\n return\n }\n // Usa o evento possivelmente modificado\n this.buffer.push(result)\n } else {\n this.buffer.push(event)\n }\n\n this.logger.debug('buffered', event.type, `(${this.buffer.length}/${MAX_BUFFER_SIZE})`)\n\n // Se buffer cheio, flush imediato\n if (this.buffer.length >= MAX_BUFFER_SIZE) {\n this.flush()\n }\n }\n\n /** Flush manual — exposto via MonitorClient.flush() */\n flush(useBeacon = false) {\n if (this.buffer.length === 0) return\n\n const events = [...this.buffer]\n this.buffer = []\n\n this.logger.debug('flushing', events.length, 'events', useBeacon ? '(beacon)' : '')\n\n // Fire-and-forget — não bloqueia o app\n sendBatch(this.config, events, this.logger, { useBeacon }).catch(() => {\n // Silencioso — transport já loga erros via logger\n })\n }\n\n /** Número de eventos no buffer (para debug/testes) */\n get pending(): number {\n return this.buffer.length\n }\n}\n","// Detecção de ambiente — centraliza lógica de dev/server\n\nconst LOCAL_HOSTNAMES = new Set(['localhost', '127.0.0.1', '0.0.0.0', '[::1]'])\n\n/** Detecta se estamos em ambiente de desenvolvimento */\nexport function isDev(): boolean {\n // Node.js / bundler env\n if (typeof process !== 'undefined' && process.env?.NODE_ENV === 'development') return true\n if (typeof process !== 'undefined' && process.env?.NODE_ENV === 'test') return true\n\n // Browser\n if (typeof window !== 'undefined' && LOCAL_HOSTNAMES.has(window.location?.hostname)) return true\n\n return false\n}\n\n/** Detecta se estamos rodando no servidor (Node.js) */\nexport function isServer(): boolean {\n return typeof window === 'undefined'\n}\n\n/** Detecta se estamos no browser */\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined'\n}\n","// Logger — debug mode com prefixo [monitor]\n\nconst PREFIX = '[monitor]'\n\nexport interface Logger {\n debug(...args: unknown[]): void\n warn(...args: unknown[]): void\n error(...args: unknown[]): void\n}\n\n/** Cria logger que loga no console quando debug=true, noop caso contrário */\nexport function createLogger(debug: boolean): Logger {\n if (!debug) {\n return { debug: noop, warn: noop, error: noop }\n }\n\n return {\n debug: (...args: unknown[]) => console.debug(PREFIX, ...args),\n warn: (...args: unknown[]) => console.warn(PREFIX, ...args),\n error: (...args: unknown[]) => console.error(PREFIX, ...args),\n }\n}\n\nfunction noop() {\n // silencioso\n}\n","// MonitorClient — instância principal do SDK\n\nimport type {\n HeartbeatData,\n RequestData,\n VitalData,\n AdapterData,\n ErrorData,\n DeployData,\n BeforeSendHook,\n} from '../types'\nimport { Collector } from './collector'\nimport { isDev } from './env'\nimport { createLogger, type Logger } from './logger'\n\nexport interface MonitorConfig {\n /** ID do projeto no Nuvio */\n projectId: string\n /** API key gerada no Nuvio */\n apiKey: string\n /** URL do endpoint de ingest */\n endpoint: string\n /** Intervalo do heartbeat em ms (default: 60000) */\n heartbeatInterval?: number\n /** Intervalo do flush do buffer em ms (default: 30000) */\n flushInterval?: number\n /** Timeout do fetch em ms (default: 10000) */\n timeout?: number\n /** Max tentativas de retry (default: 3) */\n maxRetries?: number\n /** Desabilitar em desenvolvimento (default: true) */\n disableInDev?: boolean\n /** Taxa de amostragem 0.0-1.0 (default: 1.0). Heartbeats nunca são amostrados */\n sampleRate?: number\n /** Hook chamado antes de enfileirar cada evento. Retorna null para dropar */\n beforeSend?: BeforeSendHook\n /** Habilitar logs de debug no console (default: false) */\n debug?: boolean\n}\n\nexport class MonitorClient {\n readonly config: MonitorConfig\n private readonly collector: Collector\n private readonly logger: Logger\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null\n private active = false\n\n constructor(config: MonitorConfig) {\n this.config = config\n this.logger = createLogger(config.debug ?? false)\n this.collector = new Collector(\n {\n endpoint: config.endpoint,\n apiKey: config.apiKey,\n timeout: config.timeout,\n maxRetries: config.maxRetries,\n },\n this.logger,\n {\n flushInterval: config.flushInterval,\n beforeSend: config.beforeSend,\n sampleRate: config.sampleRate,\n },\n )\n }\n\n /** Inicia o monitoring (heartbeat + collector) */\n start() {\n // Não roda em dev por padrão\n if (this.config.disableInDev !== false && isDev()) {\n this.logger.debug('disabled in dev — call start() with disableInDev: false to override')\n return\n }\n\n if (this.active) return\n\n this.active = true\n this.collector.start()\n this.startHeartbeat()\n this.logger.debug('started', `endpoint=${this.config.endpoint}`)\n }\n\n /** Para o monitoring */\n stop() {\n if (!this.active) return\n\n this.active = false\n this.collector.stop()\n\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer)\n this.heartbeatTimer = null\n }\n\n this.logger.debug('stopped')\n }\n\n /** Força um flush imediato do buffer */\n flush() {\n this.collector.flush()\n }\n\n /** Verifica se o monitoring está ativo */\n get isActive(): boolean {\n return this.active\n }\n\n /** Registra um evento de request HTTP (usado pelo middleware) */\n trackRequest(data: RequestData) {\n if (!this.active) return\n this.collector.push({ type: 'request', data })\n }\n\n /** Registra um Web Vital (usado pelo MonitorScript) */\n trackVital(data: VitalData) {\n if (!this.active) return\n this.collector.push({ type: 'vital', data })\n }\n\n /** Registra um evento de adapter (DB, cache, AI, queue, email) */\n trackAdapter(data: AdapterData) {\n if (!this.active) return\n this.collector.push({ type: 'adapter', data })\n }\n\n /** Registra um erro capturado */\n captureError(data: ErrorData) {\n if (!this.active) return\n this.collector.push({ type: 'error', data })\n }\n\n /** Registra um evento de deploy */\n trackDeploy(data: DeployData) {\n if (!this.active) return\n this.collector.push({ type: 'deploy', data })\n }\n\n // ─── Private ────────────────────────────────────────\n\n private startHeartbeat() {\n const interval = this.config.heartbeatInterval ?? 60_000\n\n // Primeiro heartbeat imediato\n this.sendHeartbeat()\n\n this.heartbeatTimer = setInterval(() => {\n this.sendHeartbeat()\n }, interval)\n }\n\n private async sendHeartbeat() {\n const start = performance.now()\n\n try {\n const response = await fetch(this.config.endpoint, {\n method: 'HEAD',\n cache: 'no-store',\n })\n\n const latencyMs = Math.round(performance.now() - start)\n\n this.collector.push({\n type: 'heartbeat',\n data: {\n status: response.ok ? 'online' : 'offline',\n latencyMs,\n } satisfies HeartbeatData,\n })\n } catch {\n // Network error — o endpoint não respondeu, reporta offline\n this.collector.push({\n type: 'heartbeat',\n data: {\n status: 'offline',\n latencyMs: Math.round(performance.now() - start),\n } satisfies HeartbeatData,\n })\n }\n }\n}\n","// @victor-studio/monitor — SDK de monitoramento\n\nimport { MonitorClient, type MonitorConfig } from './core/client'\n\nexport { MonitorClient, type MonitorConfig } from './core/client'\nexport type {\n MonitorEvent,\n MonitorEventInput,\n MonitorEventType,\n BeforeSendHook,\n HeartbeatData,\n RequestData,\n VitalData,\n ErrorData,\n DeployData,\n AdapterData,\n} from './types'\n\n/**\n * Cria e inicia uma instância do monitor.\n *\n * @example\n * ```ts\n * import { createMonitor } from '@victor-studio/monitor'\n *\n * export const monitor = createMonitor({\n * projectId: 'uuid-do-projeto',\n * apiKey: 'nuvio_mon_xxxxxxxx',\n * endpoint: 'https://nuvio.app/api/monitor/ingest',\n * })\n * ```\n */\nexport function createMonitor(config: MonitorConfig): MonitorClient {\n const client = new MonitorClient(config)\n client.start()\n return client\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -1,42 +1,112 @@
1
- interface MonitorEvent {
2
- type: 'heartbeat' | 'request' | 'vital';
3
- data: Record<string, unknown>;
4
- timestamp: string;
1
+ interface HeartbeatData {
2
+ status: 'online' | 'offline';
3
+ latencyMs: number;
5
4
  }
6
- interface TransportConfig {
7
- endpoint: string;
8
- apiKey: string;
5
+ interface RequestData {
6
+ method: string;
7
+ route: string;
8
+ statusCode: number;
9
+ responseTimeMs: number;
10
+ userAgent?: string;
11
+ region?: string;
9
12
  }
10
-
11
- declare class Collector {
12
- private buffer;
13
- private timer;
14
- private config;
15
- private flushInterval;
16
- constructor(config: TransportConfig, flushInterval?: number);
17
- start(): void;
18
- stop(): void;
19
- push(event: Omit<MonitorEvent, 'timestamp'>): void;
20
- private flush;
13
+ interface VitalData {
14
+ name: 'LCP' | 'INP' | 'CLS' | 'FCP' | 'TTFB';
15
+ value: number;
16
+ rating: 'good' | 'needs-improvement' | 'poor';
17
+ page?: string;
18
+ deviceType?: string;
19
+ browser?: string;
20
+ }
21
+ interface ErrorData {
22
+ type: 'unhandled' | 'caught' | 'promise';
23
+ message: string;
24
+ stack?: string;
25
+ groupingKey: string;
26
+ route?: string;
27
+ method?: string;
28
+ statusCode?: number;
29
+ environment?: string;
30
+ commitHash?: string;
31
+ extra?: Record<string, string>;
32
+ }
33
+ interface DeployData {
34
+ commitHash: string;
35
+ branch?: string;
36
+ author?: string;
37
+ status: 'started' | 'succeeded' | 'failed';
38
+ buildDurationMs?: number;
39
+ url?: string;
40
+ environment?: string;
41
+ provider?: string;
21
42
  }
43
+ interface AdapterData {
44
+ adapter: string;
45
+ operation: string;
46
+ durationMs: number;
47
+ success: boolean;
48
+ error?: string;
49
+ meta?: Record<string, string>;
50
+ }
51
+ type MonitorEvent = {
52
+ type: 'heartbeat';
53
+ data: HeartbeatData;
54
+ timestamp: string;
55
+ } | {
56
+ type: 'request';
57
+ data: RequestData;
58
+ timestamp: string;
59
+ } | {
60
+ type: 'vital';
61
+ data: VitalData;
62
+ timestamp: string;
63
+ } | {
64
+ type: 'error';
65
+ data: ErrorData;
66
+ timestamp: string;
67
+ } | {
68
+ type: 'deploy';
69
+ data: DeployData;
70
+ timestamp: string;
71
+ } | {
72
+ type: 'adapter';
73
+ data: AdapterData;
74
+ timestamp: string;
75
+ };
76
+ type MonitorEventType = MonitorEvent['type'];
77
+ /** Evento sem timestamp — usado pelo collector ao receber do client */
78
+ type MonitorEventInput = Omit<MonitorEvent, 'timestamp'>;
79
+ /** Hook para filtrar/modificar eventos antes do envio */
80
+ type BeforeSendHook = (event: MonitorEvent) => MonitorEvent | null;
22
81
 
23
82
  interface MonitorConfig {
24
83
  /** ID do projeto no Nuvio */
25
84
  projectId: string;
26
85
  /** API key gerada no Nuvio */
27
86
  apiKey: string;
28
- /** URL do endpoint de ingest (ex: https://app.nuvio.com/api/monitor/ingest) */
87
+ /** URL do endpoint de ingest */
29
88
  endpoint: string;
30
89
  /** Intervalo do heartbeat em ms (default: 60000) */
31
90
  heartbeatInterval?: number;
32
91
  /** Intervalo do flush do buffer em ms (default: 30000) */
33
92
  flushInterval?: number;
93
+ /** Timeout do fetch em ms (default: 10000) */
94
+ timeout?: number;
95
+ /** Max tentativas de retry (default: 3) */
96
+ maxRetries?: number;
34
97
  /** Desabilitar em desenvolvimento (default: true) */
35
98
  disableInDev?: boolean;
99
+ /** Taxa de amostragem 0.0-1.0 (default: 1.0). Heartbeats nunca são amostrados */
100
+ sampleRate?: number;
101
+ /** Hook chamado antes de enfileirar cada evento. Retorna null para dropar */
102
+ beforeSend?: BeforeSendHook;
103
+ /** Habilitar logs de debug no console (default: false) */
104
+ debug?: boolean;
36
105
  }
37
106
  declare class MonitorClient {
38
107
  readonly config: MonitorConfig;
39
- readonly collector: Collector;
108
+ private readonly collector;
109
+ private readonly logger;
40
110
  private heartbeatTimer;
41
111
  private active;
42
112
  constructor(config: MonitorConfig);
@@ -44,27 +114,22 @@ declare class MonitorClient {
44
114
  start(): void;
45
115
  /** Para o monitoring */
46
116
  stop(): void;
117
+ /** Força um flush imediato do buffer */
118
+ flush(): void;
119
+ /** Verifica se o monitoring está ativo */
120
+ get isActive(): boolean;
47
121
  /** Registra um evento de request HTTP (usado pelo middleware) */
48
- trackRequest(data: {
49
- method: string;
50
- route: string;
51
- statusCode: number;
52
- responseTimeMs: number;
53
- userAgent?: string;
54
- region?: string;
55
- }): void;
122
+ trackRequest(data: RequestData): void;
56
123
  /** Registra um Web Vital (usado pelo MonitorScript) */
57
- trackVital(data: {
58
- name: 'LCP' | 'INP' | 'CLS' | 'FCP' | 'TTFB';
59
- value: number;
60
- rating: 'good' | 'needs-improvement' | 'poor';
61
- page?: string;
62
- deviceType?: string;
63
- browser?: string;
64
- }): void;
124
+ trackVital(data: VitalData): void;
125
+ /** Registra um evento de adapter (DB, cache, AI, queue, email) */
126
+ trackAdapter(data: AdapterData): void;
127
+ /** Registra um erro capturado */
128
+ captureError(data: ErrorData): void;
129
+ /** Registra um evento de deploy */
130
+ trackDeploy(data: DeployData): void;
65
131
  private startHeartbeat;
66
132
  private sendHeartbeat;
67
- private isDev;
68
133
  }
69
134
 
70
135
  /**
@@ -77,10 +142,10 @@ declare class MonitorClient {
77
142
  * export const monitor = createMonitor({
78
143
  * projectId: 'uuid-do-projeto',
79
144
  * apiKey: 'nuvio_mon_xxxxxxxx',
80
- * endpoint: 'https://app.nuvio.com/api/monitor/ingest',
145
+ * endpoint: 'https://nuvio.app/api/monitor/ingest',
81
146
  * })
82
147
  * ```
83
148
  */
84
149
  declare function createMonitor(config: MonitorConfig): MonitorClient;
85
150
 
86
- export { MonitorClient, type MonitorConfig, createMonitor };
151
+ export { type AdapterData, type BeforeSendHook, type DeployData, type ErrorData, type HeartbeatData, MonitorClient, type MonitorConfig, type MonitorEvent, type MonitorEventInput, type MonitorEventType, type RequestData, type VitalData, createMonitor };