@geenius/tools 0.1.0

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 (160) hide show
  1. package/.changeset/config.json +11 -0
  2. package/.env.example +2 -0
  3. package/.github/CODEOWNERS +1 -0
  4. package/.github/ISSUE_TEMPLATE/bug_report.md +16 -0
  5. package/.github/ISSUE_TEMPLATE/feature_request.md +11 -0
  6. package/.github/PULL_REQUEST_TEMPLATE.md +10 -0
  7. package/.github/dependabot.yml +11 -0
  8. package/.github/workflows/ci.yml +23 -0
  9. package/.github/workflows/release.yml +29 -0
  10. package/.node-version +1 -0
  11. package/.nvmrc +1 -0
  12. package/.prettierrc +7 -0
  13. package/.project/ACCOUNT.yaml +4 -0
  14. package/.project/IDEAS.yaml +7 -0
  15. package/.project/PROJECT.yaml +11 -0
  16. package/.project/ROADMAP.yaml +15 -0
  17. package/CHANGELOG.md +16 -0
  18. package/CODE_OF_CONDUCT.md +26 -0
  19. package/CONTRIBUTING.md +69 -0
  20. package/LICENSE +21 -0
  21. package/README.md +1 -0
  22. package/SECURITY.md +18 -0
  23. package/SUPPORT.md +14 -0
  24. package/package.json +75 -0
  25. package/packages/convex/shared/README.md +1 -0
  26. package/packages/convex/shared/package.json +42 -0
  27. package/packages/convex/shared/src/audit/index.ts +5 -0
  28. package/packages/convex/shared/src/audit/presets.ts +165 -0
  29. package/packages/convex/shared/src/audit/schema.ts +85 -0
  30. package/packages/convex/shared/src/audit/write.ts +102 -0
  31. package/packages/convex/shared/src/extract.ts +75 -0
  32. package/packages/convex/shared/src/index.ts +41 -0
  33. package/packages/convex/shared/src/messages.ts +45 -0
  34. package/packages/convex/shared/src/security.ts +112 -0
  35. package/packages/convex/shared/src/throw.ts +184 -0
  36. package/packages/convex/shared/src/types.ts +57 -0
  37. package/packages/convex/shared/src/utils.ts +58 -0
  38. package/packages/convex/shared/tsconfig.json +28 -0
  39. package/packages/convex/shared/tsup.config.ts +12 -0
  40. package/packages/devtools/package.json +27 -0
  41. package/packages/devtools/react/README.md +1 -0
  42. package/packages/devtools/react/package.json +53 -0
  43. package/packages/devtools/react/src/components/DesignPreview.tsx +59 -0
  44. package/packages/devtools/react/src/components/DesignSwitcherDropdown.tsx +99 -0
  45. package/packages/devtools/react/src/components/DevSidebar.tsx +247 -0
  46. package/packages/devtools/react/src/components/DevToolbar.tsx +242 -0
  47. package/packages/devtools/react/src/components/GitHubIssueDialog.tsx +402 -0
  48. package/packages/devtools/react/src/components/InspectorOverlay.tsx +312 -0
  49. package/packages/devtools/react/src/components/PageLoadWaterfall.tsx +144 -0
  50. package/packages/devtools/react/src/components/PerformancePanel.tsx +330 -0
  51. package/packages/devtools/react/src/context/DevModeContext.tsx +226 -0
  52. package/packages/devtools/react/src/context/PerformanceContext.tsx +143 -0
  53. package/packages/devtools/react/src/data/designs.ts +13 -0
  54. package/packages/devtools/react/src/hooks/useGitHubLabels.ts +47 -0
  55. package/packages/devtools/react/src/hooks/useVirtualList.ts +124 -0
  56. package/packages/devtools/react/src/index.ts +77 -0
  57. package/packages/devtools/react/src/panels/ConvexSpy.tsx +130 -0
  58. package/packages/devtools/react/src/panels/DatabaseSeeder.tsx +116 -0
  59. package/packages/devtools/react/src/panels/DevModePhase2.tsx +191 -0
  60. package/packages/devtools/react/src/panels/DevModePhase3.tsx +234 -0
  61. package/packages/devtools/react/src/panels/FeatureFlagsToggle.tsx +104 -0
  62. package/packages/devtools/react/src/panels/QuickRouteJump.tsx +152 -0
  63. package/packages/devtools/react/src/services/github-service.ts +247 -0
  64. package/packages/devtools/react/tsconfig.json +31 -0
  65. package/packages/devtools/react/tsup.config.ts +18 -0
  66. package/packages/devtools/solidjs/README.md +1 -0
  67. package/packages/devtools/solidjs/package.json +49 -0
  68. package/packages/devtools/solidjs/src/components/DesignPreview.tsx +51 -0
  69. package/packages/devtools/solidjs/src/components/DesignSwitcherDropdown.tsx +95 -0
  70. package/packages/devtools/solidjs/src/components/DevSidebar.tsx +247 -0
  71. package/packages/devtools/solidjs/src/components/DevToolbar.tsx +242 -0
  72. package/packages/devtools/solidjs/src/components/GitHubIssueDialog.tsx +400 -0
  73. package/packages/devtools/solidjs/src/components/InspectorOverlay.tsx +311 -0
  74. package/packages/devtools/solidjs/src/components/PageLoadWaterfall.tsx +144 -0
  75. package/packages/devtools/solidjs/src/components/PerformancePanel.tsx +330 -0
  76. package/packages/devtools/solidjs/src/context/DevModeContext.tsx +216 -0
  77. package/packages/devtools/solidjs/src/context/PerformanceContext.tsx +135 -0
  78. package/packages/devtools/solidjs/src/data/designs.ts +13 -0
  79. package/packages/devtools/solidjs/src/hooks/createGitHubLabels.ts +47 -0
  80. package/packages/devtools/solidjs/src/index.ts +64 -0
  81. package/packages/devtools/solidjs/src/services/github-service.ts +247 -0
  82. package/packages/devtools/solidjs/tsconfig.json +21 -0
  83. package/packages/devtools/src/index.ts +377 -0
  84. package/packages/devtools/tsup.config.ts +12 -0
  85. package/packages/env/package.json +30 -0
  86. package/packages/env/src/index.ts +264 -0
  87. package/packages/env/tsup.config.ts +12 -0
  88. package/packages/errors/package.json +27 -0
  89. package/packages/errors/react/README.md +1 -0
  90. package/packages/errors/react/package.json +72 -0
  91. package/packages/errors/react/src/analytics.ts +16 -0
  92. package/packages/errors/react/src/components/ErrorBoundary.tsx +248 -0
  93. package/packages/errors/react/src/components/ErrorDisplay.tsx +328 -0
  94. package/packages/errors/react/src/components/ValidationErrors.tsx +102 -0
  95. package/packages/errors/react/src/config.ts +199 -0
  96. package/packages/errors/react/src/constants.ts +74 -0
  97. package/packages/errors/react/src/hooks/useErrorBoundary.ts +92 -0
  98. package/packages/errors/react/src/hooks/useErrorHandler.ts +87 -0
  99. package/packages/errors/react/src/index.ts +96 -0
  100. package/packages/errors/react/src/types.ts +102 -0
  101. package/packages/errors/react/src/utils/errorMessages.ts +35 -0
  102. package/packages/errors/react/src/utils/errorPolicy.ts +139 -0
  103. package/packages/errors/react/src/utils/extractAppError.ts +174 -0
  104. package/packages/errors/react/src/utils/formatError.ts +112 -0
  105. package/packages/errors/react/tsconfig.json +25 -0
  106. package/packages/errors/react/tsup.config.ts +24 -0
  107. package/packages/errors/solidjs/README.md +1 -0
  108. package/packages/errors/solidjs/package.json +46 -0
  109. package/packages/errors/solidjs/src/components/ErrorDisplay.tsx +179 -0
  110. package/packages/errors/solidjs/src/config.ts +98 -0
  111. package/packages/errors/solidjs/src/hooks/createErrorHandler.ts +107 -0
  112. package/packages/errors/solidjs/src/index.ts +61 -0
  113. package/packages/errors/solidjs/src/types.ts +34 -0
  114. package/packages/errors/solidjs/src/utils/errorPolicy.ts +56 -0
  115. package/packages/errors/solidjs/src/utils/extractAppError.ts +94 -0
  116. package/packages/errors/solidjs/src/utils/formatError.ts +33 -0
  117. package/packages/errors/solidjs/tsconfig.json +26 -0
  118. package/packages/errors/solidjs/tsup.config.ts +21 -0
  119. package/packages/errors/src/index.ts +320 -0
  120. package/packages/errors/tsup.config.ts +12 -0
  121. package/packages/logger/package.json +27 -0
  122. package/packages/logger/react/README.md +1 -0
  123. package/packages/logger/react/package.json +46 -0
  124. package/packages/logger/react/src/index.ts +4 -0
  125. package/packages/logger/react/src/useMetrics.ts +42 -0
  126. package/packages/logger/react/src/usePerformanceLog.ts +61 -0
  127. package/packages/logger/react/tsconfig.json +31 -0
  128. package/packages/logger/react/tsup.config.ts +12 -0
  129. package/packages/logger/solidjs/README.md +1 -0
  130. package/packages/logger/solidjs/package.json +45 -0
  131. package/packages/logger/solidjs/src/createMetrics.ts +37 -0
  132. package/packages/logger/solidjs/src/createPerformanceLog.ts +58 -0
  133. package/packages/logger/solidjs/src/index.ts +4 -0
  134. package/packages/logger/solidjs/tsconfig.json +32 -0
  135. package/packages/logger/solidjs/tsup.config.ts +12 -0
  136. package/packages/logger/src/index.ts +363 -0
  137. package/packages/logger/tsup.config.ts +12 -0
  138. package/packages/perf/package.json +27 -0
  139. package/packages/perf/react/README.md +1 -0
  140. package/packages/perf/react/package.json +59 -0
  141. package/packages/perf/react/src/components/PerformanceDashboard.tsx +257 -0
  142. package/packages/perf/react/src/hooks/useMonitoredQuery.ts +89 -0
  143. package/packages/perf/react/src/hooks/usePerformanceMetrics.ts +78 -0
  144. package/packages/perf/react/src/index.ts +33 -0
  145. package/packages/perf/react/src/services/PerformanceMonitor.ts +313 -0
  146. package/packages/perf/react/src/types.ts +77 -0
  147. package/packages/perf/react/tsconfig.json +25 -0
  148. package/packages/perf/react/tsup.config.ts +19 -0
  149. package/packages/perf/solidjs/README.md +1 -0
  150. package/packages/perf/solidjs/package.json +41 -0
  151. package/packages/perf/solidjs/src/components/PerformanceDashboard.tsx +207 -0
  152. package/packages/perf/solidjs/src/hooks/createPerformanceMetrics.ts +73 -0
  153. package/packages/perf/solidjs/src/index.ts +31 -0
  154. package/packages/perf/solidjs/src/services/PerformanceMonitor.ts +134 -0
  155. package/packages/perf/solidjs/src/types.ts +78 -0
  156. package/packages/perf/solidjs/tsconfig.json +26 -0
  157. package/packages/perf/solidjs/tsup.config.ts +14 -0
  158. package/packages/perf/src/index.ts +410 -0
  159. package/packages/perf/tsup.config.ts +12 -0
  160. package/pnpm-workspace.yaml +2 -0
@@ -0,0 +1,313 @@
1
+ // @geenius-tools/perf-react — src/services/PerformanceMonitor.ts
2
+ // Singleton performance monitoring service (framework-agnostic)
3
+
4
+ import type {
5
+ PerformanceMetrics,
6
+ PerformanceConfig,
7
+ CacheMetrics,
8
+ QueryMetrics,
9
+ PageLoadMetrics,
10
+ ErrorMetrics,
11
+ CacheHitEvent,
12
+ CacheMissEvent,
13
+ } from '../types'
14
+
15
+ interface QueryEntry {
16
+ key: string
17
+ duration: number
18
+ timestamp: number
19
+ error?: Error
20
+ cached: boolean
21
+ }
22
+
23
+ interface CacheEntry {
24
+ type: 'hit' | 'miss'
25
+ queryKey: string
26
+ duration: number
27
+ fetchDuration?: number
28
+ timestamp: number
29
+ cacheType: 'ssr' | 'client' | 'memory'
30
+ }
31
+
32
+ interface ErrorEntry {
33
+ type: string
34
+ message: string
35
+ stack?: string
36
+ timestamp: number
37
+ source: string
38
+ }
39
+
40
+ interface PageLoadEntry {
41
+ route: string
42
+ ttfb: number
43
+ fcp: number
44
+ lcp: number
45
+ tti: number
46
+ loadTime: number
47
+ ssr: boolean
48
+ timestamp: number
49
+ }
50
+
51
+ const DEFAULT_CONFIG: PerformanceConfig = {
52
+ enableCacheTracking: true,
53
+ enableQueryTracking: true,
54
+ enablePageLoadTracking: true,
55
+ enableErrorTracking: true,
56
+ sampleRate: 1,
57
+ maxMetrics: 1000,
58
+ }
59
+
60
+ /**
61
+ * PerformanceMonitor — singleton service for tracking performance metrics
62
+ *
63
+ * @example
64
+ * PerformanceMonitor.trackQuery('users', 45, undefined, false)
65
+ * const metrics = PerformanceMonitor.getMetrics({ start: Date.now() - 3600000, end: Date.now() })
66
+ */
67
+ export class PerformanceMonitor {
68
+ private static queries: QueryEntry[] = []
69
+ private static cacheEntries: CacheEntry[] = []
70
+ private static errors: ErrorEntry[] = []
71
+ private static pageLoads: PageLoadEntry[] = []
72
+ private static config: PerformanceConfig = DEFAULT_CONFIG
73
+
74
+ /**
75
+ * Configure the performance monitor
76
+ */
77
+ static configure(config: Partial<PerformanceConfig>): void {
78
+ PerformanceMonitor.config = { ...PerformanceMonitor.config, ...config }
79
+ }
80
+
81
+ /**
82
+ * Track a query execution
83
+ */
84
+ static trackQuery(
85
+ queryKey: string,
86
+ duration: number,
87
+ error?: Error,
88
+ cached = false,
89
+ ): void {
90
+ if (!PerformanceMonitor.config.enableQueryTracking) return
91
+ if (Math.random() > (PerformanceMonitor.config.sampleRate ?? 1)) return
92
+
93
+ PerformanceMonitor.queries.push({
94
+ key: queryKey,
95
+ duration,
96
+ timestamp: Date.now(),
97
+ error,
98
+ cached,
99
+ })
100
+
101
+ // Trim if over limit
102
+ const max = PerformanceMonitor.config.maxMetrics ?? 1000
103
+ if (PerformanceMonitor.queries.length > max) {
104
+ PerformanceMonitor.queries = PerformanceMonitor.queries.slice(-max)
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Track a cache hit
110
+ */
111
+ static trackCacheHit(event: CacheHitEvent): void {
112
+ if (!PerformanceMonitor.config.enableCacheTracking) return
113
+
114
+ PerformanceMonitor.cacheEntries.push({
115
+ type: 'hit',
116
+ queryKey: event.queryKey,
117
+ duration: event.duration,
118
+ timestamp: event.timestamp,
119
+ cacheType: event.cacheType,
120
+ })
121
+
122
+ const max = PerformanceMonitor.config.maxMetrics ?? 1000
123
+ if (PerformanceMonitor.cacheEntries.length > max) {
124
+ PerformanceMonitor.cacheEntries = PerformanceMonitor.cacheEntries.slice(-max)
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Track a cache miss
130
+ */
131
+ static trackCacheMiss(event: CacheMissEvent): void {
132
+ if (!PerformanceMonitor.config.enableCacheTracking) return
133
+
134
+ PerformanceMonitor.cacheEntries.push({
135
+ type: 'miss',
136
+ queryKey: event.queryKey,
137
+ duration: event.duration,
138
+ fetchDuration: event.fetchDuration,
139
+ timestamp: event.timestamp,
140
+ cacheType: event.cacheType,
141
+ })
142
+
143
+ const max = PerformanceMonitor.config.maxMetrics ?? 1000
144
+ if (PerformanceMonitor.cacheEntries.length > max) {
145
+ PerformanceMonitor.cacheEntries = PerformanceMonitor.cacheEntries.slice(-max)
146
+ }
147
+ }
148
+
149
+ /**
150
+ * Track an error
151
+ */
152
+ static trackError(error: Error, source: string): void {
153
+ if (!PerformanceMonitor.config.enableErrorTracking) return
154
+
155
+ PerformanceMonitor.errors.push({
156
+ type: error.name || 'Error',
157
+ message: error.message,
158
+ stack: error.stack,
159
+ timestamp: Date.now(),
160
+ source,
161
+ })
162
+
163
+ const max = PerformanceMonitor.config.maxMetrics ?? 1000
164
+ if (PerformanceMonitor.errors.length > max) {
165
+ PerformanceMonitor.errors = PerformanceMonitor.errors.slice(-max)
166
+ }
167
+ }
168
+
169
+ /**
170
+ * Track page load metrics
171
+ */
172
+ static trackPageLoad(metrics: Omit<PageLoadEntry, 'timestamp'>): void {
173
+ if (!PerformanceMonitor.config.enablePageLoadTracking) return
174
+
175
+ PerformanceMonitor.pageLoads.push({
176
+ ...metrics,
177
+ timestamp: Date.now(),
178
+ })
179
+
180
+ const max = PerformanceMonitor.config.maxMetrics ?? 1000
181
+ if (PerformanceMonitor.pageLoads.length > max) {
182
+ PerformanceMonitor.pageLoads = PerformanceMonitor.pageLoads.slice(-max)
183
+ }
184
+ }
185
+
186
+ /**
187
+ * Get aggregated performance metrics for a time range
188
+ */
189
+ static getMetrics(timeRange: { start: number; end: number }): PerformanceMetrics {
190
+ const { start, end } = timeRange
191
+
192
+ // Filter entries by time range
193
+ const rangedQueries = PerformanceMonitor.queries.filter(
194
+ (q) => q.timestamp >= start && q.timestamp <= end,
195
+ )
196
+ const rangedCache = PerformanceMonitor.cacheEntries.filter(
197
+ (c) => c.timestamp >= start && c.timestamp <= end,
198
+ )
199
+ const rangedErrors = PerformanceMonitor.errors.filter(
200
+ (e) => e.timestamp >= start && e.timestamp <= end,
201
+ )
202
+ const rangedPageLoads = PerformanceMonitor.pageLoads.filter(
203
+ (p) => p.timestamp >= start && p.timestamp <= end,
204
+ )
205
+
206
+ // Aggregate cache metrics
207
+ const hits = rangedCache.filter((c) => c.type === 'hit')
208
+ const misses = rangedCache.filter((c) => c.type === 'miss')
209
+ const totalCacheRequests = hits.length + misses.length
210
+
211
+ const cache: CacheMetrics = {
212
+ totalRequests: totalCacheRequests,
213
+ hits: hits.length,
214
+ misses: misses.length,
215
+ hitRate: totalCacheRequests > 0 ? (hits.length / totalCacheRequests) * 100 : 0,
216
+ avgHitTime: hits.length > 0 ? hits.reduce((s, h) => s + h.duration, 0) / hits.length : 0,
217
+ avgMissTime: misses.length > 0 ? misses.reduce((s, m) => s + (m.fetchDuration ?? m.duration), 0) / misses.length : 0,
218
+ }
219
+
220
+ // Aggregate query metrics
221
+ const queryMap = new Map<string, QueryEntry[]>()
222
+ for (const q of rangedQueries) {
223
+ const existing = queryMap.get(q.key) || []
224
+ existing.push(q)
225
+ queryMap.set(q.key, existing)
226
+ }
227
+
228
+ const queries: QueryMetrics[] = Array.from(queryMap.entries()).map(
229
+ ([key, entries]) => {
230
+ const durations = entries.map((e) => e.duration)
231
+ return {
232
+ queryKey: key,
233
+ executions: entries.length,
234
+ avgDuration: durations.reduce((s, d) => s + d, 0) / durations.length,
235
+ minDuration: Math.min(...durations),
236
+ maxDuration: Math.max(...durations),
237
+ errors: entries.filter((e) => e.error).length,
238
+ lastExecuted: Math.max(...entries.map((e) => e.timestamp)),
239
+ cached: entries.some((e) => e.cached),
240
+ }
241
+ },
242
+ )
243
+
244
+ // Aggregate error metrics
245
+ const errorMap = new Map<string, ErrorEntry[]>()
246
+ for (const e of rangedErrors) {
247
+ const key = `${e.type}:${e.message}`
248
+ const existing = errorMap.get(key) || []
249
+ existing.push(e)
250
+ errorMap.set(key, existing)
251
+ }
252
+
253
+ const errors: ErrorMetrics[] = Array.from(errorMap.entries()).map(
254
+ ([, entries]) => ({
255
+ type: entries[0].type,
256
+ message: entries[0].message,
257
+ stack: entries[0].stack,
258
+ count: entries.length,
259
+ firstSeen: Math.min(...entries.map((e) => e.timestamp)),
260
+ lastSeen: Math.max(...entries.map((e) => e.timestamp)),
261
+ affectedUsers: 1, // No user tracking in client-side monitor
262
+ }),
263
+ )
264
+
265
+ // Aggregate page loads
266
+ const pageLoads: PageLoadMetrics[] = rangedPageLoads.map((p) => ({
267
+ route: p.route,
268
+ ttfb: p.ttfb,
269
+ fcp: p.fcp,
270
+ lcp: p.lcp,
271
+ tti: p.tti,
272
+ loadTime: p.loadTime,
273
+ ssr: p.ssr,
274
+ timestamp: p.timestamp,
275
+ }))
276
+
277
+ // Calculate score (0-100)
278
+ let score = 100
279
+ if (cache.hitRate < 80) score -= 20
280
+ if (queries.some((q) => q.avgDuration > 1000)) score -= 15
281
+ if (errors.length > 0) score -= Math.min(errors.length * 5, 30)
282
+ if (pageLoads.some((p) => p.lcp > 2500)) score -= 15
283
+ score = Math.max(0, score)
284
+
285
+ return {
286
+ cache,
287
+ queries,
288
+ pageLoads,
289
+ errors,
290
+ score,
291
+ timeRange: { start, end },
292
+ }
293
+ }
294
+
295
+ /**
296
+ * Clear all collected metrics
297
+ */
298
+ static clear(): void {
299
+ PerformanceMonitor.queries = []
300
+ PerformanceMonitor.cacheEntries = []
301
+ PerformanceMonitor.errors = []
302
+ PerformanceMonitor.pageLoads = []
303
+ }
304
+
305
+ /**
306
+ * Export metrics as JSON
307
+ */
308
+ static exportMetrics(): string {
309
+ const end = Date.now()
310
+ const start = end - 24 * 60 * 60 * 1000
311
+ return JSON.stringify(PerformanceMonitor.getMetrics({ start, end }), null, 2)
312
+ }
313
+ }
@@ -0,0 +1,77 @@
1
+ // @geenius-tools/perf-react — src/types.ts
2
+
3
+ export interface CacheMetrics {
4
+ totalRequests: number
5
+ hits: number
6
+ misses: number
7
+ hitRate: number
8
+ avgHitTime: number
9
+ avgMissTime: number
10
+ cacheSize?: number
11
+ evictions?: number
12
+ }
13
+
14
+ export interface QueryMetrics {
15
+ queryKey: string
16
+ executions: number
17
+ avgDuration: number
18
+ minDuration: number
19
+ maxDuration: number
20
+ errors: number
21
+ lastExecuted: number
22
+ cached: boolean
23
+ }
24
+
25
+ export interface PageLoadMetrics {
26
+ route: string
27
+ ttfb: number
28
+ fcp: number
29
+ lcp: number
30
+ tti: number
31
+ loadTime: number
32
+ ssr: boolean
33
+ timestamp: number
34
+ }
35
+
36
+ export interface ErrorMetrics {
37
+ type: string
38
+ message: string
39
+ stack?: string
40
+ count: number
41
+ firstSeen: number
42
+ lastSeen: number
43
+ affectedUsers: number
44
+ }
45
+
46
+ export interface PerformanceMetrics {
47
+ cache: CacheMetrics
48
+ queries: QueryMetrics[]
49
+ pageLoads: PageLoadMetrics[]
50
+ errors: ErrorMetrics[]
51
+ score: number
52
+ timeRange: { start: number; end: number }
53
+ }
54
+
55
+ export interface PerformanceConfig {
56
+ enableCacheTracking?: boolean
57
+ enableQueryTracking?: boolean
58
+ enablePageLoadTracking?: boolean
59
+ enableErrorTracking?: boolean
60
+ sampleRate?: number
61
+ maxMetrics?: number
62
+ }
63
+
64
+ export interface CacheHitEvent {
65
+ queryKey: string
66
+ duration: number
67
+ timestamp: number
68
+ cacheType: 'ssr' | 'client' | 'memory'
69
+ }
70
+
71
+ export interface CacheMissEvent {
72
+ queryKey: string
73
+ duration: number
74
+ timestamp: number
75
+ cacheType: 'ssr' | 'client' | 'memory'
76
+ fetchDuration: number
77
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "jsx": "react-jsx",
7
+ "strict": true,
8
+ "esModuleInterop": true,
9
+ "skipLibCheck": true,
10
+ "forceConsistentCasingInFileNames": true,
11
+ "declaration": true,
12
+ "declarationDir": "./dist",
13
+ "outDir": "./dist",
14
+ "sourceMap": true,
15
+ "resolveJsonModule": true,
16
+ "isolatedModules": true
17
+ },
18
+ "include": [
19
+ "src"
20
+ ],
21
+ "exclude": [
22
+ "node_modules",
23
+ "dist"
24
+ ]
25
+ }
@@ -0,0 +1,19 @@
1
+ import { defineConfig } from 'tsup'
2
+
3
+ export default defineConfig({
4
+ entry: {
5
+ index: 'src/index.ts',
6
+ },
7
+ format: ['esm'],
8
+ dts: true,
9
+ clean: true,
10
+ outDir: 'dist',
11
+ sourcemap: true,
12
+ external: [
13
+ 'react',
14
+ 'react-dom',
15
+ 'lucide-react',
16
+ '@geenius-ui/react',
17
+ '@tanstack/react-query',
18
+ ],
19
+ })
@@ -0,0 +1 @@
1
+ # ✦ @geenius-tools/perf-solidjs\n\n> SolidJS performance monitoring — metrics signals & dashboard\n\n---\n\n## Overview\nBuilt with Steve Jobs-level minimalism and Jony Ive-level craftsmanship, this package is designed to deliver unparalleled developer experience (DX) and rock-solid performance.\n\n## Installation\n\n```bash\npnpm add @geenius-tools/perf-solidjs\n```\n\n## Usage\n\n```typescript\nimport { init } from '@geenius-tools/perf-solidjs';\n\n// Initialize the module with absolute precision\ninit({\n mode: 'premium',\n});\n```\n\n## Architecture\n- **Zero-config**: It just works.\n- **Strictly Typed**: Fully written in TypeScript for flawless IntelliSense.\n- **Framework Agnostic**: seamlessly integrates into the Geenius ecosystem.\n\n---\n\n*Designed by Antigravity HQ*\n
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@geenius-tools/perf-solidjs",
3
+ "version": "0.1.0",
4
+ "private": false,
5
+ "description": "SolidJS performance monitoring \u2014 metrics signals & dashboard",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "module": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "README.md"
19
+ ],
20
+ "scripts": {
21
+ "build": "tsup",
22
+ "dev": "tsup --watch",
23
+ "typecheck": "tsc --noEmit"
24
+ },
25
+ "devDependencies": {
26
+ "solid-js": "^1.9.0",
27
+ "tsup": "^8.5.1",
28
+ "typescript": "~5.9.3"
29
+ },
30
+ "peerDependencies": {
31
+ "solid-js": "^1.8.0 || ^1.9.0"
32
+ },
33
+ "author": "Antigravity HQ",
34
+ "license": "MIT",
35
+ "engines": {
36
+ "node": ">=20.0.0"
37
+ },
38
+ "publishConfig": {
39
+ "access": "public"
40
+ }
41
+ }
@@ -0,0 +1,207 @@
1
+ /**
2
+ * @geenius-tools/perf-solidjs — components/PerformanceDashboard.tsx
3
+ *
4
+ * Rich performance dashboard with SSR cache hit rates, query performance,
5
+ * and error metrics. SolidJS variant with reactive primitives.
6
+ *
7
+ * Uses Tailwind CSS utility classes.
8
+ */
9
+
10
+ import { Show, For } from 'solid-js/web'
11
+
12
+ // ─── Types (re-exported from React variant for consistency) ─────────────────
13
+
14
+ export interface CacheMetrics {
15
+ hitRate: number
16
+ totalRequests: number
17
+ hits: number
18
+ misses: number
19
+ avgHitTime: number
20
+ avgMissTime: number
21
+ }
22
+
23
+ export interface QueryMetric {
24
+ queryKey: string
25
+ executions: number
26
+ avgDuration: number
27
+ minDuration: number
28
+ maxDuration: number
29
+ errors: number
30
+ cached: boolean
31
+ }
32
+
33
+ export interface ErrorMetric {
34
+ type: string
35
+ message: string
36
+ count: number
37
+ firstSeen: number
38
+ lastSeen: number
39
+ }
40
+
41
+ export interface PerformanceMetricsData {
42
+ score: number
43
+ cache: CacheMetrics
44
+ queries: QueryMetric[]
45
+ errors: ErrorMetric[]
46
+ }
47
+
48
+ export interface PerformanceDashboardProps {
49
+ metrics: PerformanceMetricsData | null
50
+ isLoading: boolean
51
+ error: Error | null
52
+ onRefresh: () => void
53
+ onClear: () => void
54
+ onExport: () => string
55
+ }
56
+
57
+ export function PerformanceDashboard(props: PerformanceDashboardProps) {
58
+ const downloadMetrics = () => {
59
+ const data = props.onExport()
60
+ const blob = new Blob([data], { type: 'application/json' })
61
+ const url = URL.createObjectURL(blob)
62
+ const a = document.createElement('a')
63
+ a.href = url
64
+ a.download = `performance-metrics-${Date.now()}.json`
65
+ a.click()
66
+ URL.revokeObjectURL(url)
67
+ }
68
+
69
+ const scoreBadge = () => {
70
+ const s = props.metrics?.score ?? 0
71
+ if (s >= 90) return { emoji: '🟢', label: 'Excellent', color: 'bg-green-100 text-green-800' }
72
+ if (s >= 70) return { emoji: '🟡', label: 'Good', color: 'bg-yellow-100 text-yellow-800' }
73
+ return { emoji: '🔴', label: 'Needs Improvement', color: 'bg-red-100 text-red-800' }
74
+ }
75
+
76
+ return (
77
+ <>
78
+ <Show when={props.isLoading && !props.metrics}>
79
+ <div class="flex justify-center py-8">
80
+ <div class="animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full" />
81
+ <span class="ml-3 text-muted-foreground">Loading performance metrics…</span>
82
+ </div>
83
+ </Show>
84
+
85
+ <Show when={props.error}>
86
+ <div class="rounded-xl border border-border bg-card p-6">
87
+ <div class="text-red-600">Error loading metrics: {props.error?.message}</div>
88
+ </div>
89
+ </Show>
90
+
91
+ <Show when={props.metrics}>
92
+ {(m) => (
93
+ <div class="space-y-6">
94
+ <div class="flex items-center justify-between">
95
+ <div>
96
+ <h1 class="text-2xl font-bold">Performance Monitoring</h1>
97
+ <p class="text-muted-foreground mt-1">SSR Cache, Query Performance, and Error Tracking</p>
98
+ </div>
99
+ <div class="flex gap-2">
100
+ <button type="button" onClick={props.onRefresh} class="px-4 py-2 rounded-lg border border-border text-sm font-medium hover:bg-bg-muted transition-colors">Refresh</button>
101
+ <button type="button" onClick={downloadMetrics} class="px-4 py-2 rounded-lg border border-border text-sm font-medium hover:bg-bg-muted transition-colors">Export</button>
102
+ <button type="button" onClick={props.onClear} class="px-4 py-2 rounded-lg border border-border text-sm font-medium hover:bg-bg-muted transition-colors">Clear</button>
103
+ </div>
104
+ </div>
105
+
106
+ <div class="rounded-xl border border-border bg-card p-6">
107
+ <div class="flex items-center justify-between">
108
+ <div>
109
+ <div class="text-sm text-muted-foreground mb-1">Overall Performance Score</div>
110
+ <div class="text-4xl font-bold text-foreground">{m().score}</div>
111
+ </div>
112
+ <div class="text-5xl">{scoreBadge().emoji}</div>
113
+ </div>
114
+ <div class="mt-4">
115
+ <span class={`px-2 py-1 rounded-full text-xs font-medium ${scoreBadge().color}`}>{scoreBadge().label}</span>
116
+ </div>
117
+ </div>
118
+
119
+ <div>
120
+ <h2 class="text-xl font-semibold mb-4">SSR Cache Performance</h2>
121
+ <div class="grid grid-cols-1 md:grid-cols-4 gap-4">
122
+ <MetricCard label="Cache Hit Rate" value={`${m().cache.hitRate.toFixed(1)}%`} badge={m().cache.hitRate >= 80 ? 'Excellent' : m().cache.hitRate >= 50 ? 'Good' : 'Poor'} badgeColor={m().cache.hitRate >= 80 ? 'bg-green-100 text-green-800' : m().cache.hitRate >= 50 ? 'bg-yellow-100 text-yellow-800' : 'bg-red-100 text-red-800'} />
123
+ <MetricCard label="Total Requests" value={m().cache.totalRequests.toLocaleString()} subtitle={`${m().cache.hits} hits / ${m().cache.misses} misses`} />
124
+ <MetricCard label="Avg Hit Time" value={`${m().cache.avgHitTime.toFixed(0)}`} unit="ms" badge={m().cache.avgHitTime < 50 ? 'Fast' : 'Acceptable'} badgeColor={m().cache.avgHitTime < 50 ? 'bg-green-100 text-green-800' : 'bg-yellow-100 text-yellow-800'} />
125
+ <MetricCard label="Avg Miss Time" value={`${m().cache.avgMissTime.toFixed(0)}`} unit="ms" subtitle={`Time saved: ${(m().cache.avgMissTime - m().cache.avgHitTime).toFixed(0)}ms`} />
126
+ </div>
127
+ </div>
128
+
129
+ <div>
130
+ <h2 class="text-xl font-semibold mb-4">Top Queries by Executions</h2>
131
+ <div class="rounded-xl border border-border bg-card overflow-x-auto">
132
+ <table class="w-full">
133
+ <thead>
134
+ <tr class="border-b border-border">
135
+ <For each={['Query', 'Executions', 'Avg Duration', 'Errors', 'Cached']}>
136
+ {(h) => <th class="text-left p-4 text-sm font-semibold text-muted-foreground">{h}</th>}
137
+ </For>
138
+ </tr>
139
+ </thead>
140
+ <tbody>
141
+ <For each={m().queries.slice(0, 10)}>
142
+ {(query) => (
143
+ <tr class="border-b border-border/50 hover:bg-surface">
144
+ <td class="p-4 text-sm font-mono text-foreground truncate max-w-xs">{query.queryKey}</td>
145
+ <td class="p-4 text-sm text-foreground">{query.executions}</td>
146
+ <td class="p-4 text-sm text-foreground">{query.avgDuration.toFixed(0)}ms <span class="text-xs text-muted-foreground ml-2">({query.minDuration.toFixed(0)}-{query.maxDuration.toFixed(0)}ms)</span></td>
147
+ <td class="p-4">{query.errors > 0 ? <span class="px-2 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800">{query.errors}</span> : <span class="text-sm text-muted-foreground/60">0</span>}</td>
148
+ <td class="p-4"><span class={`px-2 py-0.5 rounded-full text-xs font-medium ${query.cached ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-600'}`}>{query.cached ? 'Yes' : 'No'}</span></td>
149
+ </tr>
150
+ )}
151
+ </For>
152
+ <Show when={m().queries.length === 0}>
153
+ <tr><td colSpan={5} class="p-8 text-center text-muted-foreground">No query data available</td></tr>
154
+ </Show>
155
+ </tbody>
156
+ </table>
157
+ </div>
158
+ </div>
159
+
160
+ <Show when={m().errors.length > 0}>
161
+ <div>
162
+ <h2 class="text-xl font-semibold mb-4">Recent Errors</h2>
163
+ <div class="rounded-xl border border-border bg-card divide-y divide-border">
164
+ <For each={m().errors.slice(0, 5)}>
165
+ {(err) => (
166
+ <div class="p-4">
167
+ <div class="flex items-start justify-between">
168
+ <div class="flex-1">
169
+ <div class="flex items-center gap-2 mb-1">
170
+ <span class="px-2 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800">{err.type}</span>
171
+ <span class="text-sm font-semibold text-foreground">{err.message}</span>
172
+ </div>
173
+ <div class="text-xs text-muted-foreground">
174
+ First seen: {new Date(err.firstSeen).toLocaleString()} | Last seen: {new Date(err.lastSeen).toLocaleString()}
175
+ </div>
176
+ </div>
177
+ <div class="text-right ml-4">
178
+ <div class="text-lg font-bold text-red-600">{err.count}</div>
179
+ <div class="text-xs text-muted-foreground">occurrences</div>
180
+ </div>
181
+ </div>
182
+ </div>
183
+ )}
184
+ </For>
185
+ </div>
186
+ </div>
187
+ </Show>
188
+ </div>
189
+ )}
190
+ </Show>
191
+ </>
192
+ )
193
+ }
194
+
195
+ function MetricCard(props: { label: string; value: string; unit?: string; subtitle?: string; badge?: string; badgeColor?: string }) {
196
+ return (
197
+ <div class="rounded-xl border border-border bg-card p-6">
198
+ <div class="text-sm text-muted-foreground mb-1">{props.label}</div>
199
+ <div class="text-3xl font-bold text-foreground">
200
+ {props.value}
201
+ <Show when={props.unit}><span class="text-lg text-muted-foreground">{props.unit}</span></Show>
202
+ </div>
203
+ <Show when={props.badge}><div class="mt-2"><span class={`px-2 py-0.5 rounded-full text-xs font-medium ${props.badgeColor}`}>{props.badge}</span></div></Show>
204
+ <Show when={props.subtitle}><div class="mt-2 text-sm text-muted-foreground">{props.subtitle}</div></Show>
205
+ </div>
206
+ )
207
+ }