@geenius/tools 0.1.0 → 0.3.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 (177) hide show
  1. package/package.json +62 -3
  2. package/packages/convex/shared/README.md +1 -1
  3. package/packages/devtools/dist/index.d.ts +204 -0
  4. package/packages/devtools/dist/index.js +186 -0
  5. package/packages/devtools/dist/index.js.map +1 -0
  6. package/packages/devtools/react/README.md +1 -1
  7. package/packages/devtools/solidjs/README.md +1 -1
  8. package/packages/devtools/solidjs/dist/index.js +1830 -0
  9. package/packages/devtools/solidjs/dist/index.js.map +1 -0
  10. package/packages/env/dist/index.d.ts +151 -0
  11. package/packages/env/dist/index.js +93 -0
  12. package/packages/env/dist/index.js.map +1 -0
  13. package/packages/errors/dist/index.d.ts +177 -0
  14. package/packages/errors/dist/index.js +187 -0
  15. package/packages/errors/dist/index.js.map +1 -0
  16. package/packages/errors/react/README.md +1 -1
  17. package/packages/errors/solidjs/README.md +1 -1
  18. package/packages/logger/dist/index.d.ts +171 -0
  19. package/packages/logger/dist/index.js +216 -0
  20. package/packages/logger/dist/index.js.map +1 -0
  21. package/packages/logger/react/README.md +1 -1
  22. package/packages/logger/solidjs/README.md +1 -1
  23. package/packages/perf/dist/index.d.ts +168 -0
  24. package/packages/perf/dist/index.js +265 -0
  25. package/packages/perf/dist/index.js.map +1 -0
  26. package/packages/perf/react/README.md +1 -1
  27. package/packages/perf/solidjs/README.md +1 -1
  28. package/packages/shared/dist/index.d.ts +253 -0
  29. package/packages/shared/dist/index.js +278 -0
  30. package/packages/shared/dist/index.js.map +1 -0
  31. package/.changeset/config.json +0 -11
  32. package/.env.example +0 -2
  33. package/.github/CODEOWNERS +0 -1
  34. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -16
  35. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -11
  36. package/.github/PULL_REQUEST_TEMPLATE.md +0 -10
  37. package/.github/dependabot.yml +0 -11
  38. package/.github/workflows/ci.yml +0 -23
  39. package/.github/workflows/release.yml +0 -29
  40. package/.node-version +0 -1
  41. package/.nvmrc +0 -1
  42. package/.prettierrc +0 -7
  43. package/.project/ACCOUNT.yaml +0 -4
  44. package/.project/IDEAS.yaml +0 -7
  45. package/.project/PROJECT.yaml +0 -11
  46. package/.project/ROADMAP.yaml +0 -15
  47. package/CODE_OF_CONDUCT.md +0 -26
  48. package/CONTRIBUTING.md +0 -69
  49. package/SECURITY.md +0 -18
  50. package/SUPPORT.md +0 -14
  51. package/packages/convex/shared/package.json +0 -42
  52. package/packages/convex/shared/src/audit/index.ts +0 -5
  53. package/packages/convex/shared/src/audit/presets.ts +0 -165
  54. package/packages/convex/shared/src/audit/schema.ts +0 -85
  55. package/packages/convex/shared/src/audit/write.ts +0 -102
  56. package/packages/convex/shared/src/extract.ts +0 -75
  57. package/packages/convex/shared/src/index.ts +0 -41
  58. package/packages/convex/shared/src/messages.ts +0 -45
  59. package/packages/convex/shared/src/security.ts +0 -112
  60. package/packages/convex/shared/src/throw.ts +0 -184
  61. package/packages/convex/shared/src/types.ts +0 -57
  62. package/packages/convex/shared/src/utils.ts +0 -58
  63. package/packages/convex/shared/tsconfig.json +0 -28
  64. package/packages/convex/shared/tsup.config.ts +0 -12
  65. package/packages/devtools/package.json +0 -27
  66. package/packages/devtools/react/package.json +0 -53
  67. package/packages/devtools/react/src/components/DesignPreview.tsx +0 -59
  68. package/packages/devtools/react/src/components/DesignSwitcherDropdown.tsx +0 -99
  69. package/packages/devtools/react/src/components/DevSidebar.tsx +0 -247
  70. package/packages/devtools/react/src/components/DevToolbar.tsx +0 -242
  71. package/packages/devtools/react/src/components/GitHubIssueDialog.tsx +0 -402
  72. package/packages/devtools/react/src/components/InspectorOverlay.tsx +0 -312
  73. package/packages/devtools/react/src/components/PageLoadWaterfall.tsx +0 -144
  74. package/packages/devtools/react/src/components/PerformancePanel.tsx +0 -330
  75. package/packages/devtools/react/src/context/DevModeContext.tsx +0 -226
  76. package/packages/devtools/react/src/context/PerformanceContext.tsx +0 -143
  77. package/packages/devtools/react/src/data/designs.ts +0 -13
  78. package/packages/devtools/react/src/hooks/useGitHubLabels.ts +0 -47
  79. package/packages/devtools/react/src/hooks/useVirtualList.ts +0 -124
  80. package/packages/devtools/react/src/index.ts +0 -77
  81. package/packages/devtools/react/src/panels/ConvexSpy.tsx +0 -130
  82. package/packages/devtools/react/src/panels/DatabaseSeeder.tsx +0 -116
  83. package/packages/devtools/react/src/panels/DevModePhase2.tsx +0 -191
  84. package/packages/devtools/react/src/panels/DevModePhase3.tsx +0 -234
  85. package/packages/devtools/react/src/panels/FeatureFlagsToggle.tsx +0 -104
  86. package/packages/devtools/react/src/panels/QuickRouteJump.tsx +0 -152
  87. package/packages/devtools/react/src/services/github-service.ts +0 -247
  88. package/packages/devtools/react/tsconfig.json +0 -31
  89. package/packages/devtools/react/tsup.config.ts +0 -18
  90. package/packages/devtools/solidjs/package.json +0 -49
  91. package/packages/devtools/solidjs/src/components/DesignPreview.tsx +0 -51
  92. package/packages/devtools/solidjs/src/components/DesignSwitcherDropdown.tsx +0 -95
  93. package/packages/devtools/solidjs/src/components/DevSidebar.tsx +0 -247
  94. package/packages/devtools/solidjs/src/components/DevToolbar.tsx +0 -242
  95. package/packages/devtools/solidjs/src/components/GitHubIssueDialog.tsx +0 -400
  96. package/packages/devtools/solidjs/src/components/InspectorOverlay.tsx +0 -311
  97. package/packages/devtools/solidjs/src/components/PageLoadWaterfall.tsx +0 -144
  98. package/packages/devtools/solidjs/src/components/PerformancePanel.tsx +0 -330
  99. package/packages/devtools/solidjs/src/context/DevModeContext.tsx +0 -216
  100. package/packages/devtools/solidjs/src/context/PerformanceContext.tsx +0 -135
  101. package/packages/devtools/solidjs/src/data/designs.ts +0 -13
  102. package/packages/devtools/solidjs/src/hooks/createGitHubLabels.ts +0 -47
  103. package/packages/devtools/solidjs/src/index.ts +0 -64
  104. package/packages/devtools/solidjs/src/services/github-service.ts +0 -247
  105. package/packages/devtools/solidjs/tsconfig.json +0 -21
  106. package/packages/devtools/src/index.ts +0 -377
  107. package/packages/devtools/tsup.config.ts +0 -12
  108. package/packages/env/package.json +0 -30
  109. package/packages/env/src/index.ts +0 -264
  110. package/packages/env/tsup.config.ts +0 -12
  111. package/packages/errors/package.json +0 -27
  112. package/packages/errors/react/package.json +0 -72
  113. package/packages/errors/react/src/analytics.ts +0 -16
  114. package/packages/errors/react/src/components/ErrorBoundary.tsx +0 -248
  115. package/packages/errors/react/src/components/ErrorDisplay.tsx +0 -328
  116. package/packages/errors/react/src/components/ValidationErrors.tsx +0 -102
  117. package/packages/errors/react/src/config.ts +0 -199
  118. package/packages/errors/react/src/constants.ts +0 -74
  119. package/packages/errors/react/src/hooks/useErrorBoundary.ts +0 -92
  120. package/packages/errors/react/src/hooks/useErrorHandler.ts +0 -87
  121. package/packages/errors/react/src/index.ts +0 -96
  122. package/packages/errors/react/src/types.ts +0 -102
  123. package/packages/errors/react/src/utils/errorMessages.ts +0 -35
  124. package/packages/errors/react/src/utils/errorPolicy.ts +0 -139
  125. package/packages/errors/react/src/utils/extractAppError.ts +0 -174
  126. package/packages/errors/react/src/utils/formatError.ts +0 -112
  127. package/packages/errors/react/tsconfig.json +0 -25
  128. package/packages/errors/react/tsup.config.ts +0 -24
  129. package/packages/errors/solidjs/package.json +0 -46
  130. package/packages/errors/solidjs/src/components/ErrorDisplay.tsx +0 -179
  131. package/packages/errors/solidjs/src/config.ts +0 -98
  132. package/packages/errors/solidjs/src/hooks/createErrorHandler.ts +0 -107
  133. package/packages/errors/solidjs/src/index.ts +0 -61
  134. package/packages/errors/solidjs/src/types.ts +0 -34
  135. package/packages/errors/solidjs/src/utils/errorPolicy.ts +0 -56
  136. package/packages/errors/solidjs/src/utils/extractAppError.ts +0 -94
  137. package/packages/errors/solidjs/src/utils/formatError.ts +0 -33
  138. package/packages/errors/solidjs/tsconfig.json +0 -26
  139. package/packages/errors/solidjs/tsup.config.ts +0 -21
  140. package/packages/errors/src/index.ts +0 -320
  141. package/packages/errors/tsup.config.ts +0 -12
  142. package/packages/logger/package.json +0 -27
  143. package/packages/logger/react/package.json +0 -46
  144. package/packages/logger/react/src/index.ts +0 -4
  145. package/packages/logger/react/src/useMetrics.ts +0 -42
  146. package/packages/logger/react/src/usePerformanceLog.ts +0 -61
  147. package/packages/logger/react/tsconfig.json +0 -31
  148. package/packages/logger/react/tsup.config.ts +0 -12
  149. package/packages/logger/solidjs/package.json +0 -45
  150. package/packages/logger/solidjs/src/createMetrics.ts +0 -37
  151. package/packages/logger/solidjs/src/createPerformanceLog.ts +0 -58
  152. package/packages/logger/solidjs/src/index.ts +0 -4
  153. package/packages/logger/solidjs/tsconfig.json +0 -32
  154. package/packages/logger/solidjs/tsup.config.ts +0 -12
  155. package/packages/logger/src/index.ts +0 -363
  156. package/packages/logger/tsup.config.ts +0 -12
  157. package/packages/perf/package.json +0 -27
  158. package/packages/perf/react/package.json +0 -59
  159. package/packages/perf/react/src/components/PerformanceDashboard.tsx +0 -257
  160. package/packages/perf/react/src/hooks/useMonitoredQuery.ts +0 -89
  161. package/packages/perf/react/src/hooks/usePerformanceMetrics.ts +0 -78
  162. package/packages/perf/react/src/index.ts +0 -33
  163. package/packages/perf/react/src/services/PerformanceMonitor.ts +0 -313
  164. package/packages/perf/react/src/types.ts +0 -77
  165. package/packages/perf/react/tsconfig.json +0 -25
  166. package/packages/perf/react/tsup.config.ts +0 -19
  167. package/packages/perf/solidjs/package.json +0 -41
  168. package/packages/perf/solidjs/src/components/PerformanceDashboard.tsx +0 -207
  169. package/packages/perf/solidjs/src/hooks/createPerformanceMetrics.ts +0 -73
  170. package/packages/perf/solidjs/src/index.ts +0 -31
  171. package/packages/perf/solidjs/src/services/PerformanceMonitor.ts +0 -134
  172. package/packages/perf/solidjs/src/types.ts +0 -78
  173. package/packages/perf/solidjs/tsconfig.json +0 -26
  174. package/packages/perf/solidjs/tsup.config.ts +0 -14
  175. package/packages/perf/src/index.ts +0 -410
  176. package/packages/perf/tsup.config.ts +0 -12
  177. package/pnpm-workspace.yaml +0 -2
@@ -1,330 +0,0 @@
1
- // @geenius-tools/devtools-react — src/components/PerformancePanel.tsx
2
-
3
- import { memo, useMemo, useRef, useEffect } from 'react'
4
- import { cn } from '@geenius-ui/react'
5
- import { X, Trash2, Activity, Zap, Clock, AlertTriangle } from 'lucide-react'
6
- import { usePerformanceContext } from '../context/PerformanceContext'
7
- import type { PerformanceMetric } from '@geenius-tools/logger'
8
-
9
- function getDurationColor(duration: number | undefined): string {
10
- if (duration === undefined) return 'text-white/40'
11
- if (duration > 100) return 'text-red-400'
12
- if (duration > 50) return 'text-yellow-400'
13
- return 'text-green-400'
14
- }
15
-
16
- function getDurationBgColor(duration: number | undefined): string {
17
- if (duration === undefined) return 'bg-white/20'
18
- if (duration > 100) return 'bg-red-500'
19
- if (duration > 50) return 'bg-yellow-500'
20
- return 'bg-green-500'
21
- }
22
-
23
- function getTypeColor(type: string): string {
24
- switch (type) {
25
- case 'network':
26
- return 'text-blue-400'
27
- case 'query':
28
- return 'text-orange-400'
29
- case 'mutation':
30
- return 'text-red-400'
31
- case 'render':
32
- return 'text-purple-400'
33
- case 'route':
34
- return 'text-green-400'
35
- case 'component':
36
- return 'text-cyan-400'
37
- case 'effect':
38
- return 'text-teal-400'
39
- default:
40
- return 'text-white/60'
41
- }
42
- }
43
-
44
- function getTypeIcon(type: string) {
45
- switch (type) {
46
- case 'network':
47
- return '🌐'
48
- case 'query':
49
- return '🔍'
50
- case 'mutation':
51
- return '✏️'
52
- case 'render':
53
- return '🎨'
54
- case 'route':
55
- return '🧭'
56
- case 'component':
57
- return '📦'
58
- case 'effect':
59
- return '⚡'
60
- default:
61
- return '📝'
62
- }
63
- }
64
-
65
- const MiniBar = memo(function MiniBar({
66
- height,
67
- color,
68
- label,
69
- }: {
70
- height: number
71
- color: string
72
- label: string
73
- }) {
74
- return (
75
- <div className="flex flex-col items-center gap-0.5 flex-1 min-w-0">
76
- <div className="w-full h-12 flex items-end">
77
- <div
78
- className={cn('w-full rounded-t-sm transition-all duration-300', color)}
79
- style={{ height: `${Math.min(height, 100)}%` }}
80
- title={label}
81
- />
82
- </div>
83
- </div>
84
- )
85
- })
86
-
87
- const MetricRow = memo(function MetricRow({
88
- metric,
89
- }: {
90
- metric: PerformanceMetric
91
- }) {
92
- const duration = metric.duration
93
- const durationStr = duration ? `${duration.toFixed(1)}ms` : 'pending...'
94
-
95
- return (
96
- <div
97
- className={cn(
98
- 'flex items-center gap-3 px-3 py-2 rounded-lg',
99
- 'bg-white/5 hover:bg-white/10 transition-colors',
100
- )}
101
- >
102
- <span className="text-sm">{getTypeIcon(metric.type)}</span>
103
- <div className="flex-1 min-w-0">
104
- <div className={cn('text-xs font-medium truncate', getTypeColor(metric.type))}>
105
- {metric.name}
106
- </div>
107
- </div>
108
- <div
109
- className={cn(
110
- 'text-xs font-mono font-bold',
111
- getDurationColor(duration),
112
- )}
113
- >
114
- {durationStr}
115
- </div>
116
- </div>
117
- )
118
- })
119
-
120
- const StatCard = memo(function StatCard({
121
- icon: Icon,
122
- label,
123
- value,
124
- color = 'text-white',
125
- }: {
126
- icon: React.ElementType
127
- label: string
128
- value: string | number
129
- color?: string
130
- }) {
131
- return (
132
- <div className="flex items-center gap-2 px-3 py-2 rounded-lg bg-white/5">
133
- <Icon className={cn('w-4 h-4', color)} />
134
- <div className="flex flex-col">
135
- <span className="text-[10px] text-white/50 uppercase">{label}</span>
136
- <span className="text-sm font-bold text-white">{value}</span>
137
- </div>
138
- </div>
139
- )
140
- })
141
-
142
- const FilterToggle = memo(function FilterToggle({
143
- label,
144
- active,
145
- color,
146
- onClick,
147
- }: {
148
- label: string
149
- active: boolean
150
- color: string
151
- onClick: () => void
152
- }) {
153
- return (
154
- <button
155
- onClick={onClick}
156
- className={cn(
157
- 'px-2 py-1 rounded text-xs font-medium transition-all',
158
- active
159
- ? `${color} text-white`
160
- : 'bg-white/10 text-white/50 hover:bg-white/20',
161
- )}
162
- >
163
- {label}
164
- </button>
165
- )
166
- })
167
-
168
- export const PerformancePanel = memo(function PerformancePanel() {
169
- const {
170
- isPerformancePanelOpen,
171
- metrics,
172
- filters,
173
- stats,
174
- togglePerformancePanel,
175
- clearMetrics,
176
- toggleFilter,
177
- } = usePerformanceContext()
178
-
179
- const listRef = useRef<HTMLDivElement>(null)
180
-
181
- const filteredMetrics = useMemo(() => {
182
- return metrics.filter((m) => {
183
- if (m.type === 'network' && !filters.network) return false
184
- if (m.type === 'query' && !filters.query) return false
185
- if (m.type === 'mutation' && !filters.mutation) return false
186
- if (m.type === 'render' && !filters.render) return false
187
- if (m.type === 'route' && !filters.route) return false
188
- return true
189
- })
190
- }, [metrics, filters])
191
-
192
- const chartMetrics = useMemo(() => {
193
- return filteredMetrics.filter((m) => m.duration !== undefined).slice(-20)
194
- }, [filteredMetrics])
195
-
196
- const maxDuration = useMemo(() => {
197
- if (chartMetrics.length === 0) return 100
198
- const max = Math.max(...chartMetrics.map((m) => m.duration || 0))
199
- return Math.max(max, 100)
200
- }, [chartMetrics])
201
-
202
- useEffect(() => {
203
- if (listRef.current) {
204
- listRef.current.scrollTop = listRef.current.scrollHeight
205
- }
206
- }, [filteredMetrics.length])
207
-
208
- if (!isPerformancePanelOpen) return null
209
-
210
- return (
211
- <div
212
- data-dev-tool="true"
213
- className={cn(
214
- 'fixed bottom-20 left-1/2 -translate-x-1/2 z-50',
215
- 'w-[440px] max-h-[400px]',
216
- 'rounded-2xl border border-white/10',
217
- 'bg-gradient-to-b from-slate-900/95 via-slate-800/95 to-slate-900/95',
218
- 'backdrop-blur-xl shadow-2xl shadow-black/50',
219
- 'flex flex-col overflow-hidden',
220
- 'animate-in slide-in-from-bottom-4 fade-in duration-300',
221
- )}
222
- >
223
- {/* Header */}
224
- <div className="flex items-center justify-between px-4 py-3 border-b border-white/10">
225
- <div className="flex items-center gap-2">
226
- <Activity className="w-4 h-4 text-primary" />
227
- <span className="text-sm font-bold text-white">Performance</span>
228
- <span className="text-xs text-white/40">
229
- ({filteredMetrics.length} events)
230
- </span>
231
- </div>
232
- <div className="flex items-center gap-1">
233
- <button
234
- onClick={clearMetrics}
235
- className="p-1.5 text-white/40 hover:text-white hover:bg-white/10 rounded-lg transition-colors"
236
- title="Clear metrics"
237
- >
238
- <Trash2 className="w-3.5 h-3.5" />
239
- </button>
240
- <button
241
- onClick={togglePerformancePanel}
242
- className="p-1.5 text-white/40 hover:text-white hover:bg-white/10 rounded-lg transition-colors"
243
- title="Close panel"
244
- >
245
- <X className="w-4 h-4" />
246
- </button>
247
- </div>
248
- </div>
249
-
250
- {/* Stats Bar */}
251
- <div className="flex gap-2 px-4 py-3 border-b border-white/10 overflow-x-auto">
252
- <StatCard
253
- icon={Activity}
254
- label="Requests"
255
- value={stats.totalRequests}
256
- color="text-blue-400"
257
- />
258
- <StatCard
259
- icon={Clock}
260
- label="Avg"
261
- value={`${stats.avgDuration}ms`}
262
- color={
263
- stats.avgDuration > 100
264
- ? 'text-red-400'
265
- : stats.avgDuration > 50
266
- ? 'text-yellow-400'
267
- : 'text-green-400'
268
- }
269
- />
270
- <StatCard
271
- icon={Zap}
272
- label="Fast"
273
- value={stats.fastRequests}
274
- color="text-green-400"
275
- />
276
- <StatCard
277
- icon={AlertTriangle}
278
- label="Slow"
279
- value={stats.slowRequests}
280
- color={stats.slowRequests > 0 ? 'text-red-400' : 'text-white/50'}
281
- />
282
- </div>
283
-
284
- {/* Mini Chart */}
285
- {chartMetrics.length > 0 && (
286
- <div className="px-4 py-3 border-b border-white/10">
287
- <div className="flex items-end gap-1 h-16">
288
- {chartMetrics.map((metric) => (
289
- <MiniBar
290
- key={metric.id}
291
- height={((metric.duration || 0) / maxDuration) * 100}
292
- color={getDurationBgColor(metric.duration)}
293
- label={`${metric.name}: ${metric.duration?.toFixed(1)}ms`}
294
- />
295
- ))}
296
- </div>
297
- <div className="flex justify-between mt-1 text-xs text-white/40">
298
- <span>Recent requests</span>
299
- <span>0-{maxDuration.toFixed(0)}ms</span>
300
- </div>
301
- </div>
302
- )}
303
-
304
- {/* Filters */}
305
- <div className="flex gap-1 px-4 py-2 border-b border-white/10">
306
- <FilterToggle label="Network" active={filters.network} color="bg-blue-500" onClick={() => toggleFilter('network')} />
307
- <FilterToggle label="Query" active={filters.query} color="bg-orange-500" onClick={() => toggleFilter('query')} />
308
- <FilterToggle label="Mutation" active={filters.mutation} color="bg-red-500" onClick={() => toggleFilter('mutation')} />
309
- <FilterToggle label="Render" active={filters.render} color="bg-purple-500" onClick={() => toggleFilter('render')} />
310
- <FilterToggle label="Route" active={filters.route} color="bg-green-500" onClick={() => toggleFilter('route')} />
311
- </div>
312
-
313
- {/* Metrics List */}
314
- <div
315
- ref={listRef}
316
- className="flex-1 overflow-y-auto px-3 py-2 space-y-1 min-h-[100px] max-h-[180px]"
317
- >
318
- {filteredMetrics.length === 0 ? (
319
- <div className="flex items-center justify-center py-8 text-sm text-white/30">
320
- No metrics recorded yet
321
- </div>
322
- ) : (
323
- filteredMetrics.map((metric) => (
324
- <MetricRow key={metric.id} metric={metric} />
325
- ))
326
- )}
327
- </div>
328
- </div>
329
- )
330
- })
@@ -1,226 +0,0 @@
1
- // @geenius-tools/devtools-react — src/context/DevModeContext.tsx
2
-
3
- import {
4
- createContext,
5
- useContext,
6
- useState,
7
- useCallback,
8
- useEffect,
9
- type ReactNode,
10
- memo,
11
- } from 'react'
12
-
13
- const DEV_MODE_STORAGE_KEY = 'geenius-dev-mode-state'
14
-
15
- export interface ComponentDetails {
16
- name: string
17
- file?: string
18
- selector: string
19
- key?: string
20
- props?: Record<string, unknown>
21
- }
22
-
23
- interface DevModeState {
24
- isDevMode: boolean
25
- isSidebarOpen: boolean
26
- isInspectorMode: boolean
27
- issueDialog: {
28
- isOpen: boolean
29
- type: 'bug' | 'feature'
30
- initialDescription?: string
31
- componentDetails?: ComponentDetails[]
32
- }
33
- }
34
-
35
- export interface DevModeContextValue extends DevModeState {
36
- toggleDevMode: () => void
37
- toggleSidebar: () => void
38
- toggleInspector: () => void
39
- setDevMode: (enabled: boolean) => void
40
- setSidebarOpen: (open: boolean) => void
41
- setInspectorMode: (enabled: boolean) => void
42
- openIssueDialog: (
43
- type: 'bug' | 'feature',
44
- description?: string,
45
- componentDetails?: ComponentDetails[],
46
- ) => void
47
- closeIssueDialog: () => void
48
- }
49
-
50
- const defaultState: DevModeState = {
51
- isDevMode: false,
52
- isSidebarOpen: false,
53
- isInspectorMode: false,
54
- issueDialog: {
55
- isOpen: false,
56
- type: 'bug',
57
- initialDescription: '',
58
- },
59
- }
60
-
61
- const DevModeContext = createContext<DevModeContextValue | undefined>(undefined)
62
-
63
- export function useDevMode() {
64
- const context = useContext(DevModeContext)
65
- if (!context) {
66
- throw new Error('useDevMode must be used within a DevModeProvider')
67
- }
68
- return context
69
- }
70
-
71
- export function useDevModeOptional(): DevModeContextValue | null {
72
- return useContext(DevModeContext) ?? null
73
- }
74
-
75
- export interface DevModeProviderProps {
76
- children: ReactNode
77
- /** Whether dev tools are allowed. Default: checks import.meta.env.DEV */
78
- isAllowed?: boolean
79
- }
80
-
81
- export const DevModeProvider = memo(function DevModeProvider({
82
- children,
83
- isAllowed,
84
- }: DevModeProviderProps) {
85
- const resolvedAllowed = isAllowed ?? resolveDevAllowed()
86
-
87
- const [state, setState] = useState<DevModeState>(() => {
88
- if (!resolvedAllowed || typeof window === 'undefined') return defaultState
89
-
90
- try {
91
- const stored = localStorage.getItem(DEV_MODE_STORAGE_KEY)
92
- if (stored) {
93
- const parsed = JSON.parse(stored) as Partial<DevModeState>
94
- return {
95
- isDevMode: parsed.isDevMode ?? false,
96
- isSidebarOpen: false,
97
- isInspectorMode: false,
98
- issueDialog: defaultState.issueDialog,
99
- }
100
- }
101
- } catch {
102
- // Ignore parse errors
103
- }
104
- return defaultState
105
- })
106
-
107
- useEffect(() => {
108
- if (!resolvedAllowed || typeof window === 'undefined') return
109
-
110
- try {
111
- localStorage.setItem(
112
- DEV_MODE_STORAGE_KEY,
113
- JSON.stringify({ isDevMode: state.isDevMode }),
114
- )
115
- } catch {
116
- // Ignore storage errors
117
- }
118
- }, [state.isDevMode, resolvedAllowed])
119
-
120
- const toggleDevMode = useCallback(() => {
121
- setState((prev) => ({
122
- ...prev,
123
- isDevMode: !prev.isDevMode,
124
- isSidebarOpen: prev.isDevMode ? false : prev.isSidebarOpen,
125
- isInspectorMode: prev.isDevMode ? false : prev.isInspectorMode,
126
- }))
127
- }, [])
128
-
129
- const toggleSidebar = useCallback(() => {
130
- setState((prev) => ({ ...prev, isSidebarOpen: !prev.isSidebarOpen }))
131
- }, [])
132
-
133
- const toggleInspector = useCallback(() => {
134
- setState((prev) => ({
135
- ...prev,
136
- isInspectorMode: !prev.isInspectorMode,
137
- }))
138
- }, [])
139
-
140
- const setDevMode = useCallback((enabled: boolean) => {
141
- setState((prev) => ({
142
- ...prev,
143
- isDevMode: enabled,
144
- isSidebarOpen: enabled ? prev.isSidebarOpen : false,
145
- isInspectorMode: enabled ? prev.isInspectorMode : false,
146
- }))
147
- }, [])
148
-
149
- const setSidebarOpen = useCallback((open: boolean) => {
150
- setState((prev) => ({ ...prev, isSidebarOpen: open }))
151
- }, [])
152
-
153
- const setInspectorMode = useCallback((enabled: boolean) => {
154
- setState((prev) => ({ ...prev, isInspectorMode: enabled }))
155
- }, [])
156
-
157
- const openIssueDialog = useCallback(
158
- (
159
- type: 'bug' | 'feature',
160
- description?: string,
161
- componentDetails?: ComponentDetails[],
162
- ) => {
163
- setState((prev) => ({
164
- ...prev,
165
- issueDialog: {
166
- isOpen: true,
167
- type,
168
- initialDescription: description,
169
- componentDetails,
170
- },
171
- }))
172
- },
173
- [],
174
- )
175
-
176
- const closeIssueDialog = useCallback(() => {
177
- setState((prev) => ({
178
- ...prev,
179
- issueDialog: { ...prev.issueDialog, isOpen: false },
180
- }))
181
- }, [])
182
-
183
- if (!resolvedAllowed) {
184
- return <>{children}</>
185
- }
186
-
187
- return (
188
- <DevModeContext.Provider
189
- value={{
190
- ...state,
191
- toggleDevMode,
192
- toggleSidebar,
193
- toggleInspector,
194
- setDevMode,
195
- setSidebarOpen,
196
- setInspectorMode,
197
- openIssueDialog,
198
- closeIssueDialog,
199
- }}
200
- >
201
- {children}
202
- </DevModeContext.Provider>
203
- )
204
- })
205
-
206
- export function useIsDevToolsVisible(): boolean {
207
- const context = useDevModeOptional()
208
- if (!context) return false
209
- return context.isDevMode
210
- }
211
-
212
- export function useIsDevAllowed(isAllowed?: boolean): boolean {
213
- return isAllowed ?? resolveDevAllowed()
214
- }
215
-
216
- function resolveDevAllowed(): boolean {
217
- try {
218
- // @ts-expect-error — Vite env
219
- if (import.meta?.env?.VITE_CONVEX_IS_DEV === 'true') return true
220
- // @ts-expect-error — Vite env
221
- if (import.meta?.env?.DEV) return true
222
- } catch {
223
- // Not in Vite
224
- }
225
- return false
226
- }
@@ -1,143 +0,0 @@
1
- // @geenius-tools/devtools-react — src/context/PerformanceContext.tsx
2
-
3
- import {
4
- createContext,
5
- useContext,
6
- useState,
7
- useEffect,
8
- useCallback,
9
- type ReactNode,
10
- memo,
11
- } from 'react'
12
- import { metricsStore, type PerformanceMetric } from '@geenius-tools/logger'
13
-
14
- const MAX_METRICS = 100
15
-
16
- interface PerformanceContextValue {
17
- isPerformancePanelOpen: boolean
18
- metrics: PerformanceMetric[]
19
- filters: {
20
- network: boolean
21
- query: boolean
22
- mutation: boolean
23
- render: boolean
24
- route: boolean
25
- }
26
- stats: {
27
- totalRequests: number
28
- avgDuration: number
29
- slowRequests: number
30
- fastRequests: number
31
- }
32
- togglePerformancePanel: () => void
33
- clearMetrics: () => void
34
- toggleFilter: (filter: keyof PerformanceContextValue['filters']) => void
35
- }
36
-
37
- const PerformanceContext = createContext<PerformanceContextValue | undefined>(
38
- undefined,
39
- )
40
-
41
- export function usePerformanceContext() {
42
- const context = useContext(PerformanceContext)
43
- if (!context) {
44
- throw new Error(
45
- 'usePerformanceContext must be used within PerformanceProvider',
46
- )
47
- }
48
- return context
49
- }
50
-
51
- export function usePerformanceContextOptional(): PerformanceContextValue | null {
52
- return useContext(PerformanceContext) ?? null
53
- }
54
-
55
- interface PerformanceProviderProps {
56
- children: ReactNode
57
- }
58
-
59
- export const PerformanceProvider = memo(function PerformanceProvider({
60
- children,
61
- }: PerformanceProviderProps) {
62
- const [isPerformancePanelOpen, setIsPerformancePanelOpen] = useState(false)
63
- const [metrics, setMetrics] = useState<PerformanceMetric[]>([])
64
- const [filters, setFilters] = useState({
65
- network: true,
66
- query: true,
67
- mutation: true,
68
- render: true,
69
- route: true,
70
- })
71
-
72
- useEffect(() => {
73
- const unsubscribe = metricsStore.subscribe((newMetrics) => {
74
- setMetrics((prev) => {
75
- const combined = [...prev, ...newMetrics]
76
- if (combined.length > MAX_METRICS) {
77
- return combined.slice(-MAX_METRICS)
78
- }
79
- return combined
80
- })
81
- })
82
-
83
- return () => unsubscribe()
84
- }, [])
85
-
86
- const stats = useCallback(() => {
87
- const filtered = metrics.filter((m) => m.duration !== undefined)
88
- const total = filtered.length
89
-
90
- if (total === 0) {
91
- return {
92
- totalRequests: 0,
93
- avgDuration: 0,
94
- slowRequests: 0,
95
- fastRequests: 0,
96
- }
97
- }
98
-
99
- const durations = filtered.map((m) => m.duration!)
100
- const avg = durations.reduce((a, b) => a + b, 0) / total
101
- const slow = durations.filter((d) => d > 100).length
102
- const fast = durations.filter((d) => d < 50).length
103
-
104
- return {
105
- totalRequests: total,
106
- avgDuration: Math.round(avg * 100) / 100,
107
- slowRequests: slow,
108
- fastRequests: fast,
109
- }
110
- }, [metrics])
111
-
112
- const togglePerformancePanel = useCallback(() => {
113
- setIsPerformancePanelOpen((prev) => !prev)
114
- }, [])
115
-
116
- const clearMetrics = useCallback(() => {
117
- setMetrics([])
118
- metricsStore.clear()
119
- }, [])
120
-
121
- const toggleFilter = useCallback((filter: keyof typeof filters) => {
122
- setFilters((prev) => ({
123
- ...prev,
124
- [filter]: !prev[filter],
125
- }))
126
- }, [])
127
-
128
- return (
129
- <PerformanceContext.Provider
130
- value={{
131
- isPerformancePanelOpen,
132
- metrics,
133
- filters,
134
- stats: stats(),
135
- togglePerformancePanel,
136
- clearMetrics,
137
- toggleFilter,
138
- }}
139
- >
140
- {children}
141
- </PerformanceContext.Provider>
142
- )
143
- })
@@ -1,13 +0,0 @@
1
- // @geenius-tools/devtools — data/designs.ts
2
-
3
- export interface Design {
4
- id: string
5
- name: string
6
- path: string
7
- }
8
-
9
- export const designs: Design[] = Array.from({ length: 21 }, (_, i) => ({
10
- id: String(i + 1),
11
- name: `Design ${i + 1}`,
12
- path: `/dev/design/${i + 1}`,
13
- }))