@spfn/monitor 0.1.0-beta.17 → 0.1.0-beta.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +348 -126
- package/dist/index.d.ts +12 -12
- package/dist/index.js.map +1 -1
- package/dist/nextjs/client.js.map +1 -1
- package/dist/server.d.ts +2 -2
- package/dist/server.js.map +1 -1
- package/package.json +10 -9
- package/dist/{index-BiN0PoSx.d.ts → index-C9IUDNIv.d.ts} +10 -10
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as _spfn_core_nextjs from '@spfn/core/nextjs';
|
|
2
2
|
import * as _spfn_core_route from '@spfn/core/route';
|
|
3
3
|
import * as _sinclair_typebox from '@sinclair/typebox';
|
|
4
|
-
import { M as MonitorStats, m as monitorRouter } from './index-
|
|
5
|
-
export { a as ERROR_GROUP_STATUSES, E as ErrorGroupStatus, b as LOG_LEVELS, L as LogLevel } from './index-
|
|
4
|
+
import { M as MonitorStats, m as monitorRouter } from './index-C9IUDNIv.js';
|
|
5
|
+
export { a as ERROR_GROUP_STATUSES, E as ErrorGroupStatus, b as LOG_LEVELS, L as LogLevel } from './index-C9IUDNIv.js';
|
|
6
6
|
import 'drizzle-orm/pg-core';
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -33,14 +33,14 @@ declare const monitorApi: _spfn_core_nextjs.Client<_spfn_core_route.Router<{
|
|
|
33
33
|
offset: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
|
|
34
34
|
}>;
|
|
35
35
|
}, {}, {
|
|
36
|
+
status: "active" | "resolved" | "ignored";
|
|
37
|
+
path: string;
|
|
36
38
|
id: number;
|
|
37
39
|
fingerprint: string;
|
|
38
40
|
name: string;
|
|
39
41
|
message: string;
|
|
40
|
-
path: string;
|
|
41
42
|
method: string;
|
|
42
43
|
statusCode: number;
|
|
43
|
-
status: "active" | "resolved" | "ignored";
|
|
44
44
|
count: number;
|
|
45
45
|
firstSeenAt: Date;
|
|
46
46
|
lastSeenAt: Date;
|
|
@@ -54,14 +54,14 @@ declare const monitorApi: _spfn_core_nextjs.Client<_spfn_core_route.Router<{
|
|
|
54
54
|
}>;
|
|
55
55
|
}, {}, {
|
|
56
56
|
group: {
|
|
57
|
+
status: "active" | "resolved" | "ignored";
|
|
58
|
+
path: string;
|
|
57
59
|
id: number;
|
|
58
60
|
fingerprint: string;
|
|
59
61
|
name: string;
|
|
60
62
|
message: string;
|
|
61
|
-
path: string;
|
|
62
63
|
method: string;
|
|
63
64
|
statusCode: number;
|
|
64
|
-
status: "active" | "resolved" | "ignored";
|
|
65
65
|
count: number;
|
|
66
66
|
firstSeenAt: Date;
|
|
67
67
|
lastSeenAt: Date;
|
|
@@ -70,15 +70,15 @@ declare const monitorApi: _spfn_core_nextjs.Client<_spfn_core_route.Router<{
|
|
|
70
70
|
updatedAt: Date;
|
|
71
71
|
};
|
|
72
72
|
events: {
|
|
73
|
+
query: Record<string, string> | null;
|
|
73
74
|
id: number;
|
|
74
75
|
statusCode: number;
|
|
75
76
|
createdAt: Date;
|
|
76
77
|
updatedAt: Date;
|
|
77
|
-
|
|
78
|
+
headers: Record<string, string> | null;
|
|
78
79
|
groupId: number;
|
|
79
80
|
requestId: string | null;
|
|
80
81
|
userId: string | null;
|
|
81
|
-
headers: Record<string, string> | null;
|
|
82
82
|
stackTrace: string | null;
|
|
83
83
|
metadata: Record<string, unknown> | null;
|
|
84
84
|
}[];
|
|
@@ -91,14 +91,14 @@ declare const monitorApi: _spfn_core_nextjs.Client<_spfn_core_route.Router<{
|
|
|
91
91
|
status: _sinclair_typebox.TString;
|
|
92
92
|
}>;
|
|
93
93
|
}, {}, {
|
|
94
|
+
status: "active" | "resolved" | "ignored";
|
|
95
|
+
path: string;
|
|
94
96
|
id: number;
|
|
95
97
|
fingerprint: string;
|
|
96
98
|
name: string;
|
|
97
99
|
message: string;
|
|
98
|
-
path: string;
|
|
99
100
|
method: string;
|
|
100
101
|
statusCode: number;
|
|
101
|
-
status: "active" | "resolved" | "ignored";
|
|
102
102
|
count: number;
|
|
103
103
|
firstSeenAt: Date;
|
|
104
104
|
lastSeenAt: Date;
|
|
@@ -115,15 +115,15 @@ declare const monitorApi: _spfn_core_nextjs.Client<_spfn_core_route.Router<{
|
|
|
115
115
|
offset: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
|
|
116
116
|
}>;
|
|
117
117
|
}, {}, {
|
|
118
|
+
query: Record<string, string> | null;
|
|
118
119
|
id: number;
|
|
119
120
|
statusCode: number;
|
|
120
121
|
createdAt: Date;
|
|
121
122
|
updatedAt: Date;
|
|
122
|
-
|
|
123
|
+
headers: Record<string, string> | null;
|
|
123
124
|
groupId: number;
|
|
124
125
|
requestId: string | null;
|
|
125
126
|
userId: string | null;
|
|
126
|
-
headers: Record<string, string> | null;
|
|
127
127
|
stackTrace: string | null;
|
|
128
128
|
metadata: Record<string, unknown> | null;
|
|
129
129
|
}[]>;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/server/entities/schema.ts","../src/server/entities/error-groups.ts","../src/server/entities/error-events.ts","../src/server/entities/logs.ts"],"sourcesContent":["/**\n * @spfn/monitor\n *\n * Error tracking, log management, and monitoring dashboard for SPFN\n *\n * @example\n * ```typescript\n * // Server-side\n * import { monitorRouter, createMonitorErrorHandler } from '@spfn/monitor/server';\n *\n * // Client-side (API calls)\n * import { monitorApi } from '@spfn/monitor';\n * const stats = await monitorApi.getStats.call({});\n * ```\n */\n\n// ============================================================================\n// API Client\n// ============================================================================\nimport { createApi } from '@spfn/core/nextjs';\nimport { monitorRouter } from './server/routes';\n\n/**\n * Type-safe API client for monitor routes\n *\n * @example\n * ```typescript\n * import { monitorApi } from '@spfn/monitor';\n *\n * // Get dashboard stats\n * const stats = await monitorApi.getStats.call({});\n *\n * // List errors\n * const errors = await monitorApi.listErrors.call({\n * query: { status: 'active', limit: 20 }\n * });\n * ```\n */\nexport const monitorApi = createApi<typeof monitorRouter>({});\n\n// Router type for external use\nexport type MonitorRouter = typeof monitorRouter;\n\n// ============================================================================\n// Shared Types (client-safe)\n// ============================================================================\nexport type {\n ErrorGroupStatus,\n LogLevel,\n} from './server/entities';\n\nexport type { MonitorStats } from './server/services/stats.service';\n\nexport {\n ERROR_GROUP_STATUSES,\n LOG_LEVELS,\n} from './server/entities';\n","/**\n * @spfn/monitor - Database Schema Definition\n *\n * Defines the 'spfn_monitor' PostgreSQL schema for all monitor-related tables\n */\n\nimport { createSchema } from '@spfn/core/db';\n\n/**\n * Monitor schema for all monitoring tables\n * Tables: error_groups, error_events, logs\n */\nexport const monitorSchema = createSchema('@spfn/monitor');\n","/**\n * @spfn/monitor - Error Groups Entity\n *\n * Groups errors by fingerprint (name + message + path) to avoid\n * duplicate tracking. Tracks count, status, and first/last seen times.\n */\n\nimport { text, integer, index } from 'drizzle-orm/pg-core';\nimport { id, timestamps, enumText, utcTimestamp } from '@spfn/core/db';\nimport { monitorSchema } from './schema';\n\n/**\n * Error group status types\n */\nexport const ERROR_GROUP_STATUSES = ['active', 'resolved', 'ignored'] as const;\nexport type ErrorGroupStatus = typeof ERROR_GROUP_STATUSES[number];\n\n/**\n * Error groups table — groups errors by fingerprint\n */\nexport const errorGroups = monitorSchema.table('error_groups',\n {\n // Primary Key\n id: id(),\n\n // Business Key — SHA-256 first 16 hex chars of (name:message:path)\n fingerprint: text('fingerprint').notNull().unique(),\n\n // Error identification\n name: text('name').notNull(),\n message: text('message').notNull(),\n path: text('path').notNull(),\n method: text('method').notNull(),\n statusCode: integer('status_code').notNull(),\n\n // Status\n status: enumText('status', ERROR_GROUP_STATUSES).default('active').notNull(),\n\n // Counters\n count: integer('count').notNull().default(1),\n\n // Timeline\n firstSeenAt: utcTimestamp('first_seen_at').notNull(),\n lastSeenAt: utcTimestamp('last_seen_at').notNull(),\n resolvedAt: utcTimestamp('resolved_at'),\n\n ...timestamps(),\n },\n (table) => [\n index('monitor_eg_fingerprint_idx').on(table.fingerprint),\n index('monitor_eg_status_idx').on(table.status),\n index('monitor_eg_last_seen_at_idx').on(table.lastSeenAt),\n index('monitor_eg_path_idx').on(table.path),\n ]
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/server/entities/schema.ts","../src/server/entities/error-groups.ts","../src/server/entities/error-events.ts","../src/server/entities/logs.ts"],"sourcesContent":["/**\n * @spfn/monitor\n *\n * Error tracking, log management, and monitoring dashboard for SPFN\n *\n * @example\n * ```typescript\n * // Server-side\n * import { monitorRouter, createMonitorErrorHandler } from '@spfn/monitor/server';\n *\n * // Client-side (API calls)\n * import { monitorApi } from '@spfn/monitor';\n * const stats = await monitorApi.getStats.call({});\n * ```\n */\n\n// ============================================================================\n// API Client\n// ============================================================================\nimport { createApi } from '@spfn/core/nextjs';\nimport { monitorRouter } from './server/routes';\n\n/**\n * Type-safe API client for monitor routes\n *\n * @example\n * ```typescript\n * import { monitorApi } from '@spfn/monitor';\n *\n * // Get dashboard stats\n * const stats = await monitorApi.getStats.call({});\n *\n * // List errors\n * const errors = await monitorApi.listErrors.call({\n * query: { status: 'active', limit: 20 }\n * });\n * ```\n */\nexport const monitorApi = createApi<typeof monitorRouter>({});\n\n// Router type for external use\nexport type MonitorRouter = typeof monitorRouter;\n\n// ============================================================================\n// Shared Types (client-safe)\n// ============================================================================\nexport type {\n ErrorGroupStatus,\n LogLevel,\n} from './server/entities';\n\nexport type { MonitorStats } from './server/services/stats.service';\n\nexport {\n ERROR_GROUP_STATUSES,\n LOG_LEVELS,\n} from './server/entities';\n","/**\n * @spfn/monitor - Database Schema Definition\n *\n * Defines the 'spfn_monitor' PostgreSQL schema for all monitor-related tables\n */\n\nimport { createSchema } from '@spfn/core/db';\n\n/**\n * Monitor schema for all monitoring tables\n * Tables: error_groups, error_events, logs\n */\nexport const monitorSchema = createSchema('@spfn/monitor');\n","/**\n * @spfn/monitor - Error Groups Entity\n *\n * Groups errors by fingerprint (name + message + path) to avoid\n * duplicate tracking. Tracks count, status, and first/last seen times.\n */\n\nimport { text, integer, index } from 'drizzle-orm/pg-core';\nimport { id, timestamps, enumText, utcTimestamp } from '@spfn/core/db';\nimport { monitorSchema } from './schema';\n\n/**\n * Error group status types\n */\nexport const ERROR_GROUP_STATUSES = ['active', 'resolved', 'ignored'] as const;\nexport type ErrorGroupStatus = typeof ERROR_GROUP_STATUSES[number];\n\n/**\n * Error groups table — groups errors by fingerprint\n */\nexport const errorGroups = monitorSchema.table('error_groups',\n {\n // Primary Key\n id: id(),\n\n // Business Key — SHA-256 first 16 hex chars of (name:message:path)\n fingerprint: text('fingerprint').notNull().unique(),\n\n // Error identification\n name: text('name').notNull(),\n message: text('message').notNull(),\n path: text('path').notNull(),\n method: text('method').notNull(),\n statusCode: integer('status_code').notNull(),\n\n // Status\n status: enumText('status', ERROR_GROUP_STATUSES).default('active').notNull(),\n\n // Counters\n count: integer('count').notNull().default(1),\n\n // Timeline\n firstSeenAt: utcTimestamp('first_seen_at').notNull(),\n lastSeenAt: utcTimestamp('last_seen_at').notNull(),\n resolvedAt: utcTimestamp('resolved_at'),\n\n ...timestamps(),\n },\n (table) => [\n index('monitor_eg_fingerprint_idx').on(table.fingerprint),\n index('monitor_eg_status_idx').on(table.status),\n index('monitor_eg_last_seen_at_idx').on(table.lastSeenAt),\n index('monitor_eg_path_idx').on(table.path),\n ],\n);\n\nexport type ErrorGroup = typeof errorGroups.$inferSelect;\nexport type NewErrorGroup = typeof errorGroups.$inferInsert;\n","/**\n * @spfn/monitor - Error Events Entity\n *\n * Individual error occurrences linked to an error group.\n * Stores request-specific context (headers, query, stack trace).\n */\n\nimport { text, integer, jsonb, index } from 'drizzle-orm/pg-core';\nimport { id, timestamps, foreignKey } from '@spfn/core/db';\nimport { monitorSchema } from './schema';\nimport { errorGroups } from './error-groups';\n\n/**\n * Error events table — individual error occurrences\n */\nexport const errorEvents = monitorSchema.table('error_events',\n {\n // Primary Key\n id: id(),\n\n // Foreign Key\n groupId: foreignKey('group', () => errorGroups.id).notNull(),\n\n // Request context\n requestId: text('request_id'),\n userId: text('user_id'),\n statusCode: integer('status_code').notNull(),\n\n // Request details\n headers: jsonb('headers').$type<Record<string, string>>(),\n query: jsonb('query').$type<Record<string, string>>(),\n stackTrace: text('stack_trace'),\n metadata: jsonb('metadata').$type<Record<string, unknown>>(),\n\n ...timestamps(),\n },\n (table) => [\n index('monitor_ee_group_id_idx').on(table.groupId),\n index('monitor_ee_created_at_idx').on(table.createdAt),\n index('monitor_ee_user_id_idx').on(table.userId),\n ],\n);\n\nexport type ErrorEvent = typeof errorEvents.$inferSelect;\nexport type NewErrorEvent = typeof errorEvents.$inferInsert;\n","/**\n * @spfn/monitor - Logs Entity\n *\n * Developer logs stored in DB for retrieval via admin dashboard.\n * Supports level-based filtering, source tracking, and metadata.\n */\n\nimport { text, jsonb, index } from 'drizzle-orm/pg-core';\nimport { id, timestamps, enumText } from '@spfn/core/db';\nimport { monitorSchema } from './schema';\n\n/**\n * Log level types\n */\nexport const LOG_LEVELS = ['debug', 'info', 'warn', 'error', 'fatal'] as const;\nexport type LogLevel = typeof LOG_LEVELS[number];\n\n/**\n * Logs table — developer log entries\n */\nexport const logs = monitorSchema.table('logs',\n {\n // Primary Key\n id: id(),\n\n // Log data\n level: enumText('level', LOG_LEVELS).notNull(),\n message: text('message').notNull(),\n source: text('source'),\n\n // Request context\n requestId: text('request_id'),\n userId: text('user_id'),\n\n // Extra data\n metadata: jsonb('metadata').$type<Record<string, unknown>>(),\n\n ...timestamps(),\n },\n (table) => [\n index('monitor_log_level_idx').on(table.level),\n index('monitor_log_source_idx').on(table.source),\n index('monitor_log_created_at_idx').on(table.createdAt),\n ],\n);\n\nexport type Log = typeof logs.$inferSelect;\nexport type NewLog = typeof logs.$inferInsert;\n"],"mappings":"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","names":["text","integer","index","id","timestamps","id","text","integer","timestamps","index","text","jsonb","index","id","timestamps","enumText","id","enumText","text","jsonb","timestamps","index"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/nextjs/components/monitor-dashboard.tsx","../../src/nextjs/components/stats-overview.tsx","../../src/nextjs/components/error-list-view.tsx","../../src/nextjs/components/error-detail-view.tsx","../../src/nextjs/components/log-viewer.tsx"],"sourcesContent":["/**\n * @spfn/monitor - Monitor Dashboard Component\n *\n * Main entry point combining StatsOverview, ErrorListView, and LogViewer in tabs\n */\n\nimport { useState } from 'react';\nimport { StatsOverview } from './stats-overview';\nimport { ErrorListView } from './error-list-view';\nimport { ErrorDetailView } from './error-detail-view';\nimport { LogViewer } from './log-viewer';\n\ntype Tab = 'errors' | 'logs';\n\nexport function MonitorDashboard()\n{\n const [tab, setTab] = useState<Tab>('errors');\n const [selectedErrorId, setSelectedErrorId] = useState<number | null>(null);\n\n return (\n <div className=\"space-y-6\">\n {/* Stats */}\n <StatsOverview />\n\n {/* Tabs */}\n <div className=\"flex gap-1 border-b border-neutral-200 dark:border-neutral-800\">\n <TabButton active={tab === 'errors'} onClick={() => { setTab('errors'); setSelectedErrorId(null); }}>\n Errors\n </TabButton>\n <TabButton active={tab === 'logs'} onClick={() => setTab('logs')}>\n Logs\n </TabButton>\n </div>\n\n {/* Content */}\n {tab === 'errors' && !selectedErrorId && (\n <ErrorListView onSelect={setSelectedErrorId} />\n )}\n {tab === 'errors' && selectedErrorId && (\n <ErrorDetailView\n errorId={selectedErrorId}\n onBack={() => setSelectedErrorId(null)}\n />\n )}\n {tab === 'logs' && (\n <LogViewer />\n )}\n </div>\n );\n}\n\nfunction TabButton({\n active,\n onClick,\n children,\n}: {\n active: boolean;\n onClick: () => void;\n children: React.ReactNode;\n})\n{\n return (\n <button\n onClick={onClick}\n className={`px-4 py-2 text-sm font-medium border-b-2 -mb-px transition-colors ${\n active\n ? 'border-neutral-900 dark:border-neutral-100 text-neutral-900 dark:text-neutral-100'\n : 'border-transparent text-neutral-500 hover:text-neutral-700 dark:hover:text-neutral-300'\n }`}\n >\n {children}\n </button>\n );\n}\n","/**\n * @spfn/monitor - Stats Overview Component\n *\n * Displays error/log counts and trend indicators\n */\n\nimport { useState, useEffect, useCallback } from 'react';\nimport { monitorApi } from '@spfn/monitor';\nimport type { MonitorStats } from '@spfn/monitor';\n\nexport function StatsOverview()\n{\n const [stats, setStats] = useState<MonitorStats | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n\n const fetchStats = useCallback(async () =>\n {\n try\n {\n const data = await monitorApi.getStats.call({});\n setStats(data as MonitorStats);\n }\n finally\n {\n setIsLoading(false);\n }\n }, []);\n\n useEffect(() =>\n {\n fetchStats();\n const interval = setInterval(fetchStats, 30_000);\n return () => clearInterval(interval);\n }, [fetchStats]);\n\n if (isLoading || !stats)\n {\n return (\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-4\">\n {[...Array(4)].map((_, i) => (\n <div key={i} className=\"rounded-lg border border-neutral-200 dark:border-neutral-800 p-4 animate-pulse\">\n <div className=\"h-4 w-20 bg-neutral-200 dark:bg-neutral-700 rounded mb-2\" />\n <div className=\"h-8 w-12 bg-neutral-200 dark:bg-neutral-700 rounded\" />\n </div>\n ))}\n </div>\n );\n }\n\n const cards = [\n { label: 'Active Errors', value: stats.errors.active, color: 'text-red-600 dark:text-red-400' },\n { label: 'Resolved', value: stats.errors.resolved, color: 'text-green-600 dark:text-green-400' },\n { label: 'Ignored', value: stats.errors.ignored, color: 'text-neutral-500 dark:text-neutral-400' },\n { label: 'Errors (24h)', value: stats.trends.errorsLast24h, color: 'text-orange-600 dark:text-orange-400' },\n ];\n\n return (\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-4\">\n {cards.map((card) => (\n <div\n key={card.label}\n className=\"rounded-lg border border-neutral-200 dark:border-neutral-800 p-4\"\n >\n <p className=\"text-sm text-neutral-500 dark:text-neutral-400\">{card.label}</p>\n <p className={`text-2xl font-semibold mt-1 ${card.color}`}>{card.value}</p>\n </div>\n ))}\n </div>\n );\n}\n","/**\n * @spfn/monitor - Error List View Component\n *\n * Displays error groups in a filterable table with status badges\n */\n\nimport { useState, useEffect } from 'react';\nimport { monitorApi } from '@spfn/monitor';\nimport type { ErrorGroupStatus } from '@spfn/monitor';\n\ninterface ErrorListViewProps\n{\n onSelect?: (id: number) => void;\n}\n\nconst STATUS_BADGE: Record<ErrorGroupStatus, string> = {\n active: 'bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400',\n resolved: 'bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400',\n ignored: 'bg-neutral-100 text-neutral-600 dark:bg-neutral-800 dark:text-neutral-400',\n};\n\nexport function ErrorListView({ onSelect }: ErrorListViewProps)\n{\n const [status, setStatus] = useState<string>('');\n const [search, setSearch] = useState('');\n const [errors, setErrors] = useState<any[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n\n useEffect(() =>\n {\n let cancelled = false;\n setIsLoading(true);\n\n monitorApi.listErrors.call({\n query: {\n ...(status ? { status } : {}),\n ...(search ? { search } : {}),\n limit: 50,\n },\n }).then((data) =>\n {\n if (!cancelled)\n {\n setErrors(data as any[]);\n setIsLoading(false);\n }\n }).catch(() =>\n {\n if (!cancelled)\n {\n setIsLoading(false);\n }\n });\n\n return () => { cancelled = true; };\n }, [status, search]);\n\n return (\n <div className=\"space-y-4\">\n {/* Filters */}\n <div className=\"flex gap-3\">\n <select\n value={status}\n onChange={(e) => setStatus(e.target.value)}\n className=\"rounded border border-neutral-300 dark:border-neutral-700 bg-white dark:bg-neutral-900 px-3 py-1.5 text-sm\"\n >\n <option value=\"\">All statuses</option>\n <option value=\"active\">Active</option>\n <option value=\"resolved\">Resolved</option>\n <option value=\"ignored\">Ignored</option>\n </select>\n <input\n type=\"text\"\n placeholder=\"Search errors...\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n className=\"rounded border border-neutral-300 dark:border-neutral-700 bg-white dark:bg-neutral-900 px-3 py-1.5 text-sm flex-1\"\n />\n </div>\n\n {/* Table */}\n {isLoading ? (\n <div className=\"text-sm text-neutral-500\">Loading...</div>\n ) : errors.length === 0 ? (\n <div className=\"text-sm text-neutral-500 py-8 text-center\">No errors found</div>\n ) : (\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-neutral-200 dark:border-neutral-800 text-left text-neutral-500\">\n <th className=\"py-2 pr-4\">Status</th>\n <th className=\"py-2 pr-4\">Error</th>\n <th className=\"py-2 pr-4\">Path</th>\n <th className=\"py-2 pr-4 text-right\">Count</th>\n <th className=\"py-2 text-right\">Last Seen</th>\n </tr>\n </thead>\n <tbody>\n {errors.map((group: any) => (\n <tr\n key={group.id}\n onClick={() => onSelect?.(group.id)}\n className=\"border-b border-neutral-100 dark:border-neutral-800/50 hover:bg-neutral-50 dark:hover:bg-neutral-800/50 cursor-pointer\"\n >\n <td className=\"py-2 pr-4\">\n <span className={`inline-block px-2 py-0.5 rounded text-xs font-medium ${STATUS_BADGE[group.status as ErrorGroupStatus]}`}>\n {group.status}\n </span>\n </td>\n <td className=\"py-2 pr-4\">\n <div className=\"font-medium text-neutral-900 dark:text-neutral-100\">{group.name}</div>\n <div className=\"text-neutral-500 truncate max-w-xs\">{group.message}</div>\n </td>\n <td className=\"py-2 pr-4 font-mono text-xs text-neutral-600 dark:text-neutral-400\">\n {group.method} {group.path}\n </td>\n <td className=\"py-2 pr-4 text-right font-mono\">{group.count}</td>\n <td className=\"py-2 text-right text-neutral-500\">\n {formatRelativeTime(group.lastSeenAt)}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n </div>\n );\n}\n\nfunction formatRelativeTime(date: string | Date): string\n{\n const d = typeof date === 'string' ? new Date(date) : date;\n const now = Date.now();\n const diff = now - d.getTime();\n const mins = Math.floor(diff / 60_000);\n\n if (mins < 1)\n {\n return 'just now';\n }\n\n if (mins < 60)\n {\n return `${mins}m ago`;\n }\n\n const hours = Math.floor(mins / 60);\n if (hours < 24)\n {\n return `${hours}h ago`;\n }\n\n const days = Math.floor(hours / 24);\n return `${days}d ago`;\n}\n","/**\n * @spfn/monitor - Error Detail View Component\n *\n * Shows error group details with event timeline and status change buttons\n */\n\nimport { useState, useEffect, useCallback } from 'react';\nimport { monitorApi } from '@spfn/monitor';\nimport type { ErrorGroupStatus } from '@spfn/monitor';\n\ninterface ErrorDetailViewProps\n{\n errorId: number;\n onBack?: () => void;\n}\n\nconst STATUS_ACTIONS: Record<ErrorGroupStatus, { label: string; target: ErrorGroupStatus }[]> = {\n active: [\n { label: 'Resolve', target: 'resolved' },\n { label: 'Ignore', target: 'ignored' },\n ],\n resolved: [\n { label: 'Reopen', target: 'active' },\n ],\n ignored: [\n { label: 'Reopen', target: 'active' },\n { label: 'Resolve', target: 'resolved' },\n ],\n};\n\nexport function ErrorDetailView({ errorId, onBack }: ErrorDetailViewProps)\n{\n const [data, setData] = useState<any>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [isMutating, setIsMutating] = useState(false);\n\n const fetchDetail = useCallback(async () =>\n {\n setIsLoading(true);\n try\n {\n const result = await monitorApi.getErrorDetail.call({ params: { id: errorId } });\n setData(result);\n }\n finally\n {\n setIsLoading(false);\n }\n }, [errorId]);\n\n useEffect(() =>\n {\n fetchDetail();\n }, [fetchDetail]);\n\n async function handleStatusChange(status: string)\n {\n setIsMutating(true);\n try\n {\n await monitorApi.updateErrorStatus.call({\n params: { id: errorId },\n body: { status },\n });\n await fetchDetail();\n }\n finally\n {\n setIsMutating(false);\n }\n }\n\n if (isLoading || !data)\n {\n return <div className=\"text-sm text-neutral-500\">Loading...</div>;\n }\n\n const { group, events } = data;\n const actions = STATUS_ACTIONS[group.status as ErrorGroupStatus] ?? [];\n\n return (\n <div className=\"space-y-6\">\n {/* Header */}\n <div className=\"flex items-center gap-3\">\n {onBack && (\n <button\n onClick={onBack}\n className=\"text-sm text-neutral-500 hover:text-neutral-700 dark:hover:text-neutral-300\"\n >\n ← Back\n </button>\n )}\n <h2 className=\"text-lg font-semibold text-neutral-900 dark:text-neutral-100\">\n {group.name} — {group.statusCode}\n </h2>\n </div>\n\n {/* Error Info */}\n <div className=\"rounded-lg border border-neutral-200 dark:border-neutral-800 p-4 space-y-3\">\n <p className=\"text-neutral-700 dark:text-neutral-300\">{group.message}</p>\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-4 text-sm\">\n <div>\n <span className=\"text-neutral-500\">Method</span>\n <p className=\"font-mono\">{group.method}</p>\n </div>\n <div>\n <span className=\"text-neutral-500\">Path</span>\n <p className=\"font-mono\">{group.path}</p>\n </div>\n <div>\n <span className=\"text-neutral-500\">Count</span>\n <p className=\"font-mono\">{group.count}</p>\n </div>\n <div>\n <span className=\"text-neutral-500\">Status</span>\n <p className=\"font-medium\">{group.status}</p>\n </div>\n </div>\n\n {/* Status Actions */}\n {actions.length > 0 && (\n <div className=\"flex gap-2 pt-2\">\n {actions.map((action) => (\n <button\n key={action.target}\n onClick={() => handleStatusChange(action.target)}\n disabled={isMutating}\n className=\"px-3 py-1.5 text-sm rounded border border-neutral-300 dark:border-neutral-700 hover:bg-neutral-100 dark:hover:bg-neutral-800 disabled:opacity-50\"\n >\n {action.label}\n </button>\n ))}\n </div>\n )}\n </div>\n\n {/* Event Timeline */}\n <div>\n <h3 className=\"text-sm font-medium text-neutral-500 mb-3\">Recent Events</h3>\n <div className=\"space-y-2\">\n {(events as any[]).map((event: any) => (\n <div\n key={event.id}\n className=\"rounded border border-neutral-200 dark:border-neutral-800 p-3 text-sm\"\n >\n <div className=\"flex justify-between items-start\">\n <div className=\"space-y-1\">\n <div className=\"flex gap-3 text-neutral-500\">\n <span>User: {event.userId ?? '(anonymous)'}</span>\n <span>Request: {event.requestId ?? '(none)'}</span>\n </div>\n {event.stackTrace && (\n <pre className=\"text-xs text-neutral-600 dark:text-neutral-400 overflow-x-auto whitespace-pre-wrap mt-2 bg-neutral-50 dark:bg-neutral-900 p-2 rounded\">\n {event.stackTrace.split('\\n').slice(0, 5).join('\\n')}\n </pre>\n )}\n </div>\n <span className=\"text-xs text-neutral-400 whitespace-nowrap ml-4\">\n {new Date(event.createdAt).toLocaleString()}\n </span>\n </div>\n </div>\n ))}\n </div>\n </div>\n </div>\n );\n}\n","/**\n * @spfn/monitor - Log Viewer Component\n *\n * Searchable, filterable log list with expandable metadata\n */\n\nimport { useState, useEffect } from 'react';\nimport { monitorApi } from '@spfn/monitor';\n\nconst LEVEL_BADGE: Record<string, string> = {\n debug: 'bg-neutral-100 text-neutral-600 dark:bg-neutral-800 dark:text-neutral-400',\n info: 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400',\n warn: 'bg-yellow-100 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-400',\n error: 'bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400',\n fatal: 'bg-red-200 text-red-800 dark:bg-red-900/50 dark:text-red-300',\n};\n\nexport function LogViewer()\n{\n const [level, setLevel] = useState('');\n const [search, setSearch] = useState('');\n const [logs, setLogs] = useState<any[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n const [expanded, setExpanded] = useState<Set<number>>(new Set());\n\n useEffect(() =>\n {\n let cancelled = false;\n setIsLoading(true);\n\n monitorApi.listLogs.call({\n query: {\n ...(level ? { level } : {}),\n ...(search ? { search } : {}),\n limit: 100,\n },\n }).then((data) =>\n {\n if (!cancelled)\n {\n setLogs(data as any[]);\n setIsLoading(false);\n }\n }).catch(() =>\n {\n if (!cancelled)\n {\n setIsLoading(false);\n }\n });\n\n return () => { cancelled = true; };\n }, [level, search]);\n\n function toggleExpand(id: number)\n {\n setExpanded((prev) =>\n {\n const next = new Set(prev);\n if (next.has(id))\n {\n next.delete(id);\n }\n else\n {\n next.add(id);\n }\n\n return next;\n });\n }\n\n return (\n <div className=\"space-y-4\">\n {/* Filters */}\n <div className=\"flex gap-3\">\n <select\n value={level}\n onChange={(e) => setLevel(e.target.value)}\n className=\"rounded border border-neutral-300 dark:border-neutral-700 bg-white dark:bg-neutral-900 px-3 py-1.5 text-sm\"\n >\n <option value=\"\">All levels</option>\n <option value=\"debug\">Debug</option>\n <option value=\"info\">Info</option>\n <option value=\"warn\">Warn</option>\n <option value=\"error\">Error</option>\n <option value=\"fatal\">Fatal</option>\n </select>\n <input\n type=\"text\"\n placeholder=\"Search logs...\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n className=\"rounded border border-neutral-300 dark:border-neutral-700 bg-white dark:bg-neutral-900 px-3 py-1.5 text-sm flex-1\"\n />\n </div>\n\n {/* Log List */}\n {isLoading ? (\n <div className=\"text-sm text-neutral-500\">Loading...</div>\n ) : logs.length === 0 ? (\n <div className=\"text-sm text-neutral-500 py-8 text-center\">No logs found</div>\n ) : (\n <div className=\"space-y-1\">\n {logs.map((log: any) => (\n <div\n key={log.id}\n className=\"rounded border border-neutral-200 dark:border-neutral-800 text-sm\"\n >\n <div\n onClick={() => log.metadata && toggleExpand(log.id)}\n className={`flex items-start gap-3 p-2 ${log.metadata ? 'cursor-pointer hover:bg-neutral-50 dark:hover:bg-neutral-800/50' : ''}`}\n >\n <span className={`inline-block px-1.5 py-0.5 rounded text-xs font-medium ${LEVEL_BADGE[log.level] ?? ''}`}>\n {log.level}\n </span>\n <span className=\"flex-1 text-neutral-800 dark:text-neutral-200\">\n {log.message}\n </span>\n {log.source && (\n <span className=\"text-xs text-neutral-400 font-mono\">{log.source}</span>\n )}\n <span className=\"text-xs text-neutral-400 whitespace-nowrap\">\n {new Date(log.createdAt).toLocaleTimeString()}\n </span>\n </div>\n {expanded.has(log.id) && log.metadata && (\n <pre className=\"px-3 py-2 text-xs bg-neutral-50 dark:bg-neutral-900 border-t border-neutral-200 dark:border-neutral-800 overflow-x-auto\">\n {JSON.stringify(log.metadata, null, 2)}\n </pre>\n )}\n </div>\n ))}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":["useState","useState","useEffect","monitorApi","jsx","jsxs","useState","useEffect","useCallback","monitorApi","jsx","jsxs","useState","useEffect","monitorApi","jsx","jsxs","jsx","jsxs","useState"]}
|
|
1
|
+
{"version":3,"sources":["../../src/nextjs/components/monitor-dashboard.tsx","../../src/nextjs/components/stats-overview.tsx","../../src/nextjs/components/error-list-view.tsx","../../src/nextjs/components/error-detail-view.tsx","../../src/nextjs/components/log-viewer.tsx"],"sourcesContent":["/**\n * @spfn/monitor - Monitor Dashboard Component\n *\n * Main entry point combining StatsOverview, ErrorListView, and LogViewer in tabs\n */\n\nimport { useState } from 'react';\nimport { StatsOverview } from './stats-overview';\nimport { ErrorListView } from './error-list-view';\nimport { ErrorDetailView } from './error-detail-view';\nimport { LogViewer } from './log-viewer';\n\ntype Tab = 'errors' | 'logs';\n\nexport function MonitorDashboard()\n{\n const [tab, setTab] = useState<Tab>('errors');\n const [selectedErrorId, setSelectedErrorId] = useState<number | null>(null);\n\n return (\n <div className=\"space-y-6\">\n {/* Stats */}\n <StatsOverview />\n\n {/* Tabs */}\n <div className=\"flex gap-1 border-b border-neutral-200 dark:border-neutral-800\">\n <TabButton active={tab === 'errors'} onClick={() => \n {\n setTab('errors'); setSelectedErrorId(null); \n }}>\n Errors\n </TabButton>\n <TabButton active={tab === 'logs'} onClick={() => setTab('logs')}>\n Logs\n </TabButton>\n </div>\n\n {/* Content */}\n {tab === 'errors' && !selectedErrorId && (\n <ErrorListView onSelect={setSelectedErrorId} />\n )}\n {tab === 'errors' && selectedErrorId && (\n <ErrorDetailView\n errorId={selectedErrorId}\n onBack={() => setSelectedErrorId(null)}\n />\n )}\n {tab === 'logs' && (\n <LogViewer />\n )}\n </div>\n );\n}\n\nfunction TabButton({\n active,\n onClick,\n children,\n}: {\n active: boolean;\n onClick: () => void;\n children: React.ReactNode;\n})\n{\n return (\n <button\n onClick={onClick}\n className={`px-4 py-2 text-sm font-medium border-b-2 -mb-px transition-colors ${\n active\n ? 'border-neutral-900 dark:border-neutral-100 text-neutral-900 dark:text-neutral-100'\n : 'border-transparent text-neutral-500 hover:text-neutral-700 dark:hover:text-neutral-300'\n }`}\n >\n {children}\n </button>\n );\n}\n","/**\n * @spfn/monitor - Stats Overview Component\n *\n * Displays error/log counts and trend indicators\n */\n\nimport { useState, useEffect, useCallback } from 'react';\nimport { monitorApi } from '@spfn/monitor';\nimport type { MonitorStats } from '@spfn/monitor';\n\nexport function StatsOverview()\n{\n const [stats, setStats] = useState<MonitorStats | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n\n const fetchStats = useCallback(async () =>\n {\n try\n {\n const data = await monitorApi.getStats.call({});\n setStats(data as MonitorStats);\n }\n finally\n {\n setIsLoading(false);\n }\n }, []);\n\n useEffect(() =>\n {\n fetchStats();\n const interval = setInterval(fetchStats, 30_000);\n\n return () => clearInterval(interval);\n }, [fetchStats]);\n\n if (isLoading || !stats)\n {\n return (\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-4\">\n {[...Array(4)].map((_, i) => (\n <div key={i} className=\"rounded-lg border border-neutral-200 dark:border-neutral-800 p-4 animate-pulse\">\n <div className=\"h-4 w-20 bg-neutral-200 dark:bg-neutral-700 rounded mb-2\" />\n <div className=\"h-8 w-12 bg-neutral-200 dark:bg-neutral-700 rounded\" />\n </div>\n ))}\n </div>\n );\n }\n\n const cards = [\n { label: 'Active Errors', value: stats.errors.active, color: 'text-red-600 dark:text-red-400' },\n { label: 'Resolved', value: stats.errors.resolved, color: 'text-green-600 dark:text-green-400' },\n { label: 'Ignored', value: stats.errors.ignored, color: 'text-neutral-500 dark:text-neutral-400' },\n { label: 'Errors (24h)', value: stats.trends.errorsLast24h, color: 'text-orange-600 dark:text-orange-400' },\n ];\n\n return (\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-4\">\n {cards.map((card) => (\n <div\n key={card.label}\n className=\"rounded-lg border border-neutral-200 dark:border-neutral-800 p-4\"\n >\n <p className=\"text-sm text-neutral-500 dark:text-neutral-400\">{card.label}</p>\n <p className={`text-2xl font-semibold mt-1 ${card.color}`}>{card.value}</p>\n </div>\n ))}\n </div>\n );\n}\n","/**\n * @spfn/monitor - Error List View Component\n *\n * Displays error groups in a filterable table with status badges\n */\n\nimport { useState, useEffect } from 'react';\nimport { monitorApi } from '@spfn/monitor';\nimport type { ErrorGroupStatus } from '@spfn/monitor';\n\ninterface ErrorListViewProps\n{\n onSelect?: (id: number) => void;\n}\n\nconst STATUS_BADGE: Record<ErrorGroupStatus, string> = {\n active: 'bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400',\n resolved: 'bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400',\n ignored: 'bg-neutral-100 text-neutral-600 dark:bg-neutral-800 dark:text-neutral-400',\n};\n\nexport function ErrorListView({ onSelect }: ErrorListViewProps)\n{\n const [status, setStatus] = useState<string>('');\n const [search, setSearch] = useState('');\n const [errors, setErrors] = useState<any[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n\n useEffect(() =>\n {\n let cancelled = false;\n setIsLoading(true);\n\n monitorApi.listErrors.call({\n query: {\n ...(status ? { status } : {}),\n ...(search ? { search } : {}),\n limit: 50,\n },\n }).then((data) =>\n {\n if (!cancelled)\n {\n setErrors(data as any[]);\n setIsLoading(false);\n }\n }).catch(() =>\n {\n if (!cancelled)\n {\n setIsLoading(false);\n }\n });\n\n return () => \n {\n cancelled = true; \n };\n }, [status, search]);\n\n return (\n <div className=\"space-y-4\">\n {/* Filters */}\n <div className=\"flex gap-3\">\n <select\n value={status}\n onChange={(e) => setStatus(e.target.value)}\n className=\"rounded border border-neutral-300 dark:border-neutral-700 bg-white dark:bg-neutral-900 px-3 py-1.5 text-sm\"\n >\n <option value=\"\">All statuses</option>\n <option value=\"active\">Active</option>\n <option value=\"resolved\">Resolved</option>\n <option value=\"ignored\">Ignored</option>\n </select>\n <input\n type=\"text\"\n placeholder=\"Search errors...\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n className=\"rounded border border-neutral-300 dark:border-neutral-700 bg-white dark:bg-neutral-900 px-3 py-1.5 text-sm flex-1\"\n />\n </div>\n\n {/* Table */}\n {isLoading ? (\n <div className=\"text-sm text-neutral-500\">Loading...</div>\n ) : errors.length === 0 ? (\n <div className=\"text-sm text-neutral-500 py-8 text-center\">No errors found</div>\n ) : (\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-neutral-200 dark:border-neutral-800 text-left text-neutral-500\">\n <th className=\"py-2 pr-4\">Status</th>\n <th className=\"py-2 pr-4\">Error</th>\n <th className=\"py-2 pr-4\">Path</th>\n <th className=\"py-2 pr-4 text-right\">Count</th>\n <th className=\"py-2 text-right\">Last Seen</th>\n </tr>\n </thead>\n <tbody>\n {errors.map((group: any) => (\n <tr\n key={group.id}\n onClick={() => onSelect?.(group.id)}\n className=\"border-b border-neutral-100 dark:border-neutral-800/50 hover:bg-neutral-50 dark:hover:bg-neutral-800/50 cursor-pointer\"\n >\n <td className=\"py-2 pr-4\">\n <span className={`inline-block px-2 py-0.5 rounded text-xs font-medium ${STATUS_BADGE[group.status as ErrorGroupStatus]}`}>\n {group.status}\n </span>\n </td>\n <td className=\"py-2 pr-4\">\n <div className=\"font-medium text-neutral-900 dark:text-neutral-100\">{group.name}</div>\n <div className=\"text-neutral-500 truncate max-w-xs\">{group.message}</div>\n </td>\n <td className=\"py-2 pr-4 font-mono text-xs text-neutral-600 dark:text-neutral-400\">\n {group.method} {group.path}\n </td>\n <td className=\"py-2 pr-4 text-right font-mono\">{group.count}</td>\n <td className=\"py-2 text-right text-neutral-500\">\n {formatRelativeTime(group.lastSeenAt)}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n </div>\n );\n}\n\nfunction formatRelativeTime(date: string | Date): string\n{\n const d = typeof date === 'string' ? new Date(date) : date;\n const now = Date.now();\n const diff = now - d.getTime();\n const mins = Math.floor(diff / 60_000);\n\n if (mins < 1)\n {\n return 'just now';\n }\n\n if (mins < 60)\n {\n return `${mins}m ago`;\n }\n\n const hours = Math.floor(mins / 60);\n if (hours < 24)\n {\n return `${hours}h ago`;\n }\n\n const days = Math.floor(hours / 24);\n\n return `${days}d ago`;\n}\n","/**\n * @spfn/monitor - Error Detail View Component\n *\n * Shows error group details with event timeline and status change buttons\n */\n\nimport { useState, useEffect, useCallback } from 'react';\nimport { monitorApi } from '@spfn/monitor';\nimport type { ErrorGroupStatus } from '@spfn/monitor';\n\ninterface ErrorDetailViewProps\n{\n errorId: number;\n onBack?: () => void;\n}\n\nconst STATUS_ACTIONS: Record<ErrorGroupStatus, { label: string; target: ErrorGroupStatus }[]> = {\n active: [\n { label: 'Resolve', target: 'resolved' },\n { label: 'Ignore', target: 'ignored' },\n ],\n resolved: [\n { label: 'Reopen', target: 'active' },\n ],\n ignored: [\n { label: 'Reopen', target: 'active' },\n { label: 'Resolve', target: 'resolved' },\n ],\n};\n\nexport function ErrorDetailView({ errorId, onBack }: ErrorDetailViewProps)\n{\n const [data, setData] = useState<any>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [isMutating, setIsMutating] = useState(false);\n\n const fetchDetail = useCallback(async () =>\n {\n setIsLoading(true);\n try\n {\n const result = await monitorApi.getErrorDetail.call({ params: { id: errorId } });\n setData(result);\n }\n finally\n {\n setIsLoading(false);\n }\n }, [errorId]);\n\n useEffect(() =>\n {\n fetchDetail();\n }, [fetchDetail]);\n\n async function handleStatusChange(status: string)\n {\n setIsMutating(true);\n try\n {\n await monitorApi.updateErrorStatus.call({\n params: { id: errorId },\n body: { status },\n });\n await fetchDetail();\n }\n finally\n {\n setIsMutating(false);\n }\n }\n\n if (isLoading || !data)\n {\n return <div className=\"text-sm text-neutral-500\">Loading...</div>;\n }\n\n const { group, events } = data;\n const actions = STATUS_ACTIONS[group.status as ErrorGroupStatus] ?? [];\n\n return (\n <div className=\"space-y-6\">\n {/* Header */}\n <div className=\"flex items-center gap-3\">\n {onBack && (\n <button\n onClick={onBack}\n className=\"text-sm text-neutral-500 hover:text-neutral-700 dark:hover:text-neutral-300\"\n >\n ← Back\n </button>\n )}\n <h2 className=\"text-lg font-semibold text-neutral-900 dark:text-neutral-100\">\n {group.name} — {group.statusCode}\n </h2>\n </div>\n\n {/* Error Info */}\n <div className=\"rounded-lg border border-neutral-200 dark:border-neutral-800 p-4 space-y-3\">\n <p className=\"text-neutral-700 dark:text-neutral-300\">{group.message}</p>\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-4 text-sm\">\n <div>\n <span className=\"text-neutral-500\">Method</span>\n <p className=\"font-mono\">{group.method}</p>\n </div>\n <div>\n <span className=\"text-neutral-500\">Path</span>\n <p className=\"font-mono\">{group.path}</p>\n </div>\n <div>\n <span className=\"text-neutral-500\">Count</span>\n <p className=\"font-mono\">{group.count}</p>\n </div>\n <div>\n <span className=\"text-neutral-500\">Status</span>\n <p className=\"font-medium\">{group.status}</p>\n </div>\n </div>\n\n {/* Status Actions */}\n {actions.length > 0 && (\n <div className=\"flex gap-2 pt-2\">\n {actions.map((action) => (\n <button\n key={action.target}\n onClick={() => handleStatusChange(action.target)}\n disabled={isMutating}\n className=\"px-3 py-1.5 text-sm rounded border border-neutral-300 dark:border-neutral-700 hover:bg-neutral-100 dark:hover:bg-neutral-800 disabled:opacity-50\"\n >\n {action.label}\n </button>\n ))}\n </div>\n )}\n </div>\n\n {/* Event Timeline */}\n <div>\n <h3 className=\"text-sm font-medium text-neutral-500 mb-3\">Recent Events</h3>\n <div className=\"space-y-2\">\n {(events as any[]).map((event: any) => (\n <div\n key={event.id}\n className=\"rounded border border-neutral-200 dark:border-neutral-800 p-3 text-sm\"\n >\n <div className=\"flex justify-between items-start\">\n <div className=\"space-y-1\">\n <div className=\"flex gap-3 text-neutral-500\">\n <span>User: {event.userId ?? '(anonymous)'}</span>\n <span>Request: {event.requestId ?? '(none)'}</span>\n </div>\n {event.stackTrace && (\n <pre className=\"text-xs text-neutral-600 dark:text-neutral-400 overflow-x-auto whitespace-pre-wrap mt-2 bg-neutral-50 dark:bg-neutral-900 p-2 rounded\">\n {event.stackTrace.split('\\n').slice(0, 5).join('\\n')}\n </pre>\n )}\n </div>\n <span className=\"text-xs text-neutral-400 whitespace-nowrap ml-4\">\n {new Date(event.createdAt).toLocaleString()}\n </span>\n </div>\n </div>\n ))}\n </div>\n </div>\n </div>\n );\n}\n","/**\n * @spfn/monitor - Log Viewer Component\n *\n * Searchable, filterable log list with expandable metadata\n */\n\nimport { useState, useEffect } from 'react';\nimport { monitorApi } from '@spfn/monitor';\n\nconst LEVEL_BADGE: Record<string, string> = {\n debug: 'bg-neutral-100 text-neutral-600 dark:bg-neutral-800 dark:text-neutral-400',\n info: 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400',\n warn: 'bg-yellow-100 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-400',\n error: 'bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400',\n fatal: 'bg-red-200 text-red-800 dark:bg-red-900/50 dark:text-red-300',\n};\n\nexport function LogViewer()\n{\n const [level, setLevel] = useState('');\n const [search, setSearch] = useState('');\n const [logs, setLogs] = useState<any[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n const [expanded, setExpanded] = useState<Set<number>>(new Set());\n\n useEffect(() =>\n {\n let cancelled = false;\n setIsLoading(true);\n\n monitorApi.listLogs.call({\n query: {\n ...(level ? { level } : {}),\n ...(search ? { search } : {}),\n limit: 100,\n },\n }).then((data) =>\n {\n if (!cancelled)\n {\n setLogs(data as any[]);\n setIsLoading(false);\n }\n }).catch(() =>\n {\n if (!cancelled)\n {\n setIsLoading(false);\n }\n });\n\n return () => \n {\n cancelled = true; \n };\n }, [level, search]);\n\n function toggleExpand(id: number)\n {\n setExpanded((prev) =>\n {\n const next = new Set(prev);\n if (next.has(id))\n {\n next.delete(id);\n }\n else\n {\n next.add(id);\n }\n\n return next;\n });\n }\n\n return (\n <div className=\"space-y-4\">\n {/* Filters */}\n <div className=\"flex gap-3\">\n <select\n value={level}\n onChange={(e) => setLevel(e.target.value)}\n className=\"rounded border border-neutral-300 dark:border-neutral-700 bg-white dark:bg-neutral-900 px-3 py-1.5 text-sm\"\n >\n <option value=\"\">All levels</option>\n <option value=\"debug\">Debug</option>\n <option value=\"info\">Info</option>\n <option value=\"warn\">Warn</option>\n <option value=\"error\">Error</option>\n <option value=\"fatal\">Fatal</option>\n </select>\n <input\n type=\"text\"\n placeholder=\"Search logs...\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n className=\"rounded border border-neutral-300 dark:border-neutral-700 bg-white dark:bg-neutral-900 px-3 py-1.5 text-sm flex-1\"\n />\n </div>\n\n {/* Log List */}\n {isLoading ? (\n <div className=\"text-sm text-neutral-500\">Loading...</div>\n ) : logs.length === 0 ? (\n <div className=\"text-sm text-neutral-500 py-8 text-center\">No logs found</div>\n ) : (\n <div className=\"space-y-1\">\n {logs.map((log: any) => (\n <div\n key={log.id}\n className=\"rounded border border-neutral-200 dark:border-neutral-800 text-sm\"\n >\n <div\n onClick={() => log.metadata && toggleExpand(log.id)}\n className={`flex items-start gap-3 p-2 ${log.metadata ? 'cursor-pointer hover:bg-neutral-50 dark:hover:bg-neutral-800/50' : ''}`}\n >\n <span className={`inline-block px-1.5 py-0.5 rounded text-xs font-medium ${LEVEL_BADGE[log.level] ?? ''}`}>\n {log.level}\n </span>\n <span className=\"flex-1 text-neutral-800 dark:text-neutral-200\">\n {log.message}\n </span>\n {log.source && (\n <span className=\"text-xs text-neutral-400 font-mono\">{log.source}</span>\n )}\n <span className=\"text-xs text-neutral-400 whitespace-nowrap\">\n {new Date(log.createdAt).toLocaleTimeString()}\n </span>\n </div>\n {expanded.has(log.id) && log.metadata && (\n <pre className=\"px-3 py-2 text-xs bg-neutral-50 dark:bg-neutral-900 border-t border-neutral-200 dark:border-neutral-800 overflow-x-auto\">\n {JSON.stringify(log.metadata, null, 2)}\n </pre>\n )}\n </div>\n ))}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":["useState","useState","useEffect","monitorApi","jsx","jsxs","useState","useEffect","useCallback","monitorApi","jsx","jsxs","useState","useEffect","monitorApi","jsx","jsxs","jsx","jsxs","useState"]}
|
package/dist/server.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { E as ErrorGroupStatus, c as ErrorGroup, N as NewErrorGroup, L as LogLevel, d as NewLog, e as Log } from './index-
|
|
2
|
-
export { a as ERROR_GROUP_STATUSES, b as LOG_LEVELS, M as MonitorStats, f as errorGroups, g as getMonitorStats, l as logs, m as monitorRouter } from './index-
|
|
1
|
+
import { E as ErrorGroupStatus, c as ErrorGroup, N as NewErrorGroup, L as LogLevel, d as NewLog, e as Log } from './index-C9IUDNIv.js';
|
|
2
|
+
export { a as ERROR_GROUP_STATUSES, b as LOG_LEVELS, M as MonitorStats, f as errorGroups, g as getMonitorStats, l as logs, m as monitorRouter } from './index-C9IUDNIv.js';
|
|
3
3
|
import { BaseRepository } from '@spfn/core/db';
|
|
4
4
|
import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
|
|
5
5
|
import * as _spfn_core_logger from '@spfn/core/logger';
|