@vinetechke/next-error-logger 0.1.0-beta.3 → 0.1.0-beta.4

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.
@@ -1,4 +1,3 @@
1
- "use client";
2
1
  "use strict";
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/adapters/drizzle.ts"],"sourcesContent":["import type { DatabaseAdapter, ErrorLogEntry, QueryOptions } from '../types'\n\n/**\n * Drizzle table interface\n * Using flexible typing to support various Drizzle table definitions\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype DrizzleTable = any\n\n/**\n * Drizzle database interface\n * Using flexible typing to support various Drizzle dialects and query patterns\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype DrizzleDB = any\n\n/**\n * Configuration for the Drizzle adapter\n */\nexport interface DrizzleAdapterConfig {\n /** Your Drizzle database instance */\n db: DrizzleDB\n /** Your ErrorLog table definition */\n table: DrizzleTable\n /** Drizzle operators (eq, and, or, like, lt, desc, etc.) */\n operators: {\n eq: (column: unknown, value: unknown) => unknown\n and: (...conditions: unknown[]) => unknown\n or: (...conditions: unknown[]) => unknown\n like: (column: unknown, value: string) => unknown\n lt: (column: unknown, value: unknown) => unknown\n gte: (column: unknown, value: unknown) => unknown\n lte: (column: unknown, value: unknown) => unknown\n desc: (column: unknown) => unknown\n asc: (column: unknown) => unknown\n }\n}\n\n/**\n * Create a Drizzle database adapter\n *\n * Requires an errorLogs table in your Drizzle schema:\n *\n * ```ts\n * // schema.ts\n * import { pgTable, text, timestamp, json } from 'drizzle-orm/pg-core'\n *\n * export const errorLogs = pgTable('error_logs', {\n * id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()),\n * level: text('level').notNull(),\n * message: text('message').notNull(),\n * stack: text('stack'),\n * userId: text('user_id'),\n * userEmail: text('user_email'),\n * userName: text('user_name'),\n * path: text('path'),\n * method: text('method'),\n * userAgent: text('user_agent'),\n * ip: text('ip'),\n * metadata: json('metadata'),\n * createdAt: timestamp('created_at').defaultNow().notNull(),\n * })\n * ```\n *\n * @example\n * ```ts\n * import { createDrizzleAdapter } from '@vinetechke/next-error-logger/adapters/drizzle'\n * import { db } from '@/lib/db'\n * import { errorLogs } from '@/lib/schema'\n * import { eq, and, or, like, lt, gte, lte, desc, asc } from 'drizzle-orm'\n *\n * const adapter = createDrizzleAdapter({\n * db,\n * table: errorLogs,\n * operators: { eq, and, or, like, lt, gte, lte, desc, asc },\n * })\n * ```\n */\nexport function createDrizzleAdapter(\n config: DrizzleAdapterConfig,\n): DatabaseAdapter {\n const { db, table, operators } = config\n const { eq, and, or, like, lt, gte, lte, desc, asc } = operators\n\n return {\n async create(entry) {\n const id = crypto.randomUUID()\n const result = await db\n .insert(table)\n .values({\n id,\n level: entry.level,\n message: entry.message,\n stack: entry.stack,\n userId: entry.userId,\n userEmail: entry.userEmail,\n userName: entry.userName,\n path: entry.path,\n method: entry.method,\n userAgent: entry.userAgent,\n ip: entry.ip,\n metadata: entry.metadata,\n })\n .returning()\n\n return result[0] as ErrorLogEntry\n },\n\n async findMany(options: QueryOptions) {\n const {\n page = 1,\n limit = 50,\n level,\n userId,\n search,\n startDate,\n endDate,\n orderBy = 'createdAt',\n order = 'desc',\n } = options\n\n // Build conditions array\n const conditions: unknown[] = []\n\n if (level) {\n conditions.push(eq(table.level, level))\n }\n\n if (userId) {\n conditions.push(eq(table.userId, userId))\n }\n\n if (search) {\n conditions.push(\n or(\n like(table.message, `%${search}%`),\n like(table.stack, `%${search}%`),\n like(table.path, `%${search}%`),\n like(table.userEmail, `%${search}%`),\n ),\n )\n }\n\n if (startDate) {\n conditions.push(gte(table.createdAt, startDate))\n }\n\n if (endDate) {\n conditions.push(lte(table.createdAt, endDate))\n }\n\n const whereCondition =\n conditions.length > 0 ? and(...conditions) : undefined\n const orderFn = order === 'desc' ? desc : asc\n const orderColumn =\n orderBy === 'level' ? table.level : table.createdAt\n\n let query = db.select().from(table)\n\n if (whereCondition) {\n query = query.where(whereCondition) as typeof query\n }\n\n const logs = await query\n .orderBy(orderFn(orderColumn))\n .limit(limit)\n .offset((page - 1) * limit)\n\n const total = await db.$count(table, whereCondition)\n\n return { logs: logs as ErrorLogEntry[], total }\n },\n\n async findById(id: string) {\n const results = await db\n .select()\n .from(table)\n .where(eq(table.id, id))\n .limit(1)\n .offset(0)\n\n return (results[0] as ErrorLogEntry) || null\n },\n\n async delete(id: string) {\n await db.delete(table).where(eq(table.id, id))\n },\n\n async deleteMany(options) {\n const conditions: unknown[] = []\n\n if (options.before) {\n conditions.push(lt(table.createdAt, options.before))\n }\n\n if (options.level) {\n conditions.push(eq(table.level, options.level))\n }\n\n const whereCondition =\n conditions.length > 0 ? and(...conditions) : undefined\n\n if (!whereCondition) {\n return 0\n }\n\n const result = await db.delete(table).where(whereCondition)\n return result.rowCount || 0\n },\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/adapters/drizzle.ts"],"sourcesContent":["import type { DatabaseAdapter, ErrorLogEntry, QueryOptions } from '../types'\n\n/**\n * Drizzle table interface\n * Using flexible typing to support various Drizzle table definitions\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype DrizzleTable = any\n\n/**\n * Drizzle database interface\n * Using flexible typing to support various Drizzle dialects and query patterns\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype DrizzleDB = any\n\n/**\n * Configuration for the Drizzle adapter\n */\nexport interface DrizzleAdapterConfig {\n /** Your Drizzle database instance */\n db: DrizzleDB\n /** Your ErrorLog table definition */\n table: DrizzleTable\n /** Drizzle operators (eq, and, or, like, lt, desc, etc.) */\n operators: {\n eq: (column: unknown, value: unknown) => unknown\n and: (...conditions: unknown[]) => unknown\n or: (...conditions: unknown[]) => unknown\n like: (column: unknown, value: string) => unknown\n lt: (column: unknown, value: unknown) => unknown\n gte: (column: unknown, value: unknown) => unknown\n lte: (column: unknown, value: unknown) => unknown\n desc: (column: unknown) => unknown\n asc: (column: unknown) => unknown\n }\n}\n\n/**\n * Create a Drizzle database adapter\n *\n * Requires an errorLogs table in your Drizzle schema:\n *\n * ```ts\n * // schema.ts\n * import { pgTable, text, timestamp, json } from 'drizzle-orm/pg-core'\n *\n * export const errorLogs = pgTable('error_logs', {\n * id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()),\n * level: text('level').notNull(),\n * message: text('message').notNull(),\n * stack: text('stack'),\n * userId: text('user_id'),\n * userEmail: text('user_email'),\n * userName: text('user_name'),\n * path: text('path'),\n * method: text('method'),\n * userAgent: text('user_agent'),\n * ip: text('ip'),\n * metadata: json('metadata'),\n * createdAt: timestamp('created_at').defaultNow().notNull(),\n * })\n * ```\n *\n * @example\n * ```ts\n * import { createDrizzleAdapter } from '@vinetechke/next-error-logger/adapters/drizzle'\n * import { db } from '@/lib/db'\n * import { errorLogs } from '@/lib/schema'\n * import { eq, and, or, like, lt, gte, lte, desc, asc } from 'drizzle-orm'\n *\n * const adapter = createDrizzleAdapter({\n * db,\n * table: errorLogs,\n * operators: { eq, and, or, like, lt, gte, lte, desc, asc },\n * })\n * ```\n */\nexport function createDrizzleAdapter(\n config: DrizzleAdapterConfig,\n): DatabaseAdapter {\n const { db, table, operators } = config\n const { eq, and, or, like, lt, gte, lte, desc, asc } = operators\n\n return {\n async create(entry) {\n const id = crypto.randomUUID()\n const result = await db\n .insert(table)\n .values({\n id,\n level: entry.level,\n message: entry.message,\n stack: entry.stack,\n userId: entry.userId,\n userEmail: entry.userEmail,\n userName: entry.userName,\n path: entry.path,\n method: entry.method,\n userAgent: entry.userAgent,\n ip: entry.ip,\n metadata: entry.metadata,\n })\n .returning()\n\n return result[0] as ErrorLogEntry\n },\n\n async findMany(options: QueryOptions) {\n const {\n page = 1,\n limit = 50,\n level,\n userId,\n search,\n startDate,\n endDate,\n orderBy = 'createdAt',\n order = 'desc',\n } = options\n\n // Build conditions array\n const conditions: unknown[] = []\n\n if (level) {\n conditions.push(eq(table.level, level))\n }\n\n if (userId) {\n conditions.push(eq(table.userId, userId))\n }\n\n if (search) {\n conditions.push(\n or(\n like(table.message, `%${search}%`),\n like(table.stack, `%${search}%`),\n like(table.path, `%${search}%`),\n like(table.userEmail, `%${search}%`),\n ),\n )\n }\n\n if (startDate) {\n conditions.push(gte(table.createdAt, startDate))\n }\n\n if (endDate) {\n conditions.push(lte(table.createdAt, endDate))\n }\n\n const whereCondition =\n conditions.length > 0 ? and(...conditions) : undefined\n const orderFn = order === 'desc' ? desc : asc\n const orderColumn =\n orderBy === 'level' ? table.level : table.createdAt\n\n let query = db.select().from(table)\n\n if (whereCondition) {\n query = query.where(whereCondition) as typeof query\n }\n\n const logs = await query\n .orderBy(orderFn(orderColumn))\n .limit(limit)\n .offset((page - 1) * limit)\n\n const total = await db.$count(table, whereCondition)\n\n return { logs: logs as ErrorLogEntry[], total }\n },\n\n async findById(id: string) {\n const results = await db\n .select()\n .from(table)\n .where(eq(table.id, id))\n .limit(1)\n .offset(0)\n\n return (results[0] as ErrorLogEntry) || null\n },\n\n async delete(id: string) {\n await db.delete(table).where(eq(table.id, id))\n },\n\n async deleteMany(options) {\n const conditions: unknown[] = []\n\n if (options.before) {\n conditions.push(lt(table.createdAt, options.before))\n }\n\n if (options.level) {\n conditions.push(eq(table.level, options.level))\n }\n\n const whereCondition =\n conditions.length > 0 ? and(...conditions) : undefined\n\n if (!whereCondition) {\n return 0\n }\n\n const result = await db.delete(table).where(whereCondition)\n return result.rowCount || 0\n },\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,5 +1,3 @@
1
- "use client";
2
-
3
1
  // src/adapters/drizzle.ts
4
2
  function createDrizzleAdapter(config) {
5
3
  const { db, table, operators } = config;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/adapters/drizzle.ts"],"sourcesContent":["import type { DatabaseAdapter, ErrorLogEntry, QueryOptions } from '../types'\n\n/**\n * Drizzle table interface\n * Using flexible typing to support various Drizzle table definitions\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype DrizzleTable = any\n\n/**\n * Drizzle database interface\n * Using flexible typing to support various Drizzle dialects and query patterns\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype DrizzleDB = any\n\n/**\n * Configuration for the Drizzle adapter\n */\nexport interface DrizzleAdapterConfig {\n /** Your Drizzle database instance */\n db: DrizzleDB\n /** Your ErrorLog table definition */\n table: DrizzleTable\n /** Drizzle operators (eq, and, or, like, lt, desc, etc.) */\n operators: {\n eq: (column: unknown, value: unknown) => unknown\n and: (...conditions: unknown[]) => unknown\n or: (...conditions: unknown[]) => unknown\n like: (column: unknown, value: string) => unknown\n lt: (column: unknown, value: unknown) => unknown\n gte: (column: unknown, value: unknown) => unknown\n lte: (column: unknown, value: unknown) => unknown\n desc: (column: unknown) => unknown\n asc: (column: unknown) => unknown\n }\n}\n\n/**\n * Create a Drizzle database adapter\n *\n * Requires an errorLogs table in your Drizzle schema:\n *\n * ```ts\n * // schema.ts\n * import { pgTable, text, timestamp, json } from 'drizzle-orm/pg-core'\n *\n * export const errorLogs = pgTable('error_logs', {\n * id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()),\n * level: text('level').notNull(),\n * message: text('message').notNull(),\n * stack: text('stack'),\n * userId: text('user_id'),\n * userEmail: text('user_email'),\n * userName: text('user_name'),\n * path: text('path'),\n * method: text('method'),\n * userAgent: text('user_agent'),\n * ip: text('ip'),\n * metadata: json('metadata'),\n * createdAt: timestamp('created_at').defaultNow().notNull(),\n * })\n * ```\n *\n * @example\n * ```ts\n * import { createDrizzleAdapter } from '@vinetechke/next-error-logger/adapters/drizzle'\n * import { db } from '@/lib/db'\n * import { errorLogs } from '@/lib/schema'\n * import { eq, and, or, like, lt, gte, lte, desc, asc } from 'drizzle-orm'\n *\n * const adapter = createDrizzleAdapter({\n * db,\n * table: errorLogs,\n * operators: { eq, and, or, like, lt, gte, lte, desc, asc },\n * })\n * ```\n */\nexport function createDrizzleAdapter(\n config: DrizzleAdapterConfig,\n): DatabaseAdapter {\n const { db, table, operators } = config\n const { eq, and, or, like, lt, gte, lte, desc, asc } = operators\n\n return {\n async create(entry) {\n const id = crypto.randomUUID()\n const result = await db\n .insert(table)\n .values({\n id,\n level: entry.level,\n message: entry.message,\n stack: entry.stack,\n userId: entry.userId,\n userEmail: entry.userEmail,\n userName: entry.userName,\n path: entry.path,\n method: entry.method,\n userAgent: entry.userAgent,\n ip: entry.ip,\n metadata: entry.metadata,\n })\n .returning()\n\n return result[0] as ErrorLogEntry\n },\n\n async findMany(options: QueryOptions) {\n const {\n page = 1,\n limit = 50,\n level,\n userId,\n search,\n startDate,\n endDate,\n orderBy = 'createdAt',\n order = 'desc',\n } = options\n\n // Build conditions array\n const conditions: unknown[] = []\n\n if (level) {\n conditions.push(eq(table.level, level))\n }\n\n if (userId) {\n conditions.push(eq(table.userId, userId))\n }\n\n if (search) {\n conditions.push(\n or(\n like(table.message, `%${search}%`),\n like(table.stack, `%${search}%`),\n like(table.path, `%${search}%`),\n like(table.userEmail, `%${search}%`),\n ),\n )\n }\n\n if (startDate) {\n conditions.push(gte(table.createdAt, startDate))\n }\n\n if (endDate) {\n conditions.push(lte(table.createdAt, endDate))\n }\n\n const whereCondition =\n conditions.length > 0 ? and(...conditions) : undefined\n const orderFn = order === 'desc' ? desc : asc\n const orderColumn =\n orderBy === 'level' ? table.level : table.createdAt\n\n let query = db.select().from(table)\n\n if (whereCondition) {\n query = query.where(whereCondition) as typeof query\n }\n\n const logs = await query\n .orderBy(orderFn(orderColumn))\n .limit(limit)\n .offset((page - 1) * limit)\n\n const total = await db.$count(table, whereCondition)\n\n return { logs: logs as ErrorLogEntry[], total }\n },\n\n async findById(id: string) {\n const results = await db\n .select()\n .from(table)\n .where(eq(table.id, id))\n .limit(1)\n .offset(0)\n\n return (results[0] as ErrorLogEntry) || null\n },\n\n async delete(id: string) {\n await db.delete(table).where(eq(table.id, id))\n },\n\n async deleteMany(options) {\n const conditions: unknown[] = []\n\n if (options.before) {\n conditions.push(lt(table.createdAt, options.before))\n }\n\n if (options.level) {\n conditions.push(eq(table.level, options.level))\n }\n\n const whereCondition =\n conditions.length > 0 ? and(...conditions) : undefined\n\n if (!whereCondition) {\n return 0\n }\n\n const result = await db.delete(table).where(whereCondition)\n return result.rowCount || 0\n },\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/adapters/drizzle.ts"],"sourcesContent":["import type { DatabaseAdapter, ErrorLogEntry, QueryOptions } from '../types'\n\n/**\n * Drizzle table interface\n * Using flexible typing to support various Drizzle table definitions\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype DrizzleTable = any\n\n/**\n * Drizzle database interface\n * Using flexible typing to support various Drizzle dialects and query patterns\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype DrizzleDB = any\n\n/**\n * Configuration for the Drizzle adapter\n */\nexport interface DrizzleAdapterConfig {\n /** Your Drizzle database instance */\n db: DrizzleDB\n /** Your ErrorLog table definition */\n table: DrizzleTable\n /** Drizzle operators (eq, and, or, like, lt, desc, etc.) */\n operators: {\n eq: (column: unknown, value: unknown) => unknown\n and: (...conditions: unknown[]) => unknown\n or: (...conditions: unknown[]) => unknown\n like: (column: unknown, value: string) => unknown\n lt: (column: unknown, value: unknown) => unknown\n gte: (column: unknown, value: unknown) => unknown\n lte: (column: unknown, value: unknown) => unknown\n desc: (column: unknown) => unknown\n asc: (column: unknown) => unknown\n }\n}\n\n/**\n * Create a Drizzle database adapter\n *\n * Requires an errorLogs table in your Drizzle schema:\n *\n * ```ts\n * // schema.ts\n * import { pgTable, text, timestamp, json } from 'drizzle-orm/pg-core'\n *\n * export const errorLogs = pgTable('error_logs', {\n * id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()),\n * level: text('level').notNull(),\n * message: text('message').notNull(),\n * stack: text('stack'),\n * userId: text('user_id'),\n * userEmail: text('user_email'),\n * userName: text('user_name'),\n * path: text('path'),\n * method: text('method'),\n * userAgent: text('user_agent'),\n * ip: text('ip'),\n * metadata: json('metadata'),\n * createdAt: timestamp('created_at').defaultNow().notNull(),\n * })\n * ```\n *\n * @example\n * ```ts\n * import { createDrizzleAdapter } from '@vinetechke/next-error-logger/adapters/drizzle'\n * import { db } from '@/lib/db'\n * import { errorLogs } from '@/lib/schema'\n * import { eq, and, or, like, lt, gte, lte, desc, asc } from 'drizzle-orm'\n *\n * const adapter = createDrizzleAdapter({\n * db,\n * table: errorLogs,\n * operators: { eq, and, or, like, lt, gte, lte, desc, asc },\n * })\n * ```\n */\nexport function createDrizzleAdapter(\n config: DrizzleAdapterConfig,\n): DatabaseAdapter {\n const { db, table, operators } = config\n const { eq, and, or, like, lt, gte, lte, desc, asc } = operators\n\n return {\n async create(entry) {\n const id = crypto.randomUUID()\n const result = await db\n .insert(table)\n .values({\n id,\n level: entry.level,\n message: entry.message,\n stack: entry.stack,\n userId: entry.userId,\n userEmail: entry.userEmail,\n userName: entry.userName,\n path: entry.path,\n method: entry.method,\n userAgent: entry.userAgent,\n ip: entry.ip,\n metadata: entry.metadata,\n })\n .returning()\n\n return result[0] as ErrorLogEntry\n },\n\n async findMany(options: QueryOptions) {\n const {\n page = 1,\n limit = 50,\n level,\n userId,\n search,\n startDate,\n endDate,\n orderBy = 'createdAt',\n order = 'desc',\n } = options\n\n // Build conditions array\n const conditions: unknown[] = []\n\n if (level) {\n conditions.push(eq(table.level, level))\n }\n\n if (userId) {\n conditions.push(eq(table.userId, userId))\n }\n\n if (search) {\n conditions.push(\n or(\n like(table.message, `%${search}%`),\n like(table.stack, `%${search}%`),\n like(table.path, `%${search}%`),\n like(table.userEmail, `%${search}%`),\n ),\n )\n }\n\n if (startDate) {\n conditions.push(gte(table.createdAt, startDate))\n }\n\n if (endDate) {\n conditions.push(lte(table.createdAt, endDate))\n }\n\n const whereCondition =\n conditions.length > 0 ? and(...conditions) : undefined\n const orderFn = order === 'desc' ? desc : asc\n const orderColumn =\n orderBy === 'level' ? table.level : table.createdAt\n\n let query = db.select().from(table)\n\n if (whereCondition) {\n query = query.where(whereCondition) as typeof query\n }\n\n const logs = await query\n .orderBy(orderFn(orderColumn))\n .limit(limit)\n .offset((page - 1) * limit)\n\n const total = await db.$count(table, whereCondition)\n\n return { logs: logs as ErrorLogEntry[], total }\n },\n\n async findById(id: string) {\n const results = await db\n .select()\n .from(table)\n .where(eq(table.id, id))\n .limit(1)\n .offset(0)\n\n return (results[0] as ErrorLogEntry) || null\n },\n\n async delete(id: string) {\n await db.delete(table).where(eq(table.id, id))\n },\n\n async deleteMany(options) {\n const conditions: unknown[] = []\n\n if (options.before) {\n conditions.push(lt(table.createdAt, options.before))\n }\n\n if (options.level) {\n conditions.push(eq(table.level, options.level))\n }\n\n const whereCondition =\n conditions.length > 0 ? and(...conditions) : undefined\n\n if (!whereCondition) {\n return 0\n }\n\n const result = await db.delete(table).where(whereCondition)\n return result.rowCount || 0\n },\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,4 +1,3 @@
1
- "use client";
2
1
  "use strict";
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/adapters/prisma.ts"],"sourcesContent":["import type { DatabaseAdapter, ErrorLogEntry, QueryOptions } from '../types'\n\n/**\n * Prisma ErrorLog model delegate interface\n * Uses generic function types to be compatible with any Prisma client version\n */\ninterface ErrorLogDelegate {\n create(args: unknown): Promise<unknown>\n findMany(args: unknown): Promise<unknown[]>\n findUnique(args: unknown): Promise<unknown | null>\n delete(args: unknown): Promise<unknown>\n deleteMany(args: unknown): Promise<{ count: number }>\n count(args: unknown): Promise<number>\n}\n\n/**\n * Prisma client interface - compatible with any @prisma/client version\n */\ninterface PrismaClientLike {\n errorLog: ErrorLogDelegate\n}\n\n/**\n * Create a Prisma database adapter\n *\n * Requires an ErrorLog model in your Prisma schema:\n *\n * ```prisma\n * model ErrorLog {\n * id String @id @default(cuid())\n * level String\n * message String @db.Text\n * stack String? @db.Text\n * userId String?\n * userEmail String?\n * userName String?\n * path String?\n * method String?\n * userAgent String?\n * ip String?\n * metadata Json?\n * createdAt DateTime @default(now())\n *\n * @@index([level])\n * @@index([userId])\n * @@index([createdAt])\n * }\n * ```\n *\n * @example\n * ```ts\n * import { createPrismaAdapter } from '@vinetechke/next-error-logger/adapters/prisma'\n * import { prisma } from '@/lib/prisma'\n *\n * const adapter = createPrismaAdapter(prisma)\n * ```\n */\nexport function createPrismaAdapter(prisma: PrismaClientLike): DatabaseAdapter {\n return {\n async create(entry) {\n const result = await prisma.errorLog.create({\n data: {\n level: entry.level,\n message: entry.message,\n stack: entry.stack,\n userId: entry.userId,\n userEmail: entry.userEmail,\n userName: entry.userName,\n path: entry.path,\n method: entry.method,\n userAgent: entry.userAgent,\n ip: entry.ip,\n metadata: entry.metadata\n ? JSON.parse(JSON.stringify(entry.metadata))\n : null,\n },\n })\n return result as ErrorLogEntry\n },\n\n async findMany(options: QueryOptions) {\n const {\n page = 1,\n limit = 50,\n level,\n userId,\n search,\n startDate,\n endDate,\n orderBy = 'createdAt',\n order = 'desc',\n } = options\n\n // Build where clause\n const where: Record<string, unknown> = {}\n\n if (level) {\n where.level = level\n }\n\n if (userId) {\n where.userId = userId\n }\n\n if (search) {\n where.OR = [\n { message: { contains: search, mode: 'insensitive' } },\n { stack: { contains: search, mode: 'insensitive' } },\n { path: { contains: search, mode: 'insensitive' } },\n { userEmail: { contains: search, mode: 'insensitive' } },\n ]\n }\n\n if (startDate || endDate) {\n where.createdAt = {}\n if (startDate) {\n ;(where.createdAt as Record<string, unknown>).gte =\n startDate\n }\n if (endDate) {\n ;(where.createdAt as Record<string, unknown>).lte = endDate\n }\n }\n\n const [logs, total] = await Promise.all([\n prisma.errorLog.findMany({\n where,\n orderBy: { [orderBy]: order },\n skip: (page - 1) * limit,\n take: limit,\n }),\n prisma.errorLog.count({ where }),\n ])\n\n return { logs: logs as ErrorLogEntry[], total }\n },\n\n async findById(id: string) {\n const result = await prisma.errorLog.findUnique({ where: { id } })\n return result as ErrorLogEntry | null\n },\n\n async delete(id: string) {\n await prisma.errorLog.delete({ where: { id } })\n },\n\n async deleteMany(options) {\n const where: Record<string, unknown> = {}\n\n if (options.before) {\n where.createdAt = { lt: options.before }\n }\n\n if (options.level) {\n where.level = options.level\n }\n\n const result = await prisma.errorLog.deleteMany({ where })\n return result.count\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAyDO,SAAS,oBAAoB,QAA2C;AAC3E,SAAO;AAAA,IACH,MAAM,OAAO,OAAO;AAChB,YAAM,SAAS,MAAM,OAAO,SAAS,OAAO;AAAA,QACxC,MAAM;AAAA,UACF,OAAO,MAAM;AAAA,UACb,SAAS,MAAM;AAAA,UACf,OAAO,MAAM;AAAA,UACb,QAAQ,MAAM;AAAA,UACd,WAAW,MAAM;AAAA,UACjB,UAAU,MAAM;AAAA,UAChB,MAAM,MAAM;AAAA,UACZ,QAAQ,MAAM;AAAA,UACd,WAAW,MAAM;AAAA,UACjB,IAAI,MAAM;AAAA,UACV,UAAU,MAAM,WACV,KAAK,MAAM,KAAK,UAAU,MAAM,QAAQ,CAAC,IACzC;AAAA,QACV;AAAA,MACJ,CAAC;AACD,aAAO;AAAA,IACX;AAAA,IAEA,MAAM,SAAS,SAAuB;AAClC,YAAM;AAAA,QACF,OAAO;AAAA,QACP,QAAQ;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,UAAU;AAAA,QACV,QAAQ;AAAA,MACZ,IAAI;AAGJ,YAAM,QAAiC,CAAC;AAExC,UAAI,OAAO;AACP,cAAM,QAAQ;AAAA,MAClB;AAEA,UAAI,QAAQ;AACR,cAAM,SAAS;AAAA,MACnB;AAEA,UAAI,QAAQ;AACR,cAAM,KAAK;AAAA,UACP,EAAE,SAAS,EAAE,UAAU,QAAQ,MAAM,cAAc,EAAE;AAAA,UACrD,EAAE,OAAO,EAAE,UAAU,QAAQ,MAAM,cAAc,EAAE;AAAA,UACnD,EAAE,MAAM,EAAE,UAAU,QAAQ,MAAM,cAAc,EAAE;AAAA,UAClD,EAAE,WAAW,EAAE,UAAU,QAAQ,MAAM,cAAc,EAAE;AAAA,QAC3D;AAAA,MACJ;AAEA,UAAI,aAAa,SAAS;AACtB,cAAM,YAAY,CAAC;AACnB,YAAI,WAAW;AACX;AAAC,UAAC,MAAM,UAAsC,MAC1C;AAAA,QACR;AACA,YAAI,SAAS;AACT;AAAC,UAAC,MAAM,UAAsC,MAAM;AAAA,QACxD;AAAA,MACJ;AAEA,YAAM,CAAC,MAAM,KAAK,IAAI,MAAM,QAAQ,IAAI;AAAA,QACpC,OAAO,SAAS,SAAS;AAAA,UACrB;AAAA,UACA,SAAS,EAAE,CAAC,OAAO,GAAG,MAAM;AAAA,UAC5B,OAAO,OAAO,KAAK;AAAA,UACnB,MAAM;AAAA,QACV,CAAC;AAAA,QACD,OAAO,SAAS,MAAM,EAAE,MAAM,CAAC;AAAA,MACnC,CAAC;AAED,aAAO,EAAE,MAA+B,MAAM;AAAA,IAClD;AAAA,IAEA,MAAM,SAAS,IAAY;AACvB,YAAM,SAAS,MAAM,OAAO,SAAS,WAAW,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;AACjE,aAAO;AAAA,IACX;AAAA,IAEA,MAAM,OAAO,IAAY;AACrB,YAAM,OAAO,SAAS,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;AAAA,IAClD;AAAA,IAEA,MAAM,WAAW,SAAS;AACtB,YAAM,QAAiC,CAAC;AAExC,UAAI,QAAQ,QAAQ;AAChB,cAAM,YAAY,EAAE,IAAI,QAAQ,OAAO;AAAA,MAC3C;AAEA,UAAI,QAAQ,OAAO;AACf,cAAM,QAAQ,QAAQ;AAAA,MAC1B;AAEA,YAAM,SAAS,MAAM,OAAO,SAAS,WAAW,EAAE,MAAM,CAAC;AACzD,aAAO,OAAO;AAAA,IAClB;AAAA,EACJ;AACJ;","names":[]}
1
+ {"version":3,"sources":["../../src/adapters/prisma.ts"],"sourcesContent":["import type { DatabaseAdapter, ErrorLogEntry, QueryOptions } from '../types'\n\n/**\n * Prisma ErrorLog model delegate interface\n * Uses generic function types to be compatible with any Prisma client version\n */\ninterface ErrorLogDelegate {\n create(args: unknown): Promise<unknown>\n findMany(args: unknown): Promise<unknown[]>\n findUnique(args: unknown): Promise<unknown | null>\n delete(args: unknown): Promise<unknown>\n deleteMany(args: unknown): Promise<{ count: number }>\n count(args: unknown): Promise<number>\n}\n\n/**\n * Prisma client interface - compatible with any @prisma/client version\n */\ninterface PrismaClientLike {\n errorLog: ErrorLogDelegate\n}\n\n/**\n * Create a Prisma database adapter\n *\n * Requires an ErrorLog model in your Prisma schema:\n *\n * ```prisma\n * model ErrorLog {\n * id String @id @default(cuid())\n * level String\n * message String @db.Text\n * stack String? @db.Text\n * userId String?\n * userEmail String?\n * userName String?\n * path String?\n * method String?\n * userAgent String?\n * ip String?\n * metadata Json?\n * createdAt DateTime @default(now())\n *\n * @@index([level])\n * @@index([userId])\n * @@index([createdAt])\n * }\n * ```\n *\n * @example\n * ```ts\n * import { createPrismaAdapter } from '@vinetechke/next-error-logger/adapters/prisma'\n * import { prisma } from '@/lib/prisma'\n *\n * const adapter = createPrismaAdapter(prisma)\n * ```\n */\nexport function createPrismaAdapter(prisma: PrismaClientLike): DatabaseAdapter {\n return {\n async create(entry) {\n const result = await prisma.errorLog.create({\n data: {\n level: entry.level,\n message: entry.message,\n stack: entry.stack,\n userId: entry.userId,\n userEmail: entry.userEmail,\n userName: entry.userName,\n path: entry.path,\n method: entry.method,\n userAgent: entry.userAgent,\n ip: entry.ip,\n metadata: entry.metadata\n ? JSON.parse(JSON.stringify(entry.metadata))\n : null,\n },\n })\n return result as ErrorLogEntry\n },\n\n async findMany(options: QueryOptions) {\n const {\n page = 1,\n limit = 50,\n level,\n userId,\n search,\n startDate,\n endDate,\n orderBy = 'createdAt',\n order = 'desc',\n } = options\n\n // Build where clause\n const where: Record<string, unknown> = {}\n\n if (level) {\n where.level = level\n }\n\n if (userId) {\n where.userId = userId\n }\n\n if (search) {\n where.OR = [\n { message: { contains: search, mode: 'insensitive' } },\n { stack: { contains: search, mode: 'insensitive' } },\n { path: { contains: search, mode: 'insensitive' } },\n { userEmail: { contains: search, mode: 'insensitive' } },\n ]\n }\n\n if (startDate || endDate) {\n where.createdAt = {}\n if (startDate) {\n ;(where.createdAt as Record<string, unknown>).gte =\n startDate\n }\n if (endDate) {\n ;(where.createdAt as Record<string, unknown>).lte = endDate\n }\n }\n\n const [logs, total] = await Promise.all([\n prisma.errorLog.findMany({\n where,\n orderBy: { [orderBy]: order },\n skip: (page - 1) * limit,\n take: limit,\n }),\n prisma.errorLog.count({ where }),\n ])\n\n return { logs: logs as ErrorLogEntry[], total }\n },\n\n async findById(id: string) {\n const result = await prisma.errorLog.findUnique({ where: { id } })\n return result as ErrorLogEntry | null\n },\n\n async delete(id: string) {\n await prisma.errorLog.delete({ where: { id } })\n },\n\n async deleteMany(options) {\n const where: Record<string, unknown> = {}\n\n if (options.before) {\n where.createdAt = { lt: options.before }\n }\n\n if (options.level) {\n where.level = options.level\n }\n\n const result = await prisma.errorLog.deleteMany({ where })\n return result.count\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAyDO,SAAS,oBAAoB,QAA2C;AAC3E,SAAO;AAAA,IACH,MAAM,OAAO,OAAO;AAChB,YAAM,SAAS,MAAM,OAAO,SAAS,OAAO;AAAA,QACxC,MAAM;AAAA,UACF,OAAO,MAAM;AAAA,UACb,SAAS,MAAM;AAAA,UACf,OAAO,MAAM;AAAA,UACb,QAAQ,MAAM;AAAA,UACd,WAAW,MAAM;AAAA,UACjB,UAAU,MAAM;AAAA,UAChB,MAAM,MAAM;AAAA,UACZ,QAAQ,MAAM;AAAA,UACd,WAAW,MAAM;AAAA,UACjB,IAAI,MAAM;AAAA,UACV,UAAU,MAAM,WACV,KAAK,MAAM,KAAK,UAAU,MAAM,QAAQ,CAAC,IACzC;AAAA,QACV;AAAA,MACJ,CAAC;AACD,aAAO;AAAA,IACX;AAAA,IAEA,MAAM,SAAS,SAAuB;AAClC,YAAM;AAAA,QACF,OAAO;AAAA,QACP,QAAQ;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,UAAU;AAAA,QACV,QAAQ;AAAA,MACZ,IAAI;AAGJ,YAAM,QAAiC,CAAC;AAExC,UAAI,OAAO;AACP,cAAM,QAAQ;AAAA,MAClB;AAEA,UAAI,QAAQ;AACR,cAAM,SAAS;AAAA,MACnB;AAEA,UAAI,QAAQ;AACR,cAAM,KAAK;AAAA,UACP,EAAE,SAAS,EAAE,UAAU,QAAQ,MAAM,cAAc,EAAE;AAAA,UACrD,EAAE,OAAO,EAAE,UAAU,QAAQ,MAAM,cAAc,EAAE;AAAA,UACnD,EAAE,MAAM,EAAE,UAAU,QAAQ,MAAM,cAAc,EAAE;AAAA,UAClD,EAAE,WAAW,EAAE,UAAU,QAAQ,MAAM,cAAc,EAAE;AAAA,QAC3D;AAAA,MACJ;AAEA,UAAI,aAAa,SAAS;AACtB,cAAM,YAAY,CAAC;AACnB,YAAI,WAAW;AACX;AAAC,UAAC,MAAM,UAAsC,MAC1C;AAAA,QACR;AACA,YAAI,SAAS;AACT;AAAC,UAAC,MAAM,UAAsC,MAAM;AAAA,QACxD;AAAA,MACJ;AAEA,YAAM,CAAC,MAAM,KAAK,IAAI,MAAM,QAAQ,IAAI;AAAA,QACpC,OAAO,SAAS,SAAS;AAAA,UACrB;AAAA,UACA,SAAS,EAAE,CAAC,OAAO,GAAG,MAAM;AAAA,UAC5B,OAAO,OAAO,KAAK;AAAA,UACnB,MAAM;AAAA,QACV,CAAC;AAAA,QACD,OAAO,SAAS,MAAM,EAAE,MAAM,CAAC;AAAA,MACnC,CAAC;AAED,aAAO,EAAE,MAA+B,MAAM;AAAA,IAClD;AAAA,IAEA,MAAM,SAAS,IAAY;AACvB,YAAM,SAAS,MAAM,OAAO,SAAS,WAAW,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;AACjE,aAAO;AAAA,IACX;AAAA,IAEA,MAAM,OAAO,IAAY;AACrB,YAAM,OAAO,SAAS,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;AAAA,IAClD;AAAA,IAEA,MAAM,WAAW,SAAS;AACtB,YAAM,QAAiC,CAAC;AAExC,UAAI,QAAQ,QAAQ;AAChB,cAAM,YAAY,EAAE,IAAI,QAAQ,OAAO;AAAA,MAC3C;AAEA,UAAI,QAAQ,OAAO;AACf,cAAM,QAAQ,QAAQ;AAAA,MAC1B;AAEA,YAAM,SAAS,MAAM,OAAO,SAAS,WAAW,EAAE,MAAM,CAAC;AACzD,aAAO,OAAO;AAAA,IAClB;AAAA,EACJ;AACJ;","names":[]}
@@ -1,5 +1,3 @@
1
- "use client";
2
-
3
1
  // src/adapters/prisma.ts
4
2
  function createPrismaAdapter(prisma) {
5
3
  return {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/adapters/prisma.ts"],"sourcesContent":["import type { DatabaseAdapter, ErrorLogEntry, QueryOptions } from '../types'\n\n/**\n * Prisma ErrorLog model delegate interface\n * Uses generic function types to be compatible with any Prisma client version\n */\ninterface ErrorLogDelegate {\n create(args: unknown): Promise<unknown>\n findMany(args: unknown): Promise<unknown[]>\n findUnique(args: unknown): Promise<unknown | null>\n delete(args: unknown): Promise<unknown>\n deleteMany(args: unknown): Promise<{ count: number }>\n count(args: unknown): Promise<number>\n}\n\n/**\n * Prisma client interface - compatible with any @prisma/client version\n */\ninterface PrismaClientLike {\n errorLog: ErrorLogDelegate\n}\n\n/**\n * Create a Prisma database adapter\n *\n * Requires an ErrorLog model in your Prisma schema:\n *\n * ```prisma\n * model ErrorLog {\n * id String @id @default(cuid())\n * level String\n * message String @db.Text\n * stack String? @db.Text\n * userId String?\n * userEmail String?\n * userName String?\n * path String?\n * method String?\n * userAgent String?\n * ip String?\n * metadata Json?\n * createdAt DateTime @default(now())\n *\n * @@index([level])\n * @@index([userId])\n * @@index([createdAt])\n * }\n * ```\n *\n * @example\n * ```ts\n * import { createPrismaAdapter } from '@vinetechke/next-error-logger/adapters/prisma'\n * import { prisma } from '@/lib/prisma'\n *\n * const adapter = createPrismaAdapter(prisma)\n * ```\n */\nexport function createPrismaAdapter(prisma: PrismaClientLike): DatabaseAdapter {\n return {\n async create(entry) {\n const result = await prisma.errorLog.create({\n data: {\n level: entry.level,\n message: entry.message,\n stack: entry.stack,\n userId: entry.userId,\n userEmail: entry.userEmail,\n userName: entry.userName,\n path: entry.path,\n method: entry.method,\n userAgent: entry.userAgent,\n ip: entry.ip,\n metadata: entry.metadata\n ? JSON.parse(JSON.stringify(entry.metadata))\n : null,\n },\n })\n return result as ErrorLogEntry\n },\n\n async findMany(options: QueryOptions) {\n const {\n page = 1,\n limit = 50,\n level,\n userId,\n search,\n startDate,\n endDate,\n orderBy = 'createdAt',\n order = 'desc',\n } = options\n\n // Build where clause\n const where: Record<string, unknown> = {}\n\n if (level) {\n where.level = level\n }\n\n if (userId) {\n where.userId = userId\n }\n\n if (search) {\n where.OR = [\n { message: { contains: search, mode: 'insensitive' } },\n { stack: { contains: search, mode: 'insensitive' } },\n { path: { contains: search, mode: 'insensitive' } },\n { userEmail: { contains: search, mode: 'insensitive' } },\n ]\n }\n\n if (startDate || endDate) {\n where.createdAt = {}\n if (startDate) {\n ;(where.createdAt as Record<string, unknown>).gte =\n startDate\n }\n if (endDate) {\n ;(where.createdAt as Record<string, unknown>).lte = endDate\n }\n }\n\n const [logs, total] = await Promise.all([\n prisma.errorLog.findMany({\n where,\n orderBy: { [orderBy]: order },\n skip: (page - 1) * limit,\n take: limit,\n }),\n prisma.errorLog.count({ where }),\n ])\n\n return { logs: logs as ErrorLogEntry[], total }\n },\n\n async findById(id: string) {\n const result = await prisma.errorLog.findUnique({ where: { id } })\n return result as ErrorLogEntry | null\n },\n\n async delete(id: string) {\n await prisma.errorLog.delete({ where: { id } })\n },\n\n async deleteMany(options) {\n const where: Record<string, unknown> = {}\n\n if (options.before) {\n where.createdAt = { lt: options.before }\n }\n\n if (options.level) {\n where.level = options.level\n }\n\n const result = await prisma.errorLog.deleteMany({ where })\n return result.count\n },\n }\n}\n"],"mappings":";;;AAyDO,SAAS,oBAAoB,QAA2C;AAC3E,SAAO;AAAA,IACH,MAAM,OAAO,OAAO;AAChB,YAAM,SAAS,MAAM,OAAO,SAAS,OAAO;AAAA,QACxC,MAAM;AAAA,UACF,OAAO,MAAM;AAAA,UACb,SAAS,MAAM;AAAA,UACf,OAAO,MAAM;AAAA,UACb,QAAQ,MAAM;AAAA,UACd,WAAW,MAAM;AAAA,UACjB,UAAU,MAAM;AAAA,UAChB,MAAM,MAAM;AAAA,UACZ,QAAQ,MAAM;AAAA,UACd,WAAW,MAAM;AAAA,UACjB,IAAI,MAAM;AAAA,UACV,UAAU,MAAM,WACV,KAAK,MAAM,KAAK,UAAU,MAAM,QAAQ,CAAC,IACzC;AAAA,QACV;AAAA,MACJ,CAAC;AACD,aAAO;AAAA,IACX;AAAA,IAEA,MAAM,SAAS,SAAuB;AAClC,YAAM;AAAA,QACF,OAAO;AAAA,QACP,QAAQ;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,UAAU;AAAA,QACV,QAAQ;AAAA,MACZ,IAAI;AAGJ,YAAM,QAAiC,CAAC;AAExC,UAAI,OAAO;AACP,cAAM,QAAQ;AAAA,MAClB;AAEA,UAAI,QAAQ;AACR,cAAM,SAAS;AAAA,MACnB;AAEA,UAAI,QAAQ;AACR,cAAM,KAAK;AAAA,UACP,EAAE,SAAS,EAAE,UAAU,QAAQ,MAAM,cAAc,EAAE;AAAA,UACrD,EAAE,OAAO,EAAE,UAAU,QAAQ,MAAM,cAAc,EAAE;AAAA,UACnD,EAAE,MAAM,EAAE,UAAU,QAAQ,MAAM,cAAc,EAAE;AAAA,UAClD,EAAE,WAAW,EAAE,UAAU,QAAQ,MAAM,cAAc,EAAE;AAAA,QAC3D;AAAA,MACJ;AAEA,UAAI,aAAa,SAAS;AACtB,cAAM,YAAY,CAAC;AACnB,YAAI,WAAW;AACX;AAAC,UAAC,MAAM,UAAsC,MAC1C;AAAA,QACR;AACA,YAAI,SAAS;AACT;AAAC,UAAC,MAAM,UAAsC,MAAM;AAAA,QACxD;AAAA,MACJ;AAEA,YAAM,CAAC,MAAM,KAAK,IAAI,MAAM,QAAQ,IAAI;AAAA,QACpC,OAAO,SAAS,SAAS;AAAA,UACrB;AAAA,UACA,SAAS,EAAE,CAAC,OAAO,GAAG,MAAM;AAAA,UAC5B,OAAO,OAAO,KAAK;AAAA,UACnB,MAAM;AAAA,QACV,CAAC;AAAA,QACD,OAAO,SAAS,MAAM,EAAE,MAAM,CAAC;AAAA,MACnC,CAAC;AAED,aAAO,EAAE,MAA+B,MAAM;AAAA,IAClD;AAAA,IAEA,MAAM,SAAS,IAAY;AACvB,YAAM,SAAS,MAAM,OAAO,SAAS,WAAW,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;AACjE,aAAO;AAAA,IACX;AAAA,IAEA,MAAM,OAAO,IAAY;AACrB,YAAM,OAAO,SAAS,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;AAAA,IAClD;AAAA,IAEA,MAAM,WAAW,SAAS;AACtB,YAAM,QAAiC,CAAC;AAExC,UAAI,QAAQ,QAAQ;AAChB,cAAM,YAAY,EAAE,IAAI,QAAQ,OAAO;AAAA,MAC3C;AAEA,UAAI,QAAQ,OAAO;AACf,cAAM,QAAQ,QAAQ;AAAA,MAC1B;AAEA,YAAM,SAAS,MAAM,OAAO,SAAS,WAAW,EAAE,MAAM,CAAC;AACzD,aAAO,OAAO;AAAA,IAClB;AAAA,EACJ;AACJ;","names":[]}
1
+ {"version":3,"sources":["../../src/adapters/prisma.ts"],"sourcesContent":["import type { DatabaseAdapter, ErrorLogEntry, QueryOptions } from '../types'\n\n/**\n * Prisma ErrorLog model delegate interface\n * Uses generic function types to be compatible with any Prisma client version\n */\ninterface ErrorLogDelegate {\n create(args: unknown): Promise<unknown>\n findMany(args: unknown): Promise<unknown[]>\n findUnique(args: unknown): Promise<unknown | null>\n delete(args: unknown): Promise<unknown>\n deleteMany(args: unknown): Promise<{ count: number }>\n count(args: unknown): Promise<number>\n}\n\n/**\n * Prisma client interface - compatible with any @prisma/client version\n */\ninterface PrismaClientLike {\n errorLog: ErrorLogDelegate\n}\n\n/**\n * Create a Prisma database adapter\n *\n * Requires an ErrorLog model in your Prisma schema:\n *\n * ```prisma\n * model ErrorLog {\n * id String @id @default(cuid())\n * level String\n * message String @db.Text\n * stack String? @db.Text\n * userId String?\n * userEmail String?\n * userName String?\n * path String?\n * method String?\n * userAgent String?\n * ip String?\n * metadata Json?\n * createdAt DateTime @default(now())\n *\n * @@index([level])\n * @@index([userId])\n * @@index([createdAt])\n * }\n * ```\n *\n * @example\n * ```ts\n * import { createPrismaAdapter } from '@vinetechke/next-error-logger/adapters/prisma'\n * import { prisma } from '@/lib/prisma'\n *\n * const adapter = createPrismaAdapter(prisma)\n * ```\n */\nexport function createPrismaAdapter(prisma: PrismaClientLike): DatabaseAdapter {\n return {\n async create(entry) {\n const result = await prisma.errorLog.create({\n data: {\n level: entry.level,\n message: entry.message,\n stack: entry.stack,\n userId: entry.userId,\n userEmail: entry.userEmail,\n userName: entry.userName,\n path: entry.path,\n method: entry.method,\n userAgent: entry.userAgent,\n ip: entry.ip,\n metadata: entry.metadata\n ? JSON.parse(JSON.stringify(entry.metadata))\n : null,\n },\n })\n return result as ErrorLogEntry\n },\n\n async findMany(options: QueryOptions) {\n const {\n page = 1,\n limit = 50,\n level,\n userId,\n search,\n startDate,\n endDate,\n orderBy = 'createdAt',\n order = 'desc',\n } = options\n\n // Build where clause\n const where: Record<string, unknown> = {}\n\n if (level) {\n where.level = level\n }\n\n if (userId) {\n where.userId = userId\n }\n\n if (search) {\n where.OR = [\n { message: { contains: search, mode: 'insensitive' } },\n { stack: { contains: search, mode: 'insensitive' } },\n { path: { contains: search, mode: 'insensitive' } },\n { userEmail: { contains: search, mode: 'insensitive' } },\n ]\n }\n\n if (startDate || endDate) {\n where.createdAt = {}\n if (startDate) {\n ;(where.createdAt as Record<string, unknown>).gte =\n startDate\n }\n if (endDate) {\n ;(where.createdAt as Record<string, unknown>).lte = endDate\n }\n }\n\n const [logs, total] = await Promise.all([\n prisma.errorLog.findMany({\n where,\n orderBy: { [orderBy]: order },\n skip: (page - 1) * limit,\n take: limit,\n }),\n prisma.errorLog.count({ where }),\n ])\n\n return { logs: logs as ErrorLogEntry[], total }\n },\n\n async findById(id: string) {\n const result = await prisma.errorLog.findUnique({ where: { id } })\n return result as ErrorLogEntry | null\n },\n\n async delete(id: string) {\n await prisma.errorLog.delete({ where: { id } })\n },\n\n async deleteMany(options) {\n const where: Record<string, unknown> = {}\n\n if (options.before) {\n where.createdAt = { lt: options.before }\n }\n\n if (options.level) {\n where.level = options.level\n }\n\n const result = await prisma.errorLog.deleteMany({ where })\n return result.count\n },\n }\n}\n"],"mappings":";AAyDO,SAAS,oBAAoB,QAA2C;AAC3E,SAAO;AAAA,IACH,MAAM,OAAO,OAAO;AAChB,YAAM,SAAS,MAAM,OAAO,SAAS,OAAO;AAAA,QACxC,MAAM;AAAA,UACF,OAAO,MAAM;AAAA,UACb,SAAS,MAAM;AAAA,UACf,OAAO,MAAM;AAAA,UACb,QAAQ,MAAM;AAAA,UACd,WAAW,MAAM;AAAA,UACjB,UAAU,MAAM;AAAA,UAChB,MAAM,MAAM;AAAA,UACZ,QAAQ,MAAM;AAAA,UACd,WAAW,MAAM;AAAA,UACjB,IAAI,MAAM;AAAA,UACV,UAAU,MAAM,WACV,KAAK,MAAM,KAAK,UAAU,MAAM,QAAQ,CAAC,IACzC;AAAA,QACV;AAAA,MACJ,CAAC;AACD,aAAO;AAAA,IACX;AAAA,IAEA,MAAM,SAAS,SAAuB;AAClC,YAAM;AAAA,QACF,OAAO;AAAA,QACP,QAAQ;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,UAAU;AAAA,QACV,QAAQ;AAAA,MACZ,IAAI;AAGJ,YAAM,QAAiC,CAAC;AAExC,UAAI,OAAO;AACP,cAAM,QAAQ;AAAA,MAClB;AAEA,UAAI,QAAQ;AACR,cAAM,SAAS;AAAA,MACnB;AAEA,UAAI,QAAQ;AACR,cAAM,KAAK;AAAA,UACP,EAAE,SAAS,EAAE,UAAU,QAAQ,MAAM,cAAc,EAAE;AAAA,UACrD,EAAE,OAAO,EAAE,UAAU,QAAQ,MAAM,cAAc,EAAE;AAAA,UACnD,EAAE,MAAM,EAAE,UAAU,QAAQ,MAAM,cAAc,EAAE;AAAA,UAClD,EAAE,WAAW,EAAE,UAAU,QAAQ,MAAM,cAAc,EAAE;AAAA,QAC3D;AAAA,MACJ;AAEA,UAAI,aAAa,SAAS;AACtB,cAAM,YAAY,CAAC;AACnB,YAAI,WAAW;AACX;AAAC,UAAC,MAAM,UAAsC,MAC1C;AAAA,QACR;AACA,YAAI,SAAS;AACT;AAAC,UAAC,MAAM,UAAsC,MAAM;AAAA,QACxD;AAAA,MACJ;AAEA,YAAM,CAAC,MAAM,KAAK,IAAI,MAAM,QAAQ,IAAI;AAAA,QACpC,OAAO,SAAS,SAAS;AAAA,UACrB;AAAA,UACA,SAAS,EAAE,CAAC,OAAO,GAAG,MAAM;AAAA,UAC5B,OAAO,OAAO,KAAK;AAAA,UACnB,MAAM;AAAA,QACV,CAAC;AAAA,QACD,OAAO,SAAS,MAAM,EAAE,MAAM,CAAC;AAAA,MACnC,CAAC;AAED,aAAO,EAAE,MAA+B,MAAM;AAAA,IAClD;AAAA,IAEA,MAAM,SAAS,IAAY;AACvB,YAAM,SAAS,MAAM,OAAO,SAAS,WAAW,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;AACjE,aAAO;AAAA,IACX;AAAA,IAEA,MAAM,OAAO,IAAY;AACrB,YAAM,OAAO,SAAS,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;AAAA,IAClD;AAAA,IAEA,MAAM,WAAW,SAAS;AACtB,YAAM,QAAiC,CAAC;AAExC,UAAI,QAAQ,QAAQ;AAChB,cAAM,YAAY,EAAE,IAAI,QAAQ,OAAO;AAAA,MAC3C;AAEA,UAAI,QAAQ,OAAO;AACf,cAAM,QAAQ,QAAQ;AAAA,MAC1B;AAEA,YAAM,SAAS,MAAM,OAAO,SAAS,WAAW,EAAE,MAAM,CAAC;AACzD,aAAO,OAAO;AAAA,IAClB;AAAA,EACJ;AACJ;","names":[]}
@@ -1,4 +1,3 @@
1
- "use client";
2
1
  "use strict";
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/adapters/sql.ts"],"sourcesContent":["import type { DatabaseAdapter, ErrorLogEntry, QueryOptions } from '../types'\n\n/**\n * Generic SQL query executor interface\n * Implement this to connect to any SQL database\n */\nexport interface SQLExecutor {\n /**\n * Execute a parameterized SQL query\n * @param sql - SQL query with placeholders ($1, $2, etc. for Postgres; ?, ?, etc. for MySQL)\n * @param params - Array of parameter values\n * @returns Array of result rows\n */\n query<T = unknown>(sql: string, params?: unknown[]): Promise<T[]>\n\n /**\n * Execute a parameterized SQL query that returns affected row count\n * @param sql - SQL query\n * @param params - Array of parameter values\n * @returns Number of affected rows\n */\n execute(sql: string, params?: unknown[]): Promise<number>\n}\n\n/**\n * Configuration for the SQL adapter\n */\nexport interface SQLAdapterConfig {\n /** Your SQL executor implementation */\n executor: SQLExecutor\n /** Table name (default: 'error_logs') */\n tableName?: string\n /** SQL dialect for placeholder syntax */\n dialect: 'postgres' | 'mysql' | 'sqlite'\n}\n\n/**\n * Create a raw SQL database adapter\n *\n * Works with any SQL database - just provide an executor that matches the SQLExecutor interface.\n *\n * Required table schema (PostgreSQL example):\n *\n * ```sql\n * CREATE TABLE error_logs (\n * id TEXT PRIMARY KEY,\n * level TEXT NOT NULL,\n * message TEXT NOT NULL,\n * stack TEXT,\n * user_id TEXT,\n * user_email TEXT,\n * user_name TEXT,\n * path TEXT,\n * method TEXT,\n * user_agent TEXT,\n * ip TEXT,\n * metadata JSONB,\n * created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()\n * );\n *\n * CREATE INDEX idx_error_logs_level ON error_logs(level);\n * CREATE INDEX idx_error_logs_user_id ON error_logs(user_id);\n * CREATE INDEX idx_error_logs_created_at ON error_logs(created_at);\n * ```\n *\n * @example\n * ```ts\n * // With node-postgres (pg)\n * import { createSQLAdapter } from '@vinetechke/next-error-logger/adapters/sql'\n * import { Pool } from 'pg'\n *\n * const pool = new Pool({ connectionString: process.env.DATABASE_URL })\n *\n * const adapter = createSQLAdapter({\n * executor: {\n * query: async (sql, params) => {\n * const result = await pool.query(sql, params)\n * return result.rows\n * },\n * execute: async (sql, params) => {\n * const result = await pool.query(sql, params)\n * return result.rowCount || 0\n * },\n * },\n * dialect: 'postgres',\n * })\n * ```\n *\n * @example\n * ```ts\n * // With mysql2\n * import { createSQLAdapter } from '@vinetechke/next-error-logger/adapters/sql'\n * import mysql from 'mysql2/promise'\n *\n * const pool = mysql.createPool({ uri: process.env.DATABASE_URL })\n *\n * const adapter = createSQLAdapter({\n * executor: {\n * query: async (sql, params) => {\n * const [rows] = await pool.query(sql, params)\n * return rows as unknown[]\n * },\n * execute: async (sql, params) => {\n * const [result] = await pool.query(sql, params)\n * return (result as { affectedRows: number }).affectedRows\n * },\n * },\n * dialect: 'mysql',\n * })\n * ```\n */\nexport function createSQLAdapter(config: SQLAdapterConfig): DatabaseAdapter {\n const { executor, tableName = 'error_logs', dialect } = config\n\n // Placeholder function based on dialect\n const ph = (index: number): string => {\n switch (dialect) {\n case 'postgres':\n return `$${index}`\n case 'mysql':\n case 'sqlite':\n return '?'\n }\n }\n\n // Convert snake_case DB rows to camelCase\n const toCamelCase = (row: Record<string, unknown>): ErrorLogEntry => ({\n id: row.id as string,\n level: row.level as ErrorLogEntry['level'],\n message: row.message as string,\n stack: row.stack as string | null,\n userId: row.user_id as string | null,\n userEmail: row.user_email as string | null,\n userName: row.user_name as string | null,\n path: row.path as string | null,\n method: row.method as string | null,\n userAgent: row.user_agent as string | null,\n ip: row.ip as string | null,\n metadata: row.metadata as Record<string, unknown> | null,\n createdAt: new Date(row.created_at as string),\n })\n\n return {\n async create(entry) {\n const id = crypto.randomUUID()\n const now = new Date().toISOString()\n\n const sql = `\n INSERT INTO ${tableName} (\n id, level, message, stack, user_id, user_email, user_name,\n path, method, user_agent, ip, metadata, created_at\n ) VALUES (\n ${ph(1)}, ${ph(2)}, ${ph(3)}, ${ph(4)}, ${ph(5)}, ${ph(6)}, ${ph(7)},\n ${ph(8)}, ${ph(9)}, ${ph(10)}, ${ph(11)}, ${ph(12)}, ${ph(13)}\n ) RETURNING *\n `\n\n const params = [\n id,\n entry.level,\n entry.message,\n entry.stack,\n entry.userId,\n entry.userEmail,\n entry.userName,\n entry.path,\n entry.method,\n entry.userAgent,\n entry.ip,\n entry.metadata ? JSON.stringify(entry.metadata) : null,\n now,\n ]\n\n // For MySQL/SQLite which don't support RETURNING\n if (dialect !== 'postgres') {\n const insertSql = `\n INSERT INTO ${tableName} (\n id, level, message, stack, user_id, user_email, user_name,\n path, method, user_agent, ip, metadata, created_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `\n await executor.execute(insertSql, params)\n\n const selectSql = `SELECT * FROM ${tableName} WHERE id = ?`\n const rows = await executor.query<Record<string, unknown>>(\n selectSql,\n [id],\n )\n return toCamelCase(rows[0])\n }\n\n const rows = await executor.query<Record<string, unknown>>(\n sql,\n params,\n )\n return toCamelCase(rows[0])\n },\n\n async findMany(options: QueryOptions) {\n const {\n page = 1,\n limit = 50,\n level,\n userId,\n search,\n startDate,\n endDate,\n orderBy = 'createdAt',\n order = 'desc',\n } = options\n\n const conditions: string[] = []\n const params: unknown[] = []\n let paramIndex = 1\n\n if (level) {\n conditions.push(`level = ${ph(paramIndex++)}`)\n params.push(level)\n }\n\n if (userId) {\n conditions.push(`user_id = ${ph(paramIndex++)}`)\n params.push(userId)\n }\n\n if (search) {\n const searchPattern = `%${search}%`\n conditions.push(`(\n message ILIKE ${ph(paramIndex++)} OR\n stack ILIKE ${ph(paramIndex++)} OR\n path ILIKE ${ph(paramIndex++)} OR\n user_email ILIKE ${ph(paramIndex++)}\n )`)\n params.push(\n searchPattern,\n searchPattern,\n searchPattern,\n searchPattern,\n )\n }\n\n if (startDate) {\n conditions.push(`created_at >= ${ph(paramIndex++)}`)\n params.push(startDate.toISOString())\n }\n\n if (endDate) {\n conditions.push(`created_at <= ${ph(paramIndex++)}`)\n params.push(endDate.toISOString())\n }\n\n const whereClause =\n conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : ''\n const orderColumn = orderBy === 'level' ? 'level' : 'created_at'\n const orderDirection = order.toUpperCase()\n const offset = (page - 1) * limit\n\n const sql = `\n SELECT * FROM ${tableName}\n ${whereClause}\n ORDER BY ${orderColumn} ${orderDirection}\n LIMIT ${limit} OFFSET ${offset}\n `\n\n const countSql = `SELECT COUNT(*) as count FROM ${tableName} ${whereClause}`\n\n const [rows, countResult] = await Promise.all([\n executor.query<Record<string, unknown>>(sql, params),\n executor.query<{ count: string | number }>(countSql, params),\n ])\n\n return {\n logs: rows.map(toCamelCase),\n total: Number(countResult[0]?.count || 0),\n }\n },\n\n async findById(id: string) {\n const sql = `SELECT * FROM ${tableName} WHERE id = ${ph(1)}`\n const rows = await executor.query<Record<string, unknown>>(sql, [\n id,\n ])\n\n if (rows.length === 0) {\n return null\n }\n\n return toCamelCase(rows[0])\n },\n\n async delete(id: string) {\n const sql = `DELETE FROM ${tableName} WHERE id = ${ph(1)}`\n await executor.execute(sql, [id])\n },\n\n async deleteMany(options) {\n const conditions: string[] = []\n const params: unknown[] = []\n let paramIndex = 1\n\n if (options.before) {\n conditions.push(`created_at < ${ph(paramIndex++)}`)\n params.push(options.before.toISOString())\n }\n\n if (options.level) {\n conditions.push(`level = ${ph(paramIndex++)}`)\n params.push(options.level)\n }\n\n if (conditions.length === 0) {\n return 0\n }\n\n const sql = `DELETE FROM ${tableName} WHERE ${conditions.join(' AND ')}`\n return executor.execute(sql, params)\n },\n }\n}\n"],"mappings":"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","names":["rows"]}
1
+ {"version":3,"sources":["../../src/adapters/sql.ts"],"sourcesContent":["import type { DatabaseAdapter, ErrorLogEntry, QueryOptions } from '../types'\n\n/**\n * Generic SQL query executor interface\n * Implement this to connect to any SQL database\n */\nexport interface SQLExecutor {\n /**\n * Execute a parameterized SQL query\n * @param sql - SQL query with placeholders ($1, $2, etc. for Postgres; ?, ?, etc. for MySQL)\n * @param params - Array of parameter values\n * @returns Array of result rows\n */\n query<T = unknown>(sql: string, params?: unknown[]): Promise<T[]>\n\n /**\n * Execute a parameterized SQL query that returns affected row count\n * @param sql - SQL query\n * @param params - Array of parameter values\n * @returns Number of affected rows\n */\n execute(sql: string, params?: unknown[]): Promise<number>\n}\n\n/**\n * Configuration for the SQL adapter\n */\nexport interface SQLAdapterConfig {\n /** Your SQL executor implementation */\n executor: SQLExecutor\n /** Table name (default: 'error_logs') */\n tableName?: string\n /** SQL dialect for placeholder syntax */\n dialect: 'postgres' | 'mysql' | 'sqlite'\n}\n\n/**\n * Create a raw SQL database adapter\n *\n * Works with any SQL database - just provide an executor that matches the SQLExecutor interface.\n *\n * Required table schema (PostgreSQL example):\n *\n * ```sql\n * CREATE TABLE error_logs (\n * id TEXT PRIMARY KEY,\n * level TEXT NOT NULL,\n * message TEXT NOT NULL,\n * stack TEXT,\n * user_id TEXT,\n * user_email TEXT,\n * user_name TEXT,\n * path TEXT,\n * method TEXT,\n * user_agent TEXT,\n * ip TEXT,\n * metadata JSONB,\n * created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()\n * );\n *\n * CREATE INDEX idx_error_logs_level ON error_logs(level);\n * CREATE INDEX idx_error_logs_user_id ON error_logs(user_id);\n * CREATE INDEX idx_error_logs_created_at ON error_logs(created_at);\n * ```\n *\n * @example\n * ```ts\n * // With node-postgres (pg)\n * import { createSQLAdapter } from '@vinetechke/next-error-logger/adapters/sql'\n * import { Pool } from 'pg'\n *\n * const pool = new Pool({ connectionString: process.env.DATABASE_URL })\n *\n * const adapter = createSQLAdapter({\n * executor: {\n * query: async (sql, params) => {\n * const result = await pool.query(sql, params)\n * return result.rows\n * },\n * execute: async (sql, params) => {\n * const result = await pool.query(sql, params)\n * return result.rowCount || 0\n * },\n * },\n * dialect: 'postgres',\n * })\n * ```\n *\n * @example\n * ```ts\n * // With mysql2\n * import { createSQLAdapter } from '@vinetechke/next-error-logger/adapters/sql'\n * import mysql from 'mysql2/promise'\n *\n * const pool = mysql.createPool({ uri: process.env.DATABASE_URL })\n *\n * const adapter = createSQLAdapter({\n * executor: {\n * query: async (sql, params) => {\n * const [rows] = await pool.query(sql, params)\n * return rows as unknown[]\n * },\n * execute: async (sql, params) => {\n * const [result] = await pool.query(sql, params)\n * return (result as { affectedRows: number }).affectedRows\n * },\n * },\n * dialect: 'mysql',\n * })\n * ```\n */\nexport function createSQLAdapter(config: SQLAdapterConfig): DatabaseAdapter {\n const { executor, tableName = 'error_logs', dialect } = config\n\n // Placeholder function based on dialect\n const ph = (index: number): string => {\n switch (dialect) {\n case 'postgres':\n return `$${index}`\n case 'mysql':\n case 'sqlite':\n return '?'\n }\n }\n\n // Convert snake_case DB rows to camelCase\n const toCamelCase = (row: Record<string, unknown>): ErrorLogEntry => ({\n id: row.id as string,\n level: row.level as ErrorLogEntry['level'],\n message: row.message as string,\n stack: row.stack as string | null,\n userId: row.user_id as string | null,\n userEmail: row.user_email as string | null,\n userName: row.user_name as string | null,\n path: row.path as string | null,\n method: row.method as string | null,\n userAgent: row.user_agent as string | null,\n ip: row.ip as string | null,\n metadata: row.metadata as Record<string, unknown> | null,\n createdAt: new Date(row.created_at as string),\n })\n\n return {\n async create(entry) {\n const id = crypto.randomUUID()\n const now = new Date().toISOString()\n\n const sql = `\n INSERT INTO ${tableName} (\n id, level, message, stack, user_id, user_email, user_name,\n path, method, user_agent, ip, metadata, created_at\n ) VALUES (\n ${ph(1)}, ${ph(2)}, ${ph(3)}, ${ph(4)}, ${ph(5)}, ${ph(6)}, ${ph(7)},\n ${ph(8)}, ${ph(9)}, ${ph(10)}, ${ph(11)}, ${ph(12)}, ${ph(13)}\n ) RETURNING *\n `\n\n const params = [\n id,\n entry.level,\n entry.message,\n entry.stack,\n entry.userId,\n entry.userEmail,\n entry.userName,\n entry.path,\n entry.method,\n entry.userAgent,\n entry.ip,\n entry.metadata ? JSON.stringify(entry.metadata) : null,\n now,\n ]\n\n // For MySQL/SQLite which don't support RETURNING\n if (dialect !== 'postgres') {\n const insertSql = `\n INSERT INTO ${tableName} (\n id, level, message, stack, user_id, user_email, user_name,\n path, method, user_agent, ip, metadata, created_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `\n await executor.execute(insertSql, params)\n\n const selectSql = `SELECT * FROM ${tableName} WHERE id = ?`\n const rows = await executor.query<Record<string, unknown>>(\n selectSql,\n [id],\n )\n return toCamelCase(rows[0])\n }\n\n const rows = await executor.query<Record<string, unknown>>(\n sql,\n params,\n )\n return toCamelCase(rows[0])\n },\n\n async findMany(options: QueryOptions) {\n const {\n page = 1,\n limit = 50,\n level,\n userId,\n search,\n startDate,\n endDate,\n orderBy = 'createdAt',\n order = 'desc',\n } = options\n\n const conditions: string[] = []\n const params: unknown[] = []\n let paramIndex = 1\n\n if (level) {\n conditions.push(`level = ${ph(paramIndex++)}`)\n params.push(level)\n }\n\n if (userId) {\n conditions.push(`user_id = ${ph(paramIndex++)}`)\n params.push(userId)\n }\n\n if (search) {\n const searchPattern = `%${search}%`\n conditions.push(`(\n message ILIKE ${ph(paramIndex++)} OR\n stack ILIKE ${ph(paramIndex++)} OR\n path ILIKE ${ph(paramIndex++)} OR\n user_email ILIKE ${ph(paramIndex++)}\n )`)\n params.push(\n searchPattern,\n searchPattern,\n searchPattern,\n searchPattern,\n )\n }\n\n if (startDate) {\n conditions.push(`created_at >= ${ph(paramIndex++)}`)\n params.push(startDate.toISOString())\n }\n\n if (endDate) {\n conditions.push(`created_at <= ${ph(paramIndex++)}`)\n params.push(endDate.toISOString())\n }\n\n const whereClause =\n conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : ''\n const orderColumn = orderBy === 'level' ? 'level' : 'created_at'\n const orderDirection = order.toUpperCase()\n const offset = (page - 1) * limit\n\n const sql = `\n SELECT * FROM ${tableName}\n ${whereClause}\n ORDER BY ${orderColumn} ${orderDirection}\n LIMIT ${limit} OFFSET ${offset}\n `\n\n const countSql = `SELECT COUNT(*) as count FROM ${tableName} ${whereClause}`\n\n const [rows, countResult] = await Promise.all([\n executor.query<Record<string, unknown>>(sql, params),\n executor.query<{ count: string | number }>(countSql, params),\n ])\n\n return {\n logs: rows.map(toCamelCase),\n total: Number(countResult[0]?.count || 0),\n }\n },\n\n async findById(id: string) {\n const sql = `SELECT * FROM ${tableName} WHERE id = ${ph(1)}`\n const rows = await executor.query<Record<string, unknown>>(sql, [\n id,\n ])\n\n if (rows.length === 0) {\n return null\n }\n\n return toCamelCase(rows[0])\n },\n\n async delete(id: string) {\n const sql = `DELETE FROM ${tableName} WHERE id = ${ph(1)}`\n await executor.execute(sql, [id])\n },\n\n async deleteMany(options) {\n const conditions: string[] = []\n const params: unknown[] = []\n let paramIndex = 1\n\n if (options.before) {\n conditions.push(`created_at < ${ph(paramIndex++)}`)\n params.push(options.before.toISOString())\n }\n\n if (options.level) {\n conditions.push(`level = ${ph(paramIndex++)}`)\n params.push(options.level)\n }\n\n if (conditions.length === 0) {\n return 0\n }\n\n const sql = `DELETE FROM ${tableName} WHERE ${conditions.join(' AND ')}`\n return executor.execute(sql, params)\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA+GO,SAAS,iBAAiB,QAA2C;AACxE,QAAM,EAAE,UAAU,YAAY,cAAc,QAAQ,IAAI;AAGxD,QAAM,KAAK,CAAC,UAA0B;AAClC,YAAQ,SAAS;AAAA,MACb,KAAK;AACD,eAAO,IAAI,KAAK;AAAA,MACpB,KAAK;AAAA,MACL,KAAK;AACD,eAAO;AAAA,IACf;AAAA,EACJ;AAGA,QAAM,cAAc,CAAC,SAAiD;AAAA,IAClE,IAAI,IAAI;AAAA,IACR,OAAO,IAAI;AAAA,IACX,SAAS,IAAI;AAAA,IACb,OAAO,IAAI;AAAA,IACX,QAAQ,IAAI;AAAA,IACZ,WAAW,IAAI;AAAA,IACf,UAAU,IAAI;AAAA,IACd,MAAM,IAAI;AAAA,IACV,QAAQ,IAAI;AAAA,IACZ,WAAW,IAAI;AAAA,IACf,IAAI,IAAI;AAAA,IACR,UAAU,IAAI;AAAA,IACd,WAAW,IAAI,KAAK,IAAI,UAAoB;AAAA,EAChD;AAEA,SAAO;AAAA,IACH,MAAM,OAAO,OAAO;AAChB,YAAM,KAAK,OAAO,WAAW;AAC7B,YAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AAEnC,YAAM,MAAM;AAAA,sBACF,SAAS;AAAA;AAAA;AAAA;AAAA,YAInB,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC;AAAA,YACjE,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC,KAAK,GAAG,EAAE,CAAC,KAAK,GAAG,EAAE,CAAC,KAAK,GAAG,EAAE,CAAC;AAAA;AAAA;AAI3D,YAAM,SAAS;AAAA,QACX;AAAA,QACA,MAAM;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA,QACN,MAAM,WAAW,KAAK,UAAU,MAAM,QAAQ,IAAI;AAAA,QAClD;AAAA,MACJ;AAGA,UAAI,YAAY,YAAY;AACxB,cAAM,YAAY;AAAA,wBACV,SAAS;AAAA;AAAA;AAAA;AAAA;AAKjB,cAAM,SAAS,QAAQ,WAAW,MAAM;AAExC,cAAM,YAAY,iBAAiB,SAAS;AAC5C,cAAMA,QAAO,MAAM,SAAS;AAAA,UACxB;AAAA,UACA,CAAC,EAAE;AAAA,QACP;AACA,eAAO,YAAYA,MAAK,CAAC,CAAC;AAAA,MAC9B;AAEA,YAAM,OAAO,MAAM,SAAS;AAAA,QACxB;AAAA,QACA;AAAA,MACJ;AACA,aAAO,YAAY,KAAK,CAAC,CAAC;AAAA,IAC9B;AAAA,IAEA,MAAM,SAAS,SAAuB;AAClC,YAAM;AAAA,QACF,OAAO;AAAA,QACP,QAAQ;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,UAAU;AAAA,QACV,QAAQ;AAAA,MACZ,IAAI;AAEJ,YAAM,aAAuB,CAAC;AAC9B,YAAM,SAAoB,CAAC;AAC3B,UAAI,aAAa;AAEjB,UAAI,OAAO;AACP,mBAAW,KAAK,WAAW,GAAG,YAAY,CAAC,EAAE;AAC7C,eAAO,KAAK,KAAK;AAAA,MACrB;AAEA,UAAI,QAAQ;AACR,mBAAW,KAAK,aAAa,GAAG,YAAY,CAAC,EAAE;AAC/C,eAAO,KAAK,MAAM;AAAA,MACtB;AAEA,UAAI,QAAQ;AACR,cAAM,gBAAgB,IAAI,MAAM;AAChC,mBAAW,KAAK;AAAA,0BACN,GAAG,YAAY,CAAC;AAAA,wBAClB,GAAG,YAAY,CAAC;AAAA,uBACjB,GAAG,YAAY,CAAC;AAAA,6BACV,GAAG,YAAY,CAAC;AAAA,UACnC;AACM,eAAO;AAAA,UACH;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACJ;AAAA,MACJ;AAEA,UAAI,WAAW;AACX,mBAAW,KAAK,iBAAiB,GAAG,YAAY,CAAC,EAAE;AACnD,eAAO,KAAK,UAAU,YAAY,CAAC;AAAA,MACvC;AAEA,UAAI,SAAS;AACT,mBAAW,KAAK,iBAAiB,GAAG,YAAY,CAAC,EAAE;AACnD,eAAO,KAAK,QAAQ,YAAY,CAAC;AAAA,MACrC;AAEA,YAAM,cACF,WAAW,SAAS,IAAI,SAAS,WAAW,KAAK,OAAO,CAAC,KAAK;AAClE,YAAM,cAAc,YAAY,UAAU,UAAU;AACpD,YAAM,iBAAiB,MAAM,YAAY;AACzC,YAAM,UAAU,OAAO,KAAK;AAE5B,YAAM,MAAM;AAAA,wBACA,SAAS;AAAA,UACvB,WAAW;AAAA,mBACF,WAAW,IAAI,cAAc;AAAA,gBAChC,KAAK,WAAW,MAAM;AAAA;AAG1B,YAAM,WAAW,iCAAiC,SAAS,IAAI,WAAW;AAE1E,YAAM,CAAC,MAAM,WAAW,IAAI,MAAM,QAAQ,IAAI;AAAA,QAC1C,SAAS,MAA+B,KAAK,MAAM;AAAA,QACnD,SAAS,MAAkC,UAAU,MAAM;AAAA,MAC/D,CAAC;AAED,aAAO;AAAA,QACH,MAAM,KAAK,IAAI,WAAW;AAAA,QAC1B,OAAO,OAAO,YAAY,CAAC,GAAG,SAAS,CAAC;AAAA,MAC5C;AAAA,IACJ;AAAA,IAEA,MAAM,SAAS,IAAY;AACvB,YAAM,MAAM,iBAAiB,SAAS,eAAe,GAAG,CAAC,CAAC;AAC1D,YAAM,OAAO,MAAM,SAAS,MAA+B,KAAK;AAAA,QAC5D;AAAA,MACJ,CAAC;AAED,UAAI,KAAK,WAAW,GAAG;AACnB,eAAO;AAAA,MACX;AAEA,aAAO,YAAY,KAAK,CAAC,CAAC;AAAA,IAC9B;AAAA,IAEA,MAAM,OAAO,IAAY;AACrB,YAAM,MAAM,eAAe,SAAS,eAAe,GAAG,CAAC,CAAC;AACxD,YAAM,SAAS,QAAQ,KAAK,CAAC,EAAE,CAAC;AAAA,IACpC;AAAA,IAEA,MAAM,WAAW,SAAS;AACtB,YAAM,aAAuB,CAAC;AAC9B,YAAM,SAAoB,CAAC;AAC3B,UAAI,aAAa;AAEjB,UAAI,QAAQ,QAAQ;AAChB,mBAAW,KAAK,gBAAgB,GAAG,YAAY,CAAC,EAAE;AAClD,eAAO,KAAK,QAAQ,OAAO,YAAY,CAAC;AAAA,MAC5C;AAEA,UAAI,QAAQ,OAAO;AACf,mBAAW,KAAK,WAAW,GAAG,YAAY,CAAC,EAAE;AAC7C,eAAO,KAAK,QAAQ,KAAK;AAAA,MAC7B;AAEA,UAAI,WAAW,WAAW,GAAG;AACzB,eAAO;AAAA,MACX;AAEA,YAAM,MAAM,eAAe,SAAS,UAAU,WAAW,KAAK,OAAO,CAAC;AACtE,aAAO,SAAS,QAAQ,KAAK,MAAM;AAAA,IACvC;AAAA,EACJ;AACJ;","names":["rows"]}
@@ -1,5 +1,3 @@
1
- "use client";
2
-
3
1
  // src/adapters/sql.ts
4
2
  function createSQLAdapter(config) {
5
3
  const { executor, tableName = "error_logs", dialect } = config;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/adapters/sql.ts"],"sourcesContent":["import type { DatabaseAdapter, ErrorLogEntry, QueryOptions } from '../types'\n\n/**\n * Generic SQL query executor interface\n * Implement this to connect to any SQL database\n */\nexport interface SQLExecutor {\n /**\n * Execute a parameterized SQL query\n * @param sql - SQL query with placeholders ($1, $2, etc. for Postgres; ?, ?, etc. for MySQL)\n * @param params - Array of parameter values\n * @returns Array of result rows\n */\n query<T = unknown>(sql: string, params?: unknown[]): Promise<T[]>\n\n /**\n * Execute a parameterized SQL query that returns affected row count\n * @param sql - SQL query\n * @param params - Array of parameter values\n * @returns Number of affected rows\n */\n execute(sql: string, params?: unknown[]): Promise<number>\n}\n\n/**\n * Configuration for the SQL adapter\n */\nexport interface SQLAdapterConfig {\n /** Your SQL executor implementation */\n executor: SQLExecutor\n /** Table name (default: 'error_logs') */\n tableName?: string\n /** SQL dialect for placeholder syntax */\n dialect: 'postgres' | 'mysql' | 'sqlite'\n}\n\n/**\n * Create a raw SQL database adapter\n *\n * Works with any SQL database - just provide an executor that matches the SQLExecutor interface.\n *\n * Required table schema (PostgreSQL example):\n *\n * ```sql\n * CREATE TABLE error_logs (\n * id TEXT PRIMARY KEY,\n * level TEXT NOT NULL,\n * message TEXT NOT NULL,\n * stack TEXT,\n * user_id TEXT,\n * user_email TEXT,\n * user_name TEXT,\n * path TEXT,\n * method TEXT,\n * user_agent TEXT,\n * ip TEXT,\n * metadata JSONB,\n * created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()\n * );\n *\n * CREATE INDEX idx_error_logs_level ON error_logs(level);\n * CREATE INDEX idx_error_logs_user_id ON error_logs(user_id);\n * CREATE INDEX idx_error_logs_created_at ON error_logs(created_at);\n * ```\n *\n * @example\n * ```ts\n * // With node-postgres (pg)\n * import { createSQLAdapter } from '@vinetechke/next-error-logger/adapters/sql'\n * import { Pool } from 'pg'\n *\n * const pool = new Pool({ connectionString: process.env.DATABASE_URL })\n *\n * const adapter = createSQLAdapter({\n * executor: {\n * query: async (sql, params) => {\n * const result = await pool.query(sql, params)\n * return result.rows\n * },\n * execute: async (sql, params) => {\n * const result = await pool.query(sql, params)\n * return result.rowCount || 0\n * },\n * },\n * dialect: 'postgres',\n * })\n * ```\n *\n * @example\n * ```ts\n * // With mysql2\n * import { createSQLAdapter } from '@vinetechke/next-error-logger/adapters/sql'\n * import mysql from 'mysql2/promise'\n *\n * const pool = mysql.createPool({ uri: process.env.DATABASE_URL })\n *\n * const adapter = createSQLAdapter({\n * executor: {\n * query: async (sql, params) => {\n * const [rows] = await pool.query(sql, params)\n * return rows as unknown[]\n * },\n * execute: async (sql, params) => {\n * const [result] = await pool.query(sql, params)\n * return (result as { affectedRows: number }).affectedRows\n * },\n * },\n * dialect: 'mysql',\n * })\n * ```\n */\nexport function createSQLAdapter(config: SQLAdapterConfig): DatabaseAdapter {\n const { executor, tableName = 'error_logs', dialect } = config\n\n // Placeholder function based on dialect\n const ph = (index: number): string => {\n switch (dialect) {\n case 'postgres':\n return `$${index}`\n case 'mysql':\n case 'sqlite':\n return '?'\n }\n }\n\n // Convert snake_case DB rows to camelCase\n const toCamelCase = (row: Record<string, unknown>): ErrorLogEntry => ({\n id: row.id as string,\n level: row.level as ErrorLogEntry['level'],\n message: row.message as string,\n stack: row.stack as string | null,\n userId: row.user_id as string | null,\n userEmail: row.user_email as string | null,\n userName: row.user_name as string | null,\n path: row.path as string | null,\n method: row.method as string | null,\n userAgent: row.user_agent as string | null,\n ip: row.ip as string | null,\n metadata: row.metadata as Record<string, unknown> | null,\n createdAt: new Date(row.created_at as string),\n })\n\n return {\n async create(entry) {\n const id = crypto.randomUUID()\n const now = new Date().toISOString()\n\n const sql = `\n INSERT INTO ${tableName} (\n id, level, message, stack, user_id, user_email, user_name,\n path, method, user_agent, ip, metadata, created_at\n ) VALUES (\n ${ph(1)}, ${ph(2)}, ${ph(3)}, ${ph(4)}, ${ph(5)}, ${ph(6)}, ${ph(7)},\n ${ph(8)}, ${ph(9)}, ${ph(10)}, ${ph(11)}, ${ph(12)}, ${ph(13)}\n ) RETURNING *\n `\n\n const params = [\n id,\n entry.level,\n entry.message,\n entry.stack,\n entry.userId,\n entry.userEmail,\n entry.userName,\n entry.path,\n entry.method,\n entry.userAgent,\n entry.ip,\n entry.metadata ? JSON.stringify(entry.metadata) : null,\n now,\n ]\n\n // For MySQL/SQLite which don't support RETURNING\n if (dialect !== 'postgres') {\n const insertSql = `\n INSERT INTO ${tableName} (\n id, level, message, stack, user_id, user_email, user_name,\n path, method, user_agent, ip, metadata, created_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `\n await executor.execute(insertSql, params)\n\n const selectSql = `SELECT * FROM ${tableName} WHERE id = ?`\n const rows = await executor.query<Record<string, unknown>>(\n selectSql,\n [id],\n )\n return toCamelCase(rows[0])\n }\n\n const rows = await executor.query<Record<string, unknown>>(\n sql,\n params,\n )\n return toCamelCase(rows[0])\n },\n\n async findMany(options: QueryOptions) {\n const {\n page = 1,\n limit = 50,\n level,\n userId,\n search,\n startDate,\n endDate,\n orderBy = 'createdAt',\n order = 'desc',\n } = options\n\n const conditions: string[] = []\n const params: unknown[] = []\n let paramIndex = 1\n\n if (level) {\n conditions.push(`level = ${ph(paramIndex++)}`)\n params.push(level)\n }\n\n if (userId) {\n conditions.push(`user_id = ${ph(paramIndex++)}`)\n params.push(userId)\n }\n\n if (search) {\n const searchPattern = `%${search}%`\n conditions.push(`(\n message ILIKE ${ph(paramIndex++)} OR\n stack ILIKE ${ph(paramIndex++)} OR\n path ILIKE ${ph(paramIndex++)} OR\n user_email ILIKE ${ph(paramIndex++)}\n )`)\n params.push(\n searchPattern,\n searchPattern,\n searchPattern,\n searchPattern,\n )\n }\n\n if (startDate) {\n conditions.push(`created_at >= ${ph(paramIndex++)}`)\n params.push(startDate.toISOString())\n }\n\n if (endDate) {\n conditions.push(`created_at <= ${ph(paramIndex++)}`)\n params.push(endDate.toISOString())\n }\n\n const whereClause =\n conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : ''\n const orderColumn = orderBy === 'level' ? 'level' : 'created_at'\n const orderDirection = order.toUpperCase()\n const offset = (page - 1) * limit\n\n const sql = `\n SELECT * FROM ${tableName}\n ${whereClause}\n ORDER BY ${orderColumn} ${orderDirection}\n LIMIT ${limit} OFFSET ${offset}\n `\n\n const countSql = `SELECT COUNT(*) as count FROM ${tableName} ${whereClause}`\n\n const [rows, countResult] = await Promise.all([\n executor.query<Record<string, unknown>>(sql, params),\n executor.query<{ count: string | number }>(countSql, params),\n ])\n\n return {\n logs: rows.map(toCamelCase),\n total: Number(countResult[0]?.count || 0),\n }\n },\n\n async findById(id: string) {\n const sql = `SELECT * FROM ${tableName} WHERE id = ${ph(1)}`\n const rows = await executor.query<Record<string, unknown>>(sql, [\n id,\n ])\n\n if (rows.length === 0) {\n return null\n }\n\n return toCamelCase(rows[0])\n },\n\n async delete(id: string) {\n const sql = `DELETE FROM ${tableName} WHERE id = ${ph(1)}`\n await executor.execute(sql, [id])\n },\n\n async deleteMany(options) {\n const conditions: string[] = []\n const params: unknown[] = []\n let paramIndex = 1\n\n if (options.before) {\n conditions.push(`created_at < ${ph(paramIndex++)}`)\n params.push(options.before.toISOString())\n }\n\n if (options.level) {\n conditions.push(`level = ${ph(paramIndex++)}`)\n params.push(options.level)\n }\n\n if (conditions.length === 0) {\n return 0\n }\n\n const sql = `DELETE FROM ${tableName} WHERE ${conditions.join(' AND ')}`\n return executor.execute(sql, params)\n },\n }\n}\n"],"mappings":"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","names":["rows"]}
1
+ {"version":3,"sources":["../../src/adapters/sql.ts"],"sourcesContent":["import type { DatabaseAdapter, ErrorLogEntry, QueryOptions } from '../types'\n\n/**\n * Generic SQL query executor interface\n * Implement this to connect to any SQL database\n */\nexport interface SQLExecutor {\n /**\n * Execute a parameterized SQL query\n * @param sql - SQL query with placeholders ($1, $2, etc. for Postgres; ?, ?, etc. for MySQL)\n * @param params - Array of parameter values\n * @returns Array of result rows\n */\n query<T = unknown>(sql: string, params?: unknown[]): Promise<T[]>\n\n /**\n * Execute a parameterized SQL query that returns affected row count\n * @param sql - SQL query\n * @param params - Array of parameter values\n * @returns Number of affected rows\n */\n execute(sql: string, params?: unknown[]): Promise<number>\n}\n\n/**\n * Configuration for the SQL adapter\n */\nexport interface SQLAdapterConfig {\n /** Your SQL executor implementation */\n executor: SQLExecutor\n /** Table name (default: 'error_logs') */\n tableName?: string\n /** SQL dialect for placeholder syntax */\n dialect: 'postgres' | 'mysql' | 'sqlite'\n}\n\n/**\n * Create a raw SQL database adapter\n *\n * Works with any SQL database - just provide an executor that matches the SQLExecutor interface.\n *\n * Required table schema (PostgreSQL example):\n *\n * ```sql\n * CREATE TABLE error_logs (\n * id TEXT PRIMARY KEY,\n * level TEXT NOT NULL,\n * message TEXT NOT NULL,\n * stack TEXT,\n * user_id TEXT,\n * user_email TEXT,\n * user_name TEXT,\n * path TEXT,\n * method TEXT,\n * user_agent TEXT,\n * ip TEXT,\n * metadata JSONB,\n * created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()\n * );\n *\n * CREATE INDEX idx_error_logs_level ON error_logs(level);\n * CREATE INDEX idx_error_logs_user_id ON error_logs(user_id);\n * CREATE INDEX idx_error_logs_created_at ON error_logs(created_at);\n * ```\n *\n * @example\n * ```ts\n * // With node-postgres (pg)\n * import { createSQLAdapter } from '@vinetechke/next-error-logger/adapters/sql'\n * import { Pool } from 'pg'\n *\n * const pool = new Pool({ connectionString: process.env.DATABASE_URL })\n *\n * const adapter = createSQLAdapter({\n * executor: {\n * query: async (sql, params) => {\n * const result = await pool.query(sql, params)\n * return result.rows\n * },\n * execute: async (sql, params) => {\n * const result = await pool.query(sql, params)\n * return result.rowCount || 0\n * },\n * },\n * dialect: 'postgres',\n * })\n * ```\n *\n * @example\n * ```ts\n * // With mysql2\n * import { createSQLAdapter } from '@vinetechke/next-error-logger/adapters/sql'\n * import mysql from 'mysql2/promise'\n *\n * const pool = mysql.createPool({ uri: process.env.DATABASE_URL })\n *\n * const adapter = createSQLAdapter({\n * executor: {\n * query: async (sql, params) => {\n * const [rows] = await pool.query(sql, params)\n * return rows as unknown[]\n * },\n * execute: async (sql, params) => {\n * const [result] = await pool.query(sql, params)\n * return (result as { affectedRows: number }).affectedRows\n * },\n * },\n * dialect: 'mysql',\n * })\n * ```\n */\nexport function createSQLAdapter(config: SQLAdapterConfig): DatabaseAdapter {\n const { executor, tableName = 'error_logs', dialect } = config\n\n // Placeholder function based on dialect\n const ph = (index: number): string => {\n switch (dialect) {\n case 'postgres':\n return `$${index}`\n case 'mysql':\n case 'sqlite':\n return '?'\n }\n }\n\n // Convert snake_case DB rows to camelCase\n const toCamelCase = (row: Record<string, unknown>): ErrorLogEntry => ({\n id: row.id as string,\n level: row.level as ErrorLogEntry['level'],\n message: row.message as string,\n stack: row.stack as string | null,\n userId: row.user_id as string | null,\n userEmail: row.user_email as string | null,\n userName: row.user_name as string | null,\n path: row.path as string | null,\n method: row.method as string | null,\n userAgent: row.user_agent as string | null,\n ip: row.ip as string | null,\n metadata: row.metadata as Record<string, unknown> | null,\n createdAt: new Date(row.created_at as string),\n })\n\n return {\n async create(entry) {\n const id = crypto.randomUUID()\n const now = new Date().toISOString()\n\n const sql = `\n INSERT INTO ${tableName} (\n id, level, message, stack, user_id, user_email, user_name,\n path, method, user_agent, ip, metadata, created_at\n ) VALUES (\n ${ph(1)}, ${ph(2)}, ${ph(3)}, ${ph(4)}, ${ph(5)}, ${ph(6)}, ${ph(7)},\n ${ph(8)}, ${ph(9)}, ${ph(10)}, ${ph(11)}, ${ph(12)}, ${ph(13)}\n ) RETURNING *\n `\n\n const params = [\n id,\n entry.level,\n entry.message,\n entry.stack,\n entry.userId,\n entry.userEmail,\n entry.userName,\n entry.path,\n entry.method,\n entry.userAgent,\n entry.ip,\n entry.metadata ? JSON.stringify(entry.metadata) : null,\n now,\n ]\n\n // For MySQL/SQLite which don't support RETURNING\n if (dialect !== 'postgres') {\n const insertSql = `\n INSERT INTO ${tableName} (\n id, level, message, stack, user_id, user_email, user_name,\n path, method, user_agent, ip, metadata, created_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `\n await executor.execute(insertSql, params)\n\n const selectSql = `SELECT * FROM ${tableName} WHERE id = ?`\n const rows = await executor.query<Record<string, unknown>>(\n selectSql,\n [id],\n )\n return toCamelCase(rows[0])\n }\n\n const rows = await executor.query<Record<string, unknown>>(\n sql,\n params,\n )\n return toCamelCase(rows[0])\n },\n\n async findMany(options: QueryOptions) {\n const {\n page = 1,\n limit = 50,\n level,\n userId,\n search,\n startDate,\n endDate,\n orderBy = 'createdAt',\n order = 'desc',\n } = options\n\n const conditions: string[] = []\n const params: unknown[] = []\n let paramIndex = 1\n\n if (level) {\n conditions.push(`level = ${ph(paramIndex++)}`)\n params.push(level)\n }\n\n if (userId) {\n conditions.push(`user_id = ${ph(paramIndex++)}`)\n params.push(userId)\n }\n\n if (search) {\n const searchPattern = `%${search}%`\n conditions.push(`(\n message ILIKE ${ph(paramIndex++)} OR\n stack ILIKE ${ph(paramIndex++)} OR\n path ILIKE ${ph(paramIndex++)} OR\n user_email ILIKE ${ph(paramIndex++)}\n )`)\n params.push(\n searchPattern,\n searchPattern,\n searchPattern,\n searchPattern,\n )\n }\n\n if (startDate) {\n conditions.push(`created_at >= ${ph(paramIndex++)}`)\n params.push(startDate.toISOString())\n }\n\n if (endDate) {\n conditions.push(`created_at <= ${ph(paramIndex++)}`)\n params.push(endDate.toISOString())\n }\n\n const whereClause =\n conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : ''\n const orderColumn = orderBy === 'level' ? 'level' : 'created_at'\n const orderDirection = order.toUpperCase()\n const offset = (page - 1) * limit\n\n const sql = `\n SELECT * FROM ${tableName}\n ${whereClause}\n ORDER BY ${orderColumn} ${orderDirection}\n LIMIT ${limit} OFFSET ${offset}\n `\n\n const countSql = `SELECT COUNT(*) as count FROM ${tableName} ${whereClause}`\n\n const [rows, countResult] = await Promise.all([\n executor.query<Record<string, unknown>>(sql, params),\n executor.query<{ count: string | number }>(countSql, params),\n ])\n\n return {\n logs: rows.map(toCamelCase),\n total: Number(countResult[0]?.count || 0),\n }\n },\n\n async findById(id: string) {\n const sql = `SELECT * FROM ${tableName} WHERE id = ${ph(1)}`\n const rows = await executor.query<Record<string, unknown>>(sql, [\n id,\n ])\n\n if (rows.length === 0) {\n return null\n }\n\n return toCamelCase(rows[0])\n },\n\n async delete(id: string) {\n const sql = `DELETE FROM ${tableName} WHERE id = ${ph(1)}`\n await executor.execute(sql, [id])\n },\n\n async deleteMany(options) {\n const conditions: string[] = []\n const params: unknown[] = []\n let paramIndex = 1\n\n if (options.before) {\n conditions.push(`created_at < ${ph(paramIndex++)}`)\n params.push(options.before.toISOString())\n }\n\n if (options.level) {\n conditions.push(`level = ${ph(paramIndex++)}`)\n params.push(options.level)\n }\n\n if (conditions.length === 0) {\n return 0\n }\n\n const sql = `DELETE FROM ${tableName} WHERE ${conditions.join(' AND ')}`\n return executor.execute(sql, params)\n },\n }\n}\n"],"mappings":"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","names":["rows"]}
@@ -1,4 +1,3 @@
1
- "use client";
2
1
  "use strict";
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/api/index.ts","../../src/logger.ts"],"sourcesContent":["import { NextRequest, NextResponse } from 'next/server'\nimport { getConfig, isInitialized } from '../logger'\nimport type { LogLevel } from '../types'\n\n/**\n * Configuration for API route handlers\n */\nexport interface APIHandlerConfig {\n /**\n * Function to check if user is authorized to view logs\n * Return true to allow access, false to deny\n *\n * @example\n * ```ts\n * const config = {\n * isAuthorized: async (request) => {\n * const session = await auth()\n * return session?.user?.role === 'admin'\n * }\n * }\n * ```\n */\n isAuthorized: (request: NextRequest) => Promise<boolean>\n}\n\n/**\n * Create API route handlers for the error logger\n *\n * Creates GET, DELETE handlers for listing, fetching, and deleting logs.\n *\n * @example\n * ```ts\n * // app/api/admin/logs/route.ts\n * import { createLogAPIHandlers } from '@vinetechke/next-error-logger/api'\n * import { auth } from '@/auth'\n *\n * const { GET, DELETE } = createLogAPIHandlers({\n * isAuthorized: async () => {\n * const session = await auth()\n * return session?.user?.role === 'ADMIN'\n * },\n * })\n *\n * export { GET, DELETE }\n * ```\n *\n * @example\n * ```ts\n * // app/api/admin/logs/[id]/route.ts\n * import { createLogDetailAPIHandlers } from '@vinetechke/next-error-logger/api'\n * import { auth } from '@/auth'\n *\n * const { GET, DELETE } = createLogDetailAPIHandlers({\n * isAuthorized: async () => {\n * const session = await auth()\n * return session?.user?.role === 'ADMIN'\n * },\n * })\n *\n * export { GET, DELETE }\n * ```\n */\nexport function createLogAPIHandlers(config: APIHandlerConfig) {\n const { isAuthorized } = config\n\n return {\n /**\n * GET /api/logs - List logs with filtering and pagination\n *\n * Query parameters:\n * - page: Page number (default: 1)\n * - limit: Items per page (default: 50)\n * - level: Filter by level (error, warn, info, debug)\n * - userId: Filter by user ID\n * - search: Search in message, stack, path, userEmail\n * - startDate: Filter logs after this date (ISO string)\n * - endDate: Filter logs before this date (ISO string)\n */\n GET: async (request: NextRequest): Promise<NextResponse> => {\n // Check authorization\n if (!(await isAuthorized(request))) {\n return NextResponse.json(\n { error: 'Unauthorized' },\n { status: 401 },\n )\n }\n\n // Check if logger is initialized\n if (!isInitialized()) {\n return NextResponse.json(\n { error: 'Logger not initialized' },\n { status: 500 },\n )\n }\n\n const cfg = getConfig()\n const searchParams = request.nextUrl.searchParams\n\n try {\n const options = {\n page: parseInt(searchParams.get('page') || '1', 10),\n limit: Math.min(\n parseInt(searchParams.get('limit') || '50', 10),\n 100,\n ),\n level: searchParams.get('level') as LogLevel | undefined,\n userId: searchParams.get('userId') || undefined,\n search: searchParams.get('search') || undefined,\n startDate: searchParams.get('startDate')\n ? new Date(searchParams.get('startDate')!)\n : undefined,\n endDate: searchParams.get('endDate')\n ? new Date(searchParams.get('endDate')!)\n : undefined,\n }\n\n const result = await cfg.adapter.findMany(options)\n\n return NextResponse.json(result)\n } catch (error) {\n console.error('[@vinetechke/next-error-logger] API error:', error)\n return NextResponse.json(\n { error: 'Failed to fetch logs' },\n { status: 500 },\n )\n }\n },\n\n /**\n * DELETE /api/logs - Clear logs\n *\n * Body parameters:\n * - before: Delete logs before this date (ISO string)\n * - level: Delete logs with this level only\n */\n DELETE: async (request: NextRequest): Promise<NextResponse> => {\n // Check authorization\n if (!(await isAuthorized(request))) {\n return NextResponse.json(\n { error: 'Unauthorized' },\n { status: 401 },\n )\n }\n\n // Check if logger is initialized\n if (!isInitialized()) {\n return NextResponse.json(\n { error: 'Logger not initialized' },\n { status: 500 },\n )\n }\n\n const cfg = getConfig()\n\n try {\n const body = await request.json().catch(() => ({}))\n\n const count = await cfg.adapter.deleteMany({\n before: body.before ? new Date(body.before) : undefined,\n level: body.level as LogLevel | undefined,\n })\n\n return NextResponse.json({ deleted: count })\n } catch (error) {\n console.error('[@vinetechke/next-error-logger] API error:', error)\n return NextResponse.json(\n { error: 'Failed to delete logs' },\n { status: 500 },\n )\n }\n },\n }\n}\n\n/**\n * Create API route handlers for individual log entries\n *\n * @example\n * ```ts\n * // app/api/admin/logs/[id]/route.ts\n * import { createLogDetailAPIHandlers } from '@vinetechke/next-error-logger/api'\n *\n * const { GET, DELETE } = createLogDetailAPIHandlers({\n * isAuthorized: async () => {\n * const session = await auth()\n * return session?.user?.role === 'ADMIN'\n * },\n * })\n *\n * export { GET, DELETE }\n * ```\n */\nexport function createLogDetailAPIHandlers(config: APIHandlerConfig) {\n const { isAuthorized } = config\n\n return {\n /**\n * GET /api/logs/[id] - Get a single log entry\n */\n GET: async (\n request: NextRequest,\n { params }: { params: Promise<{ id: string }> },\n ): Promise<NextResponse> => {\n // Check authorization\n if (!(await isAuthorized(request))) {\n return NextResponse.json(\n { error: 'Unauthorized' },\n { status: 401 },\n )\n }\n\n // Check if logger is initialized\n if (!isInitialized()) {\n return NextResponse.json(\n { error: 'Logger not initialized' },\n { status: 500 },\n )\n }\n\n const cfg = getConfig()\n const { id } = await params\n\n try {\n const log = await cfg.adapter.findById(id)\n\n if (!log) {\n return NextResponse.json(\n { error: 'Not found' },\n { status: 404 },\n )\n }\n\n return NextResponse.json(log)\n } catch (error) {\n console.error('[@vinetechke/next-error-logger] API error:', error)\n return NextResponse.json(\n { error: 'Failed to fetch log' },\n { status: 500 },\n )\n }\n },\n\n /**\n * DELETE /api/logs/[id] - Delete a single log entry\n */\n DELETE: async (\n request: NextRequest,\n { params }: { params: Promise<{ id: string }> },\n ): Promise<NextResponse> => {\n // Check authorization\n if (!(await isAuthorized(request))) {\n return NextResponse.json(\n { error: 'Unauthorized' },\n { status: 401 },\n )\n }\n\n // Check if logger is initialized\n if (!isInitialized()) {\n return NextResponse.json(\n { error: 'Logger not initialized' },\n { status: 500 },\n )\n }\n\n const cfg = getConfig()\n const { id } = await params\n\n try {\n await cfg.adapter.delete(id)\n return NextResponse.json({ success: true })\n } catch (error) {\n console.error('[@vinetechke/next-error-logger] API error:', error)\n return NextResponse.json(\n { error: 'Failed to delete log' },\n { status: 500 },\n )\n }\n },\n }\n}\n\n/**\n * Get log statistics\n *\n * @example\n * ```ts\n * // app/api/admin/logs/stats/route.ts\n * import { createLogStatsHandler } from '@vinetechke/next-error-logger/api'\n *\n * export const GET = createLogStatsHandler({\n * isAuthorized: async () => {\n * const session = await auth()\n * return session?.user?.role === 'ADMIN'\n * },\n * })\n * ```\n */\nexport function createLogStatsHandler(config: APIHandlerConfig) {\n const { isAuthorized } = config\n\n return async (request: NextRequest): Promise<NextResponse> => {\n // Check authorization\n if (!(await isAuthorized(request))) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n // Check if logger is initialized\n if (!isInitialized()) {\n return NextResponse.json(\n { error: 'Logger not initialized' },\n { status: 500 },\n )\n }\n\n const cfg = getConfig()\n\n try {\n // Get counts for each level\n const [errors, warnings, infos, debugs, total] = await Promise.all([\n cfg.adapter\n .findMany({ level: 'error', limit: 0 })\n .then(r => r.total),\n cfg.adapter\n .findMany({ level: 'warn', limit: 0 })\n .then(r => r.total),\n cfg.adapter\n .findMany({ level: 'info', limit: 0 })\n .then(r => r.total),\n cfg.adapter\n .findMany({ level: 'debug', limit: 0 })\n .then(r => r.total),\n cfg.adapter.findMany({ limit: 0 }).then(r => r.total),\n ])\n\n // Get recent logs (last 24 hours)\n const oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000)\n const recentResult = await cfg.adapter.findMany({\n startDate: oneDayAgo,\n limit: 0,\n })\n\n return NextResponse.json({\n total,\n byLevel: {\n error: errors,\n warn: warnings,\n info: infos,\n debug: debugs,\n },\n last24Hours: recentResult.total,\n })\n } catch (error) {\n console.error('[@vinetechke/next-error-logger] API error:', error)\n return NextResponse.json(\n { error: 'Failed to fetch stats' },\n { status: 500 },\n )\n }\n }\n}\n","import type {\n ErrorLoggerConfig,\n LogLevel,\n ErrorLogEntry,\n RequestContext,\n LogResult,\n} from './types'\n\nlet config: ErrorLoggerConfig | null = null\n\n/**\n * Initialize the error logger with your configuration\n * Must be called before using errorLogger\n *\n * @example\n * ```ts\n * import { initErrorLogger } from '@vinetechke/next-error-logger'\n * import { createPrismaAdapter } from '@vinetechke/next-error-logger/adapters/prisma'\n * import { createNextAuthAdapter } from '@vinetechke/next-error-logger/auth/next-auth'\n * import { prisma } from '@/lib/prisma'\n * import { auth } from '@/auth'\n *\n * initErrorLogger({\n * adapter: createPrismaAdapter(prisma),\n * authAdapter: createNextAuthAdapter(auth),\n * retentionDays: 30,\n * })\n * ```\n */\nexport function initErrorLogger(cfg: ErrorLoggerConfig): void {\n config = {\n consoleInDev: true,\n retentionDays: 30,\n ...cfg,\n }\n}\n\n/**\n * Get the current logger configuration\n * @throws Error if logger is not initialized\n */\nexport function getConfig(): ErrorLoggerConfig {\n if (!config) {\n throw new Error(\n '[@vinetechke/next-error-logger] Logger not initialized. Call initErrorLogger() first.',\n )\n }\n return config\n}\n\n/**\n * Check if logger is initialized\n */\nexport function isInitialized(): boolean {\n return config !== null\n}\n\n/**\n * Internal logging function\n */\nasync function log(\n level: LogLevel,\n message: string,\n error?: Error | null,\n context?: RequestContext,\n): Promise<LogResult> {\n try {\n const cfg = getConfig()\n\n // Check if this level should be captured\n if (cfg.levels && !cfg.levels.includes(level)) {\n return { success: true }\n }\n\n // Console output in development\n if (cfg.consoleInDev && process.env.NODE_ENV === 'development') {\n const consoleMethod =\n level === 'error' ? 'error' : level === 'warn' ? 'warn' : 'log'\n console[consoleMethod](\n `[${level.toUpperCase()}]`,\n message,\n error || '',\n context || '',\n )\n }\n\n // Get user context if auth adapter is provided\n let user: { id: string; email?: string; name?: string } | null = null\n if (cfg.authAdapter) {\n try {\n user = await cfg.authAdapter.getUser()\n } catch {\n // Silently ignore auth errors - user context is optional\n }\n }\n\n // Create the log entry\n const entry = await cfg.adapter.create({\n level,\n message,\n stack: error?.stack || null,\n userId: user?.id || null,\n userEmail: user?.email || null,\n userName: user?.name || null,\n path: context?.path || null,\n method: context?.method || null,\n userAgent: context?.userAgent || null,\n ip: context?.ip || null,\n metadata: context?.metadata || null,\n })\n\n return { success: true, entry }\n } catch (err) {\n // Don't throw on logging failures - just return error result\n console.error('[@vinetechke/next-error-logger] Failed to log:', err)\n return {\n success: false,\n error: err instanceof Error ? err.message : 'Unknown error',\n }\n }\n}\n\n/**\n * Extract request context from a Next.js Request object\n */\nfunction extractRequestContext(request: Request): RequestContext {\n const url = new URL(request.url)\n return {\n path: url.pathname,\n method: request.method,\n userAgent: request.headers.get('user-agent') || undefined,\n ip:\n request.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ||\n request.headers.get('x-real-ip') ||\n undefined,\n }\n}\n\n/**\n * Main error logger instance\n *\n * @example\n * ```ts\n * // Simple logging\n * await errorLogger.error('Something went wrong', error)\n * await errorLogger.warn('Deprecated API used')\n * await errorLogger.info('User completed checkout')\n *\n * // With request context (in API routes)\n * const log = errorLogger.fromRequest(request)\n * await log.error('API failed', error, { orderId: '123' })\n * ```\n */\nexport const errorLogger = {\n /**\n * Log an error with optional Error object and context\n */\n error: (\n message: string,\n error?: Error,\n context?: RequestContext,\n ): Promise<LogResult> => log('error', message, error, context),\n\n /**\n * Log a warning with optional Error object and context\n */\n warn: (\n message: string,\n error?: Error,\n context?: RequestContext,\n ): Promise<LogResult> => log('warn', message, error, context),\n\n /**\n * Log an info message with optional context\n */\n info: (message: string, context?: RequestContext): Promise<LogResult> =>\n log('info', message, null, context),\n\n /**\n * Log a debug message with optional context\n */\n debug: (message: string, context?: RequestContext): Promise<LogResult> =>\n log('debug', message, null, context),\n\n /**\n * Create a logger instance bound to a specific request\n * Automatically extracts path, method, user agent, and IP\n *\n * @example\n * ```ts\n * export async function POST(request: Request) {\n * const log = errorLogger.fromRequest(request)\n *\n * try {\n * // ... your code\n * } catch (error) {\n * await log.error('Failed to process', error as Error, { orderId: '123' })\n * return new Response('Error', { status: 500 })\n * }\n * }\n * ```\n */\n fromRequest: (request: Request) => {\n const baseContext = extractRequestContext(request)\n\n return {\n error: (\n message: string,\n error?: Error,\n metadata?: Record<string, unknown>,\n ): Promise<LogResult> =>\n log('error', message, error, { ...baseContext, metadata }),\n\n warn: (\n message: string,\n metadata?: Record<string, unknown>,\n ): Promise<LogResult> =>\n log('warn', message, null, { ...baseContext, metadata }),\n\n info: (\n message: string,\n metadata?: Record<string, unknown>,\n ): Promise<LogResult> =>\n log('info', message, null, { ...baseContext, metadata }),\n\n debug: (\n message: string,\n metadata?: Record<string, unknown>,\n ): Promise<LogResult> =>\n log('debug', message, null, { ...baseContext, metadata }),\n }\n },\n\n /**\n * Log with explicit user context (when auth adapter is not available)\n *\n * @example\n * ```ts\n * await errorLogger.withUser({ id: 'user-123', email: 'user@example.com' })\n * .error('User action failed', error)\n * ```\n */\n withUser: (user: { id: string; email?: string; name?: string }) => {\n return {\n error: async (\n message: string,\n error?: Error,\n context?: RequestContext,\n ): Promise<LogResult> => {\n const cfg = getConfig()\n try {\n const entry = await cfg.adapter.create({\n level: 'error',\n message,\n stack: error?.stack || null,\n userId: user.id,\n userEmail: user.email || null,\n userName: user.name || null,\n path: context?.path || null,\n method: context?.method || null,\n userAgent: context?.userAgent || null,\n ip: context?.ip || null,\n metadata: context?.metadata || null,\n })\n return { success: true, entry }\n } catch (err) {\n return {\n success: false,\n error:\n err instanceof Error\n ? err.message\n : 'Unknown error',\n }\n }\n },\n\n warn: async (\n message: string,\n context?: RequestContext,\n ): Promise<LogResult> => {\n const cfg = getConfig()\n try {\n const entry = await cfg.adapter.create({\n level: 'warn',\n message,\n stack: null,\n userId: user.id,\n userEmail: user.email || null,\n userName: user.name || null,\n path: context?.path || null,\n method: context?.method || null,\n userAgent: context?.userAgent || null,\n ip: context?.ip || null,\n metadata: context?.metadata || null,\n })\n return { success: true, entry }\n } catch (err) {\n return {\n success: false,\n error:\n err instanceof Error\n ? err.message\n : 'Unknown error',\n }\n }\n },\n\n info: async (\n message: string,\n context?: RequestContext,\n ): Promise<LogResult> => {\n const cfg = getConfig()\n try {\n const entry = await cfg.adapter.create({\n level: 'info',\n message,\n stack: null,\n userId: user.id,\n userEmail: user.email || null,\n userName: user.name || null,\n path: context?.path || null,\n method: context?.method || null,\n userAgent: context?.userAgent || null,\n ip: context?.ip || null,\n metadata: context?.metadata || null,\n })\n return { success: true, entry }\n } catch (err) {\n return {\n success: false,\n error:\n err instanceof Error\n ? err.message\n : 'Unknown error',\n }\n }\n },\n }\n },\n}\n"],"mappings":"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","names":["config"]}
1
+ {"version":3,"sources":["../../src/api/index.ts","../../src/logger.ts"],"sourcesContent":["import { NextRequest, NextResponse } from 'next/server'\nimport { getConfig, isInitialized } from '../logger'\nimport type { LogLevel } from '../types'\n\n/**\n * Configuration for API route handlers\n */\nexport interface APIHandlerConfig {\n /**\n * Function to check if user is authorized to view logs\n * Return true to allow access, false to deny\n *\n * @example\n * ```ts\n * const config = {\n * isAuthorized: async (request) => {\n * const session = await auth()\n * return session?.user?.role === 'admin'\n * }\n * }\n * ```\n */\n isAuthorized: (request: NextRequest) => Promise<boolean>\n}\n\n/**\n * Create API route handlers for the error logger\n *\n * Creates GET, DELETE handlers for listing, fetching, and deleting logs.\n *\n * @example\n * ```ts\n * // app/api/admin/logs/route.ts\n * import { createLogAPIHandlers } from '@vinetechke/next-error-logger/api'\n * import { auth } from '@/auth'\n *\n * const { GET, DELETE } = createLogAPIHandlers({\n * isAuthorized: async () => {\n * const session = await auth()\n * return session?.user?.role === 'ADMIN'\n * },\n * })\n *\n * export { GET, DELETE }\n * ```\n *\n * @example\n * ```ts\n * // app/api/admin/logs/[id]/route.ts\n * import { createLogDetailAPIHandlers } from '@vinetechke/next-error-logger/api'\n * import { auth } from '@/auth'\n *\n * const { GET, DELETE } = createLogDetailAPIHandlers({\n * isAuthorized: async () => {\n * const session = await auth()\n * return session?.user?.role === 'ADMIN'\n * },\n * })\n *\n * export { GET, DELETE }\n * ```\n */\nexport function createLogAPIHandlers(config: APIHandlerConfig) {\n const { isAuthorized } = config\n\n return {\n /**\n * GET /api/logs - List logs with filtering and pagination\n *\n * Query parameters:\n * - page: Page number (default: 1)\n * - limit: Items per page (default: 50)\n * - level: Filter by level (error, warn, info, debug)\n * - userId: Filter by user ID\n * - search: Search in message, stack, path, userEmail\n * - startDate: Filter logs after this date (ISO string)\n * - endDate: Filter logs before this date (ISO string)\n */\n GET: async (request: NextRequest): Promise<NextResponse> => {\n // Check authorization\n if (!(await isAuthorized(request))) {\n return NextResponse.json(\n { error: 'Unauthorized' },\n { status: 401 },\n )\n }\n\n // Check if logger is initialized\n if (!isInitialized()) {\n return NextResponse.json(\n { error: 'Logger not initialized' },\n { status: 500 },\n )\n }\n\n const cfg = getConfig()\n const searchParams = request.nextUrl.searchParams\n\n try {\n const options = {\n page: parseInt(searchParams.get('page') || '1', 10),\n limit: Math.min(\n parseInt(searchParams.get('limit') || '50', 10),\n 100,\n ),\n level: searchParams.get('level') as LogLevel | undefined,\n userId: searchParams.get('userId') || undefined,\n search: searchParams.get('search') || undefined,\n startDate: searchParams.get('startDate')\n ? new Date(searchParams.get('startDate')!)\n : undefined,\n endDate: searchParams.get('endDate')\n ? new Date(searchParams.get('endDate')!)\n : undefined,\n }\n\n const result = await cfg.adapter.findMany(options)\n\n return NextResponse.json(result)\n } catch (error) {\n console.error('[@vinetechke/next-error-logger] API error:', error)\n return NextResponse.json(\n { error: 'Failed to fetch logs' },\n { status: 500 },\n )\n }\n },\n\n /**\n * DELETE /api/logs - Clear logs\n *\n * Body parameters:\n * - before: Delete logs before this date (ISO string)\n * - level: Delete logs with this level only\n */\n DELETE: async (request: NextRequest): Promise<NextResponse> => {\n // Check authorization\n if (!(await isAuthorized(request))) {\n return NextResponse.json(\n { error: 'Unauthorized' },\n { status: 401 },\n )\n }\n\n // Check if logger is initialized\n if (!isInitialized()) {\n return NextResponse.json(\n { error: 'Logger not initialized' },\n { status: 500 },\n )\n }\n\n const cfg = getConfig()\n\n try {\n const body = await request.json().catch(() => ({}))\n\n const count = await cfg.adapter.deleteMany({\n before: body.before ? new Date(body.before) : undefined,\n level: body.level as LogLevel | undefined,\n })\n\n return NextResponse.json({ deleted: count })\n } catch (error) {\n console.error('[@vinetechke/next-error-logger] API error:', error)\n return NextResponse.json(\n { error: 'Failed to delete logs' },\n { status: 500 },\n )\n }\n },\n }\n}\n\n/**\n * Create API route handlers for individual log entries\n *\n * @example\n * ```ts\n * // app/api/admin/logs/[id]/route.ts\n * import { createLogDetailAPIHandlers } from '@vinetechke/next-error-logger/api'\n *\n * const { GET, DELETE } = createLogDetailAPIHandlers({\n * isAuthorized: async () => {\n * const session = await auth()\n * return session?.user?.role === 'ADMIN'\n * },\n * })\n *\n * export { GET, DELETE }\n * ```\n */\nexport function createLogDetailAPIHandlers(config: APIHandlerConfig) {\n const { isAuthorized } = config\n\n return {\n /**\n * GET /api/logs/[id] - Get a single log entry\n */\n GET: async (\n request: NextRequest,\n { params }: { params: Promise<{ id: string }> },\n ): Promise<NextResponse> => {\n // Check authorization\n if (!(await isAuthorized(request))) {\n return NextResponse.json(\n { error: 'Unauthorized' },\n { status: 401 },\n )\n }\n\n // Check if logger is initialized\n if (!isInitialized()) {\n return NextResponse.json(\n { error: 'Logger not initialized' },\n { status: 500 },\n )\n }\n\n const cfg = getConfig()\n const { id } = await params\n\n try {\n const log = await cfg.adapter.findById(id)\n\n if (!log) {\n return NextResponse.json(\n { error: 'Not found' },\n { status: 404 },\n )\n }\n\n return NextResponse.json(log)\n } catch (error) {\n console.error('[@vinetechke/next-error-logger] API error:', error)\n return NextResponse.json(\n { error: 'Failed to fetch log' },\n { status: 500 },\n )\n }\n },\n\n /**\n * DELETE /api/logs/[id] - Delete a single log entry\n */\n DELETE: async (\n request: NextRequest,\n { params }: { params: Promise<{ id: string }> },\n ): Promise<NextResponse> => {\n // Check authorization\n if (!(await isAuthorized(request))) {\n return NextResponse.json(\n { error: 'Unauthorized' },\n { status: 401 },\n )\n }\n\n // Check if logger is initialized\n if (!isInitialized()) {\n return NextResponse.json(\n { error: 'Logger not initialized' },\n { status: 500 },\n )\n }\n\n const cfg = getConfig()\n const { id } = await params\n\n try {\n await cfg.adapter.delete(id)\n return NextResponse.json({ success: true })\n } catch (error) {\n console.error('[@vinetechke/next-error-logger] API error:', error)\n return NextResponse.json(\n { error: 'Failed to delete log' },\n { status: 500 },\n )\n }\n },\n }\n}\n\n/**\n * Get log statistics\n *\n * @example\n * ```ts\n * // app/api/admin/logs/stats/route.ts\n * import { createLogStatsHandler } from '@vinetechke/next-error-logger/api'\n *\n * export const GET = createLogStatsHandler({\n * isAuthorized: async () => {\n * const session = await auth()\n * return session?.user?.role === 'ADMIN'\n * },\n * })\n * ```\n */\nexport function createLogStatsHandler(config: APIHandlerConfig) {\n const { isAuthorized } = config\n\n return async (request: NextRequest): Promise<NextResponse> => {\n // Check authorization\n if (!(await isAuthorized(request))) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n // Check if logger is initialized\n if (!isInitialized()) {\n return NextResponse.json(\n { error: 'Logger not initialized' },\n { status: 500 },\n )\n }\n\n const cfg = getConfig()\n\n try {\n // Get counts for each level\n const [errors, warnings, infos, debugs, total] = await Promise.all([\n cfg.adapter\n .findMany({ level: 'error', limit: 0 })\n .then(r => r.total),\n cfg.adapter\n .findMany({ level: 'warn', limit: 0 })\n .then(r => r.total),\n cfg.adapter\n .findMany({ level: 'info', limit: 0 })\n .then(r => r.total),\n cfg.adapter\n .findMany({ level: 'debug', limit: 0 })\n .then(r => r.total),\n cfg.adapter.findMany({ limit: 0 }).then(r => r.total),\n ])\n\n // Get recent logs (last 24 hours)\n const oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000)\n const recentResult = await cfg.adapter.findMany({\n startDate: oneDayAgo,\n limit: 0,\n })\n\n return NextResponse.json({\n total,\n byLevel: {\n error: errors,\n warn: warnings,\n info: infos,\n debug: debugs,\n },\n last24Hours: recentResult.total,\n })\n } catch (error) {\n console.error('[@vinetechke/next-error-logger] API error:', error)\n return NextResponse.json(\n { error: 'Failed to fetch stats' },\n { status: 500 },\n )\n }\n }\n}\n","import type {\n ErrorLoggerConfig,\n LogLevel,\n ErrorLogEntry,\n RequestContext,\n LogResult,\n} from './types'\n\nlet config: ErrorLoggerConfig | null = null\n\n/**\n * Initialize the error logger with your configuration\n * Must be called before using errorLogger\n *\n * @example\n * ```ts\n * import { initErrorLogger } from '@vinetechke/next-error-logger'\n * import { createPrismaAdapter } from '@vinetechke/next-error-logger/adapters/prisma'\n * import { createNextAuthAdapter } from '@vinetechke/next-error-logger/auth/next-auth'\n * import { prisma } from '@/lib/prisma'\n * import { auth } from '@/auth'\n *\n * initErrorLogger({\n * adapter: createPrismaAdapter(prisma),\n * authAdapter: createNextAuthAdapter(auth),\n * retentionDays: 30,\n * })\n * ```\n */\nexport function initErrorLogger(cfg: ErrorLoggerConfig): void {\n config = {\n consoleInDev: true,\n retentionDays: 30,\n ...cfg,\n }\n}\n\n/**\n * Get the current logger configuration\n * @throws Error if logger is not initialized\n */\nexport function getConfig(): ErrorLoggerConfig {\n if (!config) {\n throw new Error(\n '[@vinetechke/next-error-logger] Logger not initialized. Call initErrorLogger() first.',\n )\n }\n return config\n}\n\n/**\n * Check if logger is initialized\n */\nexport function isInitialized(): boolean {\n return config !== null\n}\n\n/**\n * Internal logging function\n */\nasync function log(\n level: LogLevel,\n message: string,\n error?: Error | null,\n context?: RequestContext,\n): Promise<LogResult> {\n try {\n const cfg = getConfig()\n\n // Check if this level should be captured\n if (cfg.levels && !cfg.levels.includes(level)) {\n return { success: true }\n }\n\n // Console output in development\n if (cfg.consoleInDev && process.env.NODE_ENV === 'development') {\n const consoleMethod =\n level === 'error' ? 'error' : level === 'warn' ? 'warn' : 'log'\n console[consoleMethod](\n `[${level.toUpperCase()}]`,\n message,\n error || '',\n context || '',\n )\n }\n\n // Get user context if auth adapter is provided\n let user: { id: string; email?: string; name?: string } | null = null\n if (cfg.authAdapter) {\n try {\n user = await cfg.authAdapter.getUser()\n } catch {\n // Silently ignore auth errors - user context is optional\n }\n }\n\n // Create the log entry\n const entry = await cfg.adapter.create({\n level,\n message,\n stack: error?.stack || null,\n userId: user?.id || null,\n userEmail: user?.email || null,\n userName: user?.name || null,\n path: context?.path || null,\n method: context?.method || null,\n userAgent: context?.userAgent || null,\n ip: context?.ip || null,\n metadata: context?.metadata || null,\n })\n\n return { success: true, entry }\n } catch (err) {\n // Don't throw on logging failures - just return error result\n console.error('[@vinetechke/next-error-logger] Failed to log:', err)\n return {\n success: false,\n error: err instanceof Error ? err.message : 'Unknown error',\n }\n }\n}\n\n/**\n * Extract request context from a Next.js Request object\n */\nfunction extractRequestContext(request: Request): RequestContext {\n const url = new URL(request.url)\n return {\n path: url.pathname,\n method: request.method,\n userAgent: request.headers.get('user-agent') || undefined,\n ip:\n request.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ||\n request.headers.get('x-real-ip') ||\n undefined,\n }\n}\n\n/**\n * Main error logger instance\n *\n * @example\n * ```ts\n * // Simple logging\n * await errorLogger.error('Something went wrong', error)\n * await errorLogger.warn('Deprecated API used')\n * await errorLogger.info('User completed checkout')\n *\n * // With request context (in API routes)\n * const log = errorLogger.fromRequest(request)\n * await log.error('API failed', error, { orderId: '123' })\n * ```\n */\nexport const errorLogger = {\n /**\n * Log an error with optional Error object and context\n */\n error: (\n message: string,\n error?: Error,\n context?: RequestContext,\n ): Promise<LogResult> => log('error', message, error, context),\n\n /**\n * Log a warning with optional Error object and context\n */\n warn: (\n message: string,\n error?: Error,\n context?: RequestContext,\n ): Promise<LogResult> => log('warn', message, error, context),\n\n /**\n * Log an info message with optional context\n */\n info: (message: string, context?: RequestContext): Promise<LogResult> =>\n log('info', message, null, context),\n\n /**\n * Log a debug message with optional context\n */\n debug: (message: string, context?: RequestContext): Promise<LogResult> =>\n log('debug', message, null, context),\n\n /**\n * Create a logger instance bound to a specific request\n * Automatically extracts path, method, user agent, and IP\n *\n * @example\n * ```ts\n * export async function POST(request: Request) {\n * const log = errorLogger.fromRequest(request)\n *\n * try {\n * // ... your code\n * } catch (error) {\n * await log.error('Failed to process', error as Error, { orderId: '123' })\n * return new Response('Error', { status: 500 })\n * }\n * }\n * ```\n */\n fromRequest: (request: Request) => {\n const baseContext = extractRequestContext(request)\n\n return {\n error: (\n message: string,\n error?: Error,\n metadata?: Record<string, unknown>,\n ): Promise<LogResult> =>\n log('error', message, error, { ...baseContext, metadata }),\n\n warn: (\n message: string,\n metadata?: Record<string, unknown>,\n ): Promise<LogResult> =>\n log('warn', message, null, { ...baseContext, metadata }),\n\n info: (\n message: string,\n metadata?: Record<string, unknown>,\n ): Promise<LogResult> =>\n log('info', message, null, { ...baseContext, metadata }),\n\n debug: (\n message: string,\n metadata?: Record<string, unknown>,\n ): Promise<LogResult> =>\n log('debug', message, null, { ...baseContext, metadata }),\n }\n },\n\n /**\n * Log with explicit user context (when auth adapter is not available)\n *\n * @example\n * ```ts\n * await errorLogger.withUser({ id: 'user-123', email: 'user@example.com' })\n * .error('User action failed', error)\n * ```\n */\n withUser: (user: { id: string; email?: string; name?: string }) => {\n return {\n error: async (\n message: string,\n error?: Error,\n context?: RequestContext,\n ): Promise<LogResult> => {\n const cfg = getConfig()\n try {\n const entry = await cfg.adapter.create({\n level: 'error',\n message,\n stack: error?.stack || null,\n userId: user.id,\n userEmail: user.email || null,\n userName: user.name || null,\n path: context?.path || null,\n method: context?.method || null,\n userAgent: context?.userAgent || null,\n ip: context?.ip || null,\n metadata: context?.metadata || null,\n })\n return { success: true, entry }\n } catch (err) {\n return {\n success: false,\n error:\n err instanceof Error\n ? err.message\n : 'Unknown error',\n }\n }\n },\n\n warn: async (\n message: string,\n context?: RequestContext,\n ): Promise<LogResult> => {\n const cfg = getConfig()\n try {\n const entry = await cfg.adapter.create({\n level: 'warn',\n message,\n stack: null,\n userId: user.id,\n userEmail: user.email || null,\n userName: user.name || null,\n path: context?.path || null,\n method: context?.method || null,\n userAgent: context?.userAgent || null,\n ip: context?.ip || null,\n metadata: context?.metadata || null,\n })\n return { success: true, entry }\n } catch (err) {\n return {\n success: false,\n error:\n err instanceof Error\n ? err.message\n : 'Unknown error',\n }\n }\n },\n\n info: async (\n message: string,\n context?: RequestContext,\n ): Promise<LogResult> => {\n const cfg = getConfig()\n try {\n const entry = await cfg.adapter.create({\n level: 'info',\n message,\n stack: null,\n userId: user.id,\n userEmail: user.email || null,\n userName: user.name || null,\n path: context?.path || null,\n method: context?.method || null,\n userAgent: context?.userAgent || null,\n ip: context?.ip || null,\n metadata: context?.metadata || null,\n })\n return { success: true, entry }\n } catch (err) {\n return {\n success: false,\n error:\n err instanceof Error\n ? err.message\n : 'Unknown error',\n }\n }\n },\n }\n },\n}\n"],"mappings":"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","names":["config"]}
package/dist/api/index.js CHANGED
@@ -1,5 +1,3 @@
1
- "use client";
2
-
3
1
  // src/api/index.ts
4
2
  import { NextResponse } from "next/server";
5
3