@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,311 +0,0 @@
1
- // @geenius-tools/devtools-solidjs — src/components/InspectorOverlay.tsx
2
-
3
- import { createSignal, createEffect, createMemo, onCleanup, type JSX } from 'solid-js'
4
- import { Portal } from 'solid-js/web'
5
- import { createDevModeOptional } from '../context/DevModeContext'
6
- import { cn } from '@geenius-ui/solid'
7
-
8
- interface Rect {
9
- top: number
10
- left: number
11
- width: number
12
- height: number
13
- }
14
-
15
- interface ComponentInfo {
16
- name: string
17
- file?: string
18
- key?: string
19
- props?: Record<string, unknown>
20
- }
21
-
22
- function getComponentInfo(element: HTMLElement): ComponentInfo | null {
23
- let fiberNode: any = null
24
- const key = Object.keys(element).find((k) => k.startsWith('__reactFiber$'))
25
- if (key) {
26
- fiberNode = (element as any)[key]
27
- }
28
- if (!fiberNode) return null
29
-
30
- const elementKey = fiberNode.key !== null ? String(fiberNode.key) : undefined
31
-
32
- let node = fiberNode
33
- while (node) {
34
- if (node.tag === 0 || node.tag === 1) {
35
- if (node.type && (node.type.displayName || node.type.name)) {
36
- return {
37
- name: node.type.displayName || node.type.name,
38
- file: node._debugSource?.fileName,
39
- key:
40
- elementKey !== undefined
41
- ? elementKey
42
- : node.key !== null
43
- ? String(node.key)
44
- : undefined,
45
- }
46
- }
47
- }
48
- node = node.return
49
- }
50
-
51
- return { name: element.tagName.toLowerCase() }
52
- }
53
-
54
- export function InspectorOverlay() {
55
- const devMode = createDevModeOptional()
56
- const [hoveredRect, setHoveredRect] = createSignal<Rect | null>(null)
57
- const [selectedComponents, setSelectedComponents] = createSignal<
58
- { rect: Rect; info: ComponentInfo }[]
59
- >([])
60
- const [hoveredComponent, setHoveredComponent] = createSignal<ComponentInfo | null>(null)
61
- const [cursorPos, setCursorPos] = createSignal({ x: 0, y: 0 })
62
- let overlayRef: HTMLDivElement | undefined
63
-
64
- const isInspectorMode = devMode?.isInspectorMode ?? false
65
- const setInspectorMode = devMode?.setInspectorMode ?? (() => { })
66
- const openIssueDialog = devMode?.openIssueDialog ?? (() => { })
67
-
68
- createEffect(() => {
69
- if (!isInspectorMode) {
70
- setHoveredRect(null)
71
- setSelectedComponents([])
72
- return
73
- }
74
-
75
- const isDevTool = (element: Element | null) => {
76
- if (!element) return false
77
- return !!element.closest('[data-dev-tool="true"]')
78
- }
79
-
80
- const handleMouseMove = (e: MouseEvent) => {
81
- setCursorPos({ x: e.clientX, y: e.clientY })
82
- const elements = document.elementsFromPoint(e.clientX, e.clientY)
83
-
84
- if (elements.length > 0 && isDevTool(elements[0])) {
85
- setHoveredRect(null)
86
- setHoveredComponent(null)
87
- return
88
- }
89
-
90
- let target: HTMLElement | null = null
91
- for (const el of elements) {
92
- if (!isDevTool(el)) {
93
- target = el as HTMLElement
94
- break
95
- }
96
- }
97
-
98
- if (
99
- target &&
100
- target !== document.body &&
101
- target !== document.documentElement
102
- ) {
103
- const rect = target.getBoundingClientRect()
104
- setHoveredRect({
105
- top: rect.top,
106
- left: rect.left,
107
- width: rect.width,
108
- height: rect.height,
109
- })
110
- setHoveredComponent(getComponentInfo(target))
111
- } else {
112
- setHoveredRect(null)
113
- setHoveredComponent(null)
114
- }
115
- }
116
-
117
- const handleClick = (e: MouseEvent) => {
118
- const elements = document.elementsFromPoint(e.clientX, e.clientY)
119
- if (elements.length > 0 && isDevTool(elements[0])) return
120
-
121
- let target: HTMLElement | null = null
122
- for (const el of elements) {
123
- if (!isDevTool(el)) {
124
- target = el as HTMLElement
125
- break
126
- }
127
- }
128
-
129
- if (target) {
130
- e.preventDefault()
131
- e.stopPropagation()
132
-
133
- const info = getComponentInfo(target)
134
- const rect = target.getBoundingClientRect()
135
-
136
- if (info) {
137
- setSelectedComponents((prev) => {
138
- const existsIndex = prev.findIndex(
139
- (p) =>
140
- p.info.name === info.name &&
141
- p.info.key === info.key &&
142
- p.info.file === info.file,
143
- )
144
-
145
- if (existsIndex >= 0) {
146
- const newSelection = [...prev]
147
- newSelection.splice(existsIndex, 1)
148
- return newSelection
149
- } else {
150
- return [
151
- ...prev,
152
- {
153
- rect: {
154
- top: rect.top,
155
- left: rect.left,
156
- width: rect.width,
157
- height: rect.height,
158
- },
159
- info,
160
- },
161
- ]
162
- }
163
- })
164
- }
165
- }
166
- }
167
-
168
- window.addEventListener('mousemove', handleMouseMove, { capture: true })
169
- window.addEventListener('click', handleClick, { capture: true })
170
-
171
- return () => {
172
- window.removeEventListener('mousemove', handleMouseMove, { capture: true })
173
- window.removeEventListener('click', handleClick, { capture: true })
174
- }
175
- })
176
-
177
- if (!devMode || !isInspectorMode) return null
178
-
179
- return /* Portal: */ (
180
- <div
181
- ref={overlayRef}
182
- class="fixed inset-0 z-[9999] pointer-events-none cursor-crosshair"
183
- style={{ background: 'transparent' }}
184
- data-dev-tool="true"
185
- >
186
- {/* Desktop Debug Panel */}
187
- <div class="hidden md:block fixed top-0 left-0 z-[10000] p-2 text-xs font-mono text-white pointer-events-auto transition-all duration-300">
188
- <div
189
- class={cn(
190
- 'group flex flex-col gap-1 min-w-[150px] p-2 rounded-lg backdrop-blur-sm transition-all duration-300',
191
- 'bg-blue-500/10 hover:bg-blue-950/90',
192
- 'border border-blue-500/30',
193
- 'text-black hover:text-white',
194
- )}
195
- >
196
- <div class="flex justify-between items-center opacity-80">
197
- <span class="font-bold opacity-100 group-hover:text-white/90">
198
- INSPECTOR
199
- </span>
200
- <span class="opacity-70 group-hover:text-white/70">
201
- {Math.round(cursorPos.x)}, {Math.round(cursorPos.y)}
202
- </span>
203
- </div>
204
- {hoveredComponent && (
205
- <div class="font-bold drop-shadow-sm truncate text-blue-700 group-hover:text-blue-300">
206
- {hoveredComponent.name}
207
- </div>
208
- )}
209
- {selectedComponents.length > 0 && (
210
- <div class="truncate text-[10px] opacity-80 text-green-700 group-hover:text-green-300 border-t border-white/10 pt-1 mt-1">
211
- {selectedComponents.length} Selected
212
- </div>
213
- )}
214
- </div>
215
- </div>
216
-
217
- {/* Hover Highlight */}
218
- {hoveredRect && (
219
- <div
220
- class="absolute border-2 border-blue-500 bg-blue-500/10 pointer-events-none transition-all duration-75 ease-out"
221
- style={{
222
- top: hoveredRect.top,
223
- left: hoveredRect.left,
224
- width: hoveredRect.width,
225
- height: hoveredRect.height,
226
- }}
227
- >
228
- <div class="absolute -top-6 left-0 bg-blue-500 text-white text-[10px] px-1.5 py-0.5 rounded-sm whitespace-nowrap">
229
- {hoveredComponent?.name} ({Math.round(hoveredRect.width)} x{' '}
230
- {Math.round(hoveredRect.height)})
231
- </div>
232
- </div>
233
- )}
234
-
235
- {/* Selection Highlights */}
236
- {selectedComponents.map((comp, i) => (
237
- <div
238
- key={i}
239
- class="absolute border-2 border-green-500 bg-green-500/20 pointer-events-none transition-all duration-75 ease-out"
240
- style={{
241
- top: comp.rect.top,
242
- left: comp.rect.left,
243
- width: comp.rect.width,
244
- height: comp.rect.height,
245
- }}
246
- >
247
- <div class="absolute -top-6 left-0 bg-green-600 text-white text-[10px] px-1.5 py-0.5 rounded-sm whitespace-nowrap z-[10001]">
248
- {comp.info.name}
249
- </div>
250
- </div>
251
- ))}
252
-
253
- {/* Floating Toolbar */}
254
- {selectedComponents.length > 0 &&
255
- (() => {
256
- const lastSelected = selectedComponents[selectedComponents.length - 1]
257
- return (
258
- <div
259
- class="fixed z-[10002] flex items-center gap-1 p-1 bg-slate-900 border border-slate-700 rounded-md shadow-xl animate-in fade-in zoom-in-95 pointer-events-auto"
260
- style={{
261
- top: Math.max(10, lastSelected.rect.top - 45),
262
- left: Math.max(10, lastSelected.rect.left),
263
- }}
264
- >
265
- <button
266
- onClick={() => {
267
- const allDetails = selectedComponents.map((c) => ({
268
- name: c.info.name,
269
- file: c.info.file,
270
- key: c.info.key,
271
- props: c.info.props,
272
- selector: 'Multi-select',
273
- }))
274
- openIssueDialog('feature', '', allDetails as any)
275
- setInspectorMode(false)
276
- }}
277
- class="px-2 py-1 text-xs font-medium text-white hover:bg-white/10 rounded transition-colors"
278
- >
279
- Feature
280
- </button>
281
- <div class="w-px h-3 bg-white/20 mx-0.5" />
282
- <button
283
- onClick={() => {
284
- const allDetails = selectedComponents.map((c) => ({
285
- name: c.info.name,
286
- file: c.info.file,
287
- key: c.info.key,
288
- props: c.info.props,
289
- selector: 'Multi-select',
290
- }))
291
- openIssueDialog('bug', '', allDetails as any)
292
- setInspectorMode(false)
293
- }}
294
- class="px-2 py-1 text-xs font-medium text-red-400 hover:bg-red-500/10 rounded transition-colors"
295
- >
296
- Bug
297
- </button>
298
- <div class="w-px h-3 bg-white/20 mx-0.5" />
299
- <button
300
- onClick={() => setSelectedComponents([])}
301
- class="px-2 py-1 text-xs text-slate-400 hover:text-white hover:bg-white/10 rounded transition-colors"
302
- >
303
- Deselect all
304
- </button>
305
- </div>
306
- )
307
- })()}
308
- </div>,
309
- document.body,
310
- )
311
- }
@@ -1,144 +0,0 @@
1
- // @geenius-tools/devtools-solidjs — components/PageLoadWaterfall.tsx
2
- import { onMount } from 'solid-js'
3
-
4
- export type SsrTiming = {
5
- ssrStart: number
6
- getAuthStart: number
7
- getAuthEnd: number
8
- translationsStart: number
9
- translationsEnd: number
10
- userPrefsStart: number
11
- userPrefsEnd: number
12
- ssrEnd: number
13
- isCachedAuth: boolean
14
- }
15
-
16
- /**
17
- * PageLoadWaterfall — invisible component that logs detailed performance
18
- * waterfall data to the browser console on first mount.
19
- *
20
- * Includes: network timing, SSR breakdown, FCP, resource loading, top-5 slowest JS bundles.
21
- * Returns `null` — no UI.
22
- */
23
- export function PageLoadWaterfall(props: { ssrTiming?: SsrTiming | null }) {
24
- let hasLogged = false
25
-
26
- onMount(() => {
27
- if (hasLogged) return
28
- hasLogged = true
29
- logWaterfall(props.ssrTiming)
30
- })
31
-
32
- return null
33
- }
34
-
35
- /** @internal Shared waterfall logging logic — framework-agnostic */
36
- export function logWaterfall(ssrTiming?: SsrTiming | null) {
37
- const clientStart = performance.now()
38
-
39
- const run = () => {
40
- const navEntry = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming | undefined
41
- const fcp = performance.getEntriesByType('paint').find((e) => e.name === 'first-contentful-paint')
42
-
43
- console.log('\n')
44
- console.log('%c╔══════════════════════════════════════════════════════╗', 'color: #4CAF50; font-weight: bold')
45
- console.log('%c║ PAGE LOAD PERFORMANCE WATERFALL ║', 'color: #4CAF50; font-weight: bold')
46
- console.log('%c╚══════════════════════════════════════════════════════╝', 'color: #4CAF50; font-weight: bold')
47
-
48
- if (navEntry) {
49
- const dns = navEntry.domainLookupEnd - navEntry.domainLookupStart
50
- const tcp = navEntry.connectEnd - navEntry.connectStart
51
- const ttfb = navEntry.responseStart - navEntry.requestStart
52
- const download = navEntry.responseEnd - navEntry.responseStart
53
- const domParsing = navEntry.domInteractive - navEntry.responseEnd
54
- const domComplete = navEntry.domComplete - navEntry.domInteractive
55
- const totalLoad = navEntry.loadEventEnd - navEntry.startTime
56
-
57
- console.log('%c\n── Network & Browser Timing ──', 'color: #FF9800; font-weight: bold')
58
- console.table({
59
- 'DNS Lookup': { ms: Math.round(dns), bar: '█'.repeat(Math.max(1, Math.round(dns / 20))) },
60
- 'TCP Connect': { ms: Math.round(tcp), bar: '█'.repeat(Math.max(1, Math.round(tcp / 20))) },
61
- 'TTFB (Time to First Byte)': { ms: Math.round(ttfb), bar: '█'.repeat(Math.max(1, Math.round(ttfb / 20))) },
62
- 'Response Download': { ms: Math.round(download), bar: '█'.repeat(Math.max(1, Math.round(download / 20))) },
63
- 'DOM Parsing': { ms: Math.round(domParsing), bar: '█'.repeat(Math.max(1, Math.round(domParsing / 20))) },
64
- 'DOM Complete': { ms: Math.round(domComplete), bar: '█'.repeat(Math.max(1, Math.round(domComplete / 20))) },
65
- 'Total Page Load': { ms: Math.round(totalLoad), bar: '█'.repeat(Math.max(1, Math.round(totalLoad / 20))) },
66
- })
67
-
68
- console.log(
69
- `%c\n⚡ TTFB: ${Math.round(ttfb)}ms — This includes all SSR processing time`,
70
- ttfb > 500 ? 'color: #F44336; font-weight: bold; font-size: 14px' : 'color: #4CAF50; font-weight: bold; font-size: 14px',
71
- )
72
- }
73
-
74
- if (ssrTiming) {
75
- console.log('%c\n── SSR beforeLoad Breakdown ──', 'color: #2196F3; font-weight: bold')
76
- const total = ssrTiming.ssrEnd - ssrTiming.ssrStart
77
- const auth = ssrTiming.getAuthEnd ? ssrTiming.getAuthEnd - ssrTiming.getAuthStart : 0
78
- const prefs = ssrTiming.userPrefsEnd ? ssrTiming.userPrefsEnd - ssrTiming.userPrefsStart : 0
79
- const trans = ssrTiming.translationsEnd ? ssrTiming.translationsEnd - ssrTiming.translationsStart : 0
80
-
81
- console.table({
82
- 'getAuth()': { ms: auth, bar: '█'.repeat(Math.max(1, Math.round(auth / 20))), note: ssrTiming.isCachedAuth ? '(cached)' : '(server call)' },
83
- 'User Prefs': { ms: prefs, bar: '█'.repeat(Math.max(1, Math.round(prefs / 20))) },
84
- 'loadTranslations()': { ms: trans, bar: '█'.repeat(Math.max(1, Math.round(trans / 20))) },
85
- 'Total SSR beforeLoad': { ms: total, bar: '█'.repeat(Math.max(1, Math.round(total / 20))) },
86
- })
87
- } else {
88
- console.log('%c\n── SSR Timing: Not available (client-side navigation) ──', 'color: #9E9E9E')
89
- }
90
-
91
- if (fcp) {
92
- console.log(
93
- `%c\n🎨 First Contentful Paint: ${Math.round(fcp.startTime)}ms`,
94
- fcp.startTime > 1500 ? 'color: #F44336; font-weight: bold; font-size: 14px' : 'color: #4CAF50; font-weight: bold; font-size: 14px',
95
- )
96
- }
97
-
98
- console.log(
99
- `%c\n🧩 Component mounted at: ${Math.round(clientStart)}ms from page start`,
100
- 'color: #2c4f7c; font-weight: bold',
101
- )
102
-
103
- const resources = performance.getEntriesByType('resource') as PerformanceResourceTiming[]
104
- const jsResources = resources.filter((r) => r.name.endsWith('.js') || r.name.endsWith('.mjs') || r.name.includes('.js?'))
105
- const cssResources = resources.filter((r) => r.name.endsWith('.css') || r.name.includes('.css?'))
106
- const fontResources = resources.filter((r) => r.name.includes('fonts.googleapis') || r.name.includes('fonts.gstatic'))
107
- const imgResources = resources.filter((r) => r.initiatorType === 'img')
108
-
109
- const totalJsSize = jsResources.reduce((sum, r) => sum + (r.transferSize || 0), 0)
110
- const slowestJs = [...jsResources].sort((a, b) => b.duration - a.duration).slice(0, 5)
111
-
112
- console.log('%c\n── Resource Loading ──', 'color: #9C27B0; font-weight: bold')
113
- console.table({
114
- 'JS bundles': { count: jsResources.length, totalKB: Math.round(totalJsSize / 1024), slowest_ms: Math.round(slowestJs[0]?.duration ?? 0) },
115
- 'CSS files': { count: cssResources.length, totalKB: Math.round(cssResources.reduce((s, r) => s + (r.transferSize || 0), 0) / 1024) },
116
- 'Font resources': { count: fontResources.length, slowest_ms: Math.round([...fontResources].sort((a, b) => b.duration - a.duration)[0]?.duration ?? 0) },
117
- 'Images': { count: imgResources.length, totalKB: Math.round(imgResources.reduce((s, r) => s + (r.transferSize || 0), 0) / 1024) },
118
- })
119
-
120
- if (slowestJs.length > 0) {
121
- console.log('%c\n── Top 5 Slowest JS Bundles ──', 'color: #E91E63; font-weight: bold')
122
- console.table(
123
- Object.fromEntries(
124
- slowestJs.map((r, i) => [
125
- `#${i + 1}`,
126
- {
127
- file: r.name.split('/').pop()?.split('?')[0] ?? r.name,
128
- duration_ms: Math.round(r.duration),
129
- size_KB: Math.round((r.transferSize || 0) / 1024),
130
- },
131
- ]),
132
- ),
133
- )
134
- }
135
-
136
- console.log('%c\n══════════════════════════════════════════════════════', 'color: #4CAF50; font-weight: bold')
137
- }
138
-
139
- if (document.readyState === 'complete') {
140
- setTimeout(run, 500)
141
- } else {
142
- window.addEventListener('load', () => setTimeout(run, 500))
143
- }
144
- }