@validors/sdk 0.1.5 → 0.1.6

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
@@ -116,6 +116,56 @@ All options are passed as a `ValidorsOptions` object to any of the middleware fa
116
116
  | `ignoreRoutes` | `string[]` | `[]` | Routes to exclude from tracking (exact match or prefix). E.g. `['/health']`. |
117
117
  | `environment` | `string` | `process.env.NODE_ENV` | Tag events with an environment label (`production`, `staging`, etc.). |
118
118
 
119
+ ### Next.js (App Router)
120
+
121
+ Create a shared monitor instance once, then wrap your route handlers with it.
122
+
123
+ **Step 1** — create `lib/monitor.ts`:
124
+
125
+ ```ts
126
+ import * as validors from '@validors/sdk';
127
+
128
+ export const monitor = validors.nextjs({
129
+ apiKey: process.env.VALIDORS_API_KEY!,
130
+ });
131
+ ```
132
+
133
+ **Step 2** — wrap your route handlers:
134
+
135
+ ```ts
136
+ // app/api/users/route.ts
137
+ import { NextResponse } from 'next/server';
138
+ import { monitor } from '@/lib/monitor';
139
+
140
+ export const GET = monitor('/api/users', async (req) => {
141
+ const users = await getUsers();
142
+ return NextResponse.json({ users });
143
+ });
144
+
145
+ export const POST = monitor('/api/users', async (req) => {
146
+ const body = await req.json();
147
+ const user = await createUser(body);
148
+ return NextResponse.json({ user }, { status: 201 });
149
+ });
150
+ ```
151
+
152
+ **With dynamic route params:**
153
+
154
+ ```ts
155
+ // app/api/users/[id]/route.ts
156
+ import { NextRequest, NextResponse } from 'next/server';
157
+ import { monitor } from '@/lib/monitor';
158
+
159
+ export const GET = monitor('/api/users/[id]', async (req, context) => {
160
+ const { id } = await (context as { params: Promise<{ id: string }> }).params;
161
+ const user = await getUserById(id);
162
+ if (!user) return NextResponse.json({ error: 'Not found' }, { status: 404 });
163
+ return NextResponse.json({ user });
164
+ });
165
+ ```
166
+
167
+ > The route name is optional — if omitted, the actual request pathname is used automatically. Specifying it explicitly gives you cleaner route grouping in the dashboard (e.g. `/api/users/[id]` instead of `/api/users/123`).
168
+
119
169
  ---
120
170
 
121
171
  ## Verifying your integration
package/dist/index.d.mts CHANGED
@@ -123,4 +123,38 @@ declare function createMiddleware(options: ValidorsOptions): (c: {
123
123
  */
124
124
  declare function wrapFetch(options: ValidorsOptions, handler: GenericHandler): GenericHandler;
125
125
 
126
- export { BatchQueue, type ExpressRequestHandler, type IngestPayload, type SdkEvent, type ValidorsOptions, createMiddleware, BatchQueue as default, express, fastify, shutdown, wrapFetch };
126
+ type NextJsRequest = {
127
+ method: string;
128
+ nextUrl?: {
129
+ pathname: string;
130
+ };
131
+ url: string;
132
+ };
133
+ type NextJsResponse = {
134
+ status: number;
135
+ };
136
+ type NextJsHandler<C = unknown> = (req: NextJsRequest, context?: C) => Promise<NextJsResponse> | NextJsResponse;
137
+ /**
138
+ * Next.js App Router route handler wrapper.
139
+ *
140
+ * Create a single `monitor` instance in a shared file and use it to wrap
141
+ * your exported route handlers. Tracks latency, status codes, and errors
142
+ * automatically — including uncaught exceptions (reported as 500).
143
+ *
144
+ * @example
145
+ * // lib/monitor.ts
146
+ * import * as validors from '@validors/sdk';
147
+ * export const monitor = validors.nextjs({ apiKey: process.env.VALIDORS_API_KEY! });
148
+ *
149
+ * // app/api/users/route.ts
150
+ * import { monitor } from '@/lib/monitor';
151
+ * export const GET = monitor('/api/users', async (req) => {
152
+ * return NextResponse.json({ users: [] });
153
+ * });
154
+ */
155
+ declare function nextjs(options: ValidorsOptions): {
156
+ <C>(route: string, handler: NextJsHandler<C>): NextJsHandler<C>;
157
+ <C>(handler: NextJsHandler<C>): NextJsHandler<C>;
158
+ };
159
+
160
+ export { BatchQueue, type ExpressRequestHandler, type IngestPayload, type SdkEvent, type ValidorsOptions, createMiddleware, BatchQueue as default, express, fastify, nextjs, shutdown, wrapFetch };
package/dist/index.d.ts CHANGED
@@ -123,4 +123,38 @@ declare function createMiddleware(options: ValidorsOptions): (c: {
123
123
  */
124
124
  declare function wrapFetch(options: ValidorsOptions, handler: GenericHandler): GenericHandler;
125
125
 
126
- export { BatchQueue, type ExpressRequestHandler, type IngestPayload, type SdkEvent, type ValidorsOptions, createMiddleware, BatchQueue as default, express, fastify, shutdown, wrapFetch };
126
+ type NextJsRequest = {
127
+ method: string;
128
+ nextUrl?: {
129
+ pathname: string;
130
+ };
131
+ url: string;
132
+ };
133
+ type NextJsResponse = {
134
+ status: number;
135
+ };
136
+ type NextJsHandler<C = unknown> = (req: NextJsRequest, context?: C) => Promise<NextJsResponse> | NextJsResponse;
137
+ /**
138
+ * Next.js App Router route handler wrapper.
139
+ *
140
+ * Create a single `monitor` instance in a shared file and use it to wrap
141
+ * your exported route handlers. Tracks latency, status codes, and errors
142
+ * automatically — including uncaught exceptions (reported as 500).
143
+ *
144
+ * @example
145
+ * // lib/monitor.ts
146
+ * import * as validors from '@validors/sdk';
147
+ * export const monitor = validors.nextjs({ apiKey: process.env.VALIDORS_API_KEY! });
148
+ *
149
+ * // app/api/users/route.ts
150
+ * import { monitor } from '@/lib/monitor';
151
+ * export const GET = monitor('/api/users', async (req) => {
152
+ * return NextResponse.json({ users: [] });
153
+ * });
154
+ */
155
+ declare function nextjs(options: ValidorsOptions): {
156
+ <C>(route: string, handler: NextJsHandler<C>): NextJsHandler<C>;
157
+ <C>(handler: NextJsHandler<C>): NextJsHandler<C>;
158
+ };
159
+
160
+ export { BatchQueue, type ExpressRequestHandler, type IngestPayload, type SdkEvent, type ValidorsOptions, createMiddleware, BatchQueue as default, express, fastify, nextjs, shutdown, wrapFetch };
package/dist/index.js CHANGED
@@ -25,6 +25,7 @@ __export(index_exports, {
25
25
  default: () => index_default,
26
26
  express: () => express,
27
27
  fastify: () => fastify,
28
+ nextjs: () => nextjs,
28
29
  shutdown: () => shutdown,
29
30
  wrapFetch: () => wrapFetch
30
31
  });
@@ -251,12 +252,51 @@ function wrapFetch(options, handler) {
251
252
  };
252
253
  }
253
254
  var index_default = BatchQueue;
255
+ function nextjs(options) {
256
+ const queue = getOrCreateQueue(options);
257
+ function monitor(routeOrHandler, maybeHandler) {
258
+ const explicitRoute = typeof routeOrHandler === "string" ? routeOrHandler : void 0;
259
+ const handler = typeof routeOrHandler === "function" ? routeOrHandler : maybeHandler;
260
+ return async (req, context) => {
261
+ const start = Date.now();
262
+ let statusCode = 200;
263
+ try {
264
+ const response = await handler(req, context);
265
+ statusCode = response.status;
266
+ return response;
267
+ } catch (err) {
268
+ statusCode = 500;
269
+ throw err;
270
+ } finally {
271
+ let route;
272
+ if (explicitRoute) {
273
+ route = explicitRoute;
274
+ } else {
275
+ try {
276
+ route = req.nextUrl?.pathname ?? new URL(req.url).pathname;
277
+ } catch {
278
+ route = "unknown";
279
+ }
280
+ }
281
+ queue.push({
282
+ route,
283
+ method: req.method,
284
+ status_code: statusCode,
285
+ duration_ms: Date.now() - start,
286
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
287
+ });
288
+ }
289
+ };
290
+ }
291
+ return monitor;
292
+ }
254
293
  // Annotate the CommonJS export names for ESM import in node:
255
294
  0 && (module.exports = {
256
295
  BatchQueue,
257
296
  createMiddleware,
258
297
  express,
259
298
  fastify,
299
+ nextjs,
260
300
  shutdown,
261
301
  wrapFetch
262
302
  });
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/core.ts"],"sourcesContent":["import { BatchQueue } from \"./core\";\nimport type { ValidorsOptions, SdkEvent } from \"./types\";\n\nexport type { ValidorsOptions, SdkEvent, IngestPayload } from \"./types\";\nexport { BatchQueue } from \"./core\";\n\n// ---------------------------------------------------------------------------\n// Module-level default queue instance (created lazily)\n// ---------------------------------------------------------------------------\n\nlet _defaultQueue: BatchQueue | null = null;\n\nfunction getOrCreateQueue(options: ValidorsOptions): BatchQueue {\n if (!_defaultQueue) {\n _defaultQueue = new BatchQueue(options);\n\n process.on(\"beforeExit\", () => {\n _defaultQueue?.flush().catch(() => undefined);\n });\n\n process.on(\"SIGTERM\", () => {\n _defaultQueue?.shutdown().catch(() => undefined);\n });\n }\n return _defaultQueue;\n}\n\n/** Flush all pending events immediately. Call before process exit if needed. */\nexport async function shutdown(): Promise<void> {\n if (_defaultQueue) {\n await _defaultQueue.shutdown();\n _defaultQueue = null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Express middleware\n// ---------------------------------------------------------------------------\n\ntype ExpressRequest = {\n method: string;\n path: string;\n route?: { path?: string };\n};\n\ntype ExpressResponse = {\n statusCode: number;\n locals: Record<string, unknown>;\n on(event: string, listener: () => void): void;\n};\n\ntype NextFunction = () => void;\n\nexport type ExpressRequestHandler = (\n req: ExpressRequest,\n res: ExpressResponse,\n next: NextFunction\n) => void;\n\n/**\n * Express middleware that tracks request latency and status codes.\n *\n * @example\n * import * as validors from '@validors/sdk';\n * app.use(validors.express({ apiKey: 'vl_...' }));\n */\nexport function express(options: ValidorsOptions): ExpressRequestHandler {\n const queue = getOrCreateQueue(options);\n\n return function validorsMiddleware(\n req: ExpressRequest,\n res: ExpressResponse,\n next: NextFunction\n ) {\n const startTime = Date.now();\n\n res.on(\"finish\", () => {\n const durationMs = Date.now() - startTime;\n const route = req.route?.path ?? req.path ?? \"unknown\";\n const error =\n typeof res.locals.error === \"string\" ? res.locals.error : undefined;\n\n const event: SdkEvent = {\n route,\n method: req.method,\n status_code: res.statusCode,\n duration_ms: durationMs,\n ...(error ? { error } : {}),\n timestamp: new Date().toISOString(),\n };\n\n queue.push(event);\n });\n\n next();\n };\n}\n\n// ---------------------------------------------------------------------------\n// Fastify plugin\n// ---------------------------------------------------------------------------\n\ntype FastifyInstance = {\n addHook(\n name: \"onResponse\",\n fn: (request: FastifyRequest, reply: FastifyReply) => Promise<void>\n ): void;\n};\n\ntype FastifyRequest = {\n method: string;\n routerPath?: string;\n routeOptions?: { url?: string };\n};\n\ntype FastifyReply = {\n statusCode: number;\n elapsedTime?: number;\n};\n\ntype FastifyPlugin = (\n fastify: FastifyInstance,\n _opts: Record<string, unknown>,\n done: () => void\n) => void;\n\n/**\n * Fastify plugin that tracks request latency and status codes.\n *\n * @example\n * import * as validors from '@validors/sdk';\n * await fastify.register(validors.fastify, { apiKey: 'vl_...' });\n */\nexport function fastify(options: ValidorsOptions): FastifyPlugin {\n const queue = getOrCreateQueue(options);\n\n return function validorsFastifyPlugin(\n fastifyInstance: FastifyInstance,\n _opts: Record<string, unknown>,\n done: () => void\n ) {\n fastifyInstance.addHook(\n \"onResponse\",\n async (request: FastifyRequest, reply: FastifyReply) => {\n const route =\n request.routerPath ??\n request.routeOptions?.url ??\n \"unknown\";\n\n const durationMs =\n typeof reply.elapsedTime === \"number\"\n ? Math.round(reply.elapsedTime)\n : 0;\n\n const event: SdkEvent = {\n route,\n method: request.method,\n status_code: reply.statusCode,\n duration_ms: durationMs,\n timestamp: new Date().toISOString(),\n };\n\n queue.push(event);\n }\n );\n\n done();\n };\n}\n\n// ---------------------------------------------------------------------------\n// Generic / Hono / Edge middleware\n// ---------------------------------------------------------------------------\n\ntype GenericHandler = (\n request: Request,\n env?: unknown\n) => Promise<Response>;\n\n/**\n * Generic fetch-based middleware wrapper for Hono, Cloudflare Workers,\n * and other edge runtimes.\n *\n * Returns a handler that you can use as a Hono middleware or wrap your\n * existing fetch handler with.\n *\n * @example\n * // Hono\n * import { Hono } from 'hono';\n * import { createMiddleware } from '@validors/sdk';\n *\n * const app = new Hono();\n * app.use('*', createMiddleware({ apiKey: 'vl_...' }));\n */\nexport function createMiddleware(options: ValidorsOptions) {\n const queue = new BatchQueue(options);\n\n return async function validorsHonoMiddleware(\n c: {\n req: { method: string; url: string; routePath?: string };\n res?: { status?: number };\n },\n next: () => Promise<void>\n ) {\n const startTime = Date.now();\n\n try {\n await next();\n } finally {\n const durationMs = Date.now() - startTime;\n\n let route: string;\n try {\n route = c.req.routePath ?? new URL(c.req.url).pathname ?? \"unknown\";\n } catch {\n route = \"unknown\";\n }\n\n const statusCode = c.res?.status ?? 200;\n\n const event: SdkEvent = {\n route,\n method: c.req.method,\n status_code: statusCode,\n duration_ms: durationMs,\n timestamp: new Date().toISOString(),\n };\n\n queue.push(event);\n }\n };\n}\n\n/**\n * Wrap a generic fetch handler (for edge runtimes like Cloudflare Workers).\n *\n * @example\n * import { wrapFetch } from '@validors/sdk';\n *\n * export default {\n * fetch: wrapFetch({ apiKey: 'vl_...' }, async (request, env) => {\n * return new Response('Hello!');\n * })\n * };\n */\nexport function wrapFetch(\n options: ValidorsOptions,\n handler: GenericHandler\n): GenericHandler {\n const queue = new BatchQueue(options);\n\n return async function wrappedFetch(request: Request, env?: unknown) {\n const startTime = Date.now();\n let statusCode = 200;\n\n try {\n const response = await handler(request, env);\n statusCode = response.status;\n return response;\n } catch (err) {\n statusCode = 500;\n throw err;\n } finally {\n const durationMs = Date.now() - startTime;\n\n let route: string;\n try {\n route = new URL(request.url).pathname ?? \"unknown\";\n } catch {\n route = \"unknown\";\n }\n\n const event: SdkEvent = {\n route,\n method: request.method,\n status_code: statusCode,\n duration_ms: durationMs,\n timestamp: new Date().toISOString(),\n };\n\n queue.push(event);\n }\n };\n}\n\nexport default BatchQueue;\n","import type { ValidorsOptions, SdkEvent, IngestPayload } from \"./types\";\n\nconst DEFAULT_INGEST_URL = \"https://validors.app/api/ingest\";\nconst DOCS_URL = \"https://validors.com\";\n\nfunction getErrorMessage(status: number, apiKey: string): string {\n const keyHint = `(key: ${apiKey.slice(0, 8)}...)`;\n\n switch (status) {\n case 401:\n return (\n `[validors] Invalid or missing API key ${keyHint}. ` +\n `Check your key in the dashboard → ${DOCS_URL}`\n );\n case 403:\n return (\n `[validors] Access denied ${keyHint}. Your plan may not support this. ` +\n `Upgrade at ${DOCS_URL}`\n );\n case 400:\n return (\n `[validors] Bad request — the event payload was rejected. ` +\n `This is likely a bug. Please report it at ${DOCS_URL}`\n );\n case 413:\n return (\n `[validors] Payload too large. ` +\n `Reduce your batch size or flush more frequently. See ${DOCS_URL}`\n );\n case 429:\n return (\n `[validors] Rate limit exceeded ${keyHint}. ` +\n `Events are being dropped. Reduce flush frequency or upgrade at ${DOCS_URL}`\n );\n case 500:\n case 502:\n case 503:\n case 504:\n return (\n `[validors] Server error (HTTP ${status}). ` +\n `Events may have been lost. Check status at ${DOCS_URL}`\n );\n default:\n return (\n `[validors] Unexpected response (HTTP ${status}). ` +\n `See ${DOCS_URL} for help.`\n );\n }\n}\nconst DEFAULT_FLUSH_INTERVAL = 5000;\nconst DEFAULT_BATCH_SIZE = 50;\n\nexport class BatchQueue {\n private queue: SdkEvent[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n private options: Required<ValidorsOptions>;\n\n constructor(options: ValidorsOptions) {\n this.options = {\n apiKey: options.apiKey,\n ingestUrl: options.ingestUrl ?? DEFAULT_INGEST_URL,\n flushInterval: options.flushInterval ?? DEFAULT_FLUSH_INTERVAL,\n batchSize: options.batchSize ?? DEFAULT_BATCH_SIZE,\n debug: options.debug ?? false,\n ignoreRoutes: options.ignoreRoutes ?? [],\n environment: options.environment ?? process.env.NODE_ENV ?? \"production\",\n };\n\n this.timer = setInterval(() => {\n this.flush().catch(() => undefined);\n }, this.options.flushInterval);\n\n // Allow process to exit even if timer is active\n if (this.timer.unref) {\n this.timer.unref();\n }\n }\n\n push(event: SdkEvent): void {\n // Check ignored routes\n for (const ignored of this.options.ignoreRoutes) {\n if (event.route === ignored || event.route.startsWith(ignored)) return;\n }\n\n this.queue.push(event);\n\n if (this.options.debug) {\n console.log(\n `[validors] queued event: ${event.method} ${event.route} ${event.status_code} ${event.duration_ms}ms (queue=${this.queue.length})`\n );\n }\n\n if (this.queue.length >= this.options.batchSize) {\n this.flush().catch(() => undefined);\n }\n }\n\n async flush(): Promise<void> {\n if (this.queue.length === 0) return;\n\n const batch = this.queue.splice(0, this.queue.length);\n\n if (this.options.debug) {\n console.log(`[validors] flushing ${batch.length} events to ${this.options.ingestUrl}`);\n }\n\n const payload: IngestPayload = { events: batch };\n\n try {\n const response = await fetch(this.options.ingestUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-API-Key\": this.options.apiKey,\n },\n body: JSON.stringify(payload),\n });\n\n if (response.ok) {\n if (this.options.debug) {\n const data = await response.json() as { received?: number };\n console.log(`[validors] flushed successfully: received=${data.received}`);\n }\n } else {\n const message = getErrorMessage(response.status, this.options.apiKey);\n console.warn(message);\n }\n } catch (err) {\n // Never throw — silently swallow network errors\n if (this.options.debug) {\n console.error(\"[validors] network error during flush:\", err);\n }\n }\n }\n\n async shutdown(): Promise<void> {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n await this.flush();\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/core.ts"],"sourcesContent":["import { BatchQueue } from \"./core\";\nimport type { ValidorsOptions, SdkEvent } from \"./types\";\n\nexport type { ValidorsOptions, SdkEvent, IngestPayload } from \"./types\";\nexport { BatchQueue } from \"./core\";\n\n// ---------------------------------------------------------------------------\n// Module-level default queue instance (created lazily)\n// ---------------------------------------------------------------------------\n\nlet _defaultQueue: BatchQueue | null = null;\n\nfunction getOrCreateQueue(options: ValidorsOptions): BatchQueue {\n if (!_defaultQueue) {\n _defaultQueue = new BatchQueue(options);\n\n process.on(\"beforeExit\", () => {\n _defaultQueue?.flush().catch(() => undefined);\n });\n\n process.on(\"SIGTERM\", () => {\n _defaultQueue?.shutdown().catch(() => undefined);\n });\n }\n return _defaultQueue;\n}\n\n/** Flush all pending events immediately. Call before process exit if needed. */\nexport async function shutdown(): Promise<void> {\n if (_defaultQueue) {\n await _defaultQueue.shutdown();\n _defaultQueue = null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Express middleware\n// ---------------------------------------------------------------------------\n\ntype ExpressRequest = {\n method: string;\n path: string;\n route?: { path?: string };\n};\n\ntype ExpressResponse = {\n statusCode: number;\n locals: Record<string, unknown>;\n on(event: string, listener: () => void): void;\n};\n\ntype NextFunction = () => void;\n\nexport type ExpressRequestHandler = (\n req: ExpressRequest,\n res: ExpressResponse,\n next: NextFunction\n) => void;\n\n/**\n * Express middleware that tracks request latency and status codes.\n *\n * @example\n * import * as validors from '@validors/sdk';\n * app.use(validors.express({ apiKey: 'vl_...' }));\n */\nexport function express(options: ValidorsOptions): ExpressRequestHandler {\n const queue = getOrCreateQueue(options);\n\n return function validorsMiddleware(\n req: ExpressRequest,\n res: ExpressResponse,\n next: NextFunction\n ) {\n const startTime = Date.now();\n\n res.on(\"finish\", () => {\n const durationMs = Date.now() - startTime;\n const route = req.route?.path ?? req.path ?? \"unknown\";\n const error =\n typeof res.locals.error === \"string\" ? res.locals.error : undefined;\n\n const event: SdkEvent = {\n route,\n method: req.method,\n status_code: res.statusCode,\n duration_ms: durationMs,\n ...(error ? { error } : {}),\n timestamp: new Date().toISOString(),\n };\n\n queue.push(event);\n });\n\n next();\n };\n}\n\n// ---------------------------------------------------------------------------\n// Fastify plugin\n// ---------------------------------------------------------------------------\n\ntype FastifyInstance = {\n addHook(\n name: \"onResponse\",\n fn: (request: FastifyRequest, reply: FastifyReply) => Promise<void>\n ): void;\n};\n\ntype FastifyRequest = {\n method: string;\n routerPath?: string;\n routeOptions?: { url?: string };\n};\n\ntype FastifyReply = {\n statusCode: number;\n elapsedTime?: number;\n};\n\ntype FastifyPlugin = (\n fastify: FastifyInstance,\n _opts: Record<string, unknown>,\n done: () => void\n) => void;\n\n/**\n * Fastify plugin that tracks request latency and status codes.\n *\n * @example\n * import * as validors from '@validors/sdk';\n * await fastify.register(validors.fastify, { apiKey: 'vl_...' });\n */\nexport function fastify(options: ValidorsOptions): FastifyPlugin {\n const queue = getOrCreateQueue(options);\n\n return function validorsFastifyPlugin(\n fastifyInstance: FastifyInstance,\n _opts: Record<string, unknown>,\n done: () => void\n ) {\n fastifyInstance.addHook(\n \"onResponse\",\n async (request: FastifyRequest, reply: FastifyReply) => {\n const route =\n request.routerPath ??\n request.routeOptions?.url ??\n \"unknown\";\n\n const durationMs =\n typeof reply.elapsedTime === \"number\"\n ? Math.round(reply.elapsedTime)\n : 0;\n\n const event: SdkEvent = {\n route,\n method: request.method,\n status_code: reply.statusCode,\n duration_ms: durationMs,\n timestamp: new Date().toISOString(),\n };\n\n queue.push(event);\n }\n );\n\n done();\n };\n}\n\n// ---------------------------------------------------------------------------\n// Generic / Hono / Edge middleware\n// ---------------------------------------------------------------------------\n\ntype GenericHandler = (\n request: Request,\n env?: unknown\n) => Promise<Response>;\n\n/**\n * Generic fetch-based middleware wrapper for Hono, Cloudflare Workers,\n * and other edge runtimes.\n *\n * Returns a handler that you can use as a Hono middleware or wrap your\n * existing fetch handler with.\n *\n * @example\n * // Hono\n * import { Hono } from 'hono';\n * import { createMiddleware } from '@validors/sdk';\n *\n * const app = new Hono();\n * app.use('*', createMiddleware({ apiKey: 'vl_...' }));\n */\nexport function createMiddleware(options: ValidorsOptions) {\n const queue = new BatchQueue(options);\n\n return async function validorsHonoMiddleware(\n c: {\n req: { method: string; url: string; routePath?: string };\n res?: { status?: number };\n },\n next: () => Promise<void>\n ) {\n const startTime = Date.now();\n\n try {\n await next();\n } finally {\n const durationMs = Date.now() - startTime;\n\n let route: string;\n try {\n route = c.req.routePath ?? new URL(c.req.url).pathname ?? \"unknown\";\n } catch {\n route = \"unknown\";\n }\n\n const statusCode = c.res?.status ?? 200;\n\n const event: SdkEvent = {\n route,\n method: c.req.method,\n status_code: statusCode,\n duration_ms: durationMs,\n timestamp: new Date().toISOString(),\n };\n\n queue.push(event);\n }\n };\n}\n\n/**\n * Wrap a generic fetch handler (for edge runtimes like Cloudflare Workers).\n *\n * @example\n * import { wrapFetch } from '@validors/sdk';\n *\n * export default {\n * fetch: wrapFetch({ apiKey: 'vl_...' }, async (request, env) => {\n * return new Response('Hello!');\n * })\n * };\n */\nexport function wrapFetch(\n options: ValidorsOptions,\n handler: GenericHandler\n): GenericHandler {\n const queue = new BatchQueue(options);\n\n return async function wrappedFetch(request: Request, env?: unknown) {\n const startTime = Date.now();\n let statusCode = 200;\n\n try {\n const response = await handler(request, env);\n statusCode = response.status;\n return response;\n } catch (err) {\n statusCode = 500;\n throw err;\n } finally {\n const durationMs = Date.now() - startTime;\n\n let route: string;\n try {\n route = new URL(request.url).pathname ?? \"unknown\";\n } catch {\n route = \"unknown\";\n }\n\n const event: SdkEvent = {\n route,\n method: request.method,\n status_code: statusCode,\n duration_ms: durationMs,\n timestamp: new Date().toISOString(),\n };\n\n queue.push(event);\n }\n };\n}\n\nexport default BatchQueue;\n\n// ---------------------------------------------------------------------------\n// Next.js App Router\n// ---------------------------------------------------------------------------\n\ntype NextJsRequest = {\n method: string;\n nextUrl?: { pathname: string };\n url: string;\n};\n\ntype NextJsResponse = { status: number };\n\ntype NextJsHandler<C = unknown> = (\n req: NextJsRequest,\n context?: C\n) => Promise<NextJsResponse> | NextJsResponse;\n\n/**\n * Next.js App Router route handler wrapper.\n *\n * Create a single `monitor` instance in a shared file and use it to wrap\n * your exported route handlers. Tracks latency, status codes, and errors\n * automatically — including uncaught exceptions (reported as 500).\n *\n * @example\n * // lib/monitor.ts\n * import * as validors from '@validors/sdk';\n * export const monitor = validors.nextjs({ apiKey: process.env.VALIDORS_API_KEY! });\n *\n * // app/api/users/route.ts\n * import { monitor } from '@/lib/monitor';\n * export const GET = monitor('/api/users', async (req) => {\n * return NextResponse.json({ users: [] });\n * });\n */\nexport function nextjs(options: ValidorsOptions) {\n const queue = getOrCreateQueue(options);\n\n function monitor<C>(route: string, handler: NextJsHandler<C>): NextJsHandler<C>;\n function monitor<C>(handler: NextJsHandler<C>): NextJsHandler<C>;\n function monitor<C>(\n routeOrHandler: string | NextJsHandler<C>,\n maybeHandler?: NextJsHandler<C>\n ): NextJsHandler<C> {\n const explicitRoute = typeof routeOrHandler === \"string\" ? routeOrHandler : undefined;\n const handler = typeof routeOrHandler === \"function\" ? routeOrHandler : maybeHandler!;\n\n return async (req: NextJsRequest, context?: C) => {\n const start = Date.now();\n let statusCode = 200;\n\n try {\n const response = await handler(req, context);\n statusCode = response.status;\n return response;\n } catch (err) {\n statusCode = 500;\n throw err;\n } finally {\n let route: string;\n if (explicitRoute) {\n route = explicitRoute;\n } else {\n try {\n route = req.nextUrl?.pathname ?? new URL(req.url).pathname;\n } catch {\n route = \"unknown\";\n }\n }\n\n queue.push({\n route,\n method: req.method,\n status_code: statusCode,\n duration_ms: Date.now() - start,\n timestamp: new Date().toISOString(),\n });\n }\n };\n }\n\n return monitor;\n}\n","import type { ValidorsOptions, SdkEvent, IngestPayload } from \"./types\";\n\nconst DEFAULT_INGEST_URL = \"https://validors.app/api/ingest\";\nconst DOCS_URL = \"https://validors.com\";\n\nfunction getErrorMessage(status: number, apiKey: string): string {\n const keyHint = `(key: ${apiKey.slice(0, 8)}...)`;\n\n switch (status) {\n case 401:\n return (\n `[validors] Invalid or missing API key ${keyHint}. ` +\n `Check your key in the dashboard → ${DOCS_URL}`\n );\n case 403:\n return (\n `[validors] Access denied ${keyHint}. Your plan may not support this. ` +\n `Upgrade at ${DOCS_URL}`\n );\n case 400:\n return (\n `[validors] Bad request — the event payload was rejected. ` +\n `This is likely a bug. Please report it at ${DOCS_URL}`\n );\n case 413:\n return (\n `[validors] Payload too large. ` +\n `Reduce your batch size or flush more frequently. See ${DOCS_URL}`\n );\n case 429:\n return (\n `[validors] Rate limit exceeded ${keyHint}. ` +\n `Events are being dropped. Reduce flush frequency or upgrade at ${DOCS_URL}`\n );\n case 500:\n case 502:\n case 503:\n case 504:\n return (\n `[validors] Server error (HTTP ${status}). ` +\n `Events may have been lost. Check status at ${DOCS_URL}`\n );\n default:\n return (\n `[validors] Unexpected response (HTTP ${status}). ` +\n `See ${DOCS_URL} for help.`\n );\n }\n}\nconst DEFAULT_FLUSH_INTERVAL = 5000;\nconst DEFAULT_BATCH_SIZE = 50;\n\nexport class BatchQueue {\n private queue: SdkEvent[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n private options: Required<ValidorsOptions>;\n\n constructor(options: ValidorsOptions) {\n this.options = {\n apiKey: options.apiKey,\n ingestUrl: options.ingestUrl ?? DEFAULT_INGEST_URL,\n flushInterval: options.flushInterval ?? DEFAULT_FLUSH_INTERVAL,\n batchSize: options.batchSize ?? DEFAULT_BATCH_SIZE,\n debug: options.debug ?? false,\n ignoreRoutes: options.ignoreRoutes ?? [],\n environment: options.environment ?? process.env.NODE_ENV ?? \"production\",\n };\n\n this.timer = setInterval(() => {\n this.flush().catch(() => undefined);\n }, this.options.flushInterval);\n\n // Allow process to exit even if timer is active\n if (this.timer.unref) {\n this.timer.unref();\n }\n }\n\n push(event: SdkEvent): void {\n // Check ignored routes\n for (const ignored of this.options.ignoreRoutes) {\n if (event.route === ignored || event.route.startsWith(ignored)) return;\n }\n\n this.queue.push(event);\n\n if (this.options.debug) {\n console.log(\n `[validors] queued event: ${event.method} ${event.route} ${event.status_code} ${event.duration_ms}ms (queue=${this.queue.length})`\n );\n }\n\n if (this.queue.length >= this.options.batchSize) {\n this.flush().catch(() => undefined);\n }\n }\n\n async flush(): Promise<void> {\n if (this.queue.length === 0) return;\n\n const batch = this.queue.splice(0, this.queue.length);\n\n if (this.options.debug) {\n console.log(`[validors] flushing ${batch.length} events to ${this.options.ingestUrl}`);\n }\n\n const payload: IngestPayload = { events: batch };\n\n try {\n const response = await fetch(this.options.ingestUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-API-Key\": this.options.apiKey,\n },\n body: JSON.stringify(payload),\n });\n\n if (response.ok) {\n if (this.options.debug) {\n const data = await response.json() as { received?: number };\n console.log(`[validors] flushed successfully: received=${data.received}`);\n }\n } else {\n const message = getErrorMessage(response.status, this.options.apiKey);\n console.warn(message);\n }\n } catch (err) {\n // Never throw — silently swallow network errors\n if (this.options.debug) {\n console.error(\"[validors] network error during flush:\", err);\n }\n }\n }\n\n async shutdown(): Promise<void> {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n await this.flush();\n }\n}\n"],"mappings":"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","names":[]}
package/dist/index.mjs CHANGED
@@ -219,12 +219,51 @@ function wrapFetch(options, handler) {
219
219
  };
220
220
  }
221
221
  var index_default = BatchQueue;
222
+ function nextjs(options) {
223
+ const queue = getOrCreateQueue(options);
224
+ function monitor(routeOrHandler, maybeHandler) {
225
+ const explicitRoute = typeof routeOrHandler === "string" ? routeOrHandler : void 0;
226
+ const handler = typeof routeOrHandler === "function" ? routeOrHandler : maybeHandler;
227
+ return async (req, context) => {
228
+ const start = Date.now();
229
+ let statusCode = 200;
230
+ try {
231
+ const response = await handler(req, context);
232
+ statusCode = response.status;
233
+ return response;
234
+ } catch (err) {
235
+ statusCode = 500;
236
+ throw err;
237
+ } finally {
238
+ let route;
239
+ if (explicitRoute) {
240
+ route = explicitRoute;
241
+ } else {
242
+ try {
243
+ route = req.nextUrl?.pathname ?? new URL(req.url).pathname;
244
+ } catch {
245
+ route = "unknown";
246
+ }
247
+ }
248
+ queue.push({
249
+ route,
250
+ method: req.method,
251
+ status_code: statusCode,
252
+ duration_ms: Date.now() - start,
253
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
254
+ });
255
+ }
256
+ };
257
+ }
258
+ return monitor;
259
+ }
222
260
  export {
223
261
  BatchQueue,
224
262
  createMiddleware,
225
263
  index_default as default,
226
264
  express,
227
265
  fastify,
266
+ nextjs,
228
267
  shutdown,
229
268
  wrapFetch
230
269
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core.ts","../src/index.ts"],"sourcesContent":["import type { ValidorsOptions, SdkEvent, IngestPayload } from \"./types\";\n\nconst DEFAULT_INGEST_URL = \"https://validors.app/api/ingest\";\nconst DOCS_URL = \"https://validors.com\";\n\nfunction getErrorMessage(status: number, apiKey: string): string {\n const keyHint = `(key: ${apiKey.slice(0, 8)}...)`;\n\n switch (status) {\n case 401:\n return (\n `[validors] Invalid or missing API key ${keyHint}. ` +\n `Check your key in the dashboard → ${DOCS_URL}`\n );\n case 403:\n return (\n `[validors] Access denied ${keyHint}. Your plan may not support this. ` +\n `Upgrade at ${DOCS_URL}`\n );\n case 400:\n return (\n `[validors] Bad request — the event payload was rejected. ` +\n `This is likely a bug. Please report it at ${DOCS_URL}`\n );\n case 413:\n return (\n `[validors] Payload too large. ` +\n `Reduce your batch size or flush more frequently. See ${DOCS_URL}`\n );\n case 429:\n return (\n `[validors] Rate limit exceeded ${keyHint}. ` +\n `Events are being dropped. Reduce flush frequency or upgrade at ${DOCS_URL}`\n );\n case 500:\n case 502:\n case 503:\n case 504:\n return (\n `[validors] Server error (HTTP ${status}). ` +\n `Events may have been lost. Check status at ${DOCS_URL}`\n );\n default:\n return (\n `[validors] Unexpected response (HTTP ${status}). ` +\n `See ${DOCS_URL} for help.`\n );\n }\n}\nconst DEFAULT_FLUSH_INTERVAL = 5000;\nconst DEFAULT_BATCH_SIZE = 50;\n\nexport class BatchQueue {\n private queue: SdkEvent[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n private options: Required<ValidorsOptions>;\n\n constructor(options: ValidorsOptions) {\n this.options = {\n apiKey: options.apiKey,\n ingestUrl: options.ingestUrl ?? DEFAULT_INGEST_URL,\n flushInterval: options.flushInterval ?? DEFAULT_FLUSH_INTERVAL,\n batchSize: options.batchSize ?? DEFAULT_BATCH_SIZE,\n debug: options.debug ?? false,\n ignoreRoutes: options.ignoreRoutes ?? [],\n environment: options.environment ?? process.env.NODE_ENV ?? \"production\",\n };\n\n this.timer = setInterval(() => {\n this.flush().catch(() => undefined);\n }, this.options.flushInterval);\n\n // Allow process to exit even if timer is active\n if (this.timer.unref) {\n this.timer.unref();\n }\n }\n\n push(event: SdkEvent): void {\n // Check ignored routes\n for (const ignored of this.options.ignoreRoutes) {\n if (event.route === ignored || event.route.startsWith(ignored)) return;\n }\n\n this.queue.push(event);\n\n if (this.options.debug) {\n console.log(\n `[validors] queued event: ${event.method} ${event.route} ${event.status_code} ${event.duration_ms}ms (queue=${this.queue.length})`\n );\n }\n\n if (this.queue.length >= this.options.batchSize) {\n this.flush().catch(() => undefined);\n }\n }\n\n async flush(): Promise<void> {\n if (this.queue.length === 0) return;\n\n const batch = this.queue.splice(0, this.queue.length);\n\n if (this.options.debug) {\n console.log(`[validors] flushing ${batch.length} events to ${this.options.ingestUrl}`);\n }\n\n const payload: IngestPayload = { events: batch };\n\n try {\n const response = await fetch(this.options.ingestUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-API-Key\": this.options.apiKey,\n },\n body: JSON.stringify(payload),\n });\n\n if (response.ok) {\n if (this.options.debug) {\n const data = await response.json() as { received?: number };\n console.log(`[validors] flushed successfully: received=${data.received}`);\n }\n } else {\n const message = getErrorMessage(response.status, this.options.apiKey);\n console.warn(message);\n }\n } catch (err) {\n // Never throw — silently swallow network errors\n if (this.options.debug) {\n console.error(\"[validors] network error during flush:\", err);\n }\n }\n }\n\n async shutdown(): Promise<void> {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n await this.flush();\n }\n}\n","import { BatchQueue } from \"./core\";\nimport type { ValidorsOptions, SdkEvent } from \"./types\";\n\nexport type { ValidorsOptions, SdkEvent, IngestPayload } from \"./types\";\nexport { BatchQueue } from \"./core\";\n\n// ---------------------------------------------------------------------------\n// Module-level default queue instance (created lazily)\n// ---------------------------------------------------------------------------\n\nlet _defaultQueue: BatchQueue | null = null;\n\nfunction getOrCreateQueue(options: ValidorsOptions): BatchQueue {\n if (!_defaultQueue) {\n _defaultQueue = new BatchQueue(options);\n\n process.on(\"beforeExit\", () => {\n _defaultQueue?.flush().catch(() => undefined);\n });\n\n process.on(\"SIGTERM\", () => {\n _defaultQueue?.shutdown().catch(() => undefined);\n });\n }\n return _defaultQueue;\n}\n\n/** Flush all pending events immediately. Call before process exit if needed. */\nexport async function shutdown(): Promise<void> {\n if (_defaultQueue) {\n await _defaultQueue.shutdown();\n _defaultQueue = null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Express middleware\n// ---------------------------------------------------------------------------\n\ntype ExpressRequest = {\n method: string;\n path: string;\n route?: { path?: string };\n};\n\ntype ExpressResponse = {\n statusCode: number;\n locals: Record<string, unknown>;\n on(event: string, listener: () => void): void;\n};\n\ntype NextFunction = () => void;\n\nexport type ExpressRequestHandler = (\n req: ExpressRequest,\n res: ExpressResponse,\n next: NextFunction\n) => void;\n\n/**\n * Express middleware that tracks request latency and status codes.\n *\n * @example\n * import * as validors from '@validors/sdk';\n * app.use(validors.express({ apiKey: 'vl_...' }));\n */\nexport function express(options: ValidorsOptions): ExpressRequestHandler {\n const queue = getOrCreateQueue(options);\n\n return function validorsMiddleware(\n req: ExpressRequest,\n res: ExpressResponse,\n next: NextFunction\n ) {\n const startTime = Date.now();\n\n res.on(\"finish\", () => {\n const durationMs = Date.now() - startTime;\n const route = req.route?.path ?? req.path ?? \"unknown\";\n const error =\n typeof res.locals.error === \"string\" ? res.locals.error : undefined;\n\n const event: SdkEvent = {\n route,\n method: req.method,\n status_code: res.statusCode,\n duration_ms: durationMs,\n ...(error ? { error } : {}),\n timestamp: new Date().toISOString(),\n };\n\n queue.push(event);\n });\n\n next();\n };\n}\n\n// ---------------------------------------------------------------------------\n// Fastify plugin\n// ---------------------------------------------------------------------------\n\ntype FastifyInstance = {\n addHook(\n name: \"onResponse\",\n fn: (request: FastifyRequest, reply: FastifyReply) => Promise<void>\n ): void;\n};\n\ntype FastifyRequest = {\n method: string;\n routerPath?: string;\n routeOptions?: { url?: string };\n};\n\ntype FastifyReply = {\n statusCode: number;\n elapsedTime?: number;\n};\n\ntype FastifyPlugin = (\n fastify: FastifyInstance,\n _opts: Record<string, unknown>,\n done: () => void\n) => void;\n\n/**\n * Fastify plugin that tracks request latency and status codes.\n *\n * @example\n * import * as validors from '@validors/sdk';\n * await fastify.register(validors.fastify, { apiKey: 'vl_...' });\n */\nexport function fastify(options: ValidorsOptions): FastifyPlugin {\n const queue = getOrCreateQueue(options);\n\n return function validorsFastifyPlugin(\n fastifyInstance: FastifyInstance,\n _opts: Record<string, unknown>,\n done: () => void\n ) {\n fastifyInstance.addHook(\n \"onResponse\",\n async (request: FastifyRequest, reply: FastifyReply) => {\n const route =\n request.routerPath ??\n request.routeOptions?.url ??\n \"unknown\";\n\n const durationMs =\n typeof reply.elapsedTime === \"number\"\n ? Math.round(reply.elapsedTime)\n : 0;\n\n const event: SdkEvent = {\n route,\n method: request.method,\n status_code: reply.statusCode,\n duration_ms: durationMs,\n timestamp: new Date().toISOString(),\n };\n\n queue.push(event);\n }\n );\n\n done();\n };\n}\n\n// ---------------------------------------------------------------------------\n// Generic / Hono / Edge middleware\n// ---------------------------------------------------------------------------\n\ntype GenericHandler = (\n request: Request,\n env?: unknown\n) => Promise<Response>;\n\n/**\n * Generic fetch-based middleware wrapper for Hono, Cloudflare Workers,\n * and other edge runtimes.\n *\n * Returns a handler that you can use as a Hono middleware or wrap your\n * existing fetch handler with.\n *\n * @example\n * // Hono\n * import { Hono } from 'hono';\n * import { createMiddleware } from '@validors/sdk';\n *\n * const app = new Hono();\n * app.use('*', createMiddleware({ apiKey: 'vl_...' }));\n */\nexport function createMiddleware(options: ValidorsOptions) {\n const queue = new BatchQueue(options);\n\n return async function validorsHonoMiddleware(\n c: {\n req: { method: string; url: string; routePath?: string };\n res?: { status?: number };\n },\n next: () => Promise<void>\n ) {\n const startTime = Date.now();\n\n try {\n await next();\n } finally {\n const durationMs = Date.now() - startTime;\n\n let route: string;\n try {\n route = c.req.routePath ?? new URL(c.req.url).pathname ?? \"unknown\";\n } catch {\n route = \"unknown\";\n }\n\n const statusCode = c.res?.status ?? 200;\n\n const event: SdkEvent = {\n route,\n method: c.req.method,\n status_code: statusCode,\n duration_ms: durationMs,\n timestamp: new Date().toISOString(),\n };\n\n queue.push(event);\n }\n };\n}\n\n/**\n * Wrap a generic fetch handler (for edge runtimes like Cloudflare Workers).\n *\n * @example\n * import { wrapFetch } from '@validors/sdk';\n *\n * export default {\n * fetch: wrapFetch({ apiKey: 'vl_...' }, async (request, env) => {\n * return new Response('Hello!');\n * })\n * };\n */\nexport function wrapFetch(\n options: ValidorsOptions,\n handler: GenericHandler\n): GenericHandler {\n const queue = new BatchQueue(options);\n\n return async function wrappedFetch(request: Request, env?: unknown) {\n const startTime = Date.now();\n let statusCode = 200;\n\n try {\n const response = await handler(request, env);\n statusCode = response.status;\n return response;\n } catch (err) {\n statusCode = 500;\n throw err;\n } finally {\n const durationMs = Date.now() - startTime;\n\n let route: string;\n try {\n route = new URL(request.url).pathname ?? \"unknown\";\n } catch {\n route = \"unknown\";\n }\n\n const event: SdkEvent = {\n route,\n method: request.method,\n status_code: statusCode,\n duration_ms: durationMs,\n timestamp: new Date().toISOString(),\n };\n\n queue.push(event);\n }\n };\n}\n\nexport default BatchQueue;\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/core.ts","../src/index.ts"],"sourcesContent":["import type { ValidorsOptions, SdkEvent, IngestPayload } from \"./types\";\n\nconst DEFAULT_INGEST_URL = \"https://validors.app/api/ingest\";\nconst DOCS_URL = \"https://validors.com\";\n\nfunction getErrorMessage(status: number, apiKey: string): string {\n const keyHint = `(key: ${apiKey.slice(0, 8)}...)`;\n\n switch (status) {\n case 401:\n return (\n `[validors] Invalid or missing API key ${keyHint}. ` +\n `Check your key in the dashboard → ${DOCS_URL}`\n );\n case 403:\n return (\n `[validors] Access denied ${keyHint}. Your plan may not support this. ` +\n `Upgrade at ${DOCS_URL}`\n );\n case 400:\n return (\n `[validors] Bad request — the event payload was rejected. ` +\n `This is likely a bug. Please report it at ${DOCS_URL}`\n );\n case 413:\n return (\n `[validors] Payload too large. ` +\n `Reduce your batch size or flush more frequently. See ${DOCS_URL}`\n );\n case 429:\n return (\n `[validors] Rate limit exceeded ${keyHint}. ` +\n `Events are being dropped. Reduce flush frequency or upgrade at ${DOCS_URL}`\n );\n case 500:\n case 502:\n case 503:\n case 504:\n return (\n `[validors] Server error (HTTP ${status}). ` +\n `Events may have been lost. Check status at ${DOCS_URL}`\n );\n default:\n return (\n `[validors] Unexpected response (HTTP ${status}). ` +\n `See ${DOCS_URL} for help.`\n );\n }\n}\nconst DEFAULT_FLUSH_INTERVAL = 5000;\nconst DEFAULT_BATCH_SIZE = 50;\n\nexport class BatchQueue {\n private queue: SdkEvent[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n private options: Required<ValidorsOptions>;\n\n constructor(options: ValidorsOptions) {\n this.options = {\n apiKey: options.apiKey,\n ingestUrl: options.ingestUrl ?? DEFAULT_INGEST_URL,\n flushInterval: options.flushInterval ?? DEFAULT_FLUSH_INTERVAL,\n batchSize: options.batchSize ?? DEFAULT_BATCH_SIZE,\n debug: options.debug ?? false,\n ignoreRoutes: options.ignoreRoutes ?? [],\n environment: options.environment ?? process.env.NODE_ENV ?? \"production\",\n };\n\n this.timer = setInterval(() => {\n this.flush().catch(() => undefined);\n }, this.options.flushInterval);\n\n // Allow process to exit even if timer is active\n if (this.timer.unref) {\n this.timer.unref();\n }\n }\n\n push(event: SdkEvent): void {\n // Check ignored routes\n for (const ignored of this.options.ignoreRoutes) {\n if (event.route === ignored || event.route.startsWith(ignored)) return;\n }\n\n this.queue.push(event);\n\n if (this.options.debug) {\n console.log(\n `[validors] queued event: ${event.method} ${event.route} ${event.status_code} ${event.duration_ms}ms (queue=${this.queue.length})`\n );\n }\n\n if (this.queue.length >= this.options.batchSize) {\n this.flush().catch(() => undefined);\n }\n }\n\n async flush(): Promise<void> {\n if (this.queue.length === 0) return;\n\n const batch = this.queue.splice(0, this.queue.length);\n\n if (this.options.debug) {\n console.log(`[validors] flushing ${batch.length} events to ${this.options.ingestUrl}`);\n }\n\n const payload: IngestPayload = { events: batch };\n\n try {\n const response = await fetch(this.options.ingestUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-API-Key\": this.options.apiKey,\n },\n body: JSON.stringify(payload),\n });\n\n if (response.ok) {\n if (this.options.debug) {\n const data = await response.json() as { received?: number };\n console.log(`[validors] flushed successfully: received=${data.received}`);\n }\n } else {\n const message = getErrorMessage(response.status, this.options.apiKey);\n console.warn(message);\n }\n } catch (err) {\n // Never throw — silently swallow network errors\n if (this.options.debug) {\n console.error(\"[validors] network error during flush:\", err);\n }\n }\n }\n\n async shutdown(): Promise<void> {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n await this.flush();\n }\n}\n","import { BatchQueue } from \"./core\";\nimport type { ValidorsOptions, SdkEvent } from \"./types\";\n\nexport type { ValidorsOptions, SdkEvent, IngestPayload } from \"./types\";\nexport { BatchQueue } from \"./core\";\n\n// ---------------------------------------------------------------------------\n// Module-level default queue instance (created lazily)\n// ---------------------------------------------------------------------------\n\nlet _defaultQueue: BatchQueue | null = null;\n\nfunction getOrCreateQueue(options: ValidorsOptions): BatchQueue {\n if (!_defaultQueue) {\n _defaultQueue = new BatchQueue(options);\n\n process.on(\"beforeExit\", () => {\n _defaultQueue?.flush().catch(() => undefined);\n });\n\n process.on(\"SIGTERM\", () => {\n _defaultQueue?.shutdown().catch(() => undefined);\n });\n }\n return _defaultQueue;\n}\n\n/** Flush all pending events immediately. Call before process exit if needed. */\nexport async function shutdown(): Promise<void> {\n if (_defaultQueue) {\n await _defaultQueue.shutdown();\n _defaultQueue = null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Express middleware\n// ---------------------------------------------------------------------------\n\ntype ExpressRequest = {\n method: string;\n path: string;\n route?: { path?: string };\n};\n\ntype ExpressResponse = {\n statusCode: number;\n locals: Record<string, unknown>;\n on(event: string, listener: () => void): void;\n};\n\ntype NextFunction = () => void;\n\nexport type ExpressRequestHandler = (\n req: ExpressRequest,\n res: ExpressResponse,\n next: NextFunction\n) => void;\n\n/**\n * Express middleware that tracks request latency and status codes.\n *\n * @example\n * import * as validors from '@validors/sdk';\n * app.use(validors.express({ apiKey: 'vl_...' }));\n */\nexport function express(options: ValidorsOptions): ExpressRequestHandler {\n const queue = getOrCreateQueue(options);\n\n return function validorsMiddleware(\n req: ExpressRequest,\n res: ExpressResponse,\n next: NextFunction\n ) {\n const startTime = Date.now();\n\n res.on(\"finish\", () => {\n const durationMs = Date.now() - startTime;\n const route = req.route?.path ?? req.path ?? \"unknown\";\n const error =\n typeof res.locals.error === \"string\" ? res.locals.error : undefined;\n\n const event: SdkEvent = {\n route,\n method: req.method,\n status_code: res.statusCode,\n duration_ms: durationMs,\n ...(error ? { error } : {}),\n timestamp: new Date().toISOString(),\n };\n\n queue.push(event);\n });\n\n next();\n };\n}\n\n// ---------------------------------------------------------------------------\n// Fastify plugin\n// ---------------------------------------------------------------------------\n\ntype FastifyInstance = {\n addHook(\n name: \"onResponse\",\n fn: (request: FastifyRequest, reply: FastifyReply) => Promise<void>\n ): void;\n};\n\ntype FastifyRequest = {\n method: string;\n routerPath?: string;\n routeOptions?: { url?: string };\n};\n\ntype FastifyReply = {\n statusCode: number;\n elapsedTime?: number;\n};\n\ntype FastifyPlugin = (\n fastify: FastifyInstance,\n _opts: Record<string, unknown>,\n done: () => void\n) => void;\n\n/**\n * Fastify plugin that tracks request latency and status codes.\n *\n * @example\n * import * as validors from '@validors/sdk';\n * await fastify.register(validors.fastify, { apiKey: 'vl_...' });\n */\nexport function fastify(options: ValidorsOptions): FastifyPlugin {\n const queue = getOrCreateQueue(options);\n\n return function validorsFastifyPlugin(\n fastifyInstance: FastifyInstance,\n _opts: Record<string, unknown>,\n done: () => void\n ) {\n fastifyInstance.addHook(\n \"onResponse\",\n async (request: FastifyRequest, reply: FastifyReply) => {\n const route =\n request.routerPath ??\n request.routeOptions?.url ??\n \"unknown\";\n\n const durationMs =\n typeof reply.elapsedTime === \"number\"\n ? Math.round(reply.elapsedTime)\n : 0;\n\n const event: SdkEvent = {\n route,\n method: request.method,\n status_code: reply.statusCode,\n duration_ms: durationMs,\n timestamp: new Date().toISOString(),\n };\n\n queue.push(event);\n }\n );\n\n done();\n };\n}\n\n// ---------------------------------------------------------------------------\n// Generic / Hono / Edge middleware\n// ---------------------------------------------------------------------------\n\ntype GenericHandler = (\n request: Request,\n env?: unknown\n) => Promise<Response>;\n\n/**\n * Generic fetch-based middleware wrapper for Hono, Cloudflare Workers,\n * and other edge runtimes.\n *\n * Returns a handler that you can use as a Hono middleware or wrap your\n * existing fetch handler with.\n *\n * @example\n * // Hono\n * import { Hono } from 'hono';\n * import { createMiddleware } from '@validors/sdk';\n *\n * const app = new Hono();\n * app.use('*', createMiddleware({ apiKey: 'vl_...' }));\n */\nexport function createMiddleware(options: ValidorsOptions) {\n const queue = new BatchQueue(options);\n\n return async function validorsHonoMiddleware(\n c: {\n req: { method: string; url: string; routePath?: string };\n res?: { status?: number };\n },\n next: () => Promise<void>\n ) {\n const startTime = Date.now();\n\n try {\n await next();\n } finally {\n const durationMs = Date.now() - startTime;\n\n let route: string;\n try {\n route = c.req.routePath ?? new URL(c.req.url).pathname ?? \"unknown\";\n } catch {\n route = \"unknown\";\n }\n\n const statusCode = c.res?.status ?? 200;\n\n const event: SdkEvent = {\n route,\n method: c.req.method,\n status_code: statusCode,\n duration_ms: durationMs,\n timestamp: new Date().toISOString(),\n };\n\n queue.push(event);\n }\n };\n}\n\n/**\n * Wrap a generic fetch handler (for edge runtimes like Cloudflare Workers).\n *\n * @example\n * import { wrapFetch } from '@validors/sdk';\n *\n * export default {\n * fetch: wrapFetch({ apiKey: 'vl_...' }, async (request, env) => {\n * return new Response('Hello!');\n * })\n * };\n */\nexport function wrapFetch(\n options: ValidorsOptions,\n handler: GenericHandler\n): GenericHandler {\n const queue = new BatchQueue(options);\n\n return async function wrappedFetch(request: Request, env?: unknown) {\n const startTime = Date.now();\n let statusCode = 200;\n\n try {\n const response = await handler(request, env);\n statusCode = response.status;\n return response;\n } catch (err) {\n statusCode = 500;\n throw err;\n } finally {\n const durationMs = Date.now() - startTime;\n\n let route: string;\n try {\n route = new URL(request.url).pathname ?? \"unknown\";\n } catch {\n route = \"unknown\";\n }\n\n const event: SdkEvent = {\n route,\n method: request.method,\n status_code: statusCode,\n duration_ms: durationMs,\n timestamp: new Date().toISOString(),\n };\n\n queue.push(event);\n }\n };\n}\n\nexport default BatchQueue;\n\n// ---------------------------------------------------------------------------\n// Next.js App Router\n// ---------------------------------------------------------------------------\n\ntype NextJsRequest = {\n method: string;\n nextUrl?: { pathname: string };\n url: string;\n};\n\ntype NextJsResponse = { status: number };\n\ntype NextJsHandler<C = unknown> = (\n req: NextJsRequest,\n context?: C\n) => Promise<NextJsResponse> | NextJsResponse;\n\n/**\n * Next.js App Router route handler wrapper.\n *\n * Create a single `monitor` instance in a shared file and use it to wrap\n * your exported route handlers. Tracks latency, status codes, and errors\n * automatically — including uncaught exceptions (reported as 500).\n *\n * @example\n * // lib/monitor.ts\n * import * as validors from '@validors/sdk';\n * export const monitor = validors.nextjs({ apiKey: process.env.VALIDORS_API_KEY! });\n *\n * // app/api/users/route.ts\n * import { monitor } from '@/lib/monitor';\n * export const GET = monitor('/api/users', async (req) => {\n * return NextResponse.json({ users: [] });\n * });\n */\nexport function nextjs(options: ValidorsOptions) {\n const queue = getOrCreateQueue(options);\n\n function monitor<C>(route: string, handler: NextJsHandler<C>): NextJsHandler<C>;\n function monitor<C>(handler: NextJsHandler<C>): NextJsHandler<C>;\n function monitor<C>(\n routeOrHandler: string | NextJsHandler<C>,\n maybeHandler?: NextJsHandler<C>\n ): NextJsHandler<C> {\n const explicitRoute = typeof routeOrHandler === \"string\" ? routeOrHandler : undefined;\n const handler = typeof routeOrHandler === \"function\" ? routeOrHandler : maybeHandler!;\n\n return async (req: NextJsRequest, context?: C) => {\n const start = Date.now();\n let statusCode = 200;\n\n try {\n const response = await handler(req, context);\n statusCode = response.status;\n return response;\n } catch (err) {\n statusCode = 500;\n throw err;\n } finally {\n let route: string;\n if (explicitRoute) {\n route = explicitRoute;\n } else {\n try {\n route = req.nextUrl?.pathname ?? new URL(req.url).pathname;\n } catch {\n route = \"unknown\";\n }\n }\n\n queue.push({\n route,\n method: req.method,\n status_code: statusCode,\n duration_ms: Date.now() - start,\n timestamp: new Date().toISOString(),\n });\n }\n };\n }\n\n return monitor;\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@validors/sdk",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Backend API monitoring SDK for Validors",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",