@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
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 VineTech
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,442 @@
1
+ # @vinetechke/next-error-logger
2
+
3
+ > **Beta Release** - This package is under active development. APIs may change before v1.0.0.
4
+
5
+ Simple error logging for Next.js apps with user context, multiple database adapters, and a built-in dashboard.
6
+
7
+ [![npm version](https://badge.fury.io/js/%40vinetechke%2Fnext-error-logger.svg)](https://www.npmjs.com/package/@vinetechke/next-error-logger)
8
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
9
+
10
+ ## Features
11
+
12
+ - **User Context** - Captures user ID, email, and name from your auth provider
13
+ - **Multiple Database Adapters** - Works with Prisma, Drizzle, or raw SQL
14
+ - **Multiple Auth Adapters** - Supports NextAuth, Clerk, or custom auth
15
+ - **Built-in Dashboard** - Ready-to-use LogViewer component
16
+ - **Error Boundary** - React error boundary with automatic logging
17
+ - **TypeScript First** - Full type safety
18
+ - **Request Context** - Auto-captures path, method, IP, and user agent
19
+
20
+ ## Requirements
21
+
22
+ - Next.js 14 or later
23
+ - React 18 or later
24
+ - Node.js 18 or later
25
+
26
+ ## Installation
27
+
28
+ ```bash
29
+ npm install @vinetechke/next-error-logger
30
+ ```
31
+
32
+ ```bash
33
+ pnpm add @vinetechke/next-error-logger
34
+ ```
35
+
36
+ ```bash
37
+ yarn add @vinetechke/next-error-logger
38
+ ```
39
+
40
+ ## Quick Start
41
+
42
+ ### 1. Set Up Your Database Schema
43
+
44
+ #### Prisma
45
+
46
+ Add to your `schema.prisma`:
47
+
48
+ ```prisma
49
+ model ErrorLog {
50
+ id String @id @default(cuid())
51
+ level String
52
+ message String @db.Text
53
+ stack String? @db.Text
54
+ userId String?
55
+ userEmail String?
56
+ userName String?
57
+ path String?
58
+ method String?
59
+ userAgent String?
60
+ ip String?
61
+ metadata Json?
62
+ createdAt DateTime @default(now())
63
+
64
+ @@index([level])
65
+ @@index([userId])
66
+ @@index([createdAt])
67
+ @@map("error_logs")
68
+ }
69
+ ```
70
+
71
+ Then run:
72
+
73
+ ```bash
74
+ npx prisma db push
75
+ ```
76
+
77
+ #### Drizzle
78
+
79
+ ```typescript
80
+ import { pgTable, text, timestamp, json, index } from 'drizzle-orm/pg-core'
81
+
82
+ export const errorLogs = pgTable('error_logs', {
83
+ id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()),
84
+ level: text('level').notNull(),
85
+ message: text('message').notNull(),
86
+ stack: text('stack'),
87
+ userId: text('user_id'),
88
+ userEmail: text('user_email'),
89
+ userName: text('user_name'),
90
+ path: text('path'),
91
+ method: text('method'),
92
+ userAgent: text('user_agent'),
93
+ ip: text('ip'),
94
+ metadata: json('metadata'),
95
+ createdAt: timestamp('created_at').defaultNow().notNull(),
96
+ }, (table) => ({
97
+ levelIdx: index('error_logs_level_idx').on(table.level),
98
+ userIdIdx: index('error_logs_user_id_idx').on(table.userId),
99
+ createdAtIdx: index('error_logs_created_at_idx').on(table.createdAt),
100
+ }))
101
+ ```
102
+
103
+ #### Raw SQL
104
+
105
+ See [schemas/schema.sql](./schemas/schema.sql) for PostgreSQL, MySQL, and SQLite schemas.
106
+
107
+ ### 2. Initialize the Logger
108
+
109
+ Create `lib/error-logger.ts`:
110
+
111
+ ```typescript
112
+ import { initErrorLogger, errorLogger } from '@vinetechke/next-error-logger'
113
+ import { createPrismaAdapter } from '@vinetechke/next-error-logger/adapters/prisma'
114
+ import { createNextAuthAdapter } from '@vinetechke/next-error-logger/auth/next-auth'
115
+ import { prisma } from '@/lib/prisma'
116
+ import { auth } from '@/auth'
117
+
118
+ initErrorLogger({
119
+ adapter: createPrismaAdapter(prisma),
120
+ authAdapter: createNextAuthAdapter(auth),
121
+ retentionDays: 30,
122
+ })
123
+
124
+ export { errorLogger }
125
+ ```
126
+
127
+ ### 3. Log Errors in Your API Routes
128
+
129
+ ```typescript
130
+ import { errorLogger } from '@/lib/error-logger'
131
+
132
+ export async function POST(request: Request) {
133
+ const log = errorLogger.fromRequest(request)
134
+
135
+ try {
136
+ const body = await request.json()
137
+ // ... process order
138
+
139
+ await log.info('Order created', { orderId: order.id })
140
+ return Response.json(order)
141
+ } catch (error) {
142
+ await log.error('Failed to create order', error as Error, {
143
+ body: await request.json(),
144
+ })
145
+ return Response.json({ error: 'Failed to create order' }, { status: 500 })
146
+ }
147
+ }
148
+ ```
149
+
150
+ ### 4. Create API Routes for the Dashboard
151
+
152
+ ```typescript
153
+ // app/api/admin/logs/route.ts
154
+ import { createLogAPIHandlers } from '@vinetechke/next-error-logger/api'
155
+ import { auth } from '@/auth'
156
+
157
+ const { GET, DELETE } = createLogAPIHandlers({
158
+ isAuthorized: async () => {
159
+ const session = await auth()
160
+ return session?.user?.role === 'ADMIN'
161
+ },
162
+ })
163
+
164
+ export { GET, DELETE }
165
+ ```
166
+
167
+ ```typescript
168
+ // app/api/admin/logs/[id]/route.ts
169
+ import { createLogDetailAPIHandlers } from '@vinetechke/next-error-logger/api'
170
+ import { auth } from '@/auth'
171
+
172
+ const { GET, DELETE } = createLogDetailAPIHandlers({
173
+ isAuthorized: async () => {
174
+ const session = await auth()
175
+ return session?.user?.role === 'ADMIN'
176
+ },
177
+ })
178
+
179
+ export { GET, DELETE }
180
+ ```
181
+
182
+ ### 5. Add the Dashboard Page
183
+
184
+ ```tsx
185
+ // app/admin/logs/page.tsx
186
+ import { LogViewer } from '@vinetechke/next-error-logger/components'
187
+
188
+ export default function LogsPage() {
189
+ return (
190
+ <div className="p-6">
191
+ <h1 className="text-2xl font-bold mb-6">Error Logs</h1>
192
+ <LogViewer
193
+ apiBasePath="/api/admin/logs"
194
+ pageSize={50}
195
+ showDelete
196
+ autoRefresh={30}
197
+ />
198
+ </div>
199
+ )
200
+ }
201
+ ```
202
+
203
+ ## Database Adapters
204
+
205
+ ### Prisma
206
+
207
+ ```typescript
208
+ import { createPrismaAdapter } from '@vinetechke/next-error-logger/adapters/prisma'
209
+ import { prisma } from '@/lib/prisma'
210
+
211
+ const adapter = createPrismaAdapter(prisma)
212
+ ```
213
+
214
+ ### Drizzle
215
+
216
+ ```typescript
217
+ import { createDrizzleAdapter } from '@vinetechke/next-error-logger/adapters/drizzle'
218
+ import { db } from '@/lib/db'
219
+ import { errorLogs } from '@/lib/schema'
220
+ import { eq, and, or, like, lt, gte, lte, desc, asc } from 'drizzle-orm'
221
+
222
+ const adapter = createDrizzleAdapter({
223
+ db,
224
+ table: errorLogs,
225
+ operators: { eq, and, or, like, lt, gte, lte, desc, asc },
226
+ })
227
+ ```
228
+
229
+ ### Raw SQL
230
+
231
+ Works with any SQL database:
232
+
233
+ ```typescript
234
+ import { createSQLAdapter } from '@vinetechke/next-error-logger/adapters/sql'
235
+ import { Pool } from 'pg'
236
+
237
+ const pool = new Pool({ connectionString: process.env.DATABASE_URL })
238
+
239
+ const adapter = createSQLAdapter({
240
+ executor: {
241
+ query: async (sql, params) => {
242
+ const result = await pool.query(sql, params)
243
+ return result.rows
244
+ },
245
+ execute: async (sql, params) => {
246
+ const result = await pool.query(sql, params)
247
+ return result.rowCount || 0
248
+ },
249
+ },
250
+ dialect: 'postgres',
251
+ })
252
+ ```
253
+
254
+ ## Auth Adapters
255
+
256
+ ### NextAuth (Auth.js v5)
257
+
258
+ ```typescript
259
+ import { createNextAuthAdapter } from '@vinetechke/next-error-logger/auth/next-auth'
260
+ import { auth } from '@/auth'
261
+
262
+ const authAdapter = createNextAuthAdapter(auth)
263
+ ```
264
+
265
+ ### NextAuth v4
266
+
267
+ ```typescript
268
+ import { createNextAuthAdapter } from '@vinetechke/next-error-logger/auth/next-auth'
269
+ import { getServerSession } from 'next-auth'
270
+ import { authOptions } from '@/app/api/auth/[...nextauth]/route'
271
+
272
+ const authAdapter = createNextAuthAdapter(async () => {
273
+ return getServerSession(authOptions)
274
+ })
275
+ ```
276
+
277
+ ### Clerk
278
+
279
+ ```typescript
280
+ import { createClerkAdapter } from '@vinetechke/next-error-logger/auth/clerk'
281
+ import { auth, clerkClient } from '@clerk/nextjs/server'
282
+
283
+ const authAdapter = createClerkAdapter({
284
+ auth,
285
+ fetchUser: async (userId) => {
286
+ return clerkClient.users.getUser(userId)
287
+ },
288
+ })
289
+ ```
290
+
291
+ ### Custom Auth
292
+
293
+ ```typescript
294
+ import type { AuthAdapter } from '@vinetechke/next-error-logger'
295
+
296
+ const customAuthAdapter: AuthAdapter = {
297
+ async getUser() {
298
+ const user = await getMyUser()
299
+ if (!user) return null
300
+ return {
301
+ id: user.id,
302
+ email: user.email,
303
+ name: user.name,
304
+ }
305
+ },
306
+ }
307
+ ```
308
+
309
+ ## API Reference
310
+
311
+ ### errorLogger
312
+
313
+ ```typescript
314
+ // Simple logging
315
+ await errorLogger.error('Something went wrong', error)
316
+ await errorLogger.warn('Deprecated API used')
317
+ await errorLogger.info('User completed checkout')
318
+ await errorLogger.debug('Debug info')
319
+
320
+ // With request context (recommended for API routes)
321
+ const log = errorLogger.fromRequest(request)
322
+ await log.error('API failed', error, { orderId: '123' })
323
+
324
+ // With explicit user context
325
+ await errorLogger.withUser({ id: 'user-123', email: 'user@example.com' })
326
+ .error('User action failed', error)
327
+ ```
328
+
329
+ ### LogViewer Component
330
+
331
+ ```tsx
332
+ <LogViewer
333
+ apiBasePath="/api/admin/logs"
334
+ pageSize={50}
335
+ showDelete={true}
336
+ autoRefresh={30}
337
+ className="my-custom-class"
338
+ theme={{
339
+ errorBg: '#fee2e2',
340
+ errorText: '#dc2626',
341
+ warnBg: '#fef3c7',
342
+ warnText: '#d97706',
343
+ }}
344
+ onLogSelect={(log) => {}}
345
+ />
346
+ ```
347
+
348
+ ### ErrorBoundary Component
349
+
350
+ ```tsx
351
+ import { ErrorBoundary } from '@vinetechke/next-error-logger/components'
352
+ import { errorLogger } from '@/lib/error-logger'
353
+
354
+ <ErrorBoundary
355
+ fallback={(error, reset) => (
356
+ <div>
357
+ <h2>Something went wrong!</h2>
358
+ <button onClick={reset}>Try again</button>
359
+ </div>
360
+ )}
361
+ onError={async (error, info) => {
362
+ await errorLogger.error('React render error', error, {
363
+ metadata: { componentStack: info.componentStack },
364
+ })
365
+ }}
366
+ >
367
+ <MyApp />
368
+ </ErrorBoundary>
369
+ ```
370
+
371
+ ## Configuration Options
372
+
373
+ ```typescript
374
+ initErrorLogger({
375
+ adapter: createPrismaAdapter(prisma),
376
+ authAdapter: createNextAuthAdapter(auth),
377
+ retentionDays: 30,
378
+ levels: ['error', 'warn'],
379
+ consoleInDev: true,
380
+ })
381
+ ```
382
+
383
+ | Option | Type | Default | Description |
384
+ |--------|------|---------|-------------|
385
+ | `adapter` | `DatabaseAdapter` | required | Database adapter for storing logs |
386
+ | `authAdapter` | `AuthAdapter` | - | Auth adapter for user context |
387
+ | `retentionDays` | `number` | `30` | Days to retain logs |
388
+ | `levels` | `LogLevel[]` | all | Only capture these levels |
389
+ | `consoleInDev` | `boolean` | `true` | Console output in development |
390
+
391
+ ## TypeScript
392
+
393
+ Full TypeScript support with exported types:
394
+
395
+ ```typescript
396
+ import type {
397
+ ErrorLogEntry,
398
+ LogLevel,
399
+ DatabaseAdapter,
400
+ AuthAdapter,
401
+ ErrorLoggerConfig,
402
+ QueryOptions,
403
+ LogViewerProps,
404
+ } from '@vinetechke/next-error-logger'
405
+ ```
406
+
407
+ ## Development
408
+
409
+ ```bash
410
+ # Install dependencies
411
+ pnpm install
412
+
413
+ # Run tests
414
+ pnpm test
415
+
416
+ # Build
417
+ pnpm build
418
+
419
+ # Lint
420
+ pnpm lint
421
+
422
+ # Format
423
+ pnpm format
424
+ ```
425
+
426
+ ## Changelog
427
+
428
+ ### 0.1.0-beta.1
429
+
430
+ - Initial beta release
431
+ - Prisma, Drizzle, and raw SQL adapters
432
+ - NextAuth and Clerk auth adapters
433
+ - LogViewer dashboard component
434
+ - ErrorBoundary component
435
+
436
+ ## Contributing
437
+
438
+ Contributions welcome. Please open an issue to discuss changes before submitting a PR.
439
+
440
+ ## License
441
+
442
+ MIT License - see [LICENSE](./LICENSE) for details.
@@ -0,0 +1,123 @@
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/drizzle.ts
22
+ var drizzle_exports = {};
23
+ __export(drizzle_exports, {
24
+ createDrizzleAdapter: () => createDrizzleAdapter
25
+ });
26
+ module.exports = __toCommonJS(drizzle_exports);
27
+ function createDrizzleAdapter(config) {
28
+ const { db, table, operators } = config;
29
+ const { eq, and, or, like, lt, gte, lte, desc, asc } = operators;
30
+ return {
31
+ async create(entry) {
32
+ const id = crypto.randomUUID();
33
+ const result = await db.insert(table).values({
34
+ id,
35
+ level: entry.level,
36
+ message: entry.message,
37
+ stack: entry.stack,
38
+ userId: entry.userId,
39
+ userEmail: entry.userEmail,
40
+ userName: entry.userName,
41
+ path: entry.path,
42
+ method: entry.method,
43
+ userAgent: entry.userAgent,
44
+ ip: entry.ip,
45
+ metadata: entry.metadata
46
+ }).returning();
47
+ return result[0];
48
+ },
49
+ async findMany(options) {
50
+ const {
51
+ page = 1,
52
+ limit = 50,
53
+ level,
54
+ userId,
55
+ search,
56
+ startDate,
57
+ endDate,
58
+ orderBy = "createdAt",
59
+ order = "desc"
60
+ } = options;
61
+ const conditions = [];
62
+ if (level) {
63
+ conditions.push(eq(table.level, level));
64
+ }
65
+ if (userId) {
66
+ conditions.push(eq(table.userId, userId));
67
+ }
68
+ if (search) {
69
+ conditions.push(
70
+ or(
71
+ like(table.message, `%${search}%`),
72
+ like(table.stack, `%${search}%`),
73
+ like(table.path, `%${search}%`),
74
+ like(table.userEmail, `%${search}%`)
75
+ )
76
+ );
77
+ }
78
+ if (startDate) {
79
+ conditions.push(gte(table.createdAt, startDate));
80
+ }
81
+ if (endDate) {
82
+ conditions.push(lte(table.createdAt, endDate));
83
+ }
84
+ const whereCondition = conditions.length > 0 ? and(...conditions) : void 0;
85
+ const orderFn = order === "desc" ? desc : asc;
86
+ const orderColumn = orderBy === "level" ? table.level : table.createdAt;
87
+ let query = db.select().from(table);
88
+ if (whereCondition) {
89
+ query = query.where(whereCondition);
90
+ }
91
+ const logs = await query.orderBy(orderFn(orderColumn)).limit(limit).offset((page - 1) * limit);
92
+ const total = await db.$count(table, whereCondition);
93
+ return { logs, total };
94
+ },
95
+ async findById(id) {
96
+ const results = await db.select().from(table).where(eq(table.id, id)).limit(1).offset(0);
97
+ return results[0] || null;
98
+ },
99
+ async delete(id) {
100
+ await db.delete(table).where(eq(table.id, id));
101
+ },
102
+ async deleteMany(options) {
103
+ const conditions = [];
104
+ if (options.before) {
105
+ conditions.push(lt(table.createdAt, options.before));
106
+ }
107
+ if (options.level) {
108
+ conditions.push(eq(table.level, options.level));
109
+ }
110
+ const whereCondition = conditions.length > 0 ? and(...conditions) : void 0;
111
+ if (!whereCondition) {
112
+ return 0;
113
+ }
114
+ const result = await db.delete(table).where(whereCondition);
115
+ return result.rowCount || 0;
116
+ }
117
+ };
118
+ }
119
+ // Annotate the CommonJS export names for ESM import in node:
120
+ 0 && (module.exports = {
121
+ createDrizzleAdapter
122
+ });
123
+ //# sourceMappingURL=drizzle.cjs.map
@@ -0,0 +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":[]}
@@ -0,0 +1,76 @@
1
+ import { D as DatabaseAdapter } from '../types-C3x_Ry2e.cjs';
2
+
3
+ /**
4
+ * Drizzle table interface
5
+ * Using flexible typing to support various Drizzle table definitions
6
+ */
7
+ type DrizzleTable = any;
8
+ /**
9
+ * Drizzle database interface
10
+ * Using flexible typing to support various Drizzle dialects and query patterns
11
+ */
12
+ type DrizzleDB = any;
13
+ /**
14
+ * Configuration for the Drizzle adapter
15
+ */
16
+ interface DrizzleAdapterConfig {
17
+ /** Your Drizzle database instance */
18
+ db: DrizzleDB;
19
+ /** Your ErrorLog table definition */
20
+ table: DrizzleTable;
21
+ /** Drizzle operators (eq, and, or, like, lt, desc, etc.) */
22
+ operators: {
23
+ eq: (column: unknown, value: unknown) => unknown;
24
+ and: (...conditions: unknown[]) => unknown;
25
+ or: (...conditions: unknown[]) => unknown;
26
+ like: (column: unknown, value: string) => unknown;
27
+ lt: (column: unknown, value: unknown) => unknown;
28
+ gte: (column: unknown, value: unknown) => unknown;
29
+ lte: (column: unknown, value: unknown) => unknown;
30
+ desc: (column: unknown) => unknown;
31
+ asc: (column: unknown) => unknown;
32
+ };
33
+ }
34
+ /**
35
+ * Create a Drizzle database adapter
36
+ *
37
+ * Requires an errorLogs table in your Drizzle schema:
38
+ *
39
+ * ```ts
40
+ * // schema.ts
41
+ * import { pgTable, text, timestamp, json } from 'drizzle-orm/pg-core'
42
+ *
43
+ * export const errorLogs = pgTable('error_logs', {
44
+ * id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()),
45
+ * level: text('level').notNull(),
46
+ * message: text('message').notNull(),
47
+ * stack: text('stack'),
48
+ * userId: text('user_id'),
49
+ * userEmail: text('user_email'),
50
+ * userName: text('user_name'),
51
+ * path: text('path'),
52
+ * method: text('method'),
53
+ * userAgent: text('user_agent'),
54
+ * ip: text('ip'),
55
+ * metadata: json('metadata'),
56
+ * createdAt: timestamp('created_at').defaultNow().notNull(),
57
+ * })
58
+ * ```
59
+ *
60
+ * @example
61
+ * ```ts
62
+ * import { createDrizzleAdapter } from '@vinetechke/next-error-logger/adapters/drizzle'
63
+ * import { db } from '@/lib/db'
64
+ * import { errorLogs } from '@/lib/schema'
65
+ * import { eq, and, or, like, lt, gte, lte, desc, asc } from 'drizzle-orm'
66
+ *
67
+ * const adapter = createDrizzleAdapter({
68
+ * db,
69
+ * table: errorLogs,
70
+ * operators: { eq, and, or, like, lt, gte, lte, desc, asc },
71
+ * })
72
+ * ```
73
+ */
74
+ declare function createDrizzleAdapter(config: DrizzleAdapterConfig): DatabaseAdapter;
75
+
76
+ export { type DrizzleAdapterConfig, createDrizzleAdapter };