@vinetechke/next-error-logger 0.1.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +442 -0
  3. package/dist/adapters/drizzle.cjs +123 -0
  4. package/dist/adapters/drizzle.cjs.map +1 -0
  5. package/dist/adapters/drizzle.d.cts +76 -0
  6. package/dist/adapters/drizzle.d.ts +76 -0
  7. package/dist/adapters/drizzle.js +99 -0
  8. package/dist/adapters/drizzle.js.map +1 -0
  9. package/dist/adapters/prisma.cjs +120 -0
  10. package/dist/adapters/prisma.cjs.map +1 -0
  11. package/dist/adapters/prisma.d.cts +75 -0
  12. package/dist/adapters/prisma.d.ts +75 -0
  13. package/dist/adapters/prisma.js +96 -0
  14. package/dist/adapters/prisma.js.map +1 -0
  15. package/dist/adapters/sql.cjs +206 -0
  16. package/dist/adapters/sql.cjs.map +1 -0
  17. package/dist/adapters/sql.d.cts +111 -0
  18. package/dist/adapters/sql.d.ts +111 -0
  19. package/dist/adapters/sql.js +182 -0
  20. package/dist/adapters/sql.js.map +1 -0
  21. package/dist/api/index.cjs +257 -0
  22. package/dist/api/index.cjs.map +1 -0
  23. package/dist/api/index.d.cts +137 -0
  24. package/dist/api/index.d.ts +137 -0
  25. package/dist/api/index.js +231 -0
  26. package/dist/api/index.js.map +1 -0
  27. package/dist/auth/clerk.cjs +60 -0
  28. package/dist/auth/clerk.cjs.map +1 -0
  29. package/dist/auth/clerk.d.cts +83 -0
  30. package/dist/auth/clerk.d.ts +83 -0
  31. package/dist/auth/clerk.js +36 -0
  32. package/dist/auth/clerk.js.map +1 -0
  33. package/dist/auth/next-auth.cjs +50 -0
  34. package/dist/auth/next-auth.cjs.map +1 -0
  35. package/dist/auth/next-auth.d.cts +53 -0
  36. package/dist/auth/next-auth.d.ts +53 -0
  37. package/dist/auth/next-auth.js +26 -0
  38. package/dist/auth/next-auth.js.map +1 -0
  39. package/dist/components/index.cjs +1175 -0
  40. package/dist/components/index.cjs.map +1 -0
  41. package/dist/components/index.d.cts +141 -0
  42. package/dist/components/index.d.ts +141 -0
  43. package/dist/components/index.js +1147 -0
  44. package/dist/components/index.js.map +1 -0
  45. package/dist/index.cjs +241 -0
  46. package/dist/index.cjs.map +1 -0
  47. package/dist/index.d.cts +109 -0
  48. package/dist/index.d.ts +109 -0
  49. package/dist/index.js +212 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/schemas/drizzle.cjs +100 -0
  52. package/dist/schemas/drizzle.cjs.map +1 -0
  53. package/dist/schemas/drizzle.d.cts +32 -0
  54. package/dist/schemas/drizzle.d.ts +32 -0
  55. package/dist/schemas/drizzle.js +74 -0
  56. package/dist/schemas/drizzle.js.map +1 -0
  57. package/dist/types-C3x_Ry2e.d.cts +195 -0
  58. package/dist/types-C3x_Ry2e.d.ts +195 -0
  59. package/package.json +128 -0
  60. package/schemas/prisma.prisma +23 -0
  61. package/schemas/schema.sql +75 -0
@@ -0,0 +1,206 @@
1
+ "use client";
2
+ "use strict";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/adapters/sql.ts
22
+ var sql_exports = {};
23
+ __export(sql_exports, {
24
+ createSQLAdapter: () => createSQLAdapter
25
+ });
26
+ module.exports = __toCommonJS(sql_exports);
27
+ function createSQLAdapter(config) {
28
+ const { executor, tableName = "error_logs", dialect } = config;
29
+ const ph = (index) => {
30
+ switch (dialect) {
31
+ case "postgres":
32
+ return `$${index}`;
33
+ case "mysql":
34
+ case "sqlite":
35
+ return "?";
36
+ }
37
+ };
38
+ const toCamelCase = (row) => ({
39
+ id: row.id,
40
+ level: row.level,
41
+ message: row.message,
42
+ stack: row.stack,
43
+ userId: row.user_id,
44
+ userEmail: row.user_email,
45
+ userName: row.user_name,
46
+ path: row.path,
47
+ method: row.method,
48
+ userAgent: row.user_agent,
49
+ ip: row.ip,
50
+ metadata: row.metadata,
51
+ createdAt: new Date(row.created_at)
52
+ });
53
+ return {
54
+ async create(entry) {
55
+ const id = crypto.randomUUID();
56
+ const now = (/* @__PURE__ */ new Date()).toISOString();
57
+ const sql = `
58
+ INSERT INTO ${tableName} (
59
+ id, level, message, stack, user_id, user_email, user_name,
60
+ path, method, user_agent, ip, metadata, created_at
61
+ ) VALUES (
62
+ ${ph(1)}, ${ph(2)}, ${ph(3)}, ${ph(4)}, ${ph(5)}, ${ph(6)}, ${ph(7)},
63
+ ${ph(8)}, ${ph(9)}, ${ph(10)}, ${ph(11)}, ${ph(12)}, ${ph(13)}
64
+ ) RETURNING *
65
+ `;
66
+ const params = [
67
+ id,
68
+ entry.level,
69
+ entry.message,
70
+ entry.stack,
71
+ entry.userId,
72
+ entry.userEmail,
73
+ entry.userName,
74
+ entry.path,
75
+ entry.method,
76
+ entry.userAgent,
77
+ entry.ip,
78
+ entry.metadata ? JSON.stringify(entry.metadata) : null,
79
+ now
80
+ ];
81
+ if (dialect !== "postgres") {
82
+ const insertSql = `
83
+ INSERT INTO ${tableName} (
84
+ id, level, message, stack, user_id, user_email, user_name,
85
+ path, method, user_agent, ip, metadata, created_at
86
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
87
+ `;
88
+ await executor.execute(insertSql, params);
89
+ const selectSql = `SELECT * FROM ${tableName} WHERE id = ?`;
90
+ const rows2 = await executor.query(
91
+ selectSql,
92
+ [id]
93
+ );
94
+ return toCamelCase(rows2[0]);
95
+ }
96
+ const rows = await executor.query(
97
+ sql,
98
+ params
99
+ );
100
+ return toCamelCase(rows[0]);
101
+ },
102
+ async findMany(options) {
103
+ const {
104
+ page = 1,
105
+ limit = 50,
106
+ level,
107
+ userId,
108
+ search,
109
+ startDate,
110
+ endDate,
111
+ orderBy = "createdAt",
112
+ order = "desc"
113
+ } = options;
114
+ const conditions = [];
115
+ const params = [];
116
+ let paramIndex = 1;
117
+ if (level) {
118
+ conditions.push(`level = ${ph(paramIndex++)}`);
119
+ params.push(level);
120
+ }
121
+ if (userId) {
122
+ conditions.push(`user_id = ${ph(paramIndex++)}`);
123
+ params.push(userId);
124
+ }
125
+ if (search) {
126
+ const searchPattern = `%${search}%`;
127
+ conditions.push(`(
128
+ message ILIKE ${ph(paramIndex++)} OR
129
+ stack ILIKE ${ph(paramIndex++)} OR
130
+ path ILIKE ${ph(paramIndex++)} OR
131
+ user_email ILIKE ${ph(paramIndex++)}
132
+ )`);
133
+ params.push(
134
+ searchPattern,
135
+ searchPattern,
136
+ searchPattern,
137
+ searchPattern
138
+ );
139
+ }
140
+ if (startDate) {
141
+ conditions.push(`created_at >= ${ph(paramIndex++)}`);
142
+ params.push(startDate.toISOString());
143
+ }
144
+ if (endDate) {
145
+ conditions.push(`created_at <= ${ph(paramIndex++)}`);
146
+ params.push(endDate.toISOString());
147
+ }
148
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
149
+ const orderColumn = orderBy === "level" ? "level" : "created_at";
150
+ const orderDirection = order.toUpperCase();
151
+ const offset = (page - 1) * limit;
152
+ const sql = `
153
+ SELECT * FROM ${tableName}
154
+ ${whereClause}
155
+ ORDER BY ${orderColumn} ${orderDirection}
156
+ LIMIT ${limit} OFFSET ${offset}
157
+ `;
158
+ const countSql = `SELECT COUNT(*) as count FROM ${tableName} ${whereClause}`;
159
+ const [rows, countResult] = await Promise.all([
160
+ executor.query(sql, params),
161
+ executor.query(countSql, params)
162
+ ]);
163
+ return {
164
+ logs: rows.map(toCamelCase),
165
+ total: Number(countResult[0]?.count || 0)
166
+ };
167
+ },
168
+ async findById(id) {
169
+ const sql = `SELECT * FROM ${tableName} WHERE id = ${ph(1)}`;
170
+ const rows = await executor.query(sql, [
171
+ id
172
+ ]);
173
+ if (rows.length === 0) {
174
+ return null;
175
+ }
176
+ return toCamelCase(rows[0]);
177
+ },
178
+ async delete(id) {
179
+ const sql = `DELETE FROM ${tableName} WHERE id = ${ph(1)}`;
180
+ await executor.execute(sql, [id]);
181
+ },
182
+ async deleteMany(options) {
183
+ const conditions = [];
184
+ const params = [];
185
+ let paramIndex = 1;
186
+ if (options.before) {
187
+ conditions.push(`created_at < ${ph(paramIndex++)}`);
188
+ params.push(options.before.toISOString());
189
+ }
190
+ if (options.level) {
191
+ conditions.push(`level = ${ph(paramIndex++)}`);
192
+ params.push(options.level);
193
+ }
194
+ if (conditions.length === 0) {
195
+ return 0;
196
+ }
197
+ const sql = `DELETE FROM ${tableName} WHERE ${conditions.join(" AND ")}`;
198
+ return executor.execute(sql, params);
199
+ }
200
+ };
201
+ }
202
+ // Annotate the CommonJS export names for ESM import in node:
203
+ 0 && (module.exports = {
204
+ createSQLAdapter
205
+ });
206
+ //# sourceMappingURL=sql.cjs.map
@@ -0,0 +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"]}
@@ -0,0 +1,111 @@
1
+ import { D as DatabaseAdapter } from '../types-C3x_Ry2e.cjs';
2
+
3
+ /**
4
+ * Generic SQL query executor interface
5
+ * Implement this to connect to any SQL database
6
+ */
7
+ interface SQLExecutor {
8
+ /**
9
+ * Execute a parameterized SQL query
10
+ * @param sql - SQL query with placeholders ($1, $2, etc. for Postgres; ?, ?, etc. for MySQL)
11
+ * @param params - Array of parameter values
12
+ * @returns Array of result rows
13
+ */
14
+ query<T = unknown>(sql: string, params?: unknown[]): Promise<T[]>;
15
+ /**
16
+ * Execute a parameterized SQL query that returns affected row count
17
+ * @param sql - SQL query
18
+ * @param params - Array of parameter values
19
+ * @returns Number of affected rows
20
+ */
21
+ execute(sql: string, params?: unknown[]): Promise<number>;
22
+ }
23
+ /**
24
+ * Configuration for the SQL adapter
25
+ */
26
+ interface SQLAdapterConfig {
27
+ /** Your SQL executor implementation */
28
+ executor: SQLExecutor;
29
+ /** Table name (default: 'error_logs') */
30
+ tableName?: string;
31
+ /** SQL dialect for placeholder syntax */
32
+ dialect: 'postgres' | 'mysql' | 'sqlite';
33
+ }
34
+ /**
35
+ * Create a raw SQL database adapter
36
+ *
37
+ * Works with any SQL database - just provide an executor that matches the SQLExecutor interface.
38
+ *
39
+ * Required table schema (PostgreSQL example):
40
+ *
41
+ * ```sql
42
+ * CREATE TABLE error_logs (
43
+ * id TEXT PRIMARY KEY,
44
+ * level TEXT NOT NULL,
45
+ * message TEXT NOT NULL,
46
+ * stack TEXT,
47
+ * user_id TEXT,
48
+ * user_email TEXT,
49
+ * user_name TEXT,
50
+ * path TEXT,
51
+ * method TEXT,
52
+ * user_agent TEXT,
53
+ * ip TEXT,
54
+ * metadata JSONB,
55
+ * created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
56
+ * );
57
+ *
58
+ * CREATE INDEX idx_error_logs_level ON error_logs(level);
59
+ * CREATE INDEX idx_error_logs_user_id ON error_logs(user_id);
60
+ * CREATE INDEX idx_error_logs_created_at ON error_logs(created_at);
61
+ * ```
62
+ *
63
+ * @example
64
+ * ```ts
65
+ * // With node-postgres (pg)
66
+ * import { createSQLAdapter } from '@vinetechke/next-error-logger/adapters/sql'
67
+ * import { Pool } from 'pg'
68
+ *
69
+ * const pool = new Pool({ connectionString: process.env.DATABASE_URL })
70
+ *
71
+ * const adapter = createSQLAdapter({
72
+ * executor: {
73
+ * query: async (sql, params) => {
74
+ * const result = await pool.query(sql, params)
75
+ * return result.rows
76
+ * },
77
+ * execute: async (sql, params) => {
78
+ * const result = await pool.query(sql, params)
79
+ * return result.rowCount || 0
80
+ * },
81
+ * },
82
+ * dialect: 'postgres',
83
+ * })
84
+ * ```
85
+ *
86
+ * @example
87
+ * ```ts
88
+ * // With mysql2
89
+ * import { createSQLAdapter } from '@vinetechke/next-error-logger/adapters/sql'
90
+ * import mysql from 'mysql2/promise'
91
+ *
92
+ * const pool = mysql.createPool({ uri: process.env.DATABASE_URL })
93
+ *
94
+ * const adapter = createSQLAdapter({
95
+ * executor: {
96
+ * query: async (sql, params) => {
97
+ * const [rows] = await pool.query(sql, params)
98
+ * return rows as unknown[]
99
+ * },
100
+ * execute: async (sql, params) => {
101
+ * const [result] = await pool.query(sql, params)
102
+ * return (result as { affectedRows: number }).affectedRows
103
+ * },
104
+ * },
105
+ * dialect: 'mysql',
106
+ * })
107
+ * ```
108
+ */
109
+ declare function createSQLAdapter(config: SQLAdapterConfig): DatabaseAdapter;
110
+
111
+ export { type SQLAdapterConfig, type SQLExecutor, createSQLAdapter };
@@ -0,0 +1,111 @@
1
+ import { D as DatabaseAdapter } from '../types-C3x_Ry2e.js';
2
+
3
+ /**
4
+ * Generic SQL query executor interface
5
+ * Implement this to connect to any SQL database
6
+ */
7
+ interface SQLExecutor {
8
+ /**
9
+ * Execute a parameterized SQL query
10
+ * @param sql - SQL query with placeholders ($1, $2, etc. for Postgres; ?, ?, etc. for MySQL)
11
+ * @param params - Array of parameter values
12
+ * @returns Array of result rows
13
+ */
14
+ query<T = unknown>(sql: string, params?: unknown[]): Promise<T[]>;
15
+ /**
16
+ * Execute a parameterized SQL query that returns affected row count
17
+ * @param sql - SQL query
18
+ * @param params - Array of parameter values
19
+ * @returns Number of affected rows
20
+ */
21
+ execute(sql: string, params?: unknown[]): Promise<number>;
22
+ }
23
+ /**
24
+ * Configuration for the SQL adapter
25
+ */
26
+ interface SQLAdapterConfig {
27
+ /** Your SQL executor implementation */
28
+ executor: SQLExecutor;
29
+ /** Table name (default: 'error_logs') */
30
+ tableName?: string;
31
+ /** SQL dialect for placeholder syntax */
32
+ dialect: 'postgres' | 'mysql' | 'sqlite';
33
+ }
34
+ /**
35
+ * Create a raw SQL database adapter
36
+ *
37
+ * Works with any SQL database - just provide an executor that matches the SQLExecutor interface.
38
+ *
39
+ * Required table schema (PostgreSQL example):
40
+ *
41
+ * ```sql
42
+ * CREATE TABLE error_logs (
43
+ * id TEXT PRIMARY KEY,
44
+ * level TEXT NOT NULL,
45
+ * message TEXT NOT NULL,
46
+ * stack TEXT,
47
+ * user_id TEXT,
48
+ * user_email TEXT,
49
+ * user_name TEXT,
50
+ * path TEXT,
51
+ * method TEXT,
52
+ * user_agent TEXT,
53
+ * ip TEXT,
54
+ * metadata JSONB,
55
+ * created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
56
+ * );
57
+ *
58
+ * CREATE INDEX idx_error_logs_level ON error_logs(level);
59
+ * CREATE INDEX idx_error_logs_user_id ON error_logs(user_id);
60
+ * CREATE INDEX idx_error_logs_created_at ON error_logs(created_at);
61
+ * ```
62
+ *
63
+ * @example
64
+ * ```ts
65
+ * // With node-postgres (pg)
66
+ * import { createSQLAdapter } from '@vinetechke/next-error-logger/adapters/sql'
67
+ * import { Pool } from 'pg'
68
+ *
69
+ * const pool = new Pool({ connectionString: process.env.DATABASE_URL })
70
+ *
71
+ * const adapter = createSQLAdapter({
72
+ * executor: {
73
+ * query: async (sql, params) => {
74
+ * const result = await pool.query(sql, params)
75
+ * return result.rows
76
+ * },
77
+ * execute: async (sql, params) => {
78
+ * const result = await pool.query(sql, params)
79
+ * return result.rowCount || 0
80
+ * },
81
+ * },
82
+ * dialect: 'postgres',
83
+ * })
84
+ * ```
85
+ *
86
+ * @example
87
+ * ```ts
88
+ * // With mysql2
89
+ * import { createSQLAdapter } from '@vinetechke/next-error-logger/adapters/sql'
90
+ * import mysql from 'mysql2/promise'
91
+ *
92
+ * const pool = mysql.createPool({ uri: process.env.DATABASE_URL })
93
+ *
94
+ * const adapter = createSQLAdapter({
95
+ * executor: {
96
+ * query: async (sql, params) => {
97
+ * const [rows] = await pool.query(sql, params)
98
+ * return rows as unknown[]
99
+ * },
100
+ * execute: async (sql, params) => {
101
+ * const [result] = await pool.query(sql, params)
102
+ * return (result as { affectedRows: number }).affectedRows
103
+ * },
104
+ * },
105
+ * dialect: 'mysql',
106
+ * })
107
+ * ```
108
+ */
109
+ declare function createSQLAdapter(config: SQLAdapterConfig): DatabaseAdapter;
110
+
111
+ export { type SQLAdapterConfig, type SQLExecutor, createSQLAdapter };
@@ -0,0 +1,182 @@
1
+ "use client";
2
+
3
+ // src/adapters/sql.ts
4
+ function createSQLAdapter(config) {
5
+ const { executor, tableName = "error_logs", dialect } = config;
6
+ const ph = (index) => {
7
+ switch (dialect) {
8
+ case "postgres":
9
+ return `$${index}`;
10
+ case "mysql":
11
+ case "sqlite":
12
+ return "?";
13
+ }
14
+ };
15
+ const toCamelCase = (row) => ({
16
+ id: row.id,
17
+ level: row.level,
18
+ message: row.message,
19
+ stack: row.stack,
20
+ userId: row.user_id,
21
+ userEmail: row.user_email,
22
+ userName: row.user_name,
23
+ path: row.path,
24
+ method: row.method,
25
+ userAgent: row.user_agent,
26
+ ip: row.ip,
27
+ metadata: row.metadata,
28
+ createdAt: new Date(row.created_at)
29
+ });
30
+ return {
31
+ async create(entry) {
32
+ const id = crypto.randomUUID();
33
+ const now = (/* @__PURE__ */ new Date()).toISOString();
34
+ const sql = `
35
+ INSERT INTO ${tableName} (
36
+ id, level, message, stack, user_id, user_email, user_name,
37
+ path, method, user_agent, ip, metadata, created_at
38
+ ) VALUES (
39
+ ${ph(1)}, ${ph(2)}, ${ph(3)}, ${ph(4)}, ${ph(5)}, ${ph(6)}, ${ph(7)},
40
+ ${ph(8)}, ${ph(9)}, ${ph(10)}, ${ph(11)}, ${ph(12)}, ${ph(13)}
41
+ ) RETURNING *
42
+ `;
43
+ const params = [
44
+ id,
45
+ entry.level,
46
+ entry.message,
47
+ entry.stack,
48
+ entry.userId,
49
+ entry.userEmail,
50
+ entry.userName,
51
+ entry.path,
52
+ entry.method,
53
+ entry.userAgent,
54
+ entry.ip,
55
+ entry.metadata ? JSON.stringify(entry.metadata) : null,
56
+ now
57
+ ];
58
+ if (dialect !== "postgres") {
59
+ const insertSql = `
60
+ INSERT INTO ${tableName} (
61
+ id, level, message, stack, user_id, user_email, user_name,
62
+ path, method, user_agent, ip, metadata, created_at
63
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
64
+ `;
65
+ await executor.execute(insertSql, params);
66
+ const selectSql = `SELECT * FROM ${tableName} WHERE id = ?`;
67
+ const rows2 = await executor.query(
68
+ selectSql,
69
+ [id]
70
+ );
71
+ return toCamelCase(rows2[0]);
72
+ }
73
+ const rows = await executor.query(
74
+ sql,
75
+ params
76
+ );
77
+ return toCamelCase(rows[0]);
78
+ },
79
+ async findMany(options) {
80
+ const {
81
+ page = 1,
82
+ limit = 50,
83
+ level,
84
+ userId,
85
+ search,
86
+ startDate,
87
+ endDate,
88
+ orderBy = "createdAt",
89
+ order = "desc"
90
+ } = options;
91
+ const conditions = [];
92
+ const params = [];
93
+ let paramIndex = 1;
94
+ if (level) {
95
+ conditions.push(`level = ${ph(paramIndex++)}`);
96
+ params.push(level);
97
+ }
98
+ if (userId) {
99
+ conditions.push(`user_id = ${ph(paramIndex++)}`);
100
+ params.push(userId);
101
+ }
102
+ if (search) {
103
+ const searchPattern = `%${search}%`;
104
+ conditions.push(`(
105
+ message ILIKE ${ph(paramIndex++)} OR
106
+ stack ILIKE ${ph(paramIndex++)} OR
107
+ path ILIKE ${ph(paramIndex++)} OR
108
+ user_email ILIKE ${ph(paramIndex++)}
109
+ )`);
110
+ params.push(
111
+ searchPattern,
112
+ searchPattern,
113
+ searchPattern,
114
+ searchPattern
115
+ );
116
+ }
117
+ if (startDate) {
118
+ conditions.push(`created_at >= ${ph(paramIndex++)}`);
119
+ params.push(startDate.toISOString());
120
+ }
121
+ if (endDate) {
122
+ conditions.push(`created_at <= ${ph(paramIndex++)}`);
123
+ params.push(endDate.toISOString());
124
+ }
125
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
126
+ const orderColumn = orderBy === "level" ? "level" : "created_at";
127
+ const orderDirection = order.toUpperCase();
128
+ const offset = (page - 1) * limit;
129
+ const sql = `
130
+ SELECT * FROM ${tableName}
131
+ ${whereClause}
132
+ ORDER BY ${orderColumn} ${orderDirection}
133
+ LIMIT ${limit} OFFSET ${offset}
134
+ `;
135
+ const countSql = `SELECT COUNT(*) as count FROM ${tableName} ${whereClause}`;
136
+ const [rows, countResult] = await Promise.all([
137
+ executor.query(sql, params),
138
+ executor.query(countSql, params)
139
+ ]);
140
+ return {
141
+ logs: rows.map(toCamelCase),
142
+ total: Number(countResult[0]?.count || 0)
143
+ };
144
+ },
145
+ async findById(id) {
146
+ const sql = `SELECT * FROM ${tableName} WHERE id = ${ph(1)}`;
147
+ const rows = await executor.query(sql, [
148
+ id
149
+ ]);
150
+ if (rows.length === 0) {
151
+ return null;
152
+ }
153
+ return toCamelCase(rows[0]);
154
+ },
155
+ async delete(id) {
156
+ const sql = `DELETE FROM ${tableName} WHERE id = ${ph(1)}`;
157
+ await executor.execute(sql, [id]);
158
+ },
159
+ async deleteMany(options) {
160
+ const conditions = [];
161
+ const params = [];
162
+ let paramIndex = 1;
163
+ if (options.before) {
164
+ conditions.push(`created_at < ${ph(paramIndex++)}`);
165
+ params.push(options.before.toISOString());
166
+ }
167
+ if (options.level) {
168
+ conditions.push(`level = ${ph(paramIndex++)}`);
169
+ params.push(options.level);
170
+ }
171
+ if (conditions.length === 0) {
172
+ return 0;
173
+ }
174
+ const sql = `DELETE FROM ${tableName} WHERE ${conditions.join(" AND ")}`;
175
+ return executor.execute(sql, params);
176
+ }
177
+ };
178
+ }
179
+ export {
180
+ createSQLAdapter
181
+ };
182
+ //# sourceMappingURL=sql.js.map
@@ -0,0 +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"]}