@victor-studio/monitor 0.4.0 → 0.5.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.
Files changed (55) hide show
  1. package/dist/adapters/bullmq/bullmq.cjs +85 -0
  2. package/dist/adapters/bullmq/bullmq.cjs.map +1 -0
  3. package/dist/adapters/bullmq/bullmq.d.cts +176 -0
  4. package/dist/adapters/bullmq/bullmq.d.ts +176 -0
  5. package/dist/adapters/bullmq/bullmq.js +82 -0
  6. package/dist/adapters/bullmq/bullmq.js.map +1 -0
  7. package/dist/adapters/gemini/gemini.cjs +65 -0
  8. package/dist/adapters/gemini/gemini.cjs.map +1 -0
  9. package/dist/adapters/gemini/gemini.d.cts +173 -0
  10. package/dist/adapters/gemini/gemini.d.ts +173 -0
  11. package/dist/adapters/gemini/gemini.js +62 -0
  12. package/dist/adapters/gemini/gemini.js.map +1 -0
  13. package/dist/adapters/index.cjs +56 -0
  14. package/dist/adapters/index.cjs.map +1 -0
  15. package/dist/adapters/index.d.cts +154 -0
  16. package/dist/adapters/index.d.ts +154 -0
  17. package/dist/adapters/index.js +53 -0
  18. package/dist/adapters/index.js.map +1 -0
  19. package/dist/adapters/neon/neon.cjs +36 -0
  20. package/dist/adapters/neon/neon.cjs.map +1 -0
  21. package/dist/adapters/neon/neon.d.cts +151 -0
  22. package/dist/adapters/neon/neon.d.ts +151 -0
  23. package/dist/adapters/neon/neon.js +34 -0
  24. package/dist/adapters/neon/neon.js.map +1 -0
  25. package/dist/adapters/railway/railway.cjs +20 -0
  26. package/dist/adapters/railway/railway.cjs.map +1 -0
  27. package/dist/adapters/railway/railway.d.cts +23 -0
  28. package/dist/adapters/railway/railway.d.ts +23 -0
  29. package/dist/adapters/railway/railway.js +18 -0
  30. package/dist/adapters/railway/railway.js.map +1 -0
  31. package/dist/adapters/resend/resend.cjs +36 -0
  32. package/dist/adapters/resend/resend.cjs.map +1 -0
  33. package/dist/adapters/resend/resend.d.cts +157 -0
  34. package/dist/adapters/resend/resend.d.ts +157 -0
  35. package/dist/adapters/resend/resend.js +34 -0
  36. package/dist/adapters/resend/resend.js.map +1 -0
  37. package/dist/adapters/upstash/upstash.cjs +39 -0
  38. package/dist/adapters/upstash/upstash.cjs.map +1 -0
  39. package/dist/adapters/upstash/upstash.d.cts +150 -0
  40. package/dist/adapters/upstash/upstash.d.ts +150 -0
  41. package/dist/adapters/upstash/upstash.js +37 -0
  42. package/dist/adapters/upstash/upstash.js.map +1 -0
  43. package/dist/adapters/vercel/vercel.cjs +18 -0
  44. package/dist/adapters/vercel/vercel.cjs.map +1 -0
  45. package/dist/adapters/vercel/vercel.d.cts +23 -0
  46. package/dist/adapters/vercel/vercel.d.ts +23 -0
  47. package/dist/adapters/vercel/vercel.js +16 -0
  48. package/dist/adapters/vercel/vercel.js.map +1 -0
  49. package/dist/deploys/index.cjs +53 -0
  50. package/dist/deploys/index.cjs.map +1 -0
  51. package/dist/deploys/index.d.cts +174 -0
  52. package/dist/deploys/index.d.ts +174 -0
  53. package/dist/deploys/index.js +50 -0
  54. package/dist/deploys/index.js.map +1 -0
  55. package/package.json +46 -1
@@ -0,0 +1,154 @@
1
+ interface HeartbeatData {
2
+ status: 'online' | 'offline';
3
+ latencyMs: number;
4
+ }
5
+ interface RequestData {
6
+ method: string;
7
+ route: string;
8
+ statusCode: number;
9
+ responseTimeMs: number;
10
+ userAgent?: string;
11
+ region?: string;
12
+ }
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;
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
+ /** Hook para filtrar/modificar eventos antes do envio */
77
+ type BeforeSendHook = (event: MonitorEvent) => MonitorEvent | null;
78
+
79
+ interface MonitorConfig {
80
+ /** ID do projeto no Nuvio */
81
+ projectId: string;
82
+ /** API key gerada no Nuvio */
83
+ apiKey: string;
84
+ /** URL do endpoint de ingest */
85
+ endpoint: string;
86
+ /** Intervalo do heartbeat em ms (default: 60000) */
87
+ heartbeatInterval?: number;
88
+ /** Intervalo do flush do buffer em ms (default: 30000) */
89
+ flushInterval?: number;
90
+ /** Timeout do fetch em ms (default: 10000) */
91
+ timeout?: number;
92
+ /** Max tentativas de retry (default: 3) */
93
+ maxRetries?: number;
94
+ /** Desabilitar em desenvolvimento (default: true) */
95
+ disableInDev?: boolean;
96
+ /** Taxa de amostragem 0.0-1.0 (default: 1.0). Heartbeats nunca são amostrados */
97
+ sampleRate?: number;
98
+ /** Hook chamado antes de enfileirar cada evento. Retorna null para dropar */
99
+ beforeSend?: BeforeSendHook;
100
+ /** Habilitar logs de debug no console (default: false) */
101
+ debug?: boolean;
102
+ /** Capturar erros globais automaticamente — window.onerror (default: false) */
103
+ captureErrors?: boolean;
104
+ /** Capturar unhandled promise rejections automaticamente (default: false) */
105
+ captureUnhandledRejections?: boolean;
106
+ }
107
+ declare class MonitorClient {
108
+ readonly config: MonitorConfig;
109
+ private readonly collector;
110
+ private readonly logger;
111
+ private heartbeatTimer;
112
+ private globalHandlersCleanup;
113
+ private active;
114
+ constructor(config: MonitorConfig);
115
+ /** Inicia o monitoring (heartbeat + collector) */
116
+ start(): void;
117
+ /** Para o monitoring */
118
+ stop(): void;
119
+ /** Força um flush imediato do buffer */
120
+ flush(): void;
121
+ /** Verifica se o monitoring está ativo */
122
+ get isActive(): boolean;
123
+ /** Registra um evento de request HTTP (usado pelo middleware) */
124
+ trackRequest(data: RequestData): void;
125
+ /** Registra um Web Vital (usado pelo MonitorScript) */
126
+ trackVital(data: VitalData): void;
127
+ /** Registra um evento de adapter (DB, cache, AI, queue, email) */
128
+ trackAdapter(data: AdapterData): void;
129
+ /** Registra um erro capturado */
130
+ captureError(data: ErrorData): void;
131
+ /** Registra um evento de deploy */
132
+ trackDeploy(data: DeployData): void;
133
+ private startHeartbeat;
134
+ private sendHeartbeat;
135
+ }
136
+
137
+ /**
138
+ * Mede a duração de uma operação assíncrona e reporta ao monitor.
139
+ * Utilitário base usado por todos os adapters.
140
+ *
141
+ * @example
142
+ * ```ts
143
+ * const result = await withTiming(monitor, 'neon', 'query', () =>
144
+ * db.select().from(users),
145
+ * )
146
+ * ```
147
+ */
148
+ declare function withTiming<T>(monitor: MonitorClient, adapter: string, operation: string, fn: () => Promise<T>, meta?: Record<string, string>): Promise<T>;
149
+ /**
150
+ * Versão sync do withTiming para operações síncronas.
151
+ */
152
+ declare function withTimingSync<T>(monitor: MonitorClient, adapter: string, operation: string, fn: () => T, meta?: Record<string, string>): T;
153
+
154
+ export { withTiming, withTimingSync };
@@ -0,0 +1,53 @@
1
+ // src/adapters/core.ts
2
+ async function withTiming(monitor, adapter, operation, fn, meta) {
3
+ const start = performance.now();
4
+ try {
5
+ const result = await fn();
6
+ monitor.trackAdapter({
7
+ adapter,
8
+ operation,
9
+ durationMs: Math.round(performance.now() - start),
10
+ success: true,
11
+ meta
12
+ });
13
+ return result;
14
+ } catch (error) {
15
+ monitor.trackAdapter({
16
+ adapter,
17
+ operation,
18
+ durationMs: Math.round(performance.now() - start),
19
+ success: false,
20
+ error: error instanceof Error ? error.message : String(error),
21
+ meta
22
+ });
23
+ throw error;
24
+ }
25
+ }
26
+ function withTimingSync(monitor, adapter, operation, fn, meta) {
27
+ const start = performance.now();
28
+ try {
29
+ const result = fn();
30
+ monitor.trackAdapter({
31
+ adapter,
32
+ operation,
33
+ durationMs: Math.round(performance.now() - start),
34
+ success: true,
35
+ meta
36
+ });
37
+ return result;
38
+ } catch (error) {
39
+ monitor.trackAdapter({
40
+ adapter,
41
+ operation,
42
+ durationMs: Math.round(performance.now() - start),
43
+ success: false,
44
+ error: error instanceof Error ? error.message : String(error),
45
+ meta
46
+ });
47
+ throw error;
48
+ }
49
+ }
50
+
51
+ export { withTiming, withTimingSync };
52
+ //# sourceMappingURL=index.js.map
53
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/adapters/core.ts"],"names":[],"mappings":";AAgBA,eAAsB,UAAA,CACpB,OAAA,EACA,OAAA,EACA,SAAA,EACA,IACA,IAAA,EACY;AACZ,EAAA,MAAM,KAAA,GAAQ,YAAY,GAAA,EAAI;AAE9B,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,MAAM,EAAA,EAAG;AAExB,IAAA,OAAA,CAAQ,YAAA,CAAa;AAAA,MACnB,OAAA;AAAA,MACA,SAAA;AAAA,MACA,YAAY,IAAA,CAAK,KAAA,CAAM,WAAA,CAAY,GAAA,KAAQ,KAAK,CAAA;AAAA,MAChD,OAAA,EAAS,IAAA;AAAA,MACT;AAAA,KACqB,CAAA;AAEvB,IAAA,OAAO,MAAA;AAAA,EACT,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,YAAA,CAAa;AAAA,MACnB,OAAA;AAAA,MACA,SAAA;AAAA,MACA,YAAY,IAAA,CAAK,KAAA,CAAM,WAAA,CAAY,GAAA,KAAQ,KAAK,CAAA;AAAA,MAChD,OAAA,EAAS,KAAA;AAAA,MACT,OAAO,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK,CAAA;AAAA,MAC5D;AAAA,KACqB,CAAA;AAEvB,IAAA,MAAM,KAAA;AAAA,EACR;AACF;AAKO,SAAS,cAAA,CACd,OAAA,EACA,OAAA,EACA,SAAA,EACA,IACA,IAAA,EACG;AACH,EAAA,MAAM,KAAA,GAAQ,YAAY,GAAA,EAAI;AAE9B,EAAA,IAAI;AACF,IAAA,MAAM,SAAS,EAAA,EAAG;AAElB,IAAA,OAAA,CAAQ,YAAA,CAAa;AAAA,MACnB,OAAA;AAAA,MACA,SAAA;AAAA,MACA,YAAY,IAAA,CAAK,KAAA,CAAM,WAAA,CAAY,GAAA,KAAQ,KAAK,CAAA;AAAA,MAChD,OAAA,EAAS,IAAA;AAAA,MACT;AAAA,KACqB,CAAA;AAEvB,IAAA,OAAO,MAAA;AAAA,EACT,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,YAAA,CAAa;AAAA,MACnB,OAAA;AAAA,MACA,SAAA;AAAA,MACA,YAAY,IAAA,CAAK,KAAA,CAAM,WAAA,CAAY,GAAA,KAAQ,KAAK,CAAA;AAAA,MAChD,OAAA,EAAS,KAAA;AAAA,MACT,OAAO,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK,CAAA;AAAA,MAC5D;AAAA,KACqB,CAAA;AAEvB,IAAA,MAAM,KAAA;AAAA,EACR;AACF","file":"index.js","sourcesContent":["// Adapter core — utilitário genérico de instrumentação\n\nimport type { MonitorClient } from '../core/client'\nimport type { AdapterData } from '../types'\n\n/**\n * Mede a duração de uma operação assíncrona e reporta ao monitor.\n * Utilitário base usado por todos os adapters.\n *\n * @example\n * ```ts\n * const result = await withTiming(monitor, 'neon', 'query', () =>\n * db.select().from(users),\n * )\n * ```\n */\nexport async function withTiming<T>(\n monitor: MonitorClient,\n adapter: string,\n operation: string,\n fn: () => Promise<T>,\n meta?: Record<string, string>,\n): Promise<T> {\n const start = performance.now()\n\n try {\n const result = await fn()\n\n monitor.trackAdapter({\n adapter,\n operation,\n durationMs: Math.round(performance.now() - start),\n success: true,\n meta,\n } satisfies AdapterData)\n\n return result\n } catch (error) {\n monitor.trackAdapter({\n adapter,\n operation,\n durationMs: Math.round(performance.now() - start),\n success: false,\n error: error instanceof Error ? error.message : String(error),\n meta,\n } satisfies AdapterData)\n\n throw error // nunca engolir erros\n }\n}\n\n/**\n * Versão sync do withTiming para operações síncronas.\n */\nexport function withTimingSync<T>(\n monitor: MonitorClient,\n adapter: string,\n operation: string,\n fn: () => T,\n meta?: Record<string, string>,\n): T {\n const start = performance.now()\n\n try {\n const result = fn()\n\n monitor.trackAdapter({\n adapter,\n operation,\n durationMs: Math.round(performance.now() - start),\n success: true,\n meta,\n } satisfies AdapterData)\n\n return result\n } catch (error) {\n monitor.trackAdapter({\n adapter,\n operation,\n durationMs: Math.round(performance.now() - start),\n success: false,\n error: error instanceof Error ? error.message : String(error),\n meta,\n } satisfies AdapterData)\n\n throw error\n }\n}\n"]}
@@ -0,0 +1,36 @@
1
+ 'use strict';
2
+
3
+ // src/adapters/core.ts
4
+ async function withTiming(monitor, adapter, operation, fn, meta) {
5
+ const start = performance.now();
6
+ try {
7
+ const result = await fn();
8
+ monitor.trackAdapter({
9
+ adapter,
10
+ operation,
11
+ durationMs: Math.round(performance.now() - start),
12
+ success: true,
13
+ meta
14
+ });
15
+ return result;
16
+ } catch (error) {
17
+ monitor.trackAdapter({
18
+ adapter,
19
+ operation,
20
+ durationMs: Math.round(performance.now() - start),
21
+ success: false,
22
+ error: error instanceof Error ? error.message : String(error),
23
+ meta
24
+ });
25
+ throw error;
26
+ }
27
+ }
28
+
29
+ // src/adapters/neon.ts
30
+ function monitorQuery(monitor, operation, queryFn, meta) {
31
+ return withTiming(monitor, "neon", operation, queryFn, meta);
32
+ }
33
+
34
+ exports.monitorQuery = monitorQuery;
35
+ //# sourceMappingURL=neon.cjs.map
36
+ //# sourceMappingURL=neon.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/adapters/core.ts","../../../src/adapters/neon.ts"],"names":[],"mappings":";;;AAgBA,eAAsB,UAAA,CACpB,OAAA,EACA,OAAA,EACA,SAAA,EACA,IACA,IAAA,EACY;AACZ,EAAA,MAAM,KAAA,GAAQ,YAAY,GAAA,EAAI;AAE9B,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,MAAM,EAAA,EAAG;AAExB,IAAA,OAAA,CAAQ,YAAA,CAAa;AAAA,MACnB,OAAA;AAAA,MACA,SAAA;AAAA,MACA,YAAY,IAAA,CAAK,KAAA,CAAM,WAAA,CAAY,GAAA,KAAQ,KAAK,CAAA;AAAA,MAChD,OAAA,EAAS,IAAA;AAAA,MACT;AAAA,KACqB,CAAA;AAEvB,IAAA,OAAO,MAAA;AAAA,EACT,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,YAAA,CAAa;AAAA,MACnB,OAAA;AAAA,MACA,SAAA;AAAA,MACA,YAAY,IAAA,CAAK,KAAA,CAAM,WAAA,CAAY,GAAA,KAAQ,KAAK,CAAA;AAAA,MAChD,OAAA,EAAS,KAAA;AAAA,MACT,OAAO,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK,CAAA;AAAA,MAC5D;AAAA,KACqB,CAAA;AAEvB,IAAA,MAAM,KAAA;AAAA,EACR;AACF;;;AChCO,SAAS,YAAA,CACd,OAAA,EACA,SAAA,EACA,OAAA,EACA,IAAA,EACY;AACZ,EAAA,OAAO,UAAA,CAAW,OAAA,EAAS,MAAA,EAAQ,SAAA,EAAW,SAAS,IAAI,CAAA;AAC7D","file":"neon.cjs","sourcesContent":["// Adapter core — utilitário genérico de instrumentação\n\nimport type { MonitorClient } from '../core/client'\nimport type { AdapterData } from '../types'\n\n/**\n * Mede a duração de uma operação assíncrona e reporta ao monitor.\n * Utilitário base usado por todos os adapters.\n *\n * @example\n * ```ts\n * const result = await withTiming(monitor, 'neon', 'query', () =>\n * db.select().from(users),\n * )\n * ```\n */\nexport async function withTiming<T>(\n monitor: MonitorClient,\n adapter: string,\n operation: string,\n fn: () => Promise<T>,\n meta?: Record<string, string>,\n): Promise<T> {\n const start = performance.now()\n\n try {\n const result = await fn()\n\n monitor.trackAdapter({\n adapter,\n operation,\n durationMs: Math.round(performance.now() - start),\n success: true,\n meta,\n } satisfies AdapterData)\n\n return result\n } catch (error) {\n monitor.trackAdapter({\n adapter,\n operation,\n durationMs: Math.round(performance.now() - start),\n success: false,\n error: error instanceof Error ? error.message : String(error),\n meta,\n } satisfies AdapterData)\n\n throw error // nunca engolir erros\n }\n}\n\n/**\n * Versão sync do withTiming para operações síncronas.\n */\nexport function withTimingSync<T>(\n monitor: MonitorClient,\n adapter: string,\n operation: string,\n fn: () => T,\n meta?: Record<string, string>,\n): T {\n const start = performance.now()\n\n try {\n const result = fn()\n\n monitor.trackAdapter({\n adapter,\n operation,\n durationMs: Math.round(performance.now() - start),\n success: true,\n meta,\n } satisfies AdapterData)\n\n return result\n } catch (error) {\n monitor.trackAdapter({\n adapter,\n operation,\n durationMs: Math.round(performance.now() - start),\n success: false,\n error: error instanceof Error ? error.message : String(error),\n meta,\n } satisfies AdapterData)\n\n throw error\n }\n}\n","// Adapter NeonDB — instrumentação de queries Drizzle/Neon\n\nimport type { MonitorClient } from '../core/client'\nimport { withTiming } from './core'\n\n/**\n * Instrumenta uma query de banco de dados com timing.\n *\n * @example\n * ```ts\n * import { monitorQuery } from '@victor-studio/monitor/adapters/neon'\n *\n * const users = await monitorQuery(monitor, 'select', () =>\n * db.select().from(usersTable).where(eq(usersTable.id, id)),\n * )\n * ```\n */\nexport function monitorQuery<T>(\n monitor: MonitorClient,\n operation: string,\n queryFn: () => Promise<T>,\n meta?: Record<string, string>,\n): Promise<T> {\n return withTiming(monitor, 'neon', operation, queryFn, meta)\n}\n"]}
@@ -0,0 +1,151 @@
1
+ interface HeartbeatData {
2
+ status: 'online' | 'offline';
3
+ latencyMs: number;
4
+ }
5
+ interface RequestData {
6
+ method: string;
7
+ route: string;
8
+ statusCode: number;
9
+ responseTimeMs: number;
10
+ userAgent?: string;
11
+ region?: string;
12
+ }
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;
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
+ /** Hook para filtrar/modificar eventos antes do envio */
77
+ type BeforeSendHook = (event: MonitorEvent) => MonitorEvent | null;
78
+
79
+ interface MonitorConfig {
80
+ /** ID do projeto no Nuvio */
81
+ projectId: string;
82
+ /** API key gerada no Nuvio */
83
+ apiKey: string;
84
+ /** URL do endpoint de ingest */
85
+ endpoint: string;
86
+ /** Intervalo do heartbeat em ms (default: 60000) */
87
+ heartbeatInterval?: number;
88
+ /** Intervalo do flush do buffer em ms (default: 30000) */
89
+ flushInterval?: number;
90
+ /** Timeout do fetch em ms (default: 10000) */
91
+ timeout?: number;
92
+ /** Max tentativas de retry (default: 3) */
93
+ maxRetries?: number;
94
+ /** Desabilitar em desenvolvimento (default: true) */
95
+ disableInDev?: boolean;
96
+ /** Taxa de amostragem 0.0-1.0 (default: 1.0). Heartbeats nunca são amostrados */
97
+ sampleRate?: number;
98
+ /** Hook chamado antes de enfileirar cada evento. Retorna null para dropar */
99
+ beforeSend?: BeforeSendHook;
100
+ /** Habilitar logs de debug no console (default: false) */
101
+ debug?: boolean;
102
+ /** Capturar erros globais automaticamente — window.onerror (default: false) */
103
+ captureErrors?: boolean;
104
+ /** Capturar unhandled promise rejections automaticamente (default: false) */
105
+ captureUnhandledRejections?: boolean;
106
+ }
107
+ declare class MonitorClient {
108
+ readonly config: MonitorConfig;
109
+ private readonly collector;
110
+ private readonly logger;
111
+ private heartbeatTimer;
112
+ private globalHandlersCleanup;
113
+ private active;
114
+ constructor(config: MonitorConfig);
115
+ /** Inicia o monitoring (heartbeat + collector) */
116
+ start(): void;
117
+ /** Para o monitoring */
118
+ stop(): void;
119
+ /** Força um flush imediato do buffer */
120
+ flush(): void;
121
+ /** Verifica se o monitoring está ativo */
122
+ get isActive(): boolean;
123
+ /** Registra um evento de request HTTP (usado pelo middleware) */
124
+ trackRequest(data: RequestData): void;
125
+ /** Registra um Web Vital (usado pelo MonitorScript) */
126
+ trackVital(data: VitalData): void;
127
+ /** Registra um evento de adapter (DB, cache, AI, queue, email) */
128
+ trackAdapter(data: AdapterData): void;
129
+ /** Registra um erro capturado */
130
+ captureError(data: ErrorData): void;
131
+ /** Registra um evento de deploy */
132
+ trackDeploy(data: DeployData): void;
133
+ private startHeartbeat;
134
+ private sendHeartbeat;
135
+ }
136
+
137
+ /**
138
+ * Instrumenta uma query de banco de dados com timing.
139
+ *
140
+ * @example
141
+ * ```ts
142
+ * import { monitorQuery } from '@victor-studio/monitor/adapters/neon'
143
+ *
144
+ * const users = await monitorQuery(monitor, 'select', () =>
145
+ * db.select().from(usersTable).where(eq(usersTable.id, id)),
146
+ * )
147
+ * ```
148
+ */
149
+ declare function monitorQuery<T>(monitor: MonitorClient, operation: string, queryFn: () => Promise<T>, meta?: Record<string, string>): Promise<T>;
150
+
151
+ export { monitorQuery };
@@ -0,0 +1,151 @@
1
+ interface HeartbeatData {
2
+ status: 'online' | 'offline';
3
+ latencyMs: number;
4
+ }
5
+ interface RequestData {
6
+ method: string;
7
+ route: string;
8
+ statusCode: number;
9
+ responseTimeMs: number;
10
+ userAgent?: string;
11
+ region?: string;
12
+ }
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;
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
+ /** Hook para filtrar/modificar eventos antes do envio */
77
+ type BeforeSendHook = (event: MonitorEvent) => MonitorEvent | null;
78
+
79
+ interface MonitorConfig {
80
+ /** ID do projeto no Nuvio */
81
+ projectId: string;
82
+ /** API key gerada no Nuvio */
83
+ apiKey: string;
84
+ /** URL do endpoint de ingest */
85
+ endpoint: string;
86
+ /** Intervalo do heartbeat em ms (default: 60000) */
87
+ heartbeatInterval?: number;
88
+ /** Intervalo do flush do buffer em ms (default: 30000) */
89
+ flushInterval?: number;
90
+ /** Timeout do fetch em ms (default: 10000) */
91
+ timeout?: number;
92
+ /** Max tentativas de retry (default: 3) */
93
+ maxRetries?: number;
94
+ /** Desabilitar em desenvolvimento (default: true) */
95
+ disableInDev?: boolean;
96
+ /** Taxa de amostragem 0.0-1.0 (default: 1.0). Heartbeats nunca são amostrados */
97
+ sampleRate?: number;
98
+ /** Hook chamado antes de enfileirar cada evento. Retorna null para dropar */
99
+ beforeSend?: BeforeSendHook;
100
+ /** Habilitar logs de debug no console (default: false) */
101
+ debug?: boolean;
102
+ /** Capturar erros globais automaticamente — window.onerror (default: false) */
103
+ captureErrors?: boolean;
104
+ /** Capturar unhandled promise rejections automaticamente (default: false) */
105
+ captureUnhandledRejections?: boolean;
106
+ }
107
+ declare class MonitorClient {
108
+ readonly config: MonitorConfig;
109
+ private readonly collector;
110
+ private readonly logger;
111
+ private heartbeatTimer;
112
+ private globalHandlersCleanup;
113
+ private active;
114
+ constructor(config: MonitorConfig);
115
+ /** Inicia o monitoring (heartbeat + collector) */
116
+ start(): void;
117
+ /** Para o monitoring */
118
+ stop(): void;
119
+ /** Força um flush imediato do buffer */
120
+ flush(): void;
121
+ /** Verifica se o monitoring está ativo */
122
+ get isActive(): boolean;
123
+ /** Registra um evento de request HTTP (usado pelo middleware) */
124
+ trackRequest(data: RequestData): void;
125
+ /** Registra um Web Vital (usado pelo MonitorScript) */
126
+ trackVital(data: VitalData): void;
127
+ /** Registra um evento de adapter (DB, cache, AI, queue, email) */
128
+ trackAdapter(data: AdapterData): void;
129
+ /** Registra um erro capturado */
130
+ captureError(data: ErrorData): void;
131
+ /** Registra um evento de deploy */
132
+ trackDeploy(data: DeployData): void;
133
+ private startHeartbeat;
134
+ private sendHeartbeat;
135
+ }
136
+
137
+ /**
138
+ * Instrumenta uma query de banco de dados com timing.
139
+ *
140
+ * @example
141
+ * ```ts
142
+ * import { monitorQuery } from '@victor-studio/monitor/adapters/neon'
143
+ *
144
+ * const users = await monitorQuery(monitor, 'select', () =>
145
+ * db.select().from(usersTable).where(eq(usersTable.id, id)),
146
+ * )
147
+ * ```
148
+ */
149
+ declare function monitorQuery<T>(monitor: MonitorClient, operation: string, queryFn: () => Promise<T>, meta?: Record<string, string>): Promise<T>;
150
+
151
+ export { monitorQuery };
@@ -0,0 +1,34 @@
1
+ // src/adapters/core.ts
2
+ async function withTiming(monitor, adapter, operation, fn, meta) {
3
+ const start = performance.now();
4
+ try {
5
+ const result = await fn();
6
+ monitor.trackAdapter({
7
+ adapter,
8
+ operation,
9
+ durationMs: Math.round(performance.now() - start),
10
+ success: true,
11
+ meta
12
+ });
13
+ return result;
14
+ } catch (error) {
15
+ monitor.trackAdapter({
16
+ adapter,
17
+ operation,
18
+ durationMs: Math.round(performance.now() - start),
19
+ success: false,
20
+ error: error instanceof Error ? error.message : String(error),
21
+ meta
22
+ });
23
+ throw error;
24
+ }
25
+ }
26
+
27
+ // src/adapters/neon.ts
28
+ function monitorQuery(monitor, operation, queryFn, meta) {
29
+ return withTiming(monitor, "neon", operation, queryFn, meta);
30
+ }
31
+
32
+ export { monitorQuery };
33
+ //# sourceMappingURL=neon.js.map
34
+ //# sourceMappingURL=neon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/adapters/core.ts","../../../src/adapters/neon.ts"],"names":[],"mappings":";AAgBA,eAAsB,UAAA,CACpB,OAAA,EACA,OAAA,EACA,SAAA,EACA,IACA,IAAA,EACY;AACZ,EAAA,MAAM,KAAA,GAAQ,YAAY,GAAA,EAAI;AAE9B,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,MAAM,EAAA,EAAG;AAExB,IAAA,OAAA,CAAQ,YAAA,CAAa;AAAA,MACnB,OAAA;AAAA,MACA,SAAA;AAAA,MACA,YAAY,IAAA,CAAK,KAAA,CAAM,WAAA,CAAY,GAAA,KAAQ,KAAK,CAAA;AAAA,MAChD,OAAA,EAAS,IAAA;AAAA,MACT;AAAA,KACqB,CAAA;AAEvB,IAAA,OAAO,MAAA;AAAA,EACT,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,YAAA,CAAa;AAAA,MACnB,OAAA;AAAA,MACA,SAAA;AAAA,MACA,YAAY,IAAA,CAAK,KAAA,CAAM,WAAA,CAAY,GAAA,KAAQ,KAAK,CAAA;AAAA,MAChD,OAAA,EAAS,KAAA;AAAA,MACT,OAAO,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK,CAAA;AAAA,MAC5D;AAAA,KACqB,CAAA;AAEvB,IAAA,MAAM,KAAA;AAAA,EACR;AACF;;;AChCO,SAAS,YAAA,CACd,OAAA,EACA,SAAA,EACA,OAAA,EACA,IAAA,EACY;AACZ,EAAA,OAAO,UAAA,CAAW,OAAA,EAAS,MAAA,EAAQ,SAAA,EAAW,SAAS,IAAI,CAAA;AAC7D","file":"neon.js","sourcesContent":["// Adapter core — utilitário genérico de instrumentação\n\nimport type { MonitorClient } from '../core/client'\nimport type { AdapterData } from '../types'\n\n/**\n * Mede a duração de uma operação assíncrona e reporta ao monitor.\n * Utilitário base usado por todos os adapters.\n *\n * @example\n * ```ts\n * const result = await withTiming(monitor, 'neon', 'query', () =>\n * db.select().from(users),\n * )\n * ```\n */\nexport async function withTiming<T>(\n monitor: MonitorClient,\n adapter: string,\n operation: string,\n fn: () => Promise<T>,\n meta?: Record<string, string>,\n): Promise<T> {\n const start = performance.now()\n\n try {\n const result = await fn()\n\n monitor.trackAdapter({\n adapter,\n operation,\n durationMs: Math.round(performance.now() - start),\n success: true,\n meta,\n } satisfies AdapterData)\n\n return result\n } catch (error) {\n monitor.trackAdapter({\n adapter,\n operation,\n durationMs: Math.round(performance.now() - start),\n success: false,\n error: error instanceof Error ? error.message : String(error),\n meta,\n } satisfies AdapterData)\n\n throw error // nunca engolir erros\n }\n}\n\n/**\n * Versão sync do withTiming para operações síncronas.\n */\nexport function withTimingSync<T>(\n monitor: MonitorClient,\n adapter: string,\n operation: string,\n fn: () => T,\n meta?: Record<string, string>,\n): T {\n const start = performance.now()\n\n try {\n const result = fn()\n\n monitor.trackAdapter({\n adapter,\n operation,\n durationMs: Math.round(performance.now() - start),\n success: true,\n meta,\n } satisfies AdapterData)\n\n return result\n } catch (error) {\n monitor.trackAdapter({\n adapter,\n operation,\n durationMs: Math.round(performance.now() - start),\n success: false,\n error: error instanceof Error ? error.message : String(error),\n meta,\n } satisfies AdapterData)\n\n throw error\n }\n}\n","// Adapter NeonDB — instrumentação de queries Drizzle/Neon\n\nimport type { MonitorClient } from '../core/client'\nimport { withTiming } from './core'\n\n/**\n * Instrumenta uma query de banco de dados com timing.\n *\n * @example\n * ```ts\n * import { monitorQuery } from '@victor-studio/monitor/adapters/neon'\n *\n * const users = await monitorQuery(monitor, 'select', () =>\n * db.select().from(usersTable).where(eq(usersTable.id, id)),\n * )\n * ```\n */\nexport function monitorQuery<T>(\n monitor: MonitorClient,\n operation: string,\n queryFn: () => Promise<T>,\n meta?: Record<string, string>,\n): Promise<T> {\n return withTiming(monitor, 'neon', operation, queryFn, meta)\n}\n"]}
@@ -0,0 +1,20 @@
1
+ 'use strict';
2
+
3
+ // src/adapters/railway.ts
4
+ function getRailwayContext() {
5
+ if (typeof process === "undefined") return {};
6
+ const env = process.env;
7
+ return {
8
+ environment: env.RAILWAY_ENVIRONMENT,
9
+ commitHash: env.RAILWAY_GIT_COMMIT_SHA,
10
+ branch: env.RAILWAY_GIT_BRANCH,
11
+ author: env.RAILWAY_GIT_AUTHOR,
12
+ url: env.RAILWAY_PUBLIC_DOMAIN ? `https://${env.RAILWAY_PUBLIC_DOMAIN}` : void 0,
13
+ projectId: env.RAILWAY_PROJECT_ID,
14
+ serviceId: env.RAILWAY_SERVICE_ID
15
+ };
16
+ }
17
+
18
+ exports.getRailwayContext = getRailwayContext;
19
+ //# sourceMappingURL=railway.cjs.map
20
+ //# sourceMappingURL=railway.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/adapters/railway.ts"],"names":[],"mappings":";;;AAuBO,SAAS,iBAAA,GAAoC;AAClD,EAAA,IAAI,OAAO,OAAA,KAAY,WAAA,EAAa,OAAO,EAAC;AAC5C,EAAA,MAAM,MAAM,OAAA,CAAQ,GAAA;AAEpB,EAAA,OAAO;AAAA,IACL,aAAa,GAAA,CAAI,mBAAA;AAAA,IACjB,YAAY,GAAA,CAAI,sBAAA;AAAA,IAChB,QAAQ,GAAA,CAAI,kBAAA;AAAA,IACZ,QAAQ,GAAA,CAAI,kBAAA;AAAA,IACZ,KAAK,GAAA,CAAI,qBAAA,GAAwB,CAAA,QAAA,EAAW,GAAA,CAAI,qBAAqB,CAAA,CAAA,GAAK,MAAA;AAAA,IAC1E,WAAW,GAAA,CAAI,kBAAA;AAAA,IACf,WAAW,GAAA,CAAI;AAAA,GACjB;AACF","file":"railway.cjs","sourcesContent":["// Adapter Railway — contexto de deploy e runtime\n\n/** Contexto Railway extraído das env vars */\nexport interface RailwayContext {\n environment?: string\n commitHash?: string\n branch?: string\n author?: string\n url?: string\n projectId?: string\n serviceId?: string\n}\n\n/**\n * Lê contexto de runtime do Railway via env vars.\n *\n * @example\n * ```ts\n * import { getRailwayContext } from '@victor-studio/monitor/adapters/railway'\n *\n * const ctx = getRailwayContext()\n * ```\n */\nexport function getRailwayContext(): RailwayContext {\n if (typeof process === 'undefined') return {}\n const env = process.env\n\n return {\n environment: env.RAILWAY_ENVIRONMENT,\n commitHash: env.RAILWAY_GIT_COMMIT_SHA,\n branch: env.RAILWAY_GIT_BRANCH,\n author: env.RAILWAY_GIT_AUTHOR,\n url: env.RAILWAY_PUBLIC_DOMAIN ? `https://${env.RAILWAY_PUBLIC_DOMAIN}` : undefined,\n projectId: env.RAILWAY_PROJECT_ID,\n serviceId: env.RAILWAY_SERVICE_ID,\n }\n}\n"]}
@@ -0,0 +1,23 @@
1
+ /** Contexto Railway extraído das env vars */
2
+ interface RailwayContext {
3
+ environment?: string;
4
+ commitHash?: string;
5
+ branch?: string;
6
+ author?: string;
7
+ url?: string;
8
+ projectId?: string;
9
+ serviceId?: string;
10
+ }
11
+ /**
12
+ * Lê contexto de runtime do Railway via env vars.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * import { getRailwayContext } from '@victor-studio/monitor/adapters/railway'
17
+ *
18
+ * const ctx = getRailwayContext()
19
+ * ```
20
+ */
21
+ declare function getRailwayContext(): RailwayContext;
22
+
23
+ export { type RailwayContext, getRailwayContext };
@@ -0,0 +1,23 @@
1
+ /** Contexto Railway extraído das env vars */
2
+ interface RailwayContext {
3
+ environment?: string;
4
+ commitHash?: string;
5
+ branch?: string;
6
+ author?: string;
7
+ url?: string;
8
+ projectId?: string;
9
+ serviceId?: string;
10
+ }
11
+ /**
12
+ * Lê contexto de runtime do Railway via env vars.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * import { getRailwayContext } from '@victor-studio/monitor/adapters/railway'
17
+ *
18
+ * const ctx = getRailwayContext()
19
+ * ```
20
+ */
21
+ declare function getRailwayContext(): RailwayContext;
22
+
23
+ export { type RailwayContext, getRailwayContext };