@buoy-gg/benchmark 1.7.2

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 (36) hide show
  1. package/README.md +55 -0
  2. package/lib/commonjs/benchmarking/BenchmarkComparator.js +1 -0
  3. package/lib/commonjs/benchmarking/BenchmarkRecorder.js +1 -0
  4. package/lib/commonjs/benchmarking/BenchmarkStorage.js +1 -0
  5. package/lib/commonjs/benchmarking/index.js +1 -0
  6. package/lib/commonjs/benchmarking/types.js +1 -0
  7. package/lib/commonjs/components/BenchmarkCompareView.js +1 -0
  8. package/lib/commonjs/components/BenchmarkDetailView.js +1 -0
  9. package/lib/commonjs/components/BenchmarkModal.js +1 -0
  10. package/lib/commonjs/components/BenchmarkSessionCard.js +1 -0
  11. package/lib/commonjs/index.js +1 -0
  12. package/lib/commonjs/package.json +1 -0
  13. package/lib/commonjs/preset.js +1 -0
  14. package/lib/module/benchmarking/BenchmarkComparator.js +1 -0
  15. package/lib/module/benchmarking/BenchmarkRecorder.js +1 -0
  16. package/lib/module/benchmarking/BenchmarkStorage.js +1 -0
  17. package/lib/module/benchmarking/index.js +1 -0
  18. package/lib/module/benchmarking/types.js +1 -0
  19. package/lib/module/components/BenchmarkCompareView.js +1 -0
  20. package/lib/module/components/BenchmarkDetailView.js +1 -0
  21. package/lib/module/components/BenchmarkModal.js +1 -0
  22. package/lib/module/components/BenchmarkSessionCard.js +1 -0
  23. package/lib/module/index.js +1 -0
  24. package/lib/module/preset.js +1 -0
  25. package/lib/typescript/benchmarking/BenchmarkComparator.d.ts +45 -0
  26. package/lib/typescript/benchmarking/BenchmarkRecorder.d.ts +109 -0
  27. package/lib/typescript/benchmarking/BenchmarkStorage.d.ts +96 -0
  28. package/lib/typescript/benchmarking/index.d.ts +43 -0
  29. package/lib/typescript/benchmarking/types.d.ts +240 -0
  30. package/lib/typescript/components/BenchmarkCompareView.d.ts +15 -0
  31. package/lib/typescript/components/BenchmarkDetailView.d.ts +14 -0
  32. package/lib/typescript/components/BenchmarkModal.d.ts +17 -0
  33. package/lib/typescript/components/BenchmarkSessionCard.d.ts +19 -0
  34. package/lib/typescript/index.d.ts +28 -0
  35. package/lib/typescript/preset.d.ts +75 -0
  36. package/package.json +67 -0
package/README.md ADDED
@@ -0,0 +1,55 @@
1
+ # @buoy/benchmark
2
+
3
+ ## Description
4
+
5
+ benchmark package for the monorepo.
6
+
7
+ ## Installation
8
+
9
+ This package is part of the monorepo and is automatically available to other packages and the example app.
10
+
11
+ ## Usage
12
+
13
+ ```typescript
14
+ import { BenchmarkComponent } from '@buoy/benchmark';
15
+
16
+ // Use in your component
17
+ <BenchmarkComponent title="Hello World" />
18
+ ```
19
+
20
+ ## Development
21
+
22
+ ### Building
23
+
24
+ ```bash
25
+ pnpm build
26
+ ```
27
+
28
+ ### Type Checking
29
+
30
+ ```bash
31
+ pnpm typecheck
32
+ ```
33
+
34
+ ### Clean Build
35
+
36
+ ```bash
37
+ pnpm clean
38
+ ```
39
+
40
+ ## Structure
41
+
42
+ ```
43
+ benchmark/
44
+ ├── src/
45
+ │ └── index.ts # Main export file
46
+ ├── lib/ # Built output (git ignored)
47
+ ├── package.json
48
+ ├── tsconfig.json
49
+ └── README.md
50
+ ```
51
+
52
+ ## Dependencies
53
+
54
+ - Uses `@buoy/shared-ui` for common components and utilities
55
+ - React and React Native as peer dependencies
@@ -0,0 +1 @@
1
+ "use strict";function calculateImprovement(e,t){return 0===e?0:(e-t)/e*100}function formatPercent(e){return`${e>=0?"+":""}${e.toFixed(1)}%`}function formatMs(e){return`${e.toFixed(1)}ms`}function formatBytes(e){const t=e/1024/1024;return`${t>=0?"+":""}${t.toFixed(2)}MB`}function getIndicator(e,t=5){return e>t?"✅":e<-t?"❌":"➖"}Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=exports.BenchmarkComparator=void 0;class BenchmarkComparator{static compare(e,t){const a=e.stats,r=t.stats,m=t.duration-e.duration,o=calculateImprovement(e.duration,t.duration),n=calculateImprovement(a.avgFilterTime,r.avgFilterTime),s=calculateImprovement(a.avgMeasureTime,r.avgMeasureTime),p=calculateImprovement(a.avgTrackTime,r.avgTrackTime),i=calculateImprovement(a.avgTotalTime,r.avgTotalTime),l=calculateImprovement(a.avgOverlayRenderTime,r.avgOverlayRenderTime);let u=null;null!=e.memoryDelta&&null!=t.memoryDelta&&(u=t.memoryDelta-e.memoryDelta);let c=.4*s+.3*i+.2*l;null!=e.memoryDelta&&null!=t.memoryDelta&&0!==e.memoryDelta&&(c+=.1*calculateImprovement(e.memoryDelta,t.memoryDelta));const d=c>0,v=this.generateSummary({baseline:e,comparison:t,durationDelta:m,durationImprovement:o,measureTimeImprovement:s,pipelineTimeImprovement:i,overlayRenderImprovement:l,memoryDeltaChange:u,overallImprovement:c,isImproved:d});return{baselineId:e.id,baselineName:e.name,comparisonId:t.id,comparisonName:t.name,comparedAt:Date.now(),durationDelta:m,durationImprovement:o,filterTimeImprovement:n,measureTimeImprovement:s,trackTimeImprovement:p,pipelineTimeImprovement:i,overlayRenderImprovement:l,memoryDeltaChange:u,overallImprovement:c,isImproved:d,summary:v}}static generateSummary(e){const{baseline:t,comparison:a,measureTimeImprovement:r,pipelineTimeImprovement:m,overlayRenderImprovement:o,memoryDeltaChange:n,overallImprovement:s,isImproved:p}=e,i=[];if(i.push("╔══════════════════════════════════════════════════════════════╗"),i.push("║ BENCHMARK COMPARISON ║"),i.push("╠══════════════════════════════════════════════════════════════╣"),i.push(`║ Baseline: ${t.name.substring(0,50).padEnd(50)} ║`),i.push(`║ ${new Date(t.createdAt).toLocaleString().substring(0,58).padEnd(58)} ║`),i.push(`║ Comparison: ${a.name.substring(0,48).padEnd(48)} ║`),i.push(`║ ${new Date(a.createdAt).toLocaleString().substring(0,58).padEnd(58)} ║`),i.push("╠══════════════════════════════════════════════════════════════╣"),i.push("║ TIMING COMPARISON ║"),i.push("║ Baseline After Change ║"),i.push(`║ Measurement Time: ${formatMs(t.stats.avgMeasureTime).padStart(8)} → ${formatMs(a.stats.avgMeasureTime).padStart(8)} ${formatPercent(r).padStart(7)} ${getIndicator(r)} ║`),i.push(`║ Pipeline Time: ${formatMs(t.stats.avgTotalTime).padStart(8)} → ${formatMs(a.stats.avgTotalTime).padStart(8)} ${formatPercent(m).padStart(7)} ${getIndicator(m)} ║`),i.push(`║ Overlay Render: ${formatMs(t.stats.avgOverlayRenderTime).padStart(8)} → ${formatMs(a.stats.avgOverlayRenderTime).padStart(8)} ${formatPercent(o).padStart(7)} ${getIndicator(o)} ║`),null!=n&&null!=t.memoryDelta&&null!=a.memoryDelta){const e=calculateImprovement(t.memoryDelta,a.memoryDelta);i.push("╠══════════════════════════════════════════════════════════════╣"),i.push("║ MEMORY ║"),i.push(`║ Delta: ${formatBytes(t.memoryDelta).padStart(8)} → ${formatBytes(a.memoryDelta).padStart(8)} ${formatPercent(e).padStart(7)} ${getIndicator(e)} ║`)}i.push("╠══════════════════════════════════════════════════════════════╣"),i.push("║ PERCENTILES (P95) ║");const l=calculateImprovement(t.stats.p95TotalTime,a.stats.p95TotalTime);i.push(`║ P95 Pipeline: ${formatMs(t.stats.p95TotalTime).padStart(8)} → ${formatMs(a.stats.p95TotalTime).padStart(8)} ${formatPercent(l).padStart(7)} ${getIndicator(l)} ║`),i.push("╠══════════════════════════════════════════════════════════════╣");const u=p?"🎉":"⚠️",c=p?"IMPROVED":"REGRESSED";return i.push(`║ ${u} OVERALL: ${formatPercent(s).padStart(7)} ${c.padEnd(40)} ║`),i.push("╚══════════════════════════════════════════════════════════════╝"),i.join("\n")}static logComparison(e){console.log("\n"+e.summary+"\n")}static quickCompare(e,t){const a=this.compare(e,t);return this.logComparison(a),a}static getBriefSummary(e){const t=e.isImproved?"faster":"slower";return`${e.isImproved?"✅":"❌"} ${Math.abs(e.overallImprovement).toFixed(1)}% ${t} (measurement: ${formatPercent(e.measureTimeImprovement)}, pipeline: ${formatPercent(e.pipelineTimeImprovement)})`}}exports.BenchmarkComparator=BenchmarkComparator;var _default=exports.default=BenchmarkComparator;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=exports.benchmarkRecorder=exports.BenchmarkRecorder=void 0;var _reactNative=require("react-native");function generateSessionId(e){return`${e}_${Date.now()}_${Math.random().toString(36).substring(2,8)}`}function percentile(e,t){if(0===e.length)return 0;const s=Math.ceil(t/100*e.length)-1;return e[Math.max(0,Math.min(s,e.length-1))]}function captureMemorySnapshot(){return null}function getBenchmarkContext(e,t){let s="unknown";return"ios"===_reactNative.Platform.OS?s="ios":"android"===_reactNative.Platform.OS?s="android":"web"===_reactNative.Platform.OS&&(s="web"),{platform:s,osVersion:_reactNative.Platform.Version?.toString(),isDev:__DEV__??!1,batchSize:e,showRenderCount:t}}function computeStats(e,t){const s=e.length;if(0===s)return{batchCount:0,totalNodesReceived:0,totalNodesFiltered:0,totalNodesProcessed:0,avgFilterTime:0,avgMeasureTime:0,avgTrackTime:0,avgCallbackTime:0,avgTotalTime:0,minTotalTime:0,maxTotalTime:0,p50TotalTime:0,p95TotalTime:0,p99TotalTime:0,avgOverlayRenderTime:0,avgHighlightsPerRender:0};let o=0,r=0,a=0,i=0,n=0,l=0,c=0,m=0;const d=[];for(const t of e)o+=t.nodesReceived,r+=t.nodesFiltered,a+=t.nodesInBatch,i+=t.filteringTime,n+=t.measurementTime,l+=t.trackingTime,c+=t.callbackTime,m+=t.totalTime,d.push(t.totalTime);d.sort((e,t)=>e-t);let h=0,g=0;for(const e of t)h+=e.renderTime,g+=e.highlightCount;return{batchCount:s,totalNodesReceived:o,totalNodesFiltered:r,totalNodesProcessed:a,avgFilterTime:i/s,avgMeasureTime:n/s,avgTrackTime:l/s,avgCallbackTime:c/s,avgTotalTime:m/s,minTotalTime:d[0],maxTotalTime:d[d.length-1],p50TotalTime:percentile(d,50),p95TotalTime:percentile(d,95),p99TotalTime:percentile(d,99),avgOverlayRenderTime:t.length>0?h/t.length:0,avgHighlightsPerRender:t.length>0?g/t.length:0}}class BenchmarkRecorder{state="idle";sessionId="";sessionName="";sessionStartTime=0;verbose=!1;captureMemory=!0;batches=[];overlayRenders=[];memoryStart=null;memoryEnd=null;marks=[];measures=[];batchSize=150;showRenderCount=!0;listeners=new Set;activeMeasures=new Map;getState(){return this.state}isRecording(){return"recording"===this.state}setBatchSize(e){this.batchSize=e}setShowRenderCount(e){this.showRenderCount=e}startSession(e){"recording"!==this.state?(this.sessionId=generateSessionId(e.name),this.sessionName=e.name,this.sessionDescription=e.description,this.verbose=e.verbose??!1,this.captureMemory=e.captureMemory??!0,this.batches=[],this.overlayRenders=[],this.marks=[],this.measures=[],this.activeMeasures.clear(),this.captureMemory&&(this.memoryStart=captureMemorySnapshot()),this.sessionStartTime=performance.now(),this.marks.push({name:"session_start",startTime:0,detail:{name:this.sessionName}}),this.state="recording",this.verbose&&(console.log(`[BenchmarkRecorder] Session started: ${this.sessionName}`),console.log(` ID: ${this.sessionId}`)),this.notifyListeners("start")):console.warn("[BenchmarkRecorder] Session already recording. Stop it first.")}stopSession(){if("recording"!==this.state)return console.warn("[BenchmarkRecorder] No active session to stop."),null;const e=performance.now()-this.sessionStartTime;this.marks.push({name:"session_end",startTime:e}),this.measures.push({name:"session_total",startTime:0,duration:e}),this.captureMemory&&(this.memoryEnd=captureMemorySnapshot());let t=null;null!=this.memoryStart?.usedJSHeapSize&&null!=this.memoryEnd?.usedJSHeapSize&&(t=this.memoryEnd.usedJSHeapSize-this.memoryStart.usedJSHeapSize);const s=computeStats(this.batches,this.overlayRenders),o={version:"1.0",id:this.sessionId,name:this.sessionName,description:this.sessionDescription,createdAt:Date.now(),duration:e,context:getBenchmarkContext(this.batchSize,this.showRenderCount),batches:[...this.batches],overlayRenders:[...this.overlayRenders],marks:[...this.marks],measures:[...this.measures],stats:s,memoryStart:this.memoryStart,memoryEnd:this.memoryEnd,memoryDelta:t};return this.state="stopped",this.verbose&&this.logReport(o),this.notifyListeners("stop"),o}recordBatch(e){"recording"===this.state&&(this.batches.push(e),this.marks.push({name:`batch_${e.batchId}`,startTime:performance.now()-this.sessionStartTime,detail:{nodesReceived:e.nodesReceived,nodesProcessed:e.nodesInBatch,totalTime:e.totalTime}}),this.verbose&&console.log(`[BenchmarkRecorder] Batch ${e.batchId}: ${e.nodesInBatch} nodes in ${e.totalTime.toFixed(1)}ms`),this.notifyListeners("batch",e))}recordOverlayRender(e,t){if("recording"!==this.state)return;const s={highlightCount:e,renderTime:t,timestamp:performance.now()};this.overlayRenders.push(s),this.marks.push({name:"overlay_render",startTime:performance.now()-this.sessionStartTime,detail:{highlightCount:e,renderTime:t}}),this.verbose&&console.log(`[BenchmarkRecorder] Overlay render: ${e} highlights in ${t.toFixed(1)}ms`),this.notifyListeners("overlay",s)}mark(e,t){"recording"===this.state&&(this.marks.push({name:e,startTime:performance.now()-this.sessionStartTime,detail:t}),this.verbose&&console.log(`[BenchmarkRecorder] Mark: ${e}`))}startMeasure(e){"recording"===this.state&&(this.activeMeasures.set(e,performance.now()),this.verbose&&console.log(`[BenchmarkRecorder] Measure started: ${e}`))}endMeasure(e,t){if("recording"!==this.state)return null;const s=this.activeMeasures.get(e);if(void 0===s)return console.warn(`[BenchmarkRecorder] No active measure: ${e}`),null;const o=performance.now()-s;return this.measures.push({name:e,startTime:s-this.sessionStartTime,duration:o,detail:t}),this.activeMeasures.delete(e),this.verbose&&console.log(`[BenchmarkRecorder] Measure ended: ${e} = ${o.toFixed(1)}ms`),o}subscribe(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}notifyListeners(e,t){for(const s of this.listeners)try{s(e,t)}catch(e){console.error("[BenchmarkRecorder] Error in event listener:",e)}}logReport(e){const{stats:t,memoryDelta:s}=e;if(console.log("\n╔══════════════════════════════════════════════════════════════╗"),console.log("║ BENCHMARK REPORT ║"),console.log("╠══════════════════════════════════════════════════════════════╣"),console.log(`║ Name: ${e.name.padEnd(55)}║`),console.log(`║ ID: ${e.id.substring(0,57).padEnd(57)}║`),console.log(`║ Duration: ${e.duration.toFixed(1).padStart(8)}ms ║`),console.log("╠══════════════════════════════════════════════════════════════╣"),console.log("║ BATCH STATS ║"),console.log(`║ Count: ${t.batchCount.toString().padStart(6)} ║`),console.log(`║ Nodes received: ${t.totalNodesReceived.toString().padStart(8)} ║`),console.log(`║ Nodes processed: ${t.totalNodesProcessed.toString().padStart(7)} ║`),console.log("╠══════════════════════════════════════════════════════════════╣"),console.log("║ TIMING (avg per batch) ║"),console.log(`║ Filter: ${t.avgFilterTime.toFixed(1).padStart(8)}ms ║`),console.log(`║ Measure: ${t.avgMeasureTime.toFixed(1).padStart(7)}ms ← Primary bottleneck ║`),console.log(`║ Track: ${t.avgTrackTime.toFixed(1).padStart(9)}ms ║`),console.log(`║ Callback: ${t.avgCallbackTime.toFixed(1).padStart(6)}ms ║`),console.log(`║ Total: ${t.avgTotalTime.toFixed(1).padStart(9)}ms ║`),console.log("╠══════════════════════════════════════════════════════════════╣"),console.log("║ PERCENTILES ║"),console.log(`║ P50: ${t.p50TotalTime.toFixed(1).padStart(8)}ms ║`),console.log(`║ P95: ${t.p95TotalTime.toFixed(1).padStart(8)}ms ║`),console.log(`║ P99: ${t.p99TotalTime.toFixed(1).padStart(8)}ms ║`),console.log("╠══════════════════════════════════════════════════════════════╣"),console.log("║ OVERLAY RENDERS ║"),console.log(`║ Avg time: ${t.avgOverlayRenderTime.toFixed(1).padStart(7)}ms ║`),console.log(`║ Avg highlights: ${t.avgHighlightsPerRender.toFixed(0).padStart(5)} ║`),null!=s){const e=(s/1024/1024).toFixed(2),t=s>=0?"+":"";console.log("╠══════════════════════════════════════════════════════════════╣"),console.log("║ MEMORY ║"),console.log(`║ Delta: ${t}${e.padStart(7)}MB ║`)}console.log("╚══════════════════════════════════════════════════════════════╝\n")}}exports.BenchmarkRecorder=BenchmarkRecorder;const benchmarkRecorder=exports.benchmarkRecorder=new BenchmarkRecorder;var _default=exports.default=BenchmarkRecorder;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.BenchmarkStorage=void 0,exports.createAsyncStorageAdapter=createAsyncStorageAdapter,exports.createMemoryStorageAdapter=createMemoryStorageAdapter,exports.default=void 0;const STORAGE_PREFIX="@buoy-gg/benchmark",INDEX_KEY=`${STORAGE_PREFIX}/index`,REPORT_KEY_PREFIX=`${STORAGE_PREFIX}/report/`;function getReportKey(e){return`${REPORT_KEY_PREFIX}${e}`}function extractMetadata(e){return{id:e.id,name:e.name,description:e.description,createdAt:e.createdAt,duration:e.duration,batchCount:e.stats.batchCount}}class BenchmarkStorage{constructor(e){this.storage=e}async saveReport(e){const t=await this.loadIndex(),r=t.findIndex(t=>t.id===e.id);return r>=0?t[r]=extractMetadata(e):t.push(extractMetadata(e)),await Promise.all([this.storage.setItem(getReportKey(e.id),JSON.stringify(e)),this.storage.setItem(INDEX_KEY,JSON.stringify(t))]),console.log(`[BenchmarkStorage] Saved report: ${e.name} (${e.id})`),extractMetadata(e)}async loadReport(e){try{const t=await this.storage.getItem(getReportKey(e));return t?JSON.parse(t):null}catch(t){return console.error(`[BenchmarkStorage] Error loading report ${e}:`,t),null}}async listReports(){return(await this.loadIndex()).sort((e,t)=>t.createdAt-e.createdAt)}async deleteReport(e){const t=await this.loadIndex(),r=t.findIndex(t=>t.id===e);return!(r<0||(t.splice(r,1),await Promise.all([this.storage.removeItem(getReportKey(e)),this.storage.setItem(INDEX_KEY,JSON.stringify(t))]),console.log(`[BenchmarkStorage] Deleted report: ${e}`),0))}async clearAll(){const e=await this.loadIndex();await Promise.all([...e.map(e=>this.storage.removeItem(getReportKey(e.id))),this.storage.removeItem(INDEX_KEY)]),console.log(`[BenchmarkStorage] Cleared ${e.length} reports`)}async updateReport(e,t){const r=await this.loadReport(e);return!!r&&(void 0!==t.name&&(r.name=t.name),void 0!==t.description&&(r.description=t.description),await this.saveReport(r),console.log(`[BenchmarkStorage] Updated report: ${e}`),!0)}async getMostRecent(){const e=await this.listReports();return 0===e.length?null:this.loadReport(e[0].id)}async getReportsByName(e){return(await this.loadIndex()).filter(t=>t.name===e).sort((e,t)=>t.createdAt-e.createdAt)}async loadIndex(){try{const e=await this.storage.getItem(INDEX_KEY);return e?JSON.parse(e):[]}catch(e){return console.error("[BenchmarkStorage] Error loading index:",e),[]}}}function createAsyncStorageAdapter(){try{const e=require("@react-native-async-storage/async-storage").default;return{getItem:t=>e.getItem(t),setItem:(t,r)=>e.setItem(t,r),removeItem:t=>e.removeItem(t)}}catch{return console.warn("[BenchmarkStorage] @react-native-async-storage/async-storage not available. Provide a custom storage adapter."),null}}function createMemoryStorageAdapter(){const e=new Map;return{getItem:async t=>e.get(t)??null,setItem:async(t,r)=>{e.set(t,r)},removeItem:async t=>{e.delete(t)}}}exports.BenchmarkStorage=BenchmarkStorage;var _default=exports.default=BenchmarkStorage;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"BenchmarkComparator",{enumerable:!0,get:function(){return _BenchmarkComparator.BenchmarkComparator}}),Object.defineProperty(exports,"BenchmarkRecorder",{enumerable:!0,get:function(){return _BenchmarkRecorder.BenchmarkRecorder}}),Object.defineProperty(exports,"BenchmarkStorage",{enumerable:!0,get:function(){return _BenchmarkStorage.BenchmarkStorage}}),Object.defineProperty(exports,"benchmarkRecorder",{enumerable:!0,get:function(){return _BenchmarkRecorder.benchmarkRecorder}}),Object.defineProperty(exports,"createAsyncStorageAdapter",{enumerable:!0,get:function(){return _BenchmarkStorage.createAsyncStorageAdapter}}),Object.defineProperty(exports,"createMemoryStorageAdapter",{enumerable:!0,get:function(){return _BenchmarkStorage.createMemoryStorageAdapter}});var _BenchmarkRecorder=require("./BenchmarkRecorder"),_BenchmarkStorage=require("./BenchmarkStorage"),_BenchmarkComparator=require("./BenchmarkComparator");
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.BenchmarkCompareView=BenchmarkCompareView,exports.default=void 0;var _react=_interopRequireDefault(require("react")),_reactNative=require("react-native"),_sharedUi=require("@buoy-gg/shared-ui"),_benchmarking=require("../benchmarking"),_jsxRuntime=require("react/jsx-runtime");function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}function formatMs(e){return e<1?`${(1e3*e).toFixed(0)}μs`:e<10?`${e.toFixed(2)}ms`:e<100?`${e.toFixed(1)}ms`:`${e.toFixed(0)}ms`}function formatPercent(e){return`${e>=0?"+":""}${e.toFixed(1)}%`}function getImprovementColor(e){return e>5?_sharedUi.macOSColors.semantic.success:e<-5?_sharedUi.macOSColors.semantic.error:_sharedUi.macOSColors.text.secondary}function getIndicator(e){return e>5?"✅":e<-5?"❌":"➖"}function SectionHeader({title:e}){return(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.sectionHeader,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.sectionTitle,children:e})})}function CompareRow({label:e,baseline:t,comparison:s,improvement:a,unit:r="ms"}){return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.compareRow,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.compareLabel,children:e}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.compareValues,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.baselineValue,children:t}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.arrow,children:"→"}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.comparisonValue,children:s}),(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:[styles.improvementValue,{color:getImprovementColor(a)}],children:[formatPercent(a)," ",getIndicator(a)]})]})]})}function BenchmarkCompareView({baseline:e,comparison:t}){const s=_benchmarking.BenchmarkComparator.compare(e,t);return(0,_jsxRuntime.jsxs)(_reactNative.ScrollView,{style:styles.container,contentContainerStyle:styles.content,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.overallResult,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.overallEmoji,children:s.isImproved?"🎉":"⚠️"}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.overallText,children:s.isImproved?"IMPROVED":"REGRESSED"}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.overallPercent,{color:getImprovementColor(s.overallImprovement)}],children:formatPercent(s.overallImprovement)})]}),(0,_jsxRuntime.jsx)(SectionHeader,{title:"COMPARING"}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.section,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.reportInfo,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.reportRole,children:"BASELINE"}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.reportName,children:e.name}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.reportDate,children:new Date(e.createdAt).toLocaleString()})]}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.vsContainer,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.vsText,children:"vs"})}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.reportInfo,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.reportRole,children:"COMPARISON"}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.reportName,children:t.name}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.reportDate,children:new Date(t.createdAt).toLocaleString()})]})]}),(0,_jsxRuntime.jsx)(SectionHeader,{title:"TIMING COMPARISON"}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.section,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.columnHeaders,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.columnLabel,children:"Metric"}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.columnValues,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.columnHeader,children:"Base"}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.columnHeader}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.columnHeader,children:"After"}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.columnHeader,children:"Change"})]})]}),(0,_jsxRuntime.jsx)(CompareRow,{label:"Measure Time",baseline:formatMs(e.stats.avgMeasureTime),comparison:formatMs(t.stats.avgMeasureTime),improvement:s.measureTimeImprovement}),(0,_jsxRuntime.jsx)(CompareRow,{label:"Pipeline Time",baseline:formatMs(e.stats.avgTotalTime),comparison:formatMs(t.stats.avgTotalTime),improvement:s.pipelineTimeImprovement}),(0,_jsxRuntime.jsx)(CompareRow,{label:"Filter Time",baseline:formatMs(e.stats.avgFilterTime),comparison:formatMs(t.stats.avgFilterTime),improvement:s.filterTimeImprovement}),(0,_jsxRuntime.jsx)(CompareRow,{label:"Track Time",baseline:formatMs(e.stats.avgTrackTime),comparison:formatMs(t.stats.avgTrackTime),improvement:s.trackTimeImprovement}),(0,_jsxRuntime.jsx)(CompareRow,{label:"Overlay Render",baseline:formatMs(e.stats.avgOverlayRenderTime),comparison:formatMs(t.stats.avgOverlayRenderTime),improvement:s.overlayRenderImprovement})]}),(0,_jsxRuntime.jsx)(SectionHeader,{title:"PERCENTILES"}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.section,children:[(0,_jsxRuntime.jsx)(CompareRow,{label:"P50 (Median)",baseline:formatMs(e.stats.p50TotalTime),comparison:formatMs(t.stats.p50TotalTime),improvement:e.stats.p50TotalTime>0?(e.stats.p50TotalTime-t.stats.p50TotalTime)/e.stats.p50TotalTime*100:0}),(0,_jsxRuntime.jsx)(CompareRow,{label:"P95",baseline:formatMs(e.stats.p95TotalTime),comparison:formatMs(t.stats.p95TotalTime),improvement:e.stats.p95TotalTime>0?(e.stats.p95TotalTime-t.stats.p95TotalTime)/e.stats.p95TotalTime*100:0}),(0,_jsxRuntime.jsx)(CompareRow,{label:"P99",baseline:formatMs(e.stats.p99TotalTime),comparison:formatMs(t.stats.p99TotalTime),improvement:e.stats.p99TotalTime>0?(e.stats.p99TotalTime-t.stats.p99TotalTime)/e.stats.p99TotalTime*100:0})]}),(0,_jsxRuntime.jsx)(SectionHeader,{title:"BATCH STATISTICS"}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.section,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.statComparison,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.statLabel,children:"Total Batches"}),(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.statValues,children:[e.stats.batchCount," → ",t.stats.batchCount]})]}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.statComparison,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.statLabel,children:"Nodes Processed"}),(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.statValues,children:[e.stats.totalNodesProcessed.toLocaleString()," →"," ",t.stats.totalNodesProcessed.toLocaleString()]})]})]}),null!=e.memoryDelta&&null!=t.memoryDelta&&(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)(SectionHeader,{title:"MEMORY"}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.section,children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.statComparison,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.statLabel,children:"Memory Delta"}),(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:[styles.statValues,{color:null!=s.memoryDeltaChange&&s.memoryDeltaChange<0?_sharedUi.macOSColors.semantic.success:_sharedUi.macOSColors.text.primary}],children:[(e.memoryDelta/1024/1024).toFixed(2),"MB →"," ",(t.memoryDelta/1024/1024).toFixed(2),"MB"]})]})})]}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.footer,children:(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.footerText,children:["Compared at ",new Date(s.comparedAt).toLocaleString()]})})]})}const styles=_reactNative.StyleSheet.create({container:{flex:1},content:{paddingVertical:16},overallResult:{alignItems:"center",paddingVertical:24,backgroundColor:_sharedUi.macOSColors.background.card,marginHorizontal:16,borderRadius:12,borderWidth:1,borderColor:_sharedUi.macOSColors.border.default,marginBottom:16},overallEmoji:{fontSize:32,marginBottom:8},overallText:{fontSize:14,fontWeight:"700",color:_sharedUi.macOSColors.text.primary,fontFamily:"monospace",letterSpacing:2,marginBottom:4},overallPercent:{fontSize:24,fontWeight:"700",fontFamily:"monospace"},sectionHeader:{paddingHorizontal:16,paddingVertical:8,backgroundColor:_sharedUi.macOSColors.background.hover,borderTopWidth:1,borderBottomWidth:1,borderColor:_sharedUi.macOSColors.border.default,marginTop:8},sectionTitle:{fontSize:11,fontWeight:"600",color:_sharedUi.macOSColors.text.secondary,fontFamily:"monospace",letterSpacing:1},section:{paddingHorizontal:16,paddingVertical:8},reportInfo:{flex:1,paddingVertical:8},reportRole:{fontSize:10,fontWeight:"600",color:_sharedUi.macOSColors.text.muted,fontFamily:"monospace",letterSpacing:1,marginBottom:4},reportName:{fontSize:13,fontWeight:"600",color:_sharedUi.macOSColors.text.primary,fontFamily:"monospace",marginBottom:2},reportDate:{fontSize:11,color:_sharedUi.macOSColors.text.secondary,fontFamily:"monospace"},vsContainer:{paddingHorizontal:16,justifyContent:"center"},vsText:{fontSize:12,color:_sharedUi.macOSColors.text.muted,fontFamily:"monospace"},columnHeaders:{flexDirection:"row",justifyContent:"space-between",paddingBottom:8,borderBottomWidth:1,borderColor:_sharedUi.macOSColors.border.default,marginBottom:8},columnLabel:{fontSize:10,color:_sharedUi.macOSColors.text.muted,fontFamily:"monospace",width:80},columnValues:{flexDirection:"row",flex:1,justifyContent:"flex-end",gap:8},columnHeader:{fontSize:10,color:_sharedUi.macOSColors.text.muted,fontFamily:"monospace",width:50,textAlign:"center"},compareRow:{flexDirection:"row",justifyContent:"space-between",alignItems:"center",paddingVertical:8},compareLabel:{fontSize:12,color:_sharedUi.macOSColors.text.secondary,fontFamily:"monospace",width:80},compareValues:{flexDirection:"row",alignItems:"center",flex:1,justifyContent:"flex-end",gap:4},baselineValue:{fontSize:11,color:_sharedUi.macOSColors.text.muted,fontFamily:"monospace",width:50,textAlign:"right"},arrow:{fontSize:11,color:_sharedUi.macOSColors.text.muted,paddingHorizontal:4},comparisonValue:{fontSize:11,color:_sharedUi.macOSColors.text.primary,fontFamily:"monospace",fontWeight:"500",width:50,textAlign:"right"},improvementValue:{fontSize:11,fontFamily:"monospace",fontWeight:"600",width:70,textAlign:"right"},statComparison:{flexDirection:"row",justifyContent:"space-between",alignItems:"center",paddingVertical:6},statLabel:{fontSize:12,color:_sharedUi.macOSColors.text.secondary,fontFamily:"monospace"},statValues:{fontSize:12,color:_sharedUi.macOSColors.text.primary,fontFamily:"monospace"},footer:{paddingHorizontal:16,paddingVertical:16,marginTop:16,borderTopWidth:1,borderColor:_sharedUi.macOSColors.border.default},footerText:{fontSize:10,color:_sharedUi.macOSColors.text.muted,fontFamily:"monospace",textAlign:"center"}});var _default=exports.default=BenchmarkCompareView;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.BenchmarkDetailView=BenchmarkDetailView,exports.default=void 0;var _react=_interopRequireDefault(require("react")),_reactNative=require("react-native"),_sharedUi=require("@buoy-gg/shared-ui"),_jsxRuntime=require("react/jsx-runtime");function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}function formatMs(e){return e<1?`${(1e3*e).toFixed(0)}μs`:e<10?`${e.toFixed(2)}ms`:e<100?`${e.toFixed(1)}ms`:`${e.toFixed(0)}ms`}function formatBytes(e){return null===e?"N/A":Math.abs(e)<1024?`${e}B`:Math.abs(e)<1048576?`${(e/1024).toFixed(1)}KB`:`${(e/1024/1024).toFixed(2)}MB`}function formatDuration(e){return e<1e3?`${e.toFixed(0)}ms`:e<6e4?`${(e/1e3).toFixed(1)}s`:`${Math.floor(e/6e4)}m ${(e%6e4/1e3).toFixed(0)}s`}function SectionHeader({title:e}){return(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.sectionHeader,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.sectionTitle,children:e})})}function StatRow({label:e,value:t,highlight:a}){return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.statRow,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.statLabel,children:e}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.statValue,a&&styles.statValueHighlight],children:t})]})}function BenchmarkDetailView({report:e}){const{stats:t,context:a,memoryStart:s,memoryEnd:i,memoryDelta:l}=e;return(0,_jsxRuntime.jsxs)(_reactNative.ScrollView,{style:styles.container,contentContainerStyle:styles.content,children:[(0,_jsxRuntime.jsx)(SectionHeader,{title:"OVERVIEW"}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.section,children:[(0,_jsxRuntime.jsx)(StatRow,{label:"Name",value:e.name}),(0,_jsxRuntime.jsx)(StatRow,{label:"Duration",value:formatDuration(e.duration)}),(0,_jsxRuntime.jsx)(StatRow,{label:"Created",value:new Date(e.createdAt).toLocaleString()}),e.description&&(0,_jsxRuntime.jsx)(StatRow,{label:"Description",value:e.description})]}),(0,_jsxRuntime.jsx)(SectionHeader,{title:"CONTEXT"}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.section,children:[(0,_jsxRuntime.jsx)(StatRow,{label:"Platform",value:a.platform.toUpperCase()}),a.osVersion&&(0,_jsxRuntime.jsx)(StatRow,{label:"OS Version",value:a.osVersion}),(0,_jsxRuntime.jsx)(StatRow,{label:"Dev Mode",value:a.isDev?"Yes":"No"}),(0,_jsxRuntime.jsx)(StatRow,{label:"Batch Size",value:a.batchSize.toString()}),(0,_jsxRuntime.jsx)(StatRow,{label:"Render Count",value:a.showRenderCount?"Enabled":"Disabled"})]}),(0,_jsxRuntime.jsx)(SectionHeader,{title:"BATCH STATISTICS"}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.section,children:[(0,_jsxRuntime.jsx)(StatRow,{label:"Total Batches",value:t.batchCount.toString()}),(0,_jsxRuntime.jsx)(StatRow,{label:"Nodes Received",value:t.totalNodesReceived.toLocaleString()}),(0,_jsxRuntime.jsx)(StatRow,{label:"Nodes Filtered",value:t.totalNodesFiltered.toLocaleString()}),(0,_jsxRuntime.jsx)(StatRow,{label:"Nodes Processed",value:t.totalNodesProcessed.toLocaleString()})]}),(0,_jsxRuntime.jsx)(SectionHeader,{title:"TIMING (avg per batch)"}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.section,children:[(0,_jsxRuntime.jsx)(StatRow,{label:"Filter Time",value:formatMs(t.avgFilterTime)}),(0,_jsxRuntime.jsx)(StatRow,{label:"Measure Time",value:formatMs(t.avgMeasureTime),highlight:!0}),(0,_jsxRuntime.jsx)(StatRow,{label:"Track Time",value:formatMs(t.avgTrackTime)}),(0,_jsxRuntime.jsx)(StatRow,{label:"Callback Time",value:formatMs(t.avgCallbackTime)}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.divider}),(0,_jsxRuntime.jsx)(StatRow,{label:"Total Pipeline",value:formatMs(t.avgTotalTime),highlight:!0})]}),(0,_jsxRuntime.jsx)(SectionHeader,{title:"TIMING DISTRIBUTION"}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.section,children:[(0,_jsxRuntime.jsx)(StatRow,{label:"Min",value:formatMs(t.minTotalTime)}),(0,_jsxRuntime.jsx)(StatRow,{label:"P50 (Median)",value:formatMs(t.p50TotalTime)}),(0,_jsxRuntime.jsx)(StatRow,{label:"P95",value:formatMs(t.p95TotalTime),highlight:!0}),(0,_jsxRuntime.jsx)(StatRow,{label:"P99",value:formatMs(t.p99TotalTime)}),(0,_jsxRuntime.jsx)(StatRow,{label:"Max",value:formatMs(t.maxTotalTime)})]}),(0,_jsxRuntime.jsx)(SectionHeader,{title:"OVERLAY RENDERING"}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.section,children:[(0,_jsxRuntime.jsx)(StatRow,{label:"Avg Render Time",value:formatMs(t.avgOverlayRenderTime)}),(0,_jsxRuntime.jsx)(StatRow,{label:"Avg Highlights",value:t.avgHighlightsPerRender.toFixed(1)}),(0,_jsxRuntime.jsx)(StatRow,{label:"Total Renders",value:e.overlayRenders.length.toString()})]}),(s||i)&&(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)(SectionHeader,{title:"MEMORY"}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.section,children:[null!=s?.usedJSHeapSize&&(0,_jsxRuntime.jsx)(StatRow,{label:"Start Used",value:formatBytes(s.usedJSHeapSize)}),null!=i?.usedJSHeapSize&&(0,_jsxRuntime.jsx)(StatRow,{label:"End Used",value:formatBytes(i.usedJSHeapSize)}),null!=l&&(0,_jsxRuntime.jsx)(StatRow,{label:"Delta",value:`${l>=0?"+":""}${formatBytes(l)}`,highlight:Math.abs(l)>1048576})]})]}),e.marks.length>0&&(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)(SectionHeader,{title:`CUSTOM MARKS (${e.marks.length})`}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.section,children:[e.marks.slice(0,10).map((e,t)=>(0,_jsxRuntime.jsx)(StatRow,{label:e.name,value:formatMs(e.startTime)},t)),e.marks.length>10&&(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.moreText,children:["+",e.marks.length-10," more marks"]})]})]}),e.measures.length>0&&(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)(SectionHeader,{title:`CUSTOM MEASURES (${e.measures.length})`}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.section,children:[e.measures.slice(0,10).map((e,t)=>(0,_jsxRuntime.jsx)(StatRow,{label:e.name,value:formatMs(e.duration)},t)),e.measures.length>10&&(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.moreText,children:["+",e.measures.length-10," more measures"]})]})]}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.reportId,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.reportIdLabel,children:"Report ID"}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.reportIdValue,children:e.id})]})]})}const styles=_reactNative.StyleSheet.create({container:{flex:1},content:{paddingVertical:16},sectionHeader:{paddingHorizontal:16,paddingVertical:8,backgroundColor:_sharedUi.macOSColors.background.hover,borderTopWidth:1,borderBottomWidth:1,borderColor:_sharedUi.macOSColors.border.default,marginTop:8},sectionTitle:{fontSize:11,fontWeight:"600",color:_sharedUi.macOSColors.text.secondary,fontFamily:"monospace",letterSpacing:1},section:{paddingHorizontal:16,paddingVertical:8},statRow:{flexDirection:"row",justifyContent:"space-between",alignItems:"center",paddingVertical:6},statLabel:{fontSize:13,color:_sharedUi.macOSColors.text.secondary,fontFamily:"monospace"},statValue:{fontSize:13,color:_sharedUi.macOSColors.text.primary,fontFamily:"monospace",fontWeight:"500"},statValueHighlight:{color:_sharedUi.macOSColors.semantic.info,fontWeight:"600"},divider:{height:1,backgroundColor:_sharedUi.macOSColors.border.default,marginVertical:8},moreText:{fontSize:11,color:_sharedUi.macOSColors.text.muted,fontFamily:"monospace",fontStyle:"italic",textAlign:"center",paddingTop:8},reportId:{paddingHorizontal:16,paddingVertical:16,borderTopWidth:1,borderColor:_sharedUi.macOSColors.border.default,marginTop:16},reportIdLabel:{fontSize:10,color:_sharedUi.macOSColors.text.muted,fontFamily:"monospace",marginBottom:4},reportIdValue:{fontSize:10,color:_sharedUi.macOSColors.text.muted,fontFamily:"monospace"}});var _default=exports.default=BenchmarkDetailView;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.BenchmarkModal=BenchmarkModal,exports.default=void 0;var _react=_interopRequireWildcard(require("react")),_reactNative=require("react-native"),_sharedUi=require("@buoy-gg/shared-ui"),_benchmarking=require("../benchmarking"),_BenchmarkSessionCard=require("./BenchmarkSessionCard"),_BenchmarkDetailView=require("./BenchmarkDetailView"),_BenchmarkCompareView=require("./BenchmarkCompareView"),_jsxRuntime=require("react/jsx-runtime");function _interopRequireWildcard(e,t){if("function"==typeof WeakMap)var a=new WeakMap,r=new WeakMap;return(_interopRequireWildcard=function(e,t){if(!t&&e&&e.__esModule)return e;var s,o,i={__proto__:null,default:e};if(null===e||"object"!=typeof e&&"function"!=typeof e)return i;if(s=t?r:a){if(s.has(e))return s.get(e);s.set(e,i)}for(const t in e)"default"!==t&&{}.hasOwnProperty.call(e,t)&&((o=(s=Object.defineProperty)&&Object.getOwnPropertyDescriptor(e,t))&&(o.get||o.set)?s(i,t,o):i[t]=e[t]);return i})(e,t)}const storageAdapter=(0,_benchmarking.createAsyncStorageAdapter)(),storage=storageAdapter?new _benchmarking.BenchmarkStorage(storageAdapter):null;function BenchmarkModal({visible:e,onClose:t,onBack:a,onMinimize:r,enableSharedModalDimensions:s=!1}){const[o,i]=(0,_react.useState)(!1),[n,c]=(0,_react.useState)([]),[l,m]=(0,_react.useState)(null),[d,u]=(0,_react.useState)("list"),[_,h]=(0,_react.useState)(!1),[p,x]=(0,_react.useState)(new Set),[y,g]=(0,_react.useState)(null),[j,R]=(0,_react.useState)(0);(0,_react.useRef)(!1),(0,_react.useEffect)(()=>{e&&storage&&(async()=>{const e=await storage.listReports();c(e)})()},[e,j]),(0,_react.useEffect)(()=>{const e=_benchmarking.benchmarkRecorder.subscribe(e=>{"start"===e?i(!0):"stop"===e&&(i(!1),R(e=>e+1))});return i(_benchmarking.benchmarkRecorder.isRecording()),e},[]);const S=(0,_react.useCallback)(async()=>{if(o){const e=_benchmarking.benchmarkRecorder.stopSession();e&&storage&&(await storage.saveReport(e),R(e=>e+1))}else{const e=(new Date).toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"});_benchmarking.benchmarkRecorder.startSession({name:`Benchmark ${e}`,captureMemory:!0,verbose:!1})}},[o]),C=(0,_react.useCallback)(async e=>{if(_)x(t=>{const a=new Set(t);return a.has(e.id)?a.delete(e.id):a.size<2&&a.add(e.id),a});else{if(!storage)return;const t=await storage.loadReport(e.id);t&&(m(t),u("detail"))}},[_]),b=(0,_react.useCallback)(e=>{h(!0),x(new Set([e.id]))},[]),T=(0,_react.useCallback)(async()=>{if(2!==p.size||!storage)return;const e=Array.from(p),[t,a]=await Promise.all([storage.loadReport(e[0]),storage.loadReport(e[1])]);if(t&&a){const[e,r]=t.createdAt<a.createdAt?[t,a]:[a,t];g({baseline:e,comparison:r}),u("compare"),h(!1),x(new Set)}},[p]),k=(0,_react.useCallback)(async()=>{storage&&(await storage.clearAll(),R(e=>e+1))},[]),f=(0,_react.useCallback)(async()=>{0!==p.size&&storage&&(await Promise.all(Array.from(p).map(e=>storage.deleteReport(e))),x(new Set),h(!1),R(e=>e+1))},[p]),v=(0,_react.useCallback)(()=>{"detail"===d||"compare"===d?(u("list"),m(null),g(null)):_?(h(!1),x(new Set)):a&&a()},[d,_,a]),B=(0,_react.useCallback)(()=>{l&&storage&&_reactNative.Alert.prompt("Rename Benchmark","Enter a new name for this benchmark:",[{text:"Cancel",style:"cancel"},{text:"Save",onPress:async e=>{e&&e.trim()&&(await storage.updateReport(l.id,{name:e.trim()}),m({...l,name:e.trim()}),R(e=>e+1))}}],"plain-text","")},[l]),O=(0,_react.useCallback)(async()=>{l&&storage&&(await storage.deleteReport(l.id),u("list"),m(null),R(e=>e+1))},[l]),U=(0,_react.useCallback)(async()=>{if(!y)return;const{baseline:e,comparison:t}=y,a=_benchmarking.BenchmarkComparator.compare(e,t),r=e=>e<1?`${(1e3*e).toFixed(0)}μs`:e<10?`${e.toFixed(2)}ms`:e<100?`${e.toFixed(1)}ms`:`${e.toFixed(0)}ms`,s=e=>`${e>=0?"+":""}${e.toFixed(1)}%`,o=["BENCHMARK COMPARISON RESULTS","============================","",`Overall: ${a.isImproved?"IMPROVED":"REGRESSED"} ${s(a.overallImprovement)}`,"","COMPARING","---------",`Baseline: ${e.name}`,` Date: ${new Date(e.createdAt).toLocaleString()}`,`Comparison: ${t.name}`,` Date: ${new Date(t.createdAt).toLocaleString()}`,"","TIMING COMPARISON","-----------------",`Measure Time: ${r(e.stats.avgMeasureTime)} → ${r(t.stats.avgMeasureTime)} (${s(a.measureTimeImprovement)})`,`Pipeline Time: ${r(e.stats.avgTotalTime)} → ${r(t.stats.avgTotalTime)} (${s(a.pipelineTimeImprovement)})`,`Filter Time: ${r(e.stats.avgFilterTime)} → ${r(t.stats.avgFilterTime)} (${s(a.filterTimeImprovement)})`,`Track Time: ${r(e.stats.avgTrackTime)} → ${r(t.stats.avgTrackTime)} (${s(a.trackTimeImprovement)})`,`Overlay Render: ${r(e.stats.avgOverlayRenderTime)} → ${r(t.stats.avgOverlayRenderTime)} (${s(a.overlayRenderImprovement)})`,"","PERCENTILES","-----------",`P50 (Median): ${r(e.stats.p50TotalTime)} → ${r(t.stats.p50TotalTime)}`,`P95: ${r(e.stats.p95TotalTime)} → ${r(t.stats.p95TotalTime)}`,`P99: ${r(e.stats.p99TotalTime)} → ${r(t.stats.p99TotalTime)}`,"","BATCH STATISTICS","----------------",`Total Batches: ${e.stats.batchCount} → ${t.stats.batchCount}`,`Nodes Processed: ${e.stats.totalNodesProcessed.toLocaleString()} → ${t.stats.totalNodesProcessed.toLocaleString()}`];null!=e.memoryDelta&&null!=t.memoryDelta&&o.push("","MEMORY","------",`Memory Delta: ${(e.memoryDelta/1024/1024).toFixed(2)}MB → ${(t.memoryDelta/1024/1024).toFixed(2)}MB`),o.push("",`Compared at: ${new Date(a.comparedAt).toLocaleString()}`),await(0,_sharedUi.copyToClipboard)(o.join("\n"))},[y]),w=(0,_react.useCallback)(({item:e})=>(0,_jsxRuntime.jsx)(_BenchmarkSessionCard.BenchmarkSessionCard,{metadata:e,isSelected:p.has(e.id),onPress:()=>C(e),onLongPress:()=>b(e),selectionMode:_}),[_,p,C,b]),$=(0,_react.useCallback)(e=>e.id,[]),M=s?_sharedUi.devToolsStorageKeys.modal.root():_sharedUi.devToolsStorageKeys.benchmark.modal(),P=(0,_react.useMemo)(()=>"detail"===d&&l?l.name:"compare"===d?"Compare":_?0===p.size?"Select 2 to compare":1===p.size?"Select 1 more":`${p.size} Selected`:"Benchmarks",[d,l,_,p]),N="list"!==d||_||a;return e?(0,_jsxRuntime.jsxs)(_sharedUi.JsModal,{visible:e,onClose:t,onBack:N?v:void 0,onMinimize:r,persistenceKey:M,header:{showToggleButton:!0,customContent:(0,_jsxRuntime.jsxs)(_sharedUi.ModalHeader,{children:[N&&(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation,{onBack:v}),(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Content,{title:P}),(0,_jsxRuntime.jsxs)(_sharedUi.ModalHeader.Actions,{children:["list"===d&&!_&&(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{onPress:S,style:[styles.iconButton,o&&styles.recordingButton],children:o?(0,_jsxRuntime.jsx)(_sharedUi.Pause,{size:14,color:_sharedUi.macOSColors.semantic.error}):(0,_jsxRuntime.jsx)(_sharedUi.Play,{size:14,color:_sharedUi.macOSColors.semantic.success})}),n.length>=2&&(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{onPress:()=>h(!0),style:styles.iconButton,children:(0,_jsxRuntime.jsx)(_sharedUi.GitBranch,{size:14,color:_sharedUi.macOSColors.semantic.info})}),(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{onPress:()=>R(e=>e+1),style:styles.iconButton,children:(0,_jsxRuntime.jsx)(_sharedUi.RefreshCw,{size:14,color:_sharedUi.macOSColors.text.secondary})}),n.length>0&&(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{onPress:k,style:styles.iconButton,children:(0,_jsxRuntime.jsx)(_sharedUi.Trash2,{size:14,color:_sharedUi.macOSColors.semantic.error})})]}),"detail"===d&&l&&(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{onPress:B,style:styles.iconButton,children:(0,_jsxRuntime.jsx)(_sharedUi.Edit3,{size:14,color:_sharedUi.macOSColors.text.secondary})}),(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{onPress:O,style:styles.iconButton,children:(0,_jsxRuntime.jsx)(_sharedUi.Trash2,{size:14,color:_sharedUi.macOSColors.semantic.error})})]}),"compare"===d&&y&&(0,_jsxRuntime.jsx)(_jsxRuntime.Fragment,{children:(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{onPress:U,style:styles.iconButton,children:(0,_jsxRuntime.jsx)(_sharedUi.Copy,{size:14,color:_sharedUi.macOSColors.text.secondary})})}),_&&(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[2===p.size&&(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{onPress:T,style:[styles.iconButton,styles.compareButton],children:(0,_jsxRuntime.jsx)(_sharedUi.GitBranch,{size:14,color:_sharedUi.macOSColors.semantic.info})}),p.size>0&&(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{onPress:f,style:styles.iconButton,children:(0,_jsxRuntime.jsx)(_sharedUi.Trash2,{size:14,color:_sharedUi.macOSColors.semantic.error})})]})]})]})},enablePersistence:!0,initialMode:"bottomSheet",enableGlitchEffects:!0,children:[o&&"list"===d&&(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.recordingBanner,children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.recordingDot}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.recordingText,children:"Recording..."}),(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{onPress:S,style:styles.stopButton,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.stopButtonText,children:"Stop"})})]}),"detail"===d&&l?(0,_jsxRuntime.jsx)(_BenchmarkDetailView.BenchmarkDetailView,{report:l}):"compare"===d&&y?(0,_jsxRuntime.jsx)(_BenchmarkCompareView.BenchmarkCompareView,{baseline:y.baseline,comparison:y.comparison}):0===n.length?(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.emptyState,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.emptyIcon,children:"📊"}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.emptyTitle,children:"No Benchmarks Yet"}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.emptySubtitle,children:"Press the record button to start capturing performance metrics"})]}):(0,_jsxRuntime.jsx)(_reactNative.FlatList,{data:n,renderItem:w,keyExtractor:$,contentContainerStyle:styles.listContent,ItemSeparatorComponent:()=>(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.separator}),scrollEnabled:!1})]}):null}const styles=_reactNative.StyleSheet.create({iconButton:{width:32,height:32,borderRadius:8,backgroundColor:_sharedUi.macOSColors.background.hover,borderWidth:1,borderColor:_sharedUi.macOSColors.border.default,alignItems:"center",justifyContent:"center"},recordingButton:{backgroundColor:_sharedUi.macOSColors.semantic.errorBackground,borderColor:_sharedUi.macOSColors.semantic.error},compareButton:{backgroundColor:_sharedUi.macOSColors.semantic.infoBackground,borderColor:_sharedUi.macOSColors.semantic.info},listContent:{paddingVertical:16},separator:{height:8},emptyState:{flex:1,justifyContent:"center",alignItems:"center",padding:32},emptyIcon:{fontSize:48,marginBottom:16},emptyTitle:{fontSize:16,fontWeight:"600",color:_sharedUi.macOSColors.text.primary,fontFamily:"monospace",marginBottom:8},emptySubtitle:{fontSize:13,color:_sharedUi.macOSColors.text.secondary,fontFamily:"monospace",textAlign:"center"},recordingBanner:{flexDirection:"row",alignItems:"center",backgroundColor:_sharedUi.macOSColors.semantic.errorBackground,paddingHorizontal:16,paddingVertical:12,borderBottomWidth:1,borderColor:_sharedUi.macOSColors.semantic.error},recordingDot:{width:8,height:8,borderRadius:4,backgroundColor:_sharedUi.macOSColors.semantic.error,marginRight:8},recordingText:{flex:1,fontSize:13,fontWeight:"600",color:_sharedUi.macOSColors.semantic.error,fontFamily:"monospace"},stopButton:{paddingHorizontal:12,paddingVertical:6,backgroundColor:_sharedUi.macOSColors.semantic.error,borderRadius:4},stopButtonText:{fontSize:12,fontWeight:"600",color:"#fff",fontFamily:"monospace"}});var _default=exports.default=BenchmarkModal;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.BenchmarkSessionCard=BenchmarkSessionCard,exports.default=void 0;var _react=_interopRequireDefault(require("react")),_reactNative=require("react-native"),_sharedUi=require("@buoy-gg/shared-ui"),_jsxRuntime=require("react/jsx-runtime");function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}function formatDuration(e){return e<1e3?`${e.toFixed(0)}ms`:e<6e4?`${(e/1e3).toFixed(1)}s`:`${Math.floor(e/6e4)}m ${(e%6e4/1e3).toFixed(0)}s`}function formatDate(e){const t=new Date(e),r=(new Date).getTime()-t.getTime(),s=Math.floor(r/6e4),a=Math.floor(r/36e5),o=Math.floor(r/864e5);return s<1?"Just now":s<60?`${s}m ago`:a<24?`${a}h ago`:o<7?`${o}d ago`:t.toLocaleDateString(void 0,{month:"short",day:"numeric"})}function BenchmarkSessionCard({metadata:e,isSelected:t=!1,onPress:r,onLongPress:s,selectionMode:a=!1}){return(0,_jsxRuntime.jsxs)(_reactNative.TouchableOpacity,{onPress:r,onLongPress:s,style:[styles.card,t&&styles.cardSelected],activeOpacity:.7,children:[a&&(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.checkbox,t&&styles.checkboxSelected],children:t&&(0,_jsxRuntime.jsx)(_sharedUi.Check,{size:12,color:"#fff"})}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.content,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.header,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.name,numberOfLines:1,children:e.name}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.date,children:formatDate(e.createdAt)})]}),e.description&&(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.description,numberOfLines:1,children:e.description}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.statsRow,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.stat,children:[(0,_jsxRuntime.jsx)(_sharedUi.Clock,{size:12,color:_sharedUi.macOSColors.text.secondary}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.statValue,children:formatDuration(e.duration)})]}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.stat,children:[(0,_jsxRuntime.jsx)(_sharedUi.Layers,{size:12,color:_sharedUi.macOSColors.text.secondary}),(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.statValue,children:[e.batchCount," batch",1!==e.batchCount?"es":""]})]}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.stat,children:(0,_jsxRuntime.jsx)(_sharedUi.Zap,{size:12,color:e.duration<1e4?_sharedUi.macOSColors.semantic.success:e.duration<3e4?_sharedUi.macOSColors.semantic.warning:_sharedUi.macOSColors.semantic.error})})]})]})]})}const styles=_reactNative.StyleSheet.create({card:{flexDirection:"row",alignItems:"center",backgroundColor:_sharedUi.macOSColors.background.card,borderRadius:8,padding:12,marginHorizontal:16,borderWidth:1,borderColor:_sharedUi.macOSColors.border.default},cardSelected:{borderColor:_sharedUi.macOSColors.semantic.info,backgroundColor:_sharedUi.macOSColors.semantic.infoBackground},checkbox:{width:20,height:20,borderRadius:4,borderWidth:1.5,borderColor:_sharedUi.macOSColors.border.hover,marginRight:12,alignItems:"center",justifyContent:"center"},checkboxSelected:{backgroundColor:_sharedUi.macOSColors.semantic.info,borderColor:_sharedUi.macOSColors.semantic.info},content:{flex:1},header:{flexDirection:"row",justifyContent:"space-between",alignItems:"center",marginBottom:4},name:{fontSize:14,fontWeight:"600",color:_sharedUi.macOSColors.text.primary,fontFamily:"monospace",flex:1,marginRight:8},date:{fontSize:11,color:_sharedUi.macOSColors.text.muted,fontFamily:"monospace"},description:{fontSize:12,color:_sharedUi.macOSColors.text.secondary,fontFamily:"monospace",marginBottom:8},statsRow:{flexDirection:"row",alignItems:"center",gap:16},stat:{flexDirection:"row",alignItems:"center",gap:4},statValue:{fontSize:11,color:_sharedUi.macOSColors.text.secondary,fontFamily:"monospace"}});var _default=exports.default=BenchmarkSessionCard;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"BenchmarkComparator",{enumerable:!0,get:function(){return _benchmarking.BenchmarkComparator}}),Object.defineProperty(exports,"BenchmarkModal",{enumerable:!0,get:function(){return _BenchmarkModal.BenchmarkModal}}),Object.defineProperty(exports,"BenchmarkRecorder",{enumerable:!0,get:function(){return _benchmarking.BenchmarkRecorder}}),Object.defineProperty(exports,"BenchmarkStorage",{enumerable:!0,get:function(){return _benchmarking.BenchmarkStorage}}),Object.defineProperty(exports,"benchmarkPreset",{enumerable:!0,get:function(){return _preset.benchmarkPreset}}),Object.defineProperty(exports,"benchmarkRecorder",{enumerable:!0,get:function(){return _benchmarking.benchmarkRecorder}}),Object.defineProperty(exports,"createAsyncStorageAdapter",{enumerable:!0,get:function(){return _benchmarking.createAsyncStorageAdapter}}),Object.defineProperty(exports,"createBenchmarkTool",{enumerable:!0,get:function(){return _preset.createBenchmarkTool}}),Object.defineProperty(exports,"createMemoryStorageAdapter",{enumerable:!0,get:function(){return _benchmarking.createMemoryStorageAdapter}});var _preset=require("./preset"),_benchmarking=require("./benchmarking"),_BenchmarkModal=require("./components/BenchmarkModal");
@@ -0,0 +1 @@
1
+ {"type":"commonjs"}
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.benchmarkPreset=void 0,exports.createBenchmarkTool=createBenchmarkTool;var _react=_interopRequireDefault(require("react")),_sharedUi=require("@buoy-gg/shared-ui"),_BenchmarkModal=require("./components/BenchmarkModal"),_jsxRuntime=require("react/jsx-runtime");function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}const benchmarkPreset=exports.benchmarkPreset={id:"benchmark",name:"BENCH",description:"Performance benchmarking",slot:"both",icon:({size:e})=>(0,_jsxRuntime.jsx)(_sharedUi.BenchmarkIcon,{size:e,color:"#F59E0B"}),component:_BenchmarkModal.BenchmarkModal,props:{enableSharedModalDimensions:!1}};function createBenchmarkTool(e){const r=e?.iconColor||"#F59E0B";return{id:e?.id||"benchmark",name:e?.name||"BENCH",description:e?.description||"Performance benchmarking",slot:"both",icon:({size:e})=>(0,_jsxRuntime.jsx)(_sharedUi.BenchmarkIcon,{size:e,color:r}),component:_BenchmarkModal.BenchmarkModal,props:{enableSharedModalDimensions:!0}}}
@@ -0,0 +1 @@
1
+ "use strict";function calculateImprovement(e,t){return 0===e?0:(e-t)/e*100}function formatPercent(e){return`${e>=0?"+":""}${e.toFixed(1)}%`}function formatMs(e){return`${e.toFixed(1)}ms`}function formatBytes(e){const t=e/1024/1024;return`${t>=0?"+":""}${t.toFixed(2)}MB`}function getIndicator(e,t=5){return e>t?"✅":e<-t?"❌":"➖"}export class BenchmarkComparator{static compare(e,t){const a=e.stats,r=t.stats,m=t.duration-e.duration,o=calculateImprovement(e.duration,t.duration),n=calculateImprovement(a.avgFilterTime,r.avgFilterTime),s=calculateImprovement(a.avgMeasureTime,r.avgMeasureTime),i=calculateImprovement(a.avgTrackTime,r.avgTrackTime),l=calculateImprovement(a.avgTotalTime,r.avgTotalTime),p=calculateImprovement(a.avgOverlayRenderTime,r.avgOverlayRenderTime);let u=null;null!=e.memoryDelta&&null!=t.memoryDelta&&(u=t.memoryDelta-e.memoryDelta);let c=.4*s+.3*l+.2*p;null!=e.memoryDelta&&null!=t.memoryDelta&&0!==e.memoryDelta&&(c+=.1*calculateImprovement(e.memoryDelta,t.memoryDelta));const d=c>0,v=this.generateSummary({baseline:e,comparison:t,durationDelta:m,durationImprovement:o,measureTimeImprovement:s,pipelineTimeImprovement:l,overlayRenderImprovement:p,memoryDeltaChange:u,overallImprovement:c,isImproved:d});return{baselineId:e.id,baselineName:e.name,comparisonId:t.id,comparisonName:t.name,comparedAt:Date.now(),durationDelta:m,durationImprovement:o,filterTimeImprovement:n,measureTimeImprovement:s,trackTimeImprovement:i,pipelineTimeImprovement:l,overlayRenderImprovement:p,memoryDeltaChange:u,overallImprovement:c,isImproved:d,summary:v}}static generateSummary(e){const{baseline:t,comparison:a,measureTimeImprovement:r,pipelineTimeImprovement:m,overlayRenderImprovement:o,memoryDeltaChange:n,overallImprovement:s,isImproved:i}=e,l=[];if(l.push("╔══════════════════════════════════════════════════════════════╗"),l.push("║ BENCHMARK COMPARISON ║"),l.push("╠══════════════════════════════════════════════════════════════╣"),l.push(`║ Baseline: ${t.name.substring(0,50).padEnd(50)} ║`),l.push(`║ ${new Date(t.createdAt).toLocaleString().substring(0,58).padEnd(58)} ║`),l.push(`║ Comparison: ${a.name.substring(0,48).padEnd(48)} ║`),l.push(`║ ${new Date(a.createdAt).toLocaleString().substring(0,58).padEnd(58)} ║`),l.push("╠══════════════════════════════════════════════════════════════╣"),l.push("║ TIMING COMPARISON ║"),l.push("║ Baseline After Change ║"),l.push(`║ Measurement Time: ${formatMs(t.stats.avgMeasureTime).padStart(8)} → ${formatMs(a.stats.avgMeasureTime).padStart(8)} ${formatPercent(r).padStart(7)} ${getIndicator(r)} ║`),l.push(`║ Pipeline Time: ${formatMs(t.stats.avgTotalTime).padStart(8)} → ${formatMs(a.stats.avgTotalTime).padStart(8)} ${formatPercent(m).padStart(7)} ${getIndicator(m)} ║`),l.push(`║ Overlay Render: ${formatMs(t.stats.avgOverlayRenderTime).padStart(8)} → ${formatMs(a.stats.avgOverlayRenderTime).padStart(8)} ${formatPercent(o).padStart(7)} ${getIndicator(o)} ║`),null!=n&&null!=t.memoryDelta&&null!=a.memoryDelta){const e=calculateImprovement(t.memoryDelta,a.memoryDelta);l.push("╠══════════════════════════════════════════════════════════════╣"),l.push("║ MEMORY ║"),l.push(`║ Delta: ${formatBytes(t.memoryDelta).padStart(8)} → ${formatBytes(a.memoryDelta).padStart(8)} ${formatPercent(e).padStart(7)} ${getIndicator(e)} ║`)}l.push("╠══════════════════════════════════════════════════════════════╣"),l.push("║ PERCENTILES (P95) ║");const p=calculateImprovement(t.stats.p95TotalTime,a.stats.p95TotalTime);l.push(`║ P95 Pipeline: ${formatMs(t.stats.p95TotalTime).padStart(8)} → ${formatMs(a.stats.p95TotalTime).padStart(8)} ${formatPercent(p).padStart(7)} ${getIndicator(p)} ║`),l.push("╠══════════════════════════════════════════════════════════════╣");const u=i?"🎉":"⚠️",c=i?"IMPROVED":"REGRESSED";return l.push(`║ ${u} OVERALL: ${formatPercent(s).padStart(7)} ${c.padEnd(40)} ║`),l.push("╚══════════════════════════════════════════════════════════════╝"),l.join("\n")}static logComparison(e){console.log("\n"+e.summary+"\n")}static quickCompare(e,t){const a=this.compare(e,t);return this.logComparison(a),a}static getBriefSummary(e){const t=e.isImproved?"faster":"slower";return`${e.isImproved?"✅":"❌"} ${Math.abs(e.overallImprovement).toFixed(1)}% ${t} (measurement: ${formatPercent(e.measureTimeImprovement)}, pipeline: ${formatPercent(e.pipelineTimeImprovement)})`}}export default BenchmarkComparator;
@@ -0,0 +1 @@
1
+ "use strict";import{Platform}from"react-native";function generateSessionId(e){return`${e}_${Date.now()}_${Math.random().toString(36).substring(2,8)}`}function percentile(e,t){if(0===e.length)return 0;const s=Math.ceil(t/100*e.length)-1;return e[Math.max(0,Math.min(s,e.length-1))]}function captureMemorySnapshot(){return null}function getBenchmarkContext(e,t){let s="unknown";return"ios"===Platform.OS?s="ios":"android"===Platform.OS?s="android":"web"===Platform.OS&&(s="web"),{platform:s,osVersion:Platform.Version?.toString(),isDev:__DEV__??!1,batchSize:e,showRenderCount:t}}function computeStats(e,t){const s=e.length;if(0===s)return{batchCount:0,totalNodesReceived:0,totalNodesFiltered:0,totalNodesProcessed:0,avgFilterTime:0,avgMeasureTime:0,avgTrackTime:0,avgCallbackTime:0,avgTotalTime:0,minTotalTime:0,maxTotalTime:0,p50TotalTime:0,p95TotalTime:0,p99TotalTime:0,avgOverlayRenderTime:0,avgHighlightsPerRender:0};let o=0,r=0,a=0,i=0,n=0,l=0,c=0,m=0;const h=[];for(const t of e)o+=t.nodesReceived,r+=t.nodesFiltered,a+=t.nodesInBatch,i+=t.filteringTime,n+=t.measurementTime,l+=t.trackingTime,c+=t.callbackTime,m+=t.totalTime,h.push(t.totalTime);h.sort((e,t)=>e-t);let d=0,g=0;for(const e of t)d+=e.renderTime,g+=e.highlightCount;return{batchCount:s,totalNodesReceived:o,totalNodesFiltered:r,totalNodesProcessed:a,avgFilterTime:i/s,avgMeasureTime:n/s,avgTrackTime:l/s,avgCallbackTime:c/s,avgTotalTime:m/s,minTotalTime:h[0],maxTotalTime:h[h.length-1],p50TotalTime:percentile(h,50),p95TotalTime:percentile(h,95),p99TotalTime:percentile(h,99),avgOverlayRenderTime:t.length>0?d/t.length:0,avgHighlightsPerRender:t.length>0?g/t.length:0}}export class BenchmarkRecorder{state="idle";sessionId="";sessionName="";sessionStartTime=0;verbose=!1;captureMemory=!0;batches=[];overlayRenders=[];memoryStart=null;memoryEnd=null;marks=[];measures=[];batchSize=150;showRenderCount=!0;listeners=new Set;activeMeasures=new Map;getState(){return this.state}isRecording(){return"recording"===this.state}setBatchSize(e){this.batchSize=e}setShowRenderCount(e){this.showRenderCount=e}startSession(e){"recording"!==this.state?(this.sessionId=generateSessionId(e.name),this.sessionName=e.name,this.sessionDescription=e.description,this.verbose=e.verbose??!1,this.captureMemory=e.captureMemory??!0,this.batches=[],this.overlayRenders=[],this.marks=[],this.measures=[],this.activeMeasures.clear(),this.captureMemory&&(this.memoryStart=captureMemorySnapshot()),this.sessionStartTime=performance.now(),this.marks.push({name:"session_start",startTime:0,detail:{name:this.sessionName}}),this.state="recording",this.verbose&&(console.log(`[BenchmarkRecorder] Session started: ${this.sessionName}`),console.log(` ID: ${this.sessionId}`)),this.notifyListeners("start")):console.warn("[BenchmarkRecorder] Session already recording. Stop it first.")}stopSession(){if("recording"!==this.state)return console.warn("[BenchmarkRecorder] No active session to stop."),null;const e=performance.now()-this.sessionStartTime;this.marks.push({name:"session_end",startTime:e}),this.measures.push({name:"session_total",startTime:0,duration:e}),this.captureMemory&&(this.memoryEnd=captureMemorySnapshot());let t=null;null!=this.memoryStart?.usedJSHeapSize&&null!=this.memoryEnd?.usedJSHeapSize&&(t=this.memoryEnd.usedJSHeapSize-this.memoryStart.usedJSHeapSize);const s=computeStats(this.batches,this.overlayRenders),o={version:"1.0",id:this.sessionId,name:this.sessionName,description:this.sessionDescription,createdAt:Date.now(),duration:e,context:getBenchmarkContext(this.batchSize,this.showRenderCount),batches:[...this.batches],overlayRenders:[...this.overlayRenders],marks:[...this.marks],measures:[...this.measures],stats:s,memoryStart:this.memoryStart,memoryEnd:this.memoryEnd,memoryDelta:t};return this.state="stopped",this.verbose&&this.logReport(o),this.notifyListeners("stop"),o}recordBatch(e){"recording"===this.state&&(this.batches.push(e),this.marks.push({name:`batch_${e.batchId}`,startTime:performance.now()-this.sessionStartTime,detail:{nodesReceived:e.nodesReceived,nodesProcessed:e.nodesInBatch,totalTime:e.totalTime}}),this.verbose&&console.log(`[BenchmarkRecorder] Batch ${e.batchId}: ${e.nodesInBatch} nodes in ${e.totalTime.toFixed(1)}ms`),this.notifyListeners("batch",e))}recordOverlayRender(e,t){if("recording"!==this.state)return;const s={highlightCount:e,renderTime:t,timestamp:performance.now()};this.overlayRenders.push(s),this.marks.push({name:"overlay_render",startTime:performance.now()-this.sessionStartTime,detail:{highlightCount:e,renderTime:t}}),this.verbose&&console.log(`[BenchmarkRecorder] Overlay render: ${e} highlights in ${t.toFixed(1)}ms`),this.notifyListeners("overlay",s)}mark(e,t){"recording"===this.state&&(this.marks.push({name:e,startTime:performance.now()-this.sessionStartTime,detail:t}),this.verbose&&console.log(`[BenchmarkRecorder] Mark: ${e}`))}startMeasure(e){"recording"===this.state&&(this.activeMeasures.set(e,performance.now()),this.verbose&&console.log(`[BenchmarkRecorder] Measure started: ${e}`))}endMeasure(e,t){if("recording"!==this.state)return null;const s=this.activeMeasures.get(e);if(void 0===s)return console.warn(`[BenchmarkRecorder] No active measure: ${e}`),null;const o=performance.now()-s;return this.measures.push({name:e,startTime:s-this.sessionStartTime,duration:o,detail:t}),this.activeMeasures.delete(e),this.verbose&&console.log(`[BenchmarkRecorder] Measure ended: ${e} = ${o.toFixed(1)}ms`),o}subscribe(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}notifyListeners(e,t){for(const s of this.listeners)try{s(e,t)}catch(e){console.error("[BenchmarkRecorder] Error in event listener:",e)}}logReport(e){const{stats:t,memoryDelta:s}=e;if(console.log("\n╔══════════════════════════════════════════════════════════════╗"),console.log("║ BENCHMARK REPORT ║"),console.log("╠══════════════════════════════════════════════════════════════╣"),console.log(`║ Name: ${e.name.padEnd(55)}║`),console.log(`║ ID: ${e.id.substring(0,57).padEnd(57)}║`),console.log(`║ Duration: ${e.duration.toFixed(1).padStart(8)}ms ║`),console.log("╠══════════════════════════════════════════════════════════════╣"),console.log("║ BATCH STATS ║"),console.log(`║ Count: ${t.batchCount.toString().padStart(6)} ║`),console.log(`║ Nodes received: ${t.totalNodesReceived.toString().padStart(8)} ║`),console.log(`║ Nodes processed: ${t.totalNodesProcessed.toString().padStart(7)} ║`),console.log("╠══════════════════════════════════════════════════════════════╣"),console.log("║ TIMING (avg per batch) ║"),console.log(`║ Filter: ${t.avgFilterTime.toFixed(1).padStart(8)}ms ║`),console.log(`║ Measure: ${t.avgMeasureTime.toFixed(1).padStart(7)}ms ← Primary bottleneck ║`),console.log(`║ Track: ${t.avgTrackTime.toFixed(1).padStart(9)}ms ║`),console.log(`║ Callback: ${t.avgCallbackTime.toFixed(1).padStart(6)}ms ║`),console.log(`║ Total: ${t.avgTotalTime.toFixed(1).padStart(9)}ms ║`),console.log("╠══════════════════════════════════════════════════════════════╣"),console.log("║ PERCENTILES ║"),console.log(`║ P50: ${t.p50TotalTime.toFixed(1).padStart(8)}ms ║`),console.log(`║ P95: ${t.p95TotalTime.toFixed(1).padStart(8)}ms ║`),console.log(`║ P99: ${t.p99TotalTime.toFixed(1).padStart(8)}ms ║`),console.log("╠══════════════════════════════════════════════════════════════╣"),console.log("║ OVERLAY RENDERS ║"),console.log(`║ Avg time: ${t.avgOverlayRenderTime.toFixed(1).padStart(7)}ms ║`),console.log(`║ Avg highlights: ${t.avgHighlightsPerRender.toFixed(0).padStart(5)} ║`),null!=s){const e=(s/1024/1024).toFixed(2),t=s>=0?"+":"";console.log("╠══════════════════════════════════════════════════════════════╣"),console.log("║ MEMORY ║"),console.log(`║ Delta: ${t}${e.padStart(7)}MB ║`)}console.log("╚══════════════════════════════════════════════════════════════╝\n")}}export const benchmarkRecorder=new BenchmarkRecorder;export default BenchmarkRecorder;
@@ -0,0 +1 @@
1
+ "use strict";const STORAGE_PREFIX="@buoy-gg/benchmark",INDEX_KEY=`${STORAGE_PREFIX}/index`,REPORT_KEY_PREFIX=`${STORAGE_PREFIX}/report/`;function getReportKey(e){return`${REPORT_KEY_PREFIX}${e}`}function extractMetadata(e){return{id:e.id,name:e.name,description:e.description,createdAt:e.createdAt,duration:e.duration,batchCount:e.stats.batchCount}}export class BenchmarkStorage{constructor(e){this.storage=e}async saveReport(e){const t=await this.loadIndex(),r=t.findIndex(t=>t.id===e.id);return r>=0?t[r]=extractMetadata(e):t.push(extractMetadata(e)),await Promise.all([this.storage.setItem(getReportKey(e.id),JSON.stringify(e)),this.storage.setItem(INDEX_KEY,JSON.stringify(t))]),console.log(`[BenchmarkStorage] Saved report: ${e.name} (${e.id})`),extractMetadata(e)}async loadReport(e){try{const t=await this.storage.getItem(getReportKey(e));return t?JSON.parse(t):null}catch(t){return console.error(`[BenchmarkStorage] Error loading report ${e}:`,t),null}}async listReports(){return(await this.loadIndex()).sort((e,t)=>t.createdAt-e.createdAt)}async deleteReport(e){const t=await this.loadIndex(),r=t.findIndex(t=>t.id===e);return!(r<0||(t.splice(r,1),await Promise.all([this.storage.removeItem(getReportKey(e)),this.storage.setItem(INDEX_KEY,JSON.stringify(t))]),console.log(`[BenchmarkStorage] Deleted report: ${e}`),0))}async clearAll(){const e=await this.loadIndex();await Promise.all([...e.map(e=>this.storage.removeItem(getReportKey(e.id))),this.storage.removeItem(INDEX_KEY)]),console.log(`[BenchmarkStorage] Cleared ${e.length} reports`)}async updateReport(e,t){const r=await this.loadReport(e);return!!r&&(void 0!==t.name&&(r.name=t.name),void 0!==t.description&&(r.description=t.description),await this.saveReport(r),console.log(`[BenchmarkStorage] Updated report: ${e}`),!0)}async getMostRecent(){const e=await this.listReports();return 0===e.length?null:this.loadReport(e[0].id)}async getReportsByName(e){return(await this.loadIndex()).filter(t=>t.name===e).sort((e,t)=>t.createdAt-e.createdAt)}async loadIndex(){try{const e=await this.storage.getItem(INDEX_KEY);return e?JSON.parse(e):[]}catch(e){return console.error("[BenchmarkStorage] Error loading index:",e),[]}}}export function createAsyncStorageAdapter(){try{const e=require("@react-native-async-storage/async-storage").default;return{getItem:t=>e.getItem(t),setItem:(t,r)=>e.setItem(t,r),removeItem:t=>e.removeItem(t)}}catch{return console.warn("[BenchmarkStorage] @react-native-async-storage/async-storage not available. Provide a custom storage adapter."),null}}export function createMemoryStorageAdapter(){const e=new Map;return{getItem:async t=>e.get(t)??null,setItem:async(t,r)=>{e.set(t,r)},removeItem:async t=>{e.delete(t)}}}export default BenchmarkStorage;
@@ -0,0 +1 @@
1
+ "use strict";export{BenchmarkRecorder,benchmarkRecorder}from"./BenchmarkRecorder";export{BenchmarkStorage,createAsyncStorageAdapter,createMemoryStorageAdapter}from"./BenchmarkStorage";export{BenchmarkComparator}from"./BenchmarkComparator";
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1 @@
1
+ "use strict";import React from"react";import{View,Text,ScrollView,StyleSheet}from"react-native";import{macOSColors}from"@buoy-gg/shared-ui";import{BenchmarkComparator}from"../benchmarking";import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";function formatMs(e){return e<1?`${(1e3*e).toFixed(0)}μs`:e<10?`${e.toFixed(2)}ms`:e<100?`${e.toFixed(1)}ms`:`${e.toFixed(0)}ms`}function formatPercent(e){return`${e>=0?"+":""}${e.toFixed(1)}%`}function getImprovementColor(e){return e>5?macOSColors.semantic.success:e<-5?macOSColors.semantic.error:macOSColors.text.secondary}function getIndicator(e){return e>5?"✅":e<-5?"❌":"➖"}function SectionHeader({title:e}){return _jsx(View,{style:styles.sectionHeader,children:_jsx(Text,{style:styles.sectionTitle,children:e})})}function CompareRow({label:e,baseline:t,comparison:o,improvement:s,unit:r="ms"}){return _jsxs(View,{style:styles.compareRow,children:[_jsx(Text,{style:styles.compareLabel,children:e}),_jsxs(View,{style:styles.compareValues,children:[_jsx(Text,{style:styles.baselineValue,children:t}),_jsx(Text,{style:styles.arrow,children:"→"}),_jsx(Text,{style:styles.comparisonValue,children:o}),_jsxs(Text,{style:[styles.improvementValue,{color:getImprovementColor(s)}],children:[formatPercent(s)," ",getIndicator(s)]})]})]})}export function BenchmarkCompareView({baseline:e,comparison:t}){const o=BenchmarkComparator.compare(e,t);return _jsxs(ScrollView,{style:styles.container,contentContainerStyle:styles.content,children:[_jsxs(View,{style:styles.overallResult,children:[_jsx(Text,{style:styles.overallEmoji,children:o.isImproved?"🎉":"⚠️"}),_jsx(Text,{style:styles.overallText,children:o.isImproved?"IMPROVED":"REGRESSED"}),_jsx(Text,{style:[styles.overallPercent,{color:getImprovementColor(o.overallImprovement)}],children:formatPercent(o.overallImprovement)})]}),_jsx(SectionHeader,{title:"COMPARING"}),_jsxs(View,{style:styles.section,children:[_jsxs(View,{style:styles.reportInfo,children:[_jsx(Text,{style:styles.reportRole,children:"BASELINE"}),_jsx(Text,{style:styles.reportName,children:e.name}),_jsx(Text,{style:styles.reportDate,children:new Date(e.createdAt).toLocaleString()})]}),_jsx(View,{style:styles.vsContainer,children:_jsx(Text,{style:styles.vsText,children:"vs"})}),_jsxs(View,{style:styles.reportInfo,children:[_jsx(Text,{style:styles.reportRole,children:"COMPARISON"}),_jsx(Text,{style:styles.reportName,children:t.name}),_jsx(Text,{style:styles.reportDate,children:new Date(t.createdAt).toLocaleString()})]})]}),_jsx(SectionHeader,{title:"TIMING COMPARISON"}),_jsxs(View,{style:styles.section,children:[_jsxs(View,{style:styles.columnHeaders,children:[_jsx(Text,{style:styles.columnLabel,children:"Metric"}),_jsxs(View,{style:styles.columnValues,children:[_jsx(Text,{style:styles.columnHeader,children:"Base"}),_jsx(Text,{style:styles.columnHeader}),_jsx(Text,{style:styles.columnHeader,children:"After"}),_jsx(Text,{style:styles.columnHeader,children:"Change"})]})]}),_jsx(CompareRow,{label:"Measure Time",baseline:formatMs(e.stats.avgMeasureTime),comparison:formatMs(t.stats.avgMeasureTime),improvement:o.measureTimeImprovement}),_jsx(CompareRow,{label:"Pipeline Time",baseline:formatMs(e.stats.avgTotalTime),comparison:formatMs(t.stats.avgTotalTime),improvement:o.pipelineTimeImprovement}),_jsx(CompareRow,{label:"Filter Time",baseline:formatMs(e.stats.avgFilterTime),comparison:formatMs(t.stats.avgFilterTime),improvement:o.filterTimeImprovement}),_jsx(CompareRow,{label:"Track Time",baseline:formatMs(e.stats.avgTrackTime),comparison:formatMs(t.stats.avgTrackTime),improvement:o.trackTimeImprovement}),_jsx(CompareRow,{label:"Overlay Render",baseline:formatMs(e.stats.avgOverlayRenderTime),comparison:formatMs(t.stats.avgOverlayRenderTime),improvement:o.overlayRenderImprovement})]}),_jsx(SectionHeader,{title:"PERCENTILES"}),_jsxs(View,{style:styles.section,children:[_jsx(CompareRow,{label:"P50 (Median)",baseline:formatMs(e.stats.p50TotalTime),comparison:formatMs(t.stats.p50TotalTime),improvement:e.stats.p50TotalTime>0?(e.stats.p50TotalTime-t.stats.p50TotalTime)/e.stats.p50TotalTime*100:0}),_jsx(CompareRow,{label:"P95",baseline:formatMs(e.stats.p95TotalTime),comparison:formatMs(t.stats.p95TotalTime),improvement:e.stats.p95TotalTime>0?(e.stats.p95TotalTime-t.stats.p95TotalTime)/e.stats.p95TotalTime*100:0}),_jsx(CompareRow,{label:"P99",baseline:formatMs(e.stats.p99TotalTime),comparison:formatMs(t.stats.p99TotalTime),improvement:e.stats.p99TotalTime>0?(e.stats.p99TotalTime-t.stats.p99TotalTime)/e.stats.p99TotalTime*100:0})]}),_jsx(SectionHeader,{title:"BATCH STATISTICS"}),_jsxs(View,{style:styles.section,children:[_jsxs(View,{style:styles.statComparison,children:[_jsx(Text,{style:styles.statLabel,children:"Total Batches"}),_jsxs(Text,{style:styles.statValues,children:[e.stats.batchCount," → ",t.stats.batchCount]})]}),_jsxs(View,{style:styles.statComparison,children:[_jsx(Text,{style:styles.statLabel,children:"Nodes Processed"}),_jsxs(Text,{style:styles.statValues,children:[e.stats.totalNodesProcessed.toLocaleString()," →"," ",t.stats.totalNodesProcessed.toLocaleString()]})]})]}),null!=e.memoryDelta&&null!=t.memoryDelta&&_jsxs(_Fragment,{children:[_jsx(SectionHeader,{title:"MEMORY"}),_jsx(View,{style:styles.section,children:_jsxs(View,{style:styles.statComparison,children:[_jsx(Text,{style:styles.statLabel,children:"Memory Delta"}),_jsxs(Text,{style:[styles.statValues,{color:null!=o.memoryDeltaChange&&o.memoryDeltaChange<0?macOSColors.semantic.success:macOSColors.text.primary}],children:[(e.memoryDelta/1024/1024).toFixed(2),"MB →"," ",(t.memoryDelta/1024/1024).toFixed(2),"MB"]})]})})]}),_jsx(View,{style:styles.footer,children:_jsxs(Text,{style:styles.footerText,children:["Compared at ",new Date(o.comparedAt).toLocaleString()]})})]})}const styles=StyleSheet.create({container:{flex:1},content:{paddingVertical:16},overallResult:{alignItems:"center",paddingVertical:24,backgroundColor:macOSColors.background.card,marginHorizontal:16,borderRadius:12,borderWidth:1,borderColor:macOSColors.border.default,marginBottom:16},overallEmoji:{fontSize:32,marginBottom:8},overallText:{fontSize:14,fontWeight:"700",color:macOSColors.text.primary,fontFamily:"monospace",letterSpacing:2,marginBottom:4},overallPercent:{fontSize:24,fontWeight:"700",fontFamily:"monospace"},sectionHeader:{paddingHorizontal:16,paddingVertical:8,backgroundColor:macOSColors.background.hover,borderTopWidth:1,borderBottomWidth:1,borderColor:macOSColors.border.default,marginTop:8},sectionTitle:{fontSize:11,fontWeight:"600",color:macOSColors.text.secondary,fontFamily:"monospace",letterSpacing:1},section:{paddingHorizontal:16,paddingVertical:8},reportInfo:{flex:1,paddingVertical:8},reportRole:{fontSize:10,fontWeight:"600",color:macOSColors.text.muted,fontFamily:"monospace",letterSpacing:1,marginBottom:4},reportName:{fontSize:13,fontWeight:"600",color:macOSColors.text.primary,fontFamily:"monospace",marginBottom:2},reportDate:{fontSize:11,color:macOSColors.text.secondary,fontFamily:"monospace"},vsContainer:{paddingHorizontal:16,justifyContent:"center"},vsText:{fontSize:12,color:macOSColors.text.muted,fontFamily:"monospace"},columnHeaders:{flexDirection:"row",justifyContent:"space-between",paddingBottom:8,borderBottomWidth:1,borderColor:macOSColors.border.default,marginBottom:8},columnLabel:{fontSize:10,color:macOSColors.text.muted,fontFamily:"monospace",width:80},columnValues:{flexDirection:"row",flex:1,justifyContent:"flex-end",gap:8},columnHeader:{fontSize:10,color:macOSColors.text.muted,fontFamily:"monospace",width:50,textAlign:"center"},compareRow:{flexDirection:"row",justifyContent:"space-between",alignItems:"center",paddingVertical:8},compareLabel:{fontSize:12,color:macOSColors.text.secondary,fontFamily:"monospace",width:80},compareValues:{flexDirection:"row",alignItems:"center",flex:1,justifyContent:"flex-end",gap:4},baselineValue:{fontSize:11,color:macOSColors.text.muted,fontFamily:"monospace",width:50,textAlign:"right"},arrow:{fontSize:11,color:macOSColors.text.muted,paddingHorizontal:4},comparisonValue:{fontSize:11,color:macOSColors.text.primary,fontFamily:"monospace",fontWeight:"500",width:50,textAlign:"right"},improvementValue:{fontSize:11,fontFamily:"monospace",fontWeight:"600",width:70,textAlign:"right"},statComparison:{flexDirection:"row",justifyContent:"space-between",alignItems:"center",paddingVertical:6},statLabel:{fontSize:12,color:macOSColors.text.secondary,fontFamily:"monospace"},statValues:{fontSize:12,color:macOSColors.text.primary,fontFamily:"monospace"},footer:{paddingHorizontal:16,paddingVertical:16,marginTop:16,borderTopWidth:1,borderColor:macOSColors.border.default},footerText:{fontSize:10,color:macOSColors.text.muted,fontFamily:"monospace",textAlign:"center"}});export default BenchmarkCompareView;
@@ -0,0 +1 @@
1
+ "use strict";import React from"react";import{View,Text,ScrollView,StyleSheet}from"react-native";import{macOSColors}from"@buoy-gg/shared-ui";import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";function formatMs(e){return e<1?`${(1e3*e).toFixed(0)}μs`:e<10?`${e.toFixed(2)}ms`:e<100?`${e.toFixed(1)}ms`:`${e.toFixed(0)}ms`}function formatBytes(e){return null===e?"N/A":Math.abs(e)<1024?`${e}B`:Math.abs(e)<1048576?`${(e/1024).toFixed(1)}KB`:`${(e/1024/1024).toFixed(2)}MB`}function formatDuration(e){return e<1e3?`${e.toFixed(0)}ms`:e<6e4?`${(e/1e3).toFixed(1)}s`:`${Math.floor(e/6e4)}m ${(e%6e4/1e3).toFixed(0)}s`}function SectionHeader({title:e}){return _jsx(View,{style:styles.sectionHeader,children:_jsx(Text,{style:styles.sectionTitle,children:e})})}function StatRow({label:e,value:t,highlight:a}){return _jsxs(View,{style:styles.statRow,children:[_jsx(Text,{style:styles.statLabel,children:e}),_jsx(Text,{style:[styles.statValue,a&&styles.statValueHighlight],children:t})]})}export function BenchmarkDetailView({report:e}){const{stats:t,context:a,memoryStart:l,memoryEnd:s,memoryDelta:o}=e;return _jsxs(ScrollView,{style:styles.container,contentContainerStyle:styles.content,children:[_jsx(SectionHeader,{title:"OVERVIEW"}),_jsxs(View,{style:styles.section,children:[_jsx(StatRow,{label:"Name",value:e.name}),_jsx(StatRow,{label:"Duration",value:formatDuration(e.duration)}),_jsx(StatRow,{label:"Created",value:new Date(e.createdAt).toLocaleString()}),e.description&&_jsx(StatRow,{label:"Description",value:e.description})]}),_jsx(SectionHeader,{title:"CONTEXT"}),_jsxs(View,{style:styles.section,children:[_jsx(StatRow,{label:"Platform",value:a.platform.toUpperCase()}),a.osVersion&&_jsx(StatRow,{label:"OS Version",value:a.osVersion}),_jsx(StatRow,{label:"Dev Mode",value:a.isDev?"Yes":"No"}),_jsx(StatRow,{label:"Batch Size",value:a.batchSize.toString()}),_jsx(StatRow,{label:"Render Count",value:a.showRenderCount?"Enabled":"Disabled"})]}),_jsx(SectionHeader,{title:"BATCH STATISTICS"}),_jsxs(View,{style:styles.section,children:[_jsx(StatRow,{label:"Total Batches",value:t.batchCount.toString()}),_jsx(StatRow,{label:"Nodes Received",value:t.totalNodesReceived.toLocaleString()}),_jsx(StatRow,{label:"Nodes Filtered",value:t.totalNodesFiltered.toLocaleString()}),_jsx(StatRow,{label:"Nodes Processed",value:t.totalNodesProcessed.toLocaleString()})]}),_jsx(SectionHeader,{title:"TIMING (avg per batch)"}),_jsxs(View,{style:styles.section,children:[_jsx(StatRow,{label:"Filter Time",value:formatMs(t.avgFilterTime)}),_jsx(StatRow,{label:"Measure Time",value:formatMs(t.avgMeasureTime),highlight:!0}),_jsx(StatRow,{label:"Track Time",value:formatMs(t.avgTrackTime)}),_jsx(StatRow,{label:"Callback Time",value:formatMs(t.avgCallbackTime)}),_jsx(View,{style:styles.divider}),_jsx(StatRow,{label:"Total Pipeline",value:formatMs(t.avgTotalTime),highlight:!0})]}),_jsx(SectionHeader,{title:"TIMING DISTRIBUTION"}),_jsxs(View,{style:styles.section,children:[_jsx(StatRow,{label:"Min",value:formatMs(t.minTotalTime)}),_jsx(StatRow,{label:"P50 (Median)",value:formatMs(t.p50TotalTime)}),_jsx(StatRow,{label:"P95",value:formatMs(t.p95TotalTime),highlight:!0}),_jsx(StatRow,{label:"P99",value:formatMs(t.p99TotalTime)}),_jsx(StatRow,{label:"Max",value:formatMs(t.maxTotalTime)})]}),_jsx(SectionHeader,{title:"OVERLAY RENDERING"}),_jsxs(View,{style:styles.section,children:[_jsx(StatRow,{label:"Avg Render Time",value:formatMs(t.avgOverlayRenderTime)}),_jsx(StatRow,{label:"Avg Highlights",value:t.avgHighlightsPerRender.toFixed(1)}),_jsx(StatRow,{label:"Total Renders",value:e.overlayRenders.length.toString()})]}),(l||s)&&_jsxs(_Fragment,{children:[_jsx(SectionHeader,{title:"MEMORY"}),_jsxs(View,{style:styles.section,children:[null!=l?.usedJSHeapSize&&_jsx(StatRow,{label:"Start Used",value:formatBytes(l.usedJSHeapSize)}),null!=s?.usedJSHeapSize&&_jsx(StatRow,{label:"End Used",value:formatBytes(s.usedJSHeapSize)}),null!=o&&_jsx(StatRow,{label:"Delta",value:`${o>=0?"+":""}${formatBytes(o)}`,highlight:Math.abs(o)>1048576})]})]}),e.marks.length>0&&_jsxs(_Fragment,{children:[_jsx(SectionHeader,{title:`CUSTOM MARKS (${e.marks.length})`}),_jsxs(View,{style:styles.section,children:[e.marks.slice(0,10).map((e,t)=>_jsx(StatRow,{label:e.name,value:formatMs(e.startTime)},t)),e.marks.length>10&&_jsxs(Text,{style:styles.moreText,children:["+",e.marks.length-10," more marks"]})]})]}),e.measures.length>0&&_jsxs(_Fragment,{children:[_jsx(SectionHeader,{title:`CUSTOM MEASURES (${e.measures.length})`}),_jsxs(View,{style:styles.section,children:[e.measures.slice(0,10).map((e,t)=>_jsx(StatRow,{label:e.name,value:formatMs(e.duration)},t)),e.measures.length>10&&_jsxs(Text,{style:styles.moreText,children:["+",e.measures.length-10," more measures"]})]})]}),_jsxs(View,{style:styles.reportId,children:[_jsx(Text,{style:styles.reportIdLabel,children:"Report ID"}),_jsx(Text,{style:styles.reportIdValue,children:e.id})]})]})}const styles=StyleSheet.create({container:{flex:1},content:{paddingVertical:16},sectionHeader:{paddingHorizontal:16,paddingVertical:8,backgroundColor:macOSColors.background.hover,borderTopWidth:1,borderBottomWidth:1,borderColor:macOSColors.border.default,marginTop:8},sectionTitle:{fontSize:11,fontWeight:"600",color:macOSColors.text.secondary,fontFamily:"monospace",letterSpacing:1},section:{paddingHorizontal:16,paddingVertical:8},statRow:{flexDirection:"row",justifyContent:"space-between",alignItems:"center",paddingVertical:6},statLabel:{fontSize:13,color:macOSColors.text.secondary,fontFamily:"monospace"},statValue:{fontSize:13,color:macOSColors.text.primary,fontFamily:"monospace",fontWeight:"500"},statValueHighlight:{color:macOSColors.semantic.info,fontWeight:"600"},divider:{height:1,backgroundColor:macOSColors.border.default,marginVertical:8},moreText:{fontSize:11,color:macOSColors.text.muted,fontFamily:"monospace",fontStyle:"italic",textAlign:"center",paddingTop:8},reportId:{paddingHorizontal:16,paddingVertical:16,borderTopWidth:1,borderColor:macOSColors.border.default,marginTop:16},reportIdLabel:{fontSize:10,color:macOSColors.text.muted,fontFamily:"monospace",marginBottom:4},reportIdValue:{fontSize:10,color:macOSColors.text.muted,fontFamily:"monospace"}});export default BenchmarkDetailView;
@@ -0,0 +1 @@
1
+ "use strict";import React,{useState,useEffect,useCallback,useRef,useMemo}from"react";import{View,Text,TouchableOpacity,StyleSheet,FlatList,Alert}from"react-native";import{JsModal,ModalHeader,macOSColors,devToolsStorageKeys,Play,Pause,Trash2,RefreshCw,GitBranch,Edit3,Copy,copyToClipboard}from"@buoy-gg/shared-ui";import{benchmarkRecorder,BenchmarkStorage,BenchmarkComparator,createAsyncStorageAdapter}from"../benchmarking";import{BenchmarkSessionCard}from"./BenchmarkSessionCard";import{BenchmarkDetailView}from"./BenchmarkDetailView";import{BenchmarkCompareView}from"./BenchmarkCompareView";import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";const storageAdapter=createAsyncStorageAdapter(),storage=storageAdapter?new BenchmarkStorage(storageAdapter):null;export function BenchmarkModal({visible:e,onClose:t,onBack:o,onMinimize:a,enableSharedModalDimensions:s=!1}){const[r,n]=useState(!1),[i,l]=useState([]),[c,m]=useState(null),[d,p]=useState("list"),[u,y]=useState(!1),[h,g]=useState(new Set),[S,C]=useState(null),[x,T]=useState(0);useRef(!1),useEffect(()=>{e&&storage&&(async()=>{const e=await storage.listReports();l(e)})()},[e,x]),useEffect(()=>{const e=benchmarkRecorder.subscribe(e=>{"start"===e?n(!0):"stop"===e&&(n(!1),T(e=>e+1))});return n(benchmarkRecorder.isRecording()),e},[]);const b=useCallback(async()=>{if(r){const e=benchmarkRecorder.stopSession();e&&storage&&(await storage.saveReport(e),T(e=>e+1))}else{const e=(new Date).toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"});benchmarkRecorder.startSession({name:`Benchmark ${e}`,captureMemory:!0,verbose:!1})}},[r]),f=useCallback(async e=>{if(u)g(t=>{const o=new Set(t);return o.has(e.id)?o.delete(e.id):o.size<2&&o.add(e.id),o});else{if(!storage)return;const t=await storage.loadReport(e.id);t&&(m(t),p("detail"))}},[u]),k=useCallback(e=>{y(!0),g(new Set([e.id]))},[]),B=useCallback(async()=>{if(2!==h.size||!storage)return;const e=Array.from(h),[t,o]=await Promise.all([storage.loadReport(e[0]),storage.loadReport(e[1])]);if(t&&o){const[e,a]=t.createdAt<o.createdAt?[t,o]:[o,t];C({baseline:e,comparison:a}),p("compare"),y(!1),g(new Set)}},[h]),j=useCallback(async()=>{storage&&(await storage.clearAll(),T(e=>e+1))},[]),_=useCallback(async()=>{0!==h.size&&storage&&(await Promise.all(Array.from(h).map(e=>storage.deleteReport(e))),g(new Set),y(!1),T(e=>e+1))},[h]),O=useCallback(()=>{"detail"===d||"compare"===d?(p("list"),m(null),C(null)):u?(y(!1),g(new Set)):o&&o()},[d,u,o]),$=useCallback(()=>{c&&storage&&Alert.prompt("Rename Benchmark","Enter a new name for this benchmark:",[{text:"Cancel",style:"cancel"},{text:"Save",onPress:async e=>{e&&e.trim()&&(await storage.updateReport(c.id,{name:e.trim()}),m({...c,name:e.trim()}),T(e=>e+1))}}],"plain-text","")},[c]),R=useCallback(async()=>{c&&storage&&(await storage.deleteReport(c.id),p("list"),m(null),T(e=>e+1))},[c]),w=useCallback(async()=>{if(!S)return;const{baseline:e,comparison:t}=S,o=BenchmarkComparator.compare(e,t),a=e=>e<1?`${(1e3*e).toFixed(0)}μs`:e<10?`${e.toFixed(2)}ms`:e<100?`${e.toFixed(1)}ms`:`${e.toFixed(0)}ms`,s=e=>`${e>=0?"+":""}${e.toFixed(1)}%`,r=["BENCHMARK COMPARISON RESULTS","============================","",`Overall: ${o.isImproved?"IMPROVED":"REGRESSED"} ${s(o.overallImprovement)}`,"","COMPARING","---------",`Baseline: ${e.name}`,` Date: ${new Date(e.createdAt).toLocaleString()}`,`Comparison: ${t.name}`,` Date: ${new Date(t.createdAt).toLocaleString()}`,"","TIMING COMPARISON","-----------------",`Measure Time: ${a(e.stats.avgMeasureTime)} → ${a(t.stats.avgMeasureTime)} (${s(o.measureTimeImprovement)})`,`Pipeline Time: ${a(e.stats.avgTotalTime)} → ${a(t.stats.avgTotalTime)} (${s(o.pipelineTimeImprovement)})`,`Filter Time: ${a(e.stats.avgFilterTime)} → ${a(t.stats.avgFilterTime)} (${s(o.filterTimeImprovement)})`,`Track Time: ${a(e.stats.avgTrackTime)} → ${a(t.stats.avgTrackTime)} (${s(o.trackTimeImprovement)})`,`Overlay Render: ${a(e.stats.avgOverlayRenderTime)} → ${a(t.stats.avgOverlayRenderTime)} (${s(o.overlayRenderImprovement)})`,"","PERCENTILES","-----------",`P50 (Median): ${a(e.stats.p50TotalTime)} → ${a(t.stats.p50TotalTime)}`,`P95: ${a(e.stats.p95TotalTime)} → ${a(t.stats.p95TotalTime)}`,`P99: ${a(e.stats.p99TotalTime)} → ${a(t.stats.p99TotalTime)}`,"","BATCH STATISTICS","----------------",`Total Batches: ${e.stats.batchCount} → ${t.stats.batchCount}`,`Nodes Processed: ${e.stats.totalNodesProcessed.toLocaleString()} → ${t.stats.totalNodesProcessed.toLocaleString()}`];null!=e.memoryDelta&&null!=t.memoryDelta&&r.push("","MEMORY","------",`Memory Delta: ${(e.memoryDelta/1024/1024).toFixed(2)}MB → ${(t.memoryDelta/1024/1024).toFixed(2)}MB`),r.push("",`Compared at: ${new Date(o.comparedAt).toLocaleString()}`),await copyToClipboard(r.join("\n"))},[S]),v=useCallback(({item:e})=>_jsx(BenchmarkSessionCard,{metadata:e,isSelected:h.has(e.id),onPress:()=>f(e),onLongPress:()=>k(e),selectionMode:u}),[u,h,f,k]),P=useCallback(e=>e.id,[]),M=s?devToolsStorageKeys.modal.root():devToolsStorageKeys.benchmark.modal(),z=useMemo(()=>"detail"===d&&c?c.name:"compare"===d?"Compare":u?0===h.size?"Select 2 to compare":1===h.size?"Select 1 more":`${h.size} Selected`:"Benchmarks",[d,c,u,h]),A="list"!==d||u||o;return e?_jsxs(JsModal,{visible:e,onClose:t,onBack:A?O:void 0,onMinimize:a,persistenceKey:M,header:{showToggleButton:!0,customContent:_jsxs(ModalHeader,{children:[A&&_jsx(ModalHeader.Navigation,{onBack:O}),_jsx(ModalHeader.Content,{title:z}),_jsxs(ModalHeader.Actions,{children:["list"===d&&!u&&_jsxs(_Fragment,{children:[_jsx(TouchableOpacity,{onPress:b,style:[styles.iconButton,r&&styles.recordingButton],children:r?_jsx(Pause,{size:14,color:macOSColors.semantic.error}):_jsx(Play,{size:14,color:macOSColors.semantic.success})}),i.length>=2&&_jsx(TouchableOpacity,{onPress:()=>y(!0),style:styles.iconButton,children:_jsx(GitBranch,{size:14,color:macOSColors.semantic.info})}),_jsx(TouchableOpacity,{onPress:()=>T(e=>e+1),style:styles.iconButton,children:_jsx(RefreshCw,{size:14,color:macOSColors.text.secondary})}),i.length>0&&_jsx(TouchableOpacity,{onPress:j,style:styles.iconButton,children:_jsx(Trash2,{size:14,color:macOSColors.semantic.error})})]}),"detail"===d&&c&&_jsxs(_Fragment,{children:[_jsx(TouchableOpacity,{onPress:$,style:styles.iconButton,children:_jsx(Edit3,{size:14,color:macOSColors.text.secondary})}),_jsx(TouchableOpacity,{onPress:R,style:styles.iconButton,children:_jsx(Trash2,{size:14,color:macOSColors.semantic.error})})]}),"compare"===d&&S&&_jsx(_Fragment,{children:_jsx(TouchableOpacity,{onPress:w,style:styles.iconButton,children:_jsx(Copy,{size:14,color:macOSColors.text.secondary})})}),u&&_jsxs(_Fragment,{children:[2===h.size&&_jsx(TouchableOpacity,{onPress:B,style:[styles.iconButton,styles.compareButton],children:_jsx(GitBranch,{size:14,color:macOSColors.semantic.info})}),h.size>0&&_jsx(TouchableOpacity,{onPress:_,style:styles.iconButton,children:_jsx(Trash2,{size:14,color:macOSColors.semantic.error})})]})]})]})},enablePersistence:!0,initialMode:"bottomSheet",enableGlitchEffects:!0,children:[r&&"list"===d&&_jsxs(View,{style:styles.recordingBanner,children:[_jsx(View,{style:styles.recordingDot}),_jsx(Text,{style:styles.recordingText,children:"Recording..."}),_jsx(TouchableOpacity,{onPress:b,style:styles.stopButton,children:_jsx(Text,{style:styles.stopButtonText,children:"Stop"})})]}),"detail"===d&&c?_jsx(BenchmarkDetailView,{report:c}):"compare"===d&&S?_jsx(BenchmarkCompareView,{baseline:S.baseline,comparison:S.comparison}):0===i.length?_jsxs(View,{style:styles.emptyState,children:[_jsx(Text,{style:styles.emptyIcon,children:"📊"}),_jsx(Text,{style:styles.emptyTitle,children:"No Benchmarks Yet"}),_jsx(Text,{style:styles.emptySubtitle,children:"Press the record button to start capturing performance metrics"})]}):_jsx(FlatList,{data:i,renderItem:v,keyExtractor:P,contentContainerStyle:styles.listContent,ItemSeparatorComponent:()=>_jsx(View,{style:styles.separator}),scrollEnabled:!1})]}):null}const styles=StyleSheet.create({iconButton:{width:32,height:32,borderRadius:8,backgroundColor:macOSColors.background.hover,borderWidth:1,borderColor:macOSColors.border.default,alignItems:"center",justifyContent:"center"},recordingButton:{backgroundColor:macOSColors.semantic.errorBackground,borderColor:macOSColors.semantic.error},compareButton:{backgroundColor:macOSColors.semantic.infoBackground,borderColor:macOSColors.semantic.info},listContent:{paddingVertical:16},separator:{height:8},emptyState:{flex:1,justifyContent:"center",alignItems:"center",padding:32},emptyIcon:{fontSize:48,marginBottom:16},emptyTitle:{fontSize:16,fontWeight:"600",color:macOSColors.text.primary,fontFamily:"monospace",marginBottom:8},emptySubtitle:{fontSize:13,color:macOSColors.text.secondary,fontFamily:"monospace",textAlign:"center"},recordingBanner:{flexDirection:"row",alignItems:"center",backgroundColor:macOSColors.semantic.errorBackground,paddingHorizontal:16,paddingVertical:12,borderBottomWidth:1,borderColor:macOSColors.semantic.error},recordingDot:{width:8,height:8,borderRadius:4,backgroundColor:macOSColors.semantic.error,marginRight:8},recordingText:{flex:1,fontSize:13,fontWeight:"600",color:macOSColors.semantic.error,fontFamily:"monospace"},stopButton:{paddingHorizontal:12,paddingVertical:6,backgroundColor:macOSColors.semantic.error,borderRadius:4},stopButtonText:{fontSize:12,fontWeight:"600",color:"#fff",fontFamily:"monospace"}});export default BenchmarkModal;
@@ -0,0 +1 @@
1
+ "use strict";import React from"react";import{View,Text,TouchableOpacity,StyleSheet}from"react-native";import{macOSColors,Check,Clock,Layers,Zap}from"@buoy-gg/shared-ui";import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";function formatDuration(e){return e<1e3?`${e.toFixed(0)}ms`:e<6e4?`${(e/1e3).toFixed(1)}s`:`${Math.floor(e/6e4)}m ${(e%6e4/1e3).toFixed(0)}s`}function formatDate(e){const t=new Date(e),o=(new Date).getTime()-t.getTime(),s=Math.floor(o/6e4),r=Math.floor(o/36e5),a=Math.floor(o/864e5);return s<1?"Just now":s<60?`${s}m ago`:r<24?`${r}h ago`:a<7?`${a}d ago`:t.toLocaleDateString(void 0,{month:"short",day:"numeric"})}export function BenchmarkSessionCard({metadata:e,isSelected:t=!1,onPress:o,onLongPress:s,selectionMode:r=!1}){return _jsxs(TouchableOpacity,{onPress:o,onLongPress:s,style:[styles.card,t&&styles.cardSelected],activeOpacity:.7,children:[r&&_jsx(View,{style:[styles.checkbox,t&&styles.checkboxSelected],children:t&&_jsx(Check,{size:12,color:"#fff"})}),_jsxs(View,{style:styles.content,children:[_jsxs(View,{style:styles.header,children:[_jsx(Text,{style:styles.name,numberOfLines:1,children:e.name}),_jsx(Text,{style:styles.date,children:formatDate(e.createdAt)})]}),e.description&&_jsx(Text,{style:styles.description,numberOfLines:1,children:e.description}),_jsxs(View,{style:styles.statsRow,children:[_jsxs(View,{style:styles.stat,children:[_jsx(Clock,{size:12,color:macOSColors.text.secondary}),_jsx(Text,{style:styles.statValue,children:formatDuration(e.duration)})]}),_jsxs(View,{style:styles.stat,children:[_jsx(Layers,{size:12,color:macOSColors.text.secondary}),_jsxs(Text,{style:styles.statValue,children:[e.batchCount," batch",1!==e.batchCount?"es":""]})]}),_jsx(View,{style:styles.stat,children:_jsx(Zap,{size:12,color:e.duration<1e4?macOSColors.semantic.success:e.duration<3e4?macOSColors.semantic.warning:macOSColors.semantic.error})})]})]})]})}const styles=StyleSheet.create({card:{flexDirection:"row",alignItems:"center",backgroundColor:macOSColors.background.card,borderRadius:8,padding:12,marginHorizontal:16,borderWidth:1,borderColor:macOSColors.border.default},cardSelected:{borderColor:macOSColors.semantic.info,backgroundColor:macOSColors.semantic.infoBackground},checkbox:{width:20,height:20,borderRadius:4,borderWidth:1.5,borderColor:macOSColors.border.hover,marginRight:12,alignItems:"center",justifyContent:"center"},checkboxSelected:{backgroundColor:macOSColors.semantic.info,borderColor:macOSColors.semantic.info},content:{flex:1},header:{flexDirection:"row",justifyContent:"space-between",alignItems:"center",marginBottom:4},name:{fontSize:14,fontWeight:"600",color:macOSColors.text.primary,fontFamily:"monospace",flex:1,marginRight:8},date:{fontSize:11,color:macOSColors.text.muted,fontFamily:"monospace"},description:{fontSize:12,color:macOSColors.text.secondary,fontFamily:"monospace",marginBottom:8},statsRow:{flexDirection:"row",alignItems:"center",gap:16},stat:{flexDirection:"row",alignItems:"center",gap:4},statValue:{fontSize:11,color:macOSColors.text.secondary,fontFamily:"monospace"}});export default BenchmarkSessionCard;
@@ -0,0 +1 @@
1
+ "use strict";export{benchmarkPreset,createBenchmarkTool}from"./preset";export{BenchmarkRecorder,benchmarkRecorder,BenchmarkStorage,BenchmarkComparator,createAsyncStorageAdapter,createMemoryStorageAdapter}from"./benchmarking";export{BenchmarkModal}from"./components/BenchmarkModal";
@@ -0,0 +1 @@
1
+ "use strict";import React from"react";import{BenchmarkIcon}from"@buoy-gg/shared-ui";import{BenchmarkModal}from"./components/BenchmarkModal";import{jsx as _jsx}from"react/jsx-runtime";export const benchmarkPreset={id:"benchmark",name:"BENCH",description:"Performance benchmarking",slot:"both",icon:({size:o})=>_jsx(BenchmarkIcon,{size:o,color:"#F59E0B"}),component:BenchmarkModal,props:{enableSharedModalDimensions:!1}};export function createBenchmarkTool(o){const e=o?.iconColor||"#F59E0B";return{id:o?.id||"benchmark",name:o?.name||"BENCH",description:o?.description||"Performance benchmarking",slot:"both",icon:({size:o})=>_jsx(BenchmarkIcon,{size:o,color:e}),component:BenchmarkModal,props:{enableSharedModalDimensions:!0}}}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * BenchmarkComparator
3
+ *
4
+ * Compares two benchmark reports and generates a detailed comparison result.
5
+ * Calculates improvements/regressions across all metrics and provides
6
+ * human-readable summaries.
7
+ *
8
+ * Usage:
9
+ * const comparison = BenchmarkComparator.compare(baselineReport, comparisonReport);
10
+ * console.log(comparison.summary);
11
+ * console.log(`Overall improvement: ${comparison.overallImprovement.toFixed(1)}%`);
12
+ *
13
+ * @packageDocumentation
14
+ */
15
+ import type { BenchmarkReport, BenchmarkComparison } from "./types";
16
+ /**
17
+ * BenchmarkComparator - Compares two benchmark reports
18
+ */
19
+ export declare class BenchmarkComparator {
20
+ /**
21
+ * Compare two benchmark reports
22
+ * @param baseline - The baseline (before) report
23
+ * @param comparison - The comparison (after) report
24
+ * @returns Detailed comparison result
25
+ */
26
+ static compare(baseline: BenchmarkReport, comparison: BenchmarkReport): BenchmarkComparison;
27
+ /**
28
+ * Generate a human-readable summary
29
+ */
30
+ private static generateSummary;
31
+ /**
32
+ * Log a comparison to the console
33
+ */
34
+ static logComparison(comparison: BenchmarkComparison): void;
35
+ /**
36
+ * Quick compare: compare baseline vs comparison and log results
37
+ */
38
+ static quickCompare(baseline: BenchmarkReport, comparison: BenchmarkReport): BenchmarkComparison;
39
+ /**
40
+ * Generate a brief one-line summary
41
+ */
42
+ static getBriefSummary(comparison: BenchmarkComparison): string;
43
+ }
44
+ export default BenchmarkComparator;
45
+ //# sourceMappingURL=BenchmarkComparator.d.ts.map
@@ -0,0 +1,109 @@
1
+ /**
2
+ * BenchmarkRecorder
3
+ *
4
+ * Records performance metrics during a benchmark session. Uses performance.now()
5
+ * for high-resolution timing (the only Performance API available in React Native).
6
+ * Collects batch metrics, overlay render times, memory snapshots, and custom marks/measures.
7
+ *
8
+ * Usage:
9
+ * const recorder = new BenchmarkRecorder();
10
+ * recorder.startSession({ name: 'MyBenchmark' });
11
+ *
12
+ * // Record batch metrics (called by HighlightUpdatesController)
13
+ * recorder.recordBatch(batchMetrics);
14
+ *
15
+ * // Record overlay renders (called by HighlightUpdatesOverlay)
16
+ * recorder.recordOverlayRender(count, timeMs);
17
+ *
18
+ * // Add custom marks/measures
19
+ * recorder.mark('customEvent');
20
+ * recorder.startMeasure('apiCall');
21
+ * recorder.endMeasure('apiCall');
22
+ *
23
+ * // Stop and get report
24
+ * const report = recorder.stopSession();
25
+ *
26
+ * @packageDocumentation
27
+ */
28
+ import type { BatchMetrics, BenchmarkReport, BenchmarkSessionOptions, BenchmarkSessionState, BenchmarkEventListener, DOMHighResTimeStamp } from "./types";
29
+ /**
30
+ * BenchmarkRecorder - Records performance metrics during a benchmark session
31
+ */
32
+ export declare class BenchmarkRecorder {
33
+ private state;
34
+ private sessionId;
35
+ private sessionName;
36
+ private sessionDescription?;
37
+ private sessionStartTime;
38
+ private verbose;
39
+ private captureMemory;
40
+ private batches;
41
+ private overlayRenders;
42
+ private memoryStart;
43
+ private memoryEnd;
44
+ private marks;
45
+ private measures;
46
+ private batchSize;
47
+ private showRenderCount;
48
+ private listeners;
49
+ private activeMeasures;
50
+ /**
51
+ * Get current session state
52
+ */
53
+ getState(): BenchmarkSessionState;
54
+ /**
55
+ * Check if currently recording
56
+ */
57
+ isRecording(): boolean;
58
+ /**
59
+ * Set the batch size context (for report metadata)
60
+ */
61
+ setBatchSize(size: number): void;
62
+ /**
63
+ * Set the showRenderCount context (for report metadata)
64
+ */
65
+ setShowRenderCount(enabled: boolean): void;
66
+ /**
67
+ * Start a new benchmark session
68
+ */
69
+ startSession(options: BenchmarkSessionOptions): void;
70
+ /**
71
+ * Stop the current session and generate a report
72
+ */
73
+ stopSession(): BenchmarkReport | null;
74
+ /**
75
+ * Record a batch of highlight updates
76
+ */
77
+ recordBatch(metrics: BatchMetrics): void;
78
+ /**
79
+ * Record an overlay render
80
+ */
81
+ recordOverlayRender(highlightCount: number, renderTime: DOMHighResTimeStamp): void;
82
+ /**
83
+ * Add a custom mark at the current time
84
+ */
85
+ mark(name: string, detail?: Record<string, unknown>): void;
86
+ /**
87
+ * Start a custom measure
88
+ */
89
+ startMeasure(name: string): void;
90
+ /**
91
+ * End a custom measure
92
+ */
93
+ endMeasure(name: string, detail?: Record<string, unknown>): DOMHighResTimeStamp | null;
94
+ /**
95
+ * Subscribe to benchmark events
96
+ */
97
+ subscribe(listener: BenchmarkEventListener): () => void;
98
+ /**
99
+ * Notify event listeners
100
+ */
101
+ private notifyListeners;
102
+ /**
103
+ * Log a summary of the report
104
+ */
105
+ private logReport;
106
+ }
107
+ export declare const benchmarkRecorder: BenchmarkRecorder;
108
+ export default BenchmarkRecorder;
109
+ //# sourceMappingURL=BenchmarkRecorder.d.ts.map
@@ -0,0 +1,96 @@
1
+ /**
2
+ * BenchmarkStorage
3
+ *
4
+ * Handles persistence of benchmark reports to AsyncStorage.
5
+ * Provides methods to save, load, list, and delete benchmark reports.
6
+ *
7
+ * Storage keys:
8
+ * - @benchmark/index: Array of report metadata (id, name, createdAt)
9
+ * - @benchmark/report/{id}: Full report data
10
+ *
11
+ * @packageDocumentation
12
+ */
13
+ import type { BenchmarkReport } from "./types";
14
+ /**
15
+ * Storage adapter interface - allows for different storage backends
16
+ */
17
+ export interface StorageAdapter {
18
+ getItem(key: string): Promise<string | null>;
19
+ setItem(key: string, value: string): Promise<void>;
20
+ removeItem(key: string): Promise<void>;
21
+ }
22
+ /**
23
+ * Metadata for a stored benchmark (stored in index)
24
+ */
25
+ export interface BenchmarkMetadata {
26
+ id: string;
27
+ name: string;
28
+ description?: string;
29
+ createdAt: number;
30
+ duration: number;
31
+ batchCount: number;
32
+ }
33
+ /**
34
+ * BenchmarkStorage - Manages persistence of benchmark reports
35
+ */
36
+ export declare class BenchmarkStorage {
37
+ private storage;
38
+ /**
39
+ * Create a new BenchmarkStorage instance
40
+ * @param storage - Storage adapter (e.g., AsyncStorage)
41
+ */
42
+ constructor(storage: StorageAdapter);
43
+ /**
44
+ * Save a benchmark report
45
+ * @returns The saved report's metadata
46
+ */
47
+ saveReport(report: BenchmarkReport): Promise<BenchmarkMetadata>;
48
+ /**
49
+ * Load a benchmark report by ID
50
+ * @returns The report, or null if not found
51
+ */
52
+ loadReport(id: string): Promise<BenchmarkReport | null>;
53
+ /**
54
+ * Load all benchmark metadata (for listing)
55
+ */
56
+ listReports(): Promise<BenchmarkMetadata[]>;
57
+ /**
58
+ * Delete a benchmark report
59
+ * @returns true if deleted, false if not found
60
+ */
61
+ deleteReport(id: string): Promise<boolean>;
62
+ /**
63
+ * Delete all benchmark reports
64
+ */
65
+ clearAll(): Promise<void>;
66
+ /**
67
+ * Update a benchmark report's name and/or description
68
+ * @returns true if updated, false if not found
69
+ */
70
+ updateReport(id: string, updates: {
71
+ name?: string;
72
+ description?: string;
73
+ }): Promise<boolean>;
74
+ /**
75
+ * Get the most recent report
76
+ */
77
+ getMostRecent(): Promise<BenchmarkReport | null>;
78
+ /**
79
+ * Get reports by name (for comparing multiple runs of same benchmark)
80
+ */
81
+ getReportsByName(name: string): Promise<BenchmarkMetadata[]>;
82
+ /**
83
+ * Load the index of all benchmarks
84
+ */
85
+ private loadIndex;
86
+ }
87
+ /**
88
+ * Create a storage instance using AsyncStorage
89
+ */
90
+ export declare function createAsyncStorageAdapter(): StorageAdapter | null;
91
+ /**
92
+ * In-memory storage adapter (for testing or when AsyncStorage is not available)
93
+ */
94
+ export declare function createMemoryStorageAdapter(): StorageAdapter;
95
+ export default BenchmarkStorage;
96
+ //# sourceMappingURL=BenchmarkStorage.d.ts.map
@@ -0,0 +1,43 @@
1
+ /**
2
+ * @buoy-gg/benchmark/benchmarking
3
+ *
4
+ * Performance benchmarking system for measuring and comparing
5
+ * highlight updates performance. Uses the W3C Performance API
6
+ * for accurate timing measurements.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * import {
11
+ * benchmarkRecorder,
12
+ * BenchmarkStorage,
13
+ * BenchmarkComparator,
14
+ * createAsyncStorageAdapter,
15
+ * } from '@buoy-gg/benchmark';
16
+ *
17
+ * // Start recording
18
+ * benchmarkRecorder.startSession({ name: 'MyBenchmark' });
19
+ *
20
+ * // ... perform operations ...
21
+ *
22
+ * // Stop and get report
23
+ * const report = benchmarkRecorder.stopSession();
24
+ *
25
+ * // Save report
26
+ * const storage = new BenchmarkStorage(createAsyncStorageAdapter()!);
27
+ * await storage.saveReport(report);
28
+ *
29
+ * // Compare with previous
30
+ * const previous = await storage.getMostRecent();
31
+ * if (previous) {
32
+ * BenchmarkComparator.quickCompare(previous, report);
33
+ * }
34
+ * ```
35
+ *
36
+ * @packageDocumentation
37
+ */
38
+ export type { DOMHighResTimeStamp, MemorySnapshot, BenchmarkMark, BenchmarkMeasure, BatchMetrics, OverlayRenderMetrics, BenchmarkContext, AggregatedStats, BenchmarkReport, BenchmarkComparison, BenchmarkSessionOptions, BenchmarkSessionState, BenchmarkEventListener, } from "./types";
39
+ export { BenchmarkRecorder, benchmarkRecorder } from "./BenchmarkRecorder";
40
+ export { BenchmarkStorage, createAsyncStorageAdapter, createMemoryStorageAdapter, } from "./BenchmarkStorage";
41
+ export type { StorageAdapter, BenchmarkMetadata } from "./BenchmarkStorage";
42
+ export { BenchmarkComparator } from "./BenchmarkComparator";
43
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,240 @@
1
+ /**
2
+ * Benchmarking Types
3
+ *
4
+ * Core type definitions for the performance benchmarking system.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+ /**
9
+ * High-resolution timestamp in milliseconds
10
+ */
11
+ export type DOMHighResTimeStamp = number;
12
+ /**
13
+ * Memory information from the JavaScript heap (Hermes engine)
14
+ */
15
+ export interface MemorySnapshot {
16
+ /** Maximum heap size available (bytes) */
17
+ jsHeapSizeLimit: number | null;
18
+ /** Total allocated heap (bytes) */
19
+ totalJSHeapSize: number | null;
20
+ /** Currently used heap (bytes) */
21
+ usedJSHeapSize: number | null;
22
+ /** Timestamp when snapshot was taken */
23
+ timestamp: DOMHighResTimeStamp;
24
+ }
25
+ /**
26
+ * A single performance mark created during benchmarking
27
+ */
28
+ export interface BenchmarkMark {
29
+ /** Name of the mark */
30
+ name: string;
31
+ /** When the mark was created (relative to session start) */
32
+ startTime: DOMHighResTimeStamp;
33
+ /** Optional custom data attached to the mark */
34
+ detail?: Record<string, unknown>;
35
+ }
36
+ /**
37
+ * A performance measure (duration between two points)
38
+ */
39
+ export interface BenchmarkMeasure {
40
+ /** Name of the measure */
41
+ name: string;
42
+ /** When the measure started */
43
+ startTime: DOMHighResTimeStamp;
44
+ /** Duration of the measure in ms */
45
+ duration: DOMHighResTimeStamp;
46
+ /** Optional custom data attached to the measure */
47
+ detail?: Record<string, unknown>;
48
+ }
49
+ /**
50
+ * Metrics for a single batch of highlight updates
51
+ */
52
+ export interface BatchMetrics {
53
+ /** Unique batch identifier */
54
+ batchId: string;
55
+ /** When this batch was processed */
56
+ timestamp: DOMHighResTimeStamp;
57
+ /** Total nodes received in the traceUpdates event */
58
+ nodesReceived: number;
59
+ /** Nodes filtered out (overlay nodes) */
60
+ nodesFiltered: number;
61
+ /** Nodes remaining after filtering */
62
+ nodesToProcess: number;
63
+ /** Configured batch size limit */
64
+ batchSize: number;
65
+ /** Actual nodes processed (min of nodesToProcess, batchSize) */
66
+ nodesInBatch: number;
67
+ /** Time spent filtering nodes */
68
+ filteringTime: DOMHighResTimeStamp;
69
+ /** Time spent measuring node positions (native bridge) */
70
+ measurementTime: DOMHighResTimeStamp;
71
+ /** Time spent updating RenderTracker */
72
+ trackingTime: DOMHighResTimeStamp;
73
+ /** Time spent calling highlight callback */
74
+ callbackTime: DOMHighResTimeStamp;
75
+ /** Total pipeline time for this batch */
76
+ totalTime: DOMHighResTimeStamp;
77
+ /** Number of successful measurements */
78
+ measurementSuccessCount: number;
79
+ /** Number of failed measurements */
80
+ measurementFailCount: number;
81
+ }
82
+ /**
83
+ * Metrics for overlay render performance
84
+ */
85
+ export interface OverlayRenderMetrics {
86
+ /** Number of highlights rendered */
87
+ highlightCount: number;
88
+ /** Time to render the overlay (ms) */
89
+ renderTime: DOMHighResTimeStamp;
90
+ /** Timestamp of render */
91
+ timestamp: DOMHighResTimeStamp;
92
+ }
93
+ /**
94
+ * Device and configuration context for the benchmark
95
+ */
96
+ export interface BenchmarkContext {
97
+ /** Platform (ios/android) */
98
+ platform: "ios" | "android" | "web" | "unknown";
99
+ /** OS version string */
100
+ osVersion?: string;
101
+ /** App version string */
102
+ appVersion?: string;
103
+ /** Device model (if available) */
104
+ deviceModel?: string;
105
+ /** Whether running in development mode */
106
+ isDev: boolean;
107
+ /** Configured batch size */
108
+ batchSize: number;
109
+ /** Whether render count tracking is enabled */
110
+ showRenderCount: boolean;
111
+ }
112
+ /**
113
+ * Aggregated statistics computed from batch metrics
114
+ */
115
+ export interface AggregatedStats {
116
+ /** Total number of batches processed */
117
+ batchCount: number;
118
+ /** Total nodes received across all batches */
119
+ totalNodesReceived: number;
120
+ /** Total nodes filtered across all batches */
121
+ totalNodesFiltered: number;
122
+ /** Total nodes processed across all batches */
123
+ totalNodesProcessed: number;
124
+ /** Average filtering time per batch */
125
+ avgFilterTime: DOMHighResTimeStamp;
126
+ /** Average measurement time per batch */
127
+ avgMeasureTime: DOMHighResTimeStamp;
128
+ /** Average tracking time per batch */
129
+ avgTrackTime: DOMHighResTimeStamp;
130
+ /** Average callback time per batch */
131
+ avgCallbackTime: DOMHighResTimeStamp;
132
+ /** Average total pipeline time per batch */
133
+ avgTotalTime: DOMHighResTimeStamp;
134
+ /** Minimum total time across batches */
135
+ minTotalTime: DOMHighResTimeStamp;
136
+ /** Maximum total time across batches */
137
+ maxTotalTime: DOMHighResTimeStamp;
138
+ /** 50th percentile (median) total time */
139
+ p50TotalTime: DOMHighResTimeStamp;
140
+ /** 95th percentile total time */
141
+ p95TotalTime: DOMHighResTimeStamp;
142
+ /** 99th percentile total time */
143
+ p99TotalTime: DOMHighResTimeStamp;
144
+ /** Average overlay render time */
145
+ avgOverlayRenderTime: DOMHighResTimeStamp;
146
+ /** Average highlights per render */
147
+ avgHighlightsPerRender: number;
148
+ }
149
+ /**
150
+ * A complete benchmark report that can be saved and compared
151
+ */
152
+ export interface BenchmarkReport {
153
+ /** Schema version for forward compatibility */
154
+ version: "1.0";
155
+ /** Unique identifier for this benchmark */
156
+ id: string;
157
+ /** Human-readable name for this benchmark */
158
+ name: string;
159
+ /** Optional description of what this benchmark measures */
160
+ description?: string;
161
+ /** When the benchmark was created (Unix timestamp) */
162
+ createdAt: number;
163
+ /** Total duration of the benchmark session (ms) */
164
+ duration: DOMHighResTimeStamp;
165
+ /** Device and configuration context */
166
+ context: BenchmarkContext;
167
+ /** All batch metrics recorded during the session */
168
+ batches: BatchMetrics[];
169
+ /** All overlay render metrics recorded during the session */
170
+ overlayRenders: OverlayRenderMetrics[];
171
+ /** Custom marks created during the session */
172
+ marks: BenchmarkMark[];
173
+ /** Custom measures created during the session */
174
+ measures: BenchmarkMeasure[];
175
+ /** Computed statistics from the raw data */
176
+ stats: AggregatedStats;
177
+ /** Memory snapshot at session start */
178
+ memoryStart: MemorySnapshot | null;
179
+ /** Memory snapshot at session end */
180
+ memoryEnd: MemorySnapshot | null;
181
+ /** Memory delta (end - start) in bytes */
182
+ memoryDelta: number | null;
183
+ }
184
+ /**
185
+ * Result of comparing two benchmark reports
186
+ */
187
+ export interface BenchmarkComparison {
188
+ /** The baseline (before) benchmark */
189
+ baselineId: string;
190
+ baselineName: string;
191
+ /** The comparison (after) benchmark */
192
+ comparisonId: string;
193
+ comparisonName: string;
194
+ /** When this comparison was made */
195
+ comparedAt: number;
196
+ /** Change in total duration (negative = faster) */
197
+ durationDelta: DOMHighResTimeStamp;
198
+ /** Percentage improvement in duration (positive = better) */
199
+ durationImprovement: number;
200
+ /** Improvement in average filter time (%) */
201
+ filterTimeImprovement: number;
202
+ /** Improvement in average measurement time (%) */
203
+ measureTimeImprovement: number;
204
+ /** Improvement in average tracking time (%) */
205
+ trackTimeImprovement: number;
206
+ /** Improvement in average total pipeline time (%) */
207
+ pipelineTimeImprovement: number;
208
+ /** Improvement in average overlay render time (%) */
209
+ overlayRenderImprovement: number;
210
+ /** Change in memory delta (negative = less memory used) */
211
+ memoryDeltaChange: number | null;
212
+ /** Overall improvement percentage (weighted average) */
213
+ overallImprovement: number;
214
+ /** Whether the comparison benchmark is faster */
215
+ isImproved: boolean;
216
+ /** Human-readable summary of the comparison */
217
+ summary: string;
218
+ }
219
+ /**
220
+ * Options for creating a new benchmark session
221
+ */
222
+ export interface BenchmarkSessionOptions {
223
+ /** Name for this benchmark session */
224
+ name: string;
225
+ /** Optional description */
226
+ description?: string;
227
+ /** Whether to capture memory snapshots */
228
+ captureMemory?: boolean;
229
+ /** Whether to log to console during recording */
230
+ verbose?: boolean;
231
+ }
232
+ /**
233
+ * State of a benchmark session
234
+ */
235
+ export type BenchmarkSessionState = "idle" | "recording" | "stopped";
236
+ /**
237
+ * Listener callback for benchmark events
238
+ */
239
+ export type BenchmarkEventListener = (event: "start" | "stop" | "batch" | "overlay", data?: BatchMetrics | OverlayRenderMetrics) => void;
240
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,15 @@
1
+ /**
2
+ * BenchmarkCompareView
3
+ *
4
+ * Displays a comparison between two benchmark reports.
5
+ * Shows side-by-side metrics with improvement/regression indicators.
6
+ */
7
+ import React from "react";
8
+ import type { BenchmarkReport } from "../benchmarking";
9
+ interface BenchmarkCompareViewProps {
10
+ baseline: BenchmarkReport;
11
+ comparison: BenchmarkReport;
12
+ }
13
+ export declare function BenchmarkCompareView({ baseline, comparison, }: BenchmarkCompareViewProps): React.JSX.Element;
14
+ export default BenchmarkCompareView;
15
+ //# sourceMappingURL=BenchmarkCompareView.d.ts.map
@@ -0,0 +1,14 @@
1
+ /**
2
+ * BenchmarkDetailView
3
+ *
4
+ * Displays detailed information about a single benchmark report.
5
+ * Shows all metrics, timing breakdowns, percentiles, and memory info.
6
+ */
7
+ import React from "react";
8
+ import type { BenchmarkReport } from "../benchmarking";
9
+ interface BenchmarkDetailViewProps {
10
+ report: BenchmarkReport;
11
+ }
12
+ export declare function BenchmarkDetailView({ report }: BenchmarkDetailViewProps): React.JSX.Element;
13
+ export default BenchmarkDetailView;
14
+ //# sourceMappingURL=BenchmarkDetailView.d.ts.map
@@ -0,0 +1,17 @@
1
+ /**
2
+ * BenchmarkModal
3
+ *
4
+ * Main modal component for the Benchmark dev tool.
5
+ * Provides recording controls, session list, detail views, and comparison.
6
+ */
7
+ import React from "react";
8
+ interface BenchmarkModalProps {
9
+ visible: boolean;
10
+ onClose: () => void;
11
+ onBack?: () => void;
12
+ onMinimize?: (modalState: unknown) => void;
13
+ enableSharedModalDimensions?: boolean;
14
+ }
15
+ export declare function BenchmarkModal({ visible, onClose, onBack, onMinimize, enableSharedModalDimensions, }: BenchmarkModalProps): React.JSX.Element | null;
16
+ export default BenchmarkModal;
17
+ //# sourceMappingURL=BenchmarkModal.d.ts.map
@@ -0,0 +1,19 @@
1
+ /**
2
+ * BenchmarkSessionCard
3
+ *
4
+ * Displays a single benchmark report as a card with key metrics.
5
+ * Shows name, duration, batch count, and timing stats.
6
+ * Supports selection for comparison.
7
+ */
8
+ import React from "react";
9
+ import type { BenchmarkMetadata } from "../benchmarking";
10
+ interface BenchmarkSessionCardProps {
11
+ metadata: BenchmarkMetadata;
12
+ isSelected?: boolean;
13
+ onPress?: () => void;
14
+ onLongPress?: () => void;
15
+ selectionMode?: boolean;
16
+ }
17
+ export declare function BenchmarkSessionCard({ metadata, isSelected, onPress, onLongPress, selectionMode, }: BenchmarkSessionCardProps): React.JSX.Element;
18
+ export default BenchmarkSessionCard;
19
+ //# sourceMappingURL=BenchmarkSessionCard.d.ts.map
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @buoy-gg/benchmark
3
+ *
4
+ * Performance benchmarking system for measuring and comparing
5
+ * highlight updates performance. Uses the W3C Performance API
6
+ * for accurate timing measurements.
7
+ *
8
+ * @example
9
+ * ```tsx
10
+ * // Use the preset in FloatingDevTools
11
+ * import { benchmarkPreset } from '@buoy-gg/benchmark';
12
+ *
13
+ * <FloatingDevTools apps={[benchmarkPreset]} />
14
+ *
15
+ * // Or use the recorder programmatically
16
+ * import { benchmarkRecorder, BenchmarkStorage } from '@buoy-gg/benchmark';
17
+ *
18
+ * benchmarkRecorder.startSession({ name: 'MyBenchmark' });
19
+ * // ... perform operations ...
20
+ * const report = benchmarkRecorder.stopSession();
21
+ * ```
22
+ */
23
+ export { benchmarkPreset, createBenchmarkTool } from "./preset";
24
+ export { BenchmarkRecorder, benchmarkRecorder, BenchmarkStorage, BenchmarkComparator, createAsyncStorageAdapter, createMemoryStorageAdapter, } from "./benchmarking";
25
+ export type { BenchmarkReport, BenchmarkComparison, BenchmarkSessionOptions, BenchmarkMetadata, AggregatedStats, OverlayRenderMetrics, BatchMetrics, DOMHighResTimeStamp, MemorySnapshot, BenchmarkMark, BenchmarkMeasure, BenchmarkContext, BenchmarkSessionState, BenchmarkEventListener, } from "./benchmarking";
26
+ export type { StorageAdapter } from "./benchmarking";
27
+ export { BenchmarkModal } from "./components/BenchmarkModal";
28
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Pre-configured benchmark tool for FloatingDevTools
3
+ *
4
+ * This preset provides performance benchmarking functionality.
5
+ * Record, save, and compare performance metrics.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * import { benchmarkPreset } from '@buoy-gg/benchmark';
10
+ *
11
+ * <FloatingDevTools apps={[benchmarkPreset]} />
12
+ * ```
13
+ */
14
+ import React from "react";
15
+ import { BenchmarkModal } from "./components/BenchmarkModal";
16
+ /**
17
+ * Pre-configured benchmark tool for FloatingDevTools.
18
+ * Provides performance benchmarking with recording, saving, and comparison features.
19
+ *
20
+ * Features:
21
+ * - Start/Stop recording sessions
22
+ * - View saved benchmark reports
23
+ * - Compare two benchmarks side-by-side
24
+ * - Delete individual or all benchmarks
25
+ */
26
+ export declare const benchmarkPreset: {
27
+ id: string;
28
+ name: string;
29
+ description: string;
30
+ slot: "both";
31
+ icon: ({ size }: {
32
+ size: number;
33
+ }) => React.JSX.Element;
34
+ component: typeof BenchmarkModal;
35
+ props: {
36
+ enableSharedModalDimensions: boolean;
37
+ };
38
+ };
39
+ /**
40
+ * Create a custom benchmark tool configuration.
41
+ * Use this if you want to override default settings.
42
+ *
43
+ * @example
44
+ * ```tsx
45
+ * import { createBenchmarkTool } from '@buoy-gg/benchmark';
46
+ *
47
+ * const myBenchmarkTool = createBenchmarkTool({
48
+ * name: "PERF",
49
+ * iconColor: "#059669",
50
+ * });
51
+ * ```
52
+ */
53
+ export declare function createBenchmarkTool(options?: {
54
+ /** Tool name (default: "BENCH") */
55
+ name?: string;
56
+ /** Tool description */
57
+ description?: string;
58
+ /** Icon color (default: "#F59E0B" - amber) */
59
+ iconColor?: string;
60
+ /** Custom tool ID (default: "benchmark") */
61
+ id?: string;
62
+ }): {
63
+ id: string;
64
+ name: string;
65
+ description: string;
66
+ slot: "both";
67
+ icon: ({ size }: {
68
+ size: number;
69
+ }) => React.JSX.Element;
70
+ component: typeof BenchmarkModal;
71
+ props: {
72
+ enableSharedModalDimensions: boolean;
73
+ };
74
+ };
75
+ //# sourceMappingURL=preset.d.ts.map
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "@buoy-gg/benchmark",
3
+ "version": "1.7.2",
4
+ "description": "Performance benchmarking system for React Native dev tools",
5
+ "main": "lib/commonjs/index",
6
+ "module": "lib/module/index",
7
+ "types": "lib/typescript/index.d.ts",
8
+ "react-native": "src/index.tsx",
9
+ "source": "src/index.tsx",
10
+ "files": [
11
+ "lib"
12
+ ],
13
+ "sideEffects": false,
14
+ "scripts": {
15
+ "build": "bob build",
16
+ "typecheck": "tsc --noEmit",
17
+ "clean": "rimraf lib",
18
+ "test": "pnpm run typecheck",
19
+ "postinstall": "echo \"Run pnpm build to compile this package\""
20
+ },
21
+ "dependencies": {
22
+ "@buoy-gg/shared-ui": "workspace:*"
23
+ },
24
+ "peerDependencies": {
25
+ "@react-native-async-storage/async-storage": "*",
26
+ "react": "*",
27
+ "react-native": "*"
28
+ },
29
+ "devDependencies": {
30
+ "@react-native-async-storage/async-storage": "^2.1.2",
31
+ "@types/react": "^19.1.0",
32
+ "@types/react-native": "^0.73.0",
33
+ "typescript": "~5.8.3"
34
+ },
35
+ "react-native-builder-bob": {
36
+ "source": "src",
37
+ "output": "lib",
38
+ "targets": [
39
+ [
40
+ "commonjs",
41
+ {
42
+ "sourceMaps": false
43
+ }
44
+ ],
45
+ [
46
+ "module",
47
+ {
48
+ "sourceMaps": false
49
+ }
50
+ ],
51
+ "typescript"
52
+ ]
53
+ },
54
+ "repository": {
55
+ "type": "git",
56
+ "url": "https://github.com/LovesWorking/react-native-buoy.git",
57
+ "directory": "packages/benchmark"
58
+ },
59
+ "bugs": {
60
+ "url": "https://github.com/LovesWorking/react-native-buoy/issues"
61
+ },
62
+ "homepage": "https://github.com/LovesWorking/react-native-buoy/tree/main/packages/benchmark#readme",
63
+ "publishConfig": {
64
+ "access": "public",
65
+ "tag": "latest"
66
+ }
67
+ }