@benchkit/chart 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (219) hide show
  1. package/README.md +640 -0
  2. package/dist/ComparisonSummaryTable.test.d.ts +2 -0
  3. package/dist/ComparisonSummaryTable.test.d.ts.map +1 -0
  4. package/dist/ComparisonSummaryTable.test.js +53 -0
  5. package/dist/ComparisonSummaryTable.test.js.map +1 -0
  6. package/dist/Dashboard.d.ts +25 -0
  7. package/dist/Dashboard.d.ts.map +1 -0
  8. package/dist/Dashboard.js +87 -0
  9. package/dist/Dashboard.js.map +1 -0
  10. package/dist/Dashboard.test.d.ts +2 -0
  11. package/dist/Dashboard.test.d.ts.map +1 -0
  12. package/dist/Dashboard.test.js +49 -0
  13. package/dist/Dashboard.test.js.map +1 -0
  14. package/dist/RunDashboard.d.ts +20 -0
  15. package/dist/RunDashboard.d.ts.map +1 -0
  16. package/dist/RunDashboard.js +174 -0
  17. package/dist/RunDashboard.js.map +1 -0
  18. package/dist/RunDashboard.test.d.ts +2 -0
  19. package/dist/RunDashboard.test.d.ts.map +1 -0
  20. package/dist/RunDashboard.test.js +58 -0
  21. package/dist/RunDashboard.test.js.map +1 -0
  22. package/dist/RunDetail.d.ts +26 -0
  23. package/dist/RunDetail.d.ts.map +1 -0
  24. package/dist/RunDetail.js +100 -0
  25. package/dist/RunDetail.js.map +1 -0
  26. package/dist/RunDetail.test.d.ts +2 -0
  27. package/dist/RunDetail.test.d.ts.map +1 -0
  28. package/dist/RunDetail.test.js +168 -0
  29. package/dist/RunDetail.test.js.map +1 -0
  30. package/dist/RunSelector.test.d.ts +2 -0
  31. package/dist/RunSelector.test.d.ts.map +1 -0
  32. package/dist/RunSelector.test.js +45 -0
  33. package/dist/RunSelector.test.js.map +1 -0
  34. package/dist/SampleChart.test.d.ts +2 -0
  35. package/dist/SampleChart.test.d.ts.map +1 -0
  36. package/dist/SampleChart.test.js +48 -0
  37. package/dist/SampleChart.test.js.map +1 -0
  38. package/dist/TagFilter.test.d.ts +2 -0
  39. package/dist/TagFilter.test.d.ts.map +1 -0
  40. package/dist/TagFilter.test.js +106 -0
  41. package/dist/TagFilter.test.js.map +1 -0
  42. package/dist/VerdictBanner.test.d.ts +2 -0
  43. package/dist/VerdictBanner.test.d.ts.map +1 -0
  44. package/dist/VerdictBanner.test.js +56 -0
  45. package/dist/VerdictBanner.test.js.map +1 -0
  46. package/dist/chart-config.d.ts +100 -0
  47. package/dist/chart-config.d.ts.map +1 -0
  48. package/dist/chart-config.js +81 -0
  49. package/dist/chart-config.js.map +1 -0
  50. package/dist/colors.d.ts +11 -0
  51. package/dist/colors.d.ts.map +1 -0
  52. package/dist/colors.js +16 -0
  53. package/dist/colors.js.map +1 -0
  54. package/dist/comparison-transforms.d.ts +22 -0
  55. package/dist/comparison-transforms.d.ts.map +1 -0
  56. package/dist/comparison-transforms.js +20 -0
  57. package/dist/comparison-transforms.js.map +1 -0
  58. package/dist/comparison-transforms.test.d.ts +2 -0
  59. package/dist/comparison-transforms.test.d.ts.map +1 -0
  60. package/dist/comparison-transforms.test.js +75 -0
  61. package/dist/comparison-transforms.test.js.map +1 -0
  62. package/dist/components/ComparisonBar.d.ts +13 -0
  63. package/dist/components/ComparisonBar.d.ts.map +1 -0
  64. package/dist/components/ComparisonBar.js +94 -0
  65. package/dist/components/ComparisonBar.js.map +1 -0
  66. package/dist/components/ComparisonChart.d.ts +31 -0
  67. package/dist/components/ComparisonChart.d.ts.map +1 -0
  68. package/dist/components/ComparisonChart.js +118 -0
  69. package/dist/components/ComparisonChart.js.map +1 -0
  70. package/dist/components/ComparisonSummaryTable.d.ts +29 -0
  71. package/dist/components/ComparisonSummaryTable.d.ts.map +1 -0
  72. package/dist/components/ComparisonSummaryTable.js +41 -0
  73. package/dist/components/ComparisonSummaryTable.js.map +1 -0
  74. package/dist/components/DashboardToolbar.d.ts +21 -0
  75. package/dist/components/DashboardToolbar.d.ts.map +1 -0
  76. package/dist/components/DashboardToolbar.js +14 -0
  77. package/dist/components/DashboardToolbar.js.map +1 -0
  78. package/dist/components/DateRangeFilter.d.ts +19 -0
  79. package/dist/components/DateRangeFilter.d.ts.map +1 -0
  80. package/dist/components/DateRangeFilter.js +44 -0
  81. package/dist/components/DateRangeFilter.js.map +1 -0
  82. package/dist/components/HeroSection.d.ts +12 -0
  83. package/dist/components/HeroSection.d.ts.map +1 -0
  84. package/dist/components/HeroSection.js +6 -0
  85. package/dist/components/HeroSection.js.map +1 -0
  86. package/dist/components/Leaderboard.d.ts +9 -0
  87. package/dist/components/Leaderboard.d.ts.map +1 -0
  88. package/dist/components/Leaderboard.js +41 -0
  89. package/dist/components/Leaderboard.js.map +1 -0
  90. package/dist/components/MetricCard.d.ts +16 -0
  91. package/dist/components/MetricCard.d.ts.map +1 -0
  92. package/dist/components/MetricCard.js +25 -0
  93. package/dist/components/MetricCard.js.map +1 -0
  94. package/dist/components/MetricDetailView.d.ts +15 -0
  95. package/dist/components/MetricDetailView.d.ts.map +1 -0
  96. package/dist/components/MetricDetailView.js +11 -0
  97. package/dist/components/MetricDetailView.js.map +1 -0
  98. package/dist/components/MonitorSection.d.ts +21 -0
  99. package/dist/components/MonitorSection.d.ts.map +1 -0
  100. package/dist/components/MonitorSection.js +38 -0
  101. package/dist/components/MonitorSection.js.map +1 -0
  102. package/dist/components/OverviewGrid.d.ts +17 -0
  103. package/dist/components/OverviewGrid.d.ts.map +1 -0
  104. package/dist/components/OverviewGrid.js +15 -0
  105. package/dist/components/OverviewGrid.js.map +1 -0
  106. package/dist/components/RunSelector.d.ts +20 -0
  107. package/dist/components/RunSelector.d.ts.map +1 -0
  108. package/dist/components/RunSelector.js +53 -0
  109. package/dist/components/RunSelector.js.map +1 -0
  110. package/dist/components/RunTable.d.ts +13 -0
  111. package/dist/components/RunTable.d.ts.map +1 -0
  112. package/dist/components/RunTable.js +24 -0
  113. package/dist/components/RunTable.js.map +1 -0
  114. package/dist/components/SampleChart.d.ts +21 -0
  115. package/dist/components/SampleChart.d.ts.map +1 -0
  116. package/dist/components/SampleChart.js +77 -0
  117. package/dist/components/SampleChart.js.map +1 -0
  118. package/dist/components/TagFilter.d.ts +12 -0
  119. package/dist/components/TagFilter.d.ts.map +1 -0
  120. package/dist/components/TagFilter.js +59 -0
  121. package/dist/components/TagFilter.js.map +1 -0
  122. package/dist/components/TrendChart.d.ts +25 -0
  123. package/dist/components/TrendChart.d.ts.map +1 -0
  124. package/dist/components/TrendChart.js +95 -0
  125. package/dist/components/TrendChart.js.map +1 -0
  126. package/dist/components/VerdictBanner.d.ts +13 -0
  127. package/dist/components/VerdictBanner.d.ts.map +1 -0
  128. package/dist/components/VerdictBanner.js +22 -0
  129. package/dist/components/VerdictBanner.js.map +1 -0
  130. package/dist/dashboard-labels.d.ts +47 -0
  131. package/dist/dashboard-labels.d.ts.map +1 -0
  132. package/dist/dashboard-labels.js +44 -0
  133. package/dist/dashboard-labels.js.map +1 -0
  134. package/dist/dashboard-labels.test.d.ts +2 -0
  135. package/dist/dashboard-labels.test.d.ts.map +1 -0
  136. package/dist/dashboard-labels.test.js +34 -0
  137. package/dist/dashboard-labels.test.js.map +1 -0
  138. package/dist/dataset-transforms.d.ts +41 -0
  139. package/dist/dataset-transforms.d.ts.map +1 -0
  140. package/dist/dataset-transforms.js +132 -0
  141. package/dist/dataset-transforms.js.map +1 -0
  142. package/dist/dataset-transforms.test.d.ts +2 -0
  143. package/dist/dataset-transforms.test.d.ts.map +1 -0
  144. package/dist/dataset-transforms.test.js +208 -0
  145. package/dist/dataset-transforms.test.js.map +1 -0
  146. package/dist/date-range.test.d.ts +2 -0
  147. package/dist/date-range.test.d.ts.map +1 -0
  148. package/dist/date-range.test.js +116 -0
  149. package/dist/date-range.test.js.map +1 -0
  150. package/dist/embed.d.ts +45 -0
  151. package/dist/embed.d.ts.map +1 -0
  152. package/dist/embed.js +170 -0
  153. package/dist/embed.js.map +1 -0
  154. package/dist/embed.test.d.ts +2 -0
  155. package/dist/embed.test.d.ts.map +1 -0
  156. package/dist/embed.test.js +15 -0
  157. package/dist/embed.test.js.map +1 -0
  158. package/dist/fetch.d.ts +27 -0
  159. package/dist/fetch.d.ts.map +1 -0
  160. package/dist/fetch.js +73 -0
  161. package/dist/fetch.js.map +1 -0
  162. package/dist/fetch.test.d.ts +2 -0
  163. package/dist/fetch.test.d.ts.map +1 -0
  164. package/dist/fetch.test.js +75 -0
  165. package/dist/fetch.test.js.map +1 -0
  166. package/dist/format-utils.d.ts +48 -0
  167. package/dist/format-utils.d.ts.map +1 -0
  168. package/dist/format-utils.js +98 -0
  169. package/dist/format-utils.js.map +1 -0
  170. package/dist/format-utils.test.d.ts +2 -0
  171. package/dist/format-utils.test.d.ts.map +1 -0
  172. package/dist/format-utils.test.js +103 -0
  173. package/dist/format-utils.test.js.map +1 -0
  174. package/dist/hooks/useChartLifecycle.d.ts +20 -0
  175. package/dist/hooks/useChartLifecycle.d.ts.map +1 -0
  176. package/dist/hooks/useChartLifecycle.js +46 -0
  177. package/dist/hooks/useChartLifecycle.js.map +1 -0
  178. package/dist/index.d.ts +27 -0
  179. package/dist/index.d.ts.map +1 -0
  180. package/dist/index.js +36 -0
  181. package/dist/index.js.map +1 -0
  182. package/dist/index.test.d.ts +2 -0
  183. package/dist/index.test.d.ts.map +1 -0
  184. package/dist/index.test.js +10 -0
  185. package/dist/index.test.js.map +1 -0
  186. package/dist/labels.d.ts +5 -0
  187. package/dist/labels.d.ts.map +1 -0
  188. package/dist/labels.js +41 -0
  189. package/dist/labels.js.map +1 -0
  190. package/dist/labels.test.d.ts +2 -0
  191. package/dist/labels.test.d.ts.map +1 -0
  192. package/dist/labels.test.js +28 -0
  193. package/dist/labels.test.js.map +1 -0
  194. package/dist/leaderboard.d.ts +29 -0
  195. package/dist/leaderboard.d.ts.map +1 -0
  196. package/dist/leaderboard.js +40 -0
  197. package/dist/leaderboard.js.map +1 -0
  198. package/dist/leaderboard.test.d.ts +2 -0
  199. package/dist/leaderboard.test.d.ts.map +1 -0
  200. package/dist/leaderboard.test.js +105 -0
  201. package/dist/leaderboard.test.js.map +1 -0
  202. package/dist/sample-utils.d.ts +4 -0
  203. package/dist/sample-utils.d.ts.map +1 -0
  204. package/dist/sample-utils.js +12 -0
  205. package/dist/sample-utils.js.map +1 -0
  206. package/dist/style.css +912 -0
  207. package/dist/theme.d.ts +12 -0
  208. package/dist/theme.d.ts.map +1 -0
  209. package/dist/theme.js +17 -0
  210. package/dist/theme.js.map +1 -0
  211. package/dist/utils.d.ts +37 -0
  212. package/dist/utils.d.ts.map +1 -0
  213. package/dist/utils.js +63 -0
  214. package/dist/utils.js.map +1 -0
  215. package/dist/utils.test.d.ts +2 -0
  216. package/dist/utils.test.d.ts.map +1 -0
  217. package/dist/utils.test.js +196 -0
  218. package/dist/utils.test.js.map +1 -0
  219. package/package.json +46 -0
@@ -0,0 +1,116 @@
1
+ import { describe, it } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { presetToDateRange, filterSeriesFileByDateRange, } from "./components/DateRangeFilter.js";
4
+ function makeSeries(timestamps) {
5
+ return {
6
+ metric: "latency_ms",
7
+ unit: "ms",
8
+ direction: "smaller_is_better",
9
+ series: {
10
+ "series-a": {
11
+ points: timestamps.map((ts) => ({ timestamp: ts, value: 10 })),
12
+ },
13
+ },
14
+ };
15
+ }
16
+ describe("presetToDateRange", () => {
17
+ const now = new Date("2026-03-15T12:00:00Z");
18
+ it("returns 7 days back for '7d'", () => {
19
+ const range = presetToDateRange("7d", now);
20
+ assert.ok(range.start);
21
+ assert.equal(range.end, null);
22
+ const start = new Date(range.start);
23
+ assert.equal(start.toISOString(), "2026-03-08T12:00:00.000Z");
24
+ });
25
+ it("returns 30 days back for '30d'", () => {
26
+ const range = presetToDateRange("30d", now);
27
+ assert.ok(range.start);
28
+ const start = new Date(range.start);
29
+ assert.equal(start.toISOString(), "2026-02-13T12:00:00.000Z");
30
+ });
31
+ it("returns 90 days back for '90d'", () => {
32
+ const range = presetToDateRange("90d", now);
33
+ assert.ok(range.start);
34
+ const start = new Date(range.start);
35
+ assert.equal(start.toISOString(), "2025-12-15T12:00:00.000Z");
36
+ });
37
+ it("returns null start/end for 'all'", () => {
38
+ const range = presetToDateRange("all", now);
39
+ assert.equal(range.start, null);
40
+ assert.equal(range.end, null);
41
+ });
42
+ });
43
+ describe("filterSeriesFileByDateRange", () => {
44
+ it("returns all data when range is 'all' (null start/end)", () => {
45
+ const sf = makeSeries(["2026-01-01T00:00:00Z", "2026-03-01T00:00:00Z"]);
46
+ const filtered = filterSeriesFileByDateRange(sf, { start: null, end: null });
47
+ assert.equal(Object.keys(filtered.series).length, 1);
48
+ assert.equal(filtered.series["series-a"].points.length, 2);
49
+ });
50
+ it("filters points before the start date", () => {
51
+ const sf = makeSeries([
52
+ "2026-01-01T00:00:00Z",
53
+ "2026-02-01T00:00:00Z",
54
+ "2026-03-01T00:00:00Z",
55
+ "2026-03-10T00:00:00Z",
56
+ ]);
57
+ const range = { start: "2026-02-15T00:00:00Z", end: null };
58
+ const filtered = filterSeriesFileByDateRange(sf, range);
59
+ assert.equal(filtered.series["series-a"].points.length, 2);
60
+ assert.equal(filtered.series["series-a"].points[0].timestamp, "2026-03-01T00:00:00Z");
61
+ });
62
+ it("filters points after the end date", () => {
63
+ const sf = makeSeries([
64
+ "2026-01-01T00:00:00Z",
65
+ "2026-02-01T00:00:00Z",
66
+ "2026-03-01T00:00:00Z",
67
+ ]);
68
+ const range = { start: null, end: "2026-01-15T00:00:00Z" };
69
+ const filtered = filterSeriesFileByDateRange(sf, range);
70
+ assert.equal(filtered.series["series-a"].points.length, 1);
71
+ });
72
+ it("removes series entirely if all points are outside the range", () => {
73
+ const sf = makeSeries(["2025-01-01T00:00:00Z", "2025-06-01T00:00:00Z"]);
74
+ const range = { start: "2026-01-01T00:00:00Z", end: null };
75
+ const filtered = filterSeriesFileByDateRange(sf, range);
76
+ assert.equal(Object.keys(filtered.series).length, 0);
77
+ });
78
+ it("preserves the original series file metadata", () => {
79
+ const sf = makeSeries(["2026-03-01T00:00:00Z"]);
80
+ const filtered = filterSeriesFileByDateRange(sf, { start: "2026-01-01T00:00:00Z", end: null });
81
+ assert.equal(filtered.metric, "latency_ms");
82
+ assert.equal(filtered.unit, "ms");
83
+ assert.equal(filtered.direction, "smaller_is_better");
84
+ });
85
+ it("does not mutate the original series file", () => {
86
+ const sf = makeSeries(["2025-01-01T00:00:00Z", "2026-03-01T00:00:00Z"]);
87
+ const range = { start: "2026-01-01T00:00:00Z", end: null };
88
+ filterSeriesFileByDateRange(sf, range);
89
+ assert.equal(sf.series["series-a"].points.length, 2);
90
+ });
91
+ it("handles multiple series independently", () => {
92
+ const sf = {
93
+ metric: "latency_ms",
94
+ unit: "ms",
95
+ direction: "smaller_is_better",
96
+ series: {
97
+ "series-a": {
98
+ points: [
99
+ { timestamp: "2026-01-01T00:00:00Z", value: 10 },
100
+ { timestamp: "2026-03-01T00:00:00Z", value: 20 },
101
+ ],
102
+ },
103
+ "series-b": {
104
+ points: [
105
+ { timestamp: "2026-03-05T00:00:00Z", value: 30 },
106
+ ],
107
+ },
108
+ },
109
+ };
110
+ const range = { start: "2026-02-01T00:00:00Z", end: null };
111
+ const filtered = filterSeriesFileByDateRange(sf, range);
112
+ assert.equal(filtered.series["series-a"].points.length, 1);
113
+ assert.equal(filtered.series["series-b"].points.length, 1);
114
+ });
115
+ });
116
+ //# sourceMappingURL=date-range.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-range.test.js","sourceRoot":"","sources":["../src/date-range.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Standalone embed entry point for @benchkit/chart.
3
+ *
4
+ * Include via `<script>` tag with data attributes:
5
+ *
6
+ * ```html
7
+ * <div id="benchkit-chart"></div>
8
+ * <script
9
+ * type="module"
10
+ * src="https://cdn.example.com/@benchkit/chart/embed.js"
11
+ * data-target="#benchkit-chart"
12
+ * data-owner="strawgate"
13
+ * data-repo="benchkit"
14
+ * data-branch="bench-data"
15
+ * data-mode="dashboard"
16
+ * ></script>
17
+ * ```
18
+ *
19
+ * Supported modes: "dashboard" (default), "trend", "leaderboard"
20
+ *
21
+ * This module does NOT handle cross-file joins or arbitrary queries.
22
+ * It renders a single chart surface from the configured data source.
23
+ */
24
+ import { type DataSource } from "./fetch.js";
25
+ export type EmbedMode = "dashboard" | "trend" | "leaderboard";
26
+ export interface EmbedOptions {
27
+ /** CSS selector or HTMLElement for the mount target. */
28
+ target: string | HTMLElement;
29
+ /** Data source configuration. */
30
+ source: DataSource;
31
+ /** Which surface to render. Default: "dashboard". */
32
+ mode?: EmbedMode;
33
+ /** Metric name (required for "trend" and "leaderboard" modes). */
34
+ metric?: string;
35
+ /** Maximum data points for trend charts. Default: 30. */
36
+ maxPoints?: number;
37
+ /** Regression threshold percentage. Default: 10. */
38
+ regressionThreshold?: number;
39
+ }
40
+ /**
41
+ * Mount a benchkit chart into the given target element.
42
+ * Returns a dispose function that unmounts the component.
43
+ */
44
+ export declare function mount(options: EmbedOptions): () => void;
45
+ //# sourceMappingURL=embed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embed.d.ts","sourceRoot":"","sources":["../src/embed.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAMH,OAAO,EAAe,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAI1D,MAAM,MAAM,SAAS,GAAG,WAAW,GAAG,OAAO,GAAG,aAAa,CAAC;AAE9D,MAAM,WAAW,YAAY;IAC3B,wDAAwD;IACxD,MAAM,EAAE,MAAM,GAAG,WAAW,CAAC;IAC7B,iCAAiC;IACjC,MAAM,EAAE,UAAU,CAAC;IACnB,qDAAqD;IACrD,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,kEAAkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yDAAyD;IACzD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oDAAoD;IACpD,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;GAGG;AACH,wBAAgB,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,IAAI,CA2CvD"}
package/dist/embed.js ADDED
@@ -0,0 +1,170 @@
1
+ /**
2
+ * Standalone embed entry point for @benchkit/chart.
3
+ *
4
+ * Include via `<script>` tag with data attributes:
5
+ *
6
+ * ```html
7
+ * <div id="benchkit-chart"></div>
8
+ * <script
9
+ * type="module"
10
+ * src="https://cdn.example.com/@benchkit/chart/embed.js"
11
+ * data-target="#benchkit-chart"
12
+ * data-owner="strawgate"
13
+ * data-repo="benchkit"
14
+ * data-branch="bench-data"
15
+ * data-mode="dashboard"
16
+ * ></script>
17
+ * ```
18
+ *
19
+ * Supported modes: "dashboard" (default), "trend", "leaderboard"
20
+ *
21
+ * This module does NOT handle cross-file joins or arbitrary queries.
22
+ * It renders a single chart surface from the configured data source.
23
+ */
24
+ import { render, h } from "preact";
25
+ import { useState, useEffect } from "preact/hooks";
26
+ import { Dashboard } from "./Dashboard.js";
27
+ import { fetchSeries } from "./fetch.js";
28
+ import { TrendChart } from "./components/TrendChart.js";
29
+ import { Leaderboard } from "./components/Leaderboard.js";
30
+ /**
31
+ * Mount a benchkit chart into the given target element.
32
+ * Returns a dispose function that unmounts the component.
33
+ */
34
+ export function mount(options) {
35
+ const el = typeof options.target === "string"
36
+ ? document.querySelector(options.target)
37
+ : options.target;
38
+ if (!el || !(el instanceof HTMLElement)) {
39
+ throw new Error(`benchkit embed: target "${options.target}" not found or not an HTMLElement`);
40
+ }
41
+ const source = options.source;
42
+ const mode = options.mode ?? "dashboard";
43
+ let vnode;
44
+ if (mode === "dashboard") {
45
+ vnode = h(Dashboard, {
46
+ source,
47
+ maxPoints: options.maxPoints ?? 30,
48
+ regressionThreshold: options.regressionThreshold ?? 10,
49
+ });
50
+ }
51
+ else if (mode === "trend") {
52
+ vnode = h(EmbedTrend, {
53
+ source,
54
+ metric: options.metric ?? "",
55
+ maxPoints: options.maxPoints ?? 30,
56
+ });
57
+ }
58
+ else if (mode === "leaderboard") {
59
+ vnode = h(EmbedLeaderboard, {
60
+ source,
61
+ metric: options.metric ?? "",
62
+ });
63
+ }
64
+ else {
65
+ throw new Error(`benchkit embed: unknown mode "${mode}"`);
66
+ }
67
+ render(vnode, el);
68
+ return () => {
69
+ render(null, el);
70
+ };
71
+ }
72
+ // ── Internal wrapper components for single-metric embeds ─────────────
73
+ function EmbedTrend({ source, metric, maxPoints, }) {
74
+ const [seriesFile, setSeriesFile] = useState(null);
75
+ const [error, setError] = useState(null);
76
+ useEffect(() => {
77
+ if (!metric) {
78
+ setError("No metric specified for trend chart");
79
+ return;
80
+ }
81
+ const ctrl = new AbortController();
82
+ fetchSeries(source, metric, ctrl.signal)
83
+ .then((sf) => {
84
+ if (!ctrl.signal.aborted)
85
+ setSeriesFile(sf);
86
+ })
87
+ .catch((err) => {
88
+ if (!ctrl.signal.aborted)
89
+ setError(String(err));
90
+ });
91
+ return () => ctrl.abort();
92
+ }, [source.owner, source.repo, source.branch, source.baseUrl, metric]);
93
+ if (error)
94
+ return h("div", { class: "bk-state" }, error);
95
+ if (!seriesFile)
96
+ return h("div", { class: "bk-loading" }, "Loading…");
97
+ return h(TrendChart, {
98
+ series: seriesFile,
99
+ maxPoints,
100
+ });
101
+ }
102
+ function EmbedLeaderboard({ source, metric, }) {
103
+ const [seriesFile, setSeriesFile] = useState(null);
104
+ const [error, setError] = useState(null);
105
+ useEffect(() => {
106
+ if (!metric) {
107
+ setError("No metric specified for leaderboard");
108
+ return;
109
+ }
110
+ const ctrl = new AbortController();
111
+ fetchSeries(source, metric, ctrl.signal)
112
+ .then((sf) => {
113
+ if (!ctrl.signal.aborted)
114
+ setSeriesFile(sf);
115
+ })
116
+ .catch((err) => {
117
+ if (!ctrl.signal.aborted)
118
+ setError(String(err));
119
+ });
120
+ return () => ctrl.abort();
121
+ }, [source.owner, source.repo, source.branch, source.baseUrl, metric]);
122
+ if (error)
123
+ return h("div", { class: "bk-state" }, error);
124
+ if (!seriesFile)
125
+ return h("div", { class: "bk-loading" }, "Loading…");
126
+ return h(Leaderboard, { series: seriesFile });
127
+ }
128
+ // ── Auto-mount from script tag ───────────────────────────────────────
129
+ /**
130
+ * Parse data attributes from the current `<script>` tag and auto-mount.
131
+ * Called automatically when loaded as a `<script type="module">`.
132
+ */
133
+ function autoMount() {
134
+ const script = document.currentScript;
135
+ if (!script)
136
+ return;
137
+ const target = script.getAttribute("data-target");
138
+ if (!target)
139
+ return;
140
+ const source = {};
141
+ const owner = script.getAttribute("data-owner");
142
+ const repo = script.getAttribute("data-repo");
143
+ const branch = script.getAttribute("data-branch");
144
+ const baseUrl = script.getAttribute("data-base-url");
145
+ if (owner)
146
+ source.owner = owner;
147
+ if (repo)
148
+ source.repo = repo;
149
+ if (branch)
150
+ source.branch = branch;
151
+ if (baseUrl)
152
+ source.baseUrl = baseUrl;
153
+ const mode = (script.getAttribute("data-mode") ?? "dashboard");
154
+ const metric = script.getAttribute("data-metric") ?? undefined;
155
+ const maxPoints = script.getAttribute("data-max-points");
156
+ const threshold = script.getAttribute("data-regression-threshold");
157
+ mount({
158
+ target,
159
+ source,
160
+ mode,
161
+ metric,
162
+ maxPoints: maxPoints ? parseInt(maxPoints, 10) : undefined,
163
+ regressionThreshold: threshold ? parseFloat(threshold) : undefined,
164
+ });
165
+ }
166
+ // Auto-mount when loaded as a module script in the browser.
167
+ if (typeof document !== "undefined") {
168
+ autoMount();
169
+ }
170
+ //# sourceMappingURL=embed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embed.js","sourceRoot":"","sources":["../src/embed.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,MAAM,EAAuB,CAAC,EAAE,MAAM,QAAQ,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEnD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAmB,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAmB1D;;;GAGG;AACH,MAAM,UAAU,KAAK,CAAC,OAAqB;IACzC,MAAM,EAAE,GACN,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ;QAChC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC;QACxC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;IAErB,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,YAAY,WAAW,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CACb,2BAA2B,OAAO,CAAC,MAAM,mCAAmC,CAC7E,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAC9B,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,WAAW,CAAC;IAEzC,IAAI,KAAqB,CAAC;IAE1B,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;QACzB,KAAK,GAAG,CAAC,CAAC,SAAS,EAAE;YACnB,MAAM;YACN,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,EAAE;YAClC,mBAAmB,EAAE,OAAO,CAAC,mBAAmB,IAAI,EAAE;SACvD,CAAC,CAAC;IACL,CAAC;SAAM,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QAC5B,KAAK,GAAG,CAAC,CAAC,UAAU,EAAE;YACpB,MAAM;YACN,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE;YAC5B,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,EAAE;SACnC,CAAC,CAAC;IACL,CAAC;SAAM,IAAI,IAAI,KAAK,aAAa,EAAE,CAAC;QAClC,KAAK,GAAG,CAAC,CAAC,gBAAgB,EAAE;YAC1B,MAAM;YACN,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE;SAC7B,CAAC,CAAC;IACL,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,KAAK,CAAC,iCAAiC,IAAI,GAAG,CAAC,CAAC;IAC5D,CAAC;IAED,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAElB,OAAO,GAAG,EAAE;QACV,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACnB,CAAC,CAAC;AACJ,CAAC;AAED,wEAAwE;AAExE,SAAS,UAAU,CAAC,EAClB,MAAM,EACN,MAAM,EACN,SAAS,GAKV;IACC,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAoB,IAAI,CAAC,CAAC;IACtE,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IAExD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,QAAQ,CAAC,qCAAqC,CAAC,CAAC;YAChD,OAAO;QACT,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,eAAe,EAAE,CAAC;QACnC,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC;aACrC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE;YACX,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO;gBAAE,aAAa,CAAC,EAAE,CAAC,CAAC;QAC9C,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YACb,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO;gBAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAClD,CAAC,CAAC,CAAC;QACL,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IAC5B,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;IAEvE,IAAI,KAAK;QAAE,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,KAAK,CAAC,CAAC;IACzD,IAAI,CAAC,UAAU;QAAE,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,UAAU,CAAC,CAAC;IAEtE,OAAO,CAAC,CAAC,UAAU,EAAE;QACnB,MAAM,EAAE,UAAU;QAClB,SAAS;KACV,CAAC,CAAC;AACL,CAAC;AAED,SAAS,gBAAgB,CAAC,EACxB,MAAM,EACN,MAAM,GAIP;IACC,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAoB,IAAI,CAAC,CAAC;IACtE,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IAExD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,QAAQ,CAAC,qCAAqC,CAAC,CAAC;YAChD,OAAO;QACT,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,eAAe,EAAE,CAAC;QACnC,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC;aACrC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE;YACX,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO;gBAAE,aAAa,CAAC,EAAE,CAAC,CAAC;QAC9C,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YACb,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO;gBAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAClD,CAAC,CAAC,CAAC;QACL,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IAC5B,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;IAEvE,IAAI,KAAK;QAAE,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,KAAK,CAAC,CAAC;IACzD,IAAI,CAAC,UAAU;QAAE,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,UAAU,CAAC,CAAC;IAEtE,OAAO,CAAC,CAAC,WAAW,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;AAChD,CAAC;AAED,wEAAwE;AAExE;;;GAGG;AACH,SAAS,SAAS;IAChB,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC;IACtC,IAAI,CAAC,MAAM;QAAE,OAAO;IAEpB,MAAM,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC;IAClD,IAAI,CAAC,MAAM;QAAE,OAAO;IAEpB,MAAM,MAAM,GAAe,EAAE,CAAC;IAC9B,MAAM,KAAK,GAAG,MAAM,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC;IAChD,MAAM,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC;IAClD,MAAM,OAAO,GAAG,MAAM,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC;IAErD,IAAI,KAAK;QAAE,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;IAChC,IAAI,IAAI;QAAE,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC;IAC7B,IAAI,MAAM;QAAE,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;IACnC,IAAI,OAAO;QAAE,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC;IAEtC,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,WAAW,CAAC,IAAI,WAAW,CAAc,CAAC;IAC5E,MAAM,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC,aAAa,CAAC,IAAI,SAAS,CAAC;IAC/D,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAC;IACzD,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC,2BAA2B,CAAC,CAAC;IAEnE,KAAK,CAAC;QACJ,MAAM;QACN,MAAM;QACN,IAAI;QACJ,MAAM;QACN,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS;QAC1D,mBAAmB,EAAE,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS;KACnE,CAAC,CAAC;AACL,CAAC;AAED,4DAA4D;AAC5D,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;IACpC,SAAS,EAAE,CAAC;AACd,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=embed.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embed.test.d.ts","sourceRoot":"","sources":["../src/embed.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,15 @@
1
+ import { describe, it } from "node:test";
2
+ import * as assert from "node:assert/strict";
3
+ /**
4
+ * The embed module is designed for browser execution (uses `document`,
5
+ * `render()`, etc.), so we test the exported API shape and types here.
6
+ * Full integration tests require a browser environment.
7
+ */
8
+ describe("embed module exports", () => {
9
+ it("exports mount function and types", async () => {
10
+ // Verify the module can be imported and has the expected shape.
11
+ const mod = await import("./embed.js");
12
+ assert.equal(typeof mod.mount, "function");
13
+ });
14
+ });
15
+ //# sourceMappingURL=embed.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embed.test.js","sourceRoot":"","sources":["../src/embed.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,MAAM,MAAM,oBAAoB,CAAC;AAE7C;;;;GAIG;AAEH,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,EAAE,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;QAChD,gEAAgE;QAChE,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;QACvC,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,27 @@
1
+ import type { IndexFile, SeriesFile, PrIndexEntry, RefIndexEntry, MetricSummaryEntry, OtlpMetricsDocument } from "@octo11y/core";
2
+ import type { RunDetailView, ComparisonResult, ThresholdConfig } from "@benchkit/format";
3
+ export interface DataSource {
4
+ owner?: string;
5
+ repo?: string;
6
+ branch?: string;
7
+ /** Absolute URL override — if set, owner/repo/branch are ignored. */
8
+ baseUrl?: string;
9
+ }
10
+ export declare function rawUrl(ds: DataSource, filePath: string): string;
11
+ export declare function fetchIndex(ds: DataSource, signal?: AbortSignal): Promise<IndexFile>;
12
+ export declare function fetchSeries(ds: DataSource, metric: string, signal?: AbortSignal): Promise<SeriesFile>;
13
+ export declare function fetchRun(ds: DataSource, runId: string, signal?: AbortSignal): Promise<OtlpMetricsDocument>;
14
+ export declare function fetchPrIndex(ds: DataSource, signal?: AbortSignal): Promise<PrIndexEntry[]>;
15
+ export declare function fetchRefIndex(ds: DataSource, signal?: AbortSignal): Promise<RefIndexEntry[]>;
16
+ export declare function fetchMetricSummary(ds: DataSource, signal?: AbortSignal): Promise<MetricSummaryEntry[]>;
17
+ export declare function fetchRunDetail(ds: DataSource, runId: string, signal?: AbortSignal): Promise<RunDetailView>;
18
+ /**
19
+ * Fetch two run detail views, convert to BenchmarkResult, and compare.
20
+ * Returns the comparison result plus both detail views for downstream use.
21
+ */
22
+ export declare function compareRuns(ds: DataSource, currentRunId: string, baselineRunId: string, threshold?: ThresholdConfig, signal?: AbortSignal): Promise<{
23
+ comparison: ComparisonResult;
24
+ currentDetail: RunDetailView;
25
+ baselineDetail: RunDetailView;
26
+ }>;
27
+ //# sourceMappingURL=fetch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../src/fetch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACjI,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAGzF,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,MAAM,CAAC,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAa/D;AASD,wBAAgB,UAAU,CAAC,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC,CAEnF;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAErG;AAED,wBAAgB,QAAQ,CAAC,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAE1G;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAE1F;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAE5F;AAED,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAEtG;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,CAE1G;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,EAAE,EAAE,UAAU,EACd,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,SAAS,CAAC,EAAE,eAAe,EAC3B,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC;IAAE,UAAU,EAAE,gBAAgB,CAAC;IAAC,aAAa,EAAE,aAAa,CAAC;IAAC,cAAc,EAAE,aAAa,CAAA;CAAE,CAAC,CASxG"}
package/dist/fetch.js ADDED
@@ -0,0 +1,73 @@
1
+ import { compareRuns as compare, buildOtlpResult, MetricsBatch, DEFAULT_DATA_BRANCH } from "@benchkit/format";
2
+ export function rawUrl(ds, filePath) {
3
+ if (ds.baseUrl) {
4
+ let base = ds.baseUrl;
5
+ while (base.endsWith("/"))
6
+ base = base.slice(0, -1);
7
+ let path = filePath;
8
+ while (path.startsWith("/"))
9
+ path = path.slice(1);
10
+ return `${base}/${path}`;
11
+ }
12
+ if (!ds.owner || !ds.repo) {
13
+ throw new Error("DataSource must have either baseUrl or owner+repo");
14
+ }
15
+ const branch = ds.branch ?? DEFAULT_DATA_BRANCH;
16
+ return `https://raw.githubusercontent.com/${ds.owner}/${ds.repo}/${branch}/${filePath}`;
17
+ }
18
+ async function fetchJson(ds, filePath, signal) {
19
+ const url = rawUrl(ds, filePath);
20
+ const res = await fetch(url, { signal });
21
+ if (!res.ok)
22
+ throw new Error(`Failed to fetch ${url}: ${res.status}`);
23
+ return res.json();
24
+ }
25
+ export function fetchIndex(ds, signal) {
26
+ return fetchJson(ds, "data/index.json", signal);
27
+ }
28
+ export function fetchSeries(ds, metric, signal) {
29
+ return fetchJson(ds, `data/series/${metric}.json`, signal);
30
+ }
31
+ export function fetchRun(ds, runId, signal) {
32
+ return fetchJson(ds, `data/runs/${runId}.json`, signal);
33
+ }
34
+ export function fetchPrIndex(ds, signal) {
35
+ return fetchJson(ds, "data/index/prs.json", signal);
36
+ }
37
+ export function fetchRefIndex(ds, signal) {
38
+ return fetchJson(ds, "data/index/refs.json", signal);
39
+ }
40
+ export function fetchMetricSummary(ds, signal) {
41
+ return fetchJson(ds, "data/index/metrics.json", signal);
42
+ }
43
+ export function fetchRunDetail(ds, runId, signal) {
44
+ return fetchJson(ds, `data/views/runs/${runId}/detail.json`, signal);
45
+ }
46
+ /**
47
+ * Fetch two run detail views, convert to BenchmarkResult, and compare.
48
+ * Returns the comparison result plus both detail views for downstream use.
49
+ */
50
+ export async function compareRuns(ds, currentRunId, baselineRunId, threshold, signal) {
51
+ const [currentDetail, baselineDetail] = await Promise.all([
52
+ fetchRunDetail(ds, currentRunId, signal),
53
+ fetchRunDetail(ds, baselineRunId, signal),
54
+ ]);
55
+ const currentBatch = detailViewToBatch(currentDetail);
56
+ const baselineBatch = detailViewToBatch(baselineDetail);
57
+ const comparison = compare(currentBatch, [baselineBatch], threshold);
58
+ return { comparison, currentDetail, baselineDetail };
59
+ }
60
+ /** Convert a RunDetailView directly to MetricsBatch. */
61
+ function detailViewToBatch(detail) {
62
+ const benchmarks = detail.metricSnapshots.flatMap((snap) => snap.values.map((v) => ({
63
+ name: v.name,
64
+ tags: v.tags,
65
+ metrics: { [snap.metric]: { value: v.value, unit: v.unit, direction: v.direction } },
66
+ })));
67
+ const doc = buildOtlpResult({
68
+ benchmarks,
69
+ context: { sourceFormat: "otlp" },
70
+ });
71
+ return MetricsBatch.fromOtlp(doc);
72
+ }
73
+ //# sourceMappingURL=fetch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch.js","sourceRoot":"","sources":["../src/fetch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=fetch.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch.test.d.ts","sourceRoot":"","sources":["../src/fetch.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,75 @@
1
+ import { describe, it } from "node:test";
2
+ import * as assert from "node:assert/strict";
3
+ import { rawUrl } from "./fetch.js";
4
+ import { DEFAULT_DATA_BRANCH } from "@benchkit/format";
5
+ describe("fetch", () => {
6
+ it("constructs correct raw URLs", () => {
7
+ const ds = { owner: "strawgate", repo: "benchkit", branch: "bench-data" };
8
+ const url = rawUrl(ds, "data/index.json");
9
+ assert.equal(url, "https://raw.githubusercontent.com/strawgate/benchkit/bench-data/data/index.json");
10
+ });
11
+ it("defaults to bench-data branch", () => {
12
+ const ds = { owner: "foo", repo: "bar" };
13
+ const url = rawUrl(ds, "data/index.json");
14
+ assert.equal(url, `https://raw.githubusercontent.com/foo/bar/${DEFAULT_DATA_BRANCH}/data/index.json`);
15
+ });
16
+ it("baseUrl overrides GitHub raw URL construction", () => {
17
+ const ds = { baseUrl: "https://my-server.example.com/data" };
18
+ const url = rawUrl(ds, "data/index.json");
19
+ assert.equal(url, "https://my-server.example.com/data/data/index.json");
20
+ });
21
+ it("baseUrl ignores owner/repo/branch when set", () => {
22
+ const ds = {
23
+ owner: "strawgate",
24
+ repo: "benchkit",
25
+ branch: "main",
26
+ baseUrl: "https://custom.host/files",
27
+ };
28
+ const url = rawUrl(ds, "data/series/ns_per_op.json");
29
+ assert.equal(url, "https://custom.host/files/data/series/ns_per_op.json");
30
+ });
31
+ it("baseUrl with trailing slashes is normalized", () => {
32
+ const ds = { baseUrl: "https://my-server.example.com/data///" };
33
+ const url = rawUrl(ds, "data/index.json");
34
+ assert.equal(url, "https://my-server.example.com/data/data/index.json");
35
+ });
36
+ it("throws when neither baseUrl nor owner+repo provided", () => {
37
+ const ds = {};
38
+ assert.throws(() => rawUrl(ds, "data/index.json"), { message: "DataSource must have either baseUrl or owner+repo" });
39
+ });
40
+ it("throws when only owner is provided without repo", () => {
41
+ const ds = { owner: "foo" };
42
+ assert.throws(() => rawUrl(ds, "data/index.json"), { message: "DataSource must have either baseUrl or owner+repo" });
43
+ });
44
+ it("constructs correct URL for prs index", () => {
45
+ const ds = { owner: "strawgate", repo: "benchkit", branch: "bench-data" };
46
+ const url = rawUrl(ds, "data/index/prs.json");
47
+ assert.equal(url, "https://raw.githubusercontent.com/strawgate/benchkit/bench-data/data/index/prs.json");
48
+ });
49
+ it("constructs correct URL for refs index", () => {
50
+ const ds = { owner: "strawgate", repo: "benchkit", branch: "bench-data" };
51
+ const url = rawUrl(ds, "data/index/refs.json");
52
+ assert.equal(url, "https://raw.githubusercontent.com/strawgate/benchkit/bench-data/data/index/refs.json");
53
+ });
54
+ it("constructs correct URL for metrics index", () => {
55
+ const ds = { owner: "strawgate", repo: "benchkit", branch: "bench-data" };
56
+ const url = rawUrl(ds, "data/index/metrics.json");
57
+ assert.equal(url, "https://raw.githubusercontent.com/strawgate/benchkit/bench-data/data/index/metrics.json");
58
+ });
59
+ it("constructs correct URL for run detail view", () => {
60
+ const ds = { owner: "strawgate", repo: "benchkit", branch: "bench-data" };
61
+ const url = rawUrl(ds, "data/views/runs/123456789-1/detail.json");
62
+ assert.equal(url, "https://raw.githubusercontent.com/strawgate/benchkit/bench-data/data/views/runs/123456789-1/detail.json");
63
+ });
64
+ it("constructs correct URL for prs index with baseUrl", () => {
65
+ const ds = { baseUrl: "https://my-server.example.com/data" };
66
+ const url = rawUrl(ds, "data/index/prs.json");
67
+ assert.equal(url, "https://my-server.example.com/data/data/index/prs.json");
68
+ });
69
+ it("constructs correct URL for run detail view with baseUrl", () => {
70
+ const ds = { baseUrl: "https://my-server.example.com/data" };
71
+ const url = rawUrl(ds, "data/views/runs/abc-1/detail.json");
72
+ assert.equal(url, "https://my-server.example.com/data/data/views/runs/abc-1/detail.json");
73
+ });
74
+ });
75
+ //# sourceMappingURL=fetch.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch.test.js","sourceRoot":"","sources":["../src/fetch.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,MAAM,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAmB,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvD,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE;IACrB,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACrC,MAAM,EAAE,GAAe,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;QACtF,MAAM,GAAG,GAAG,MAAM,CAAC,EAAE,EAAE,iBAAiB,CAAC,CAAC;QAC1C,MAAM,CAAC,KAAK,CACV,GAAG,EACH,iFAAiF,CAClF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,EAAE,GAAe,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;QACrD,MAAM,GAAG,GAAG,MAAM,CAAC,EAAE,EAAE,iBAAiB,CAAC,CAAC;QAC1C,MAAM,CAAC,KAAK,CACV,GAAG,EACH,6CAA6C,mBAAmB,kBAAkB,CACnF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,EAAE,GAAe,EAAE,OAAO,EAAE,oCAAoC,EAAE,CAAC;QACzE,MAAM,GAAG,GAAG,MAAM,CAAC,EAAE,EAAE,iBAAiB,CAAC,CAAC;QAC1C,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,oDAAoD,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,EAAE,GAAe;YACrB,KAAK,EAAE,WAAW;YAClB,IAAI,EAAE,UAAU;YAChB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,2BAA2B;SACrC,CAAC;QACF,MAAM,GAAG,GAAG,MAAM,CAAC,EAAE,EAAE,4BAA4B,CAAC,CAAC;QACrD,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,sDAAsD,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,EAAE,GAAe,EAAE,OAAO,EAAE,uCAAuC,EAAE,CAAC;QAC5E,MAAM,GAAG,GAAG,MAAM,CAAC,EAAE,EAAE,iBAAiB,CAAC,CAAC;QAC1C,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,oDAAoD,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,EAAE,GAAe,EAAE,CAAC;QAC1B,MAAM,CAAC,MAAM,CACX,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,iBAAiB,CAAC,EACnC,EAAE,OAAO,EAAE,mDAAmD,EAAE,CACjE,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,EAAE,GAAe,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;QACxC,MAAM,CAAC,MAAM,CACX,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,iBAAiB,CAAC,EACnC,EAAE,OAAO,EAAE,mDAAmD,EAAE,CACjE,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,EAAE,GAAe,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;QACtF,MAAM,GAAG,GAAG,MAAM,CAAC,EAAE,EAAE,qBAAqB,CAAC,CAAC;QAC9C,MAAM,CAAC,KAAK,CACV,GAAG,EACH,qFAAqF,CACtF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,EAAE,GAAe,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;QACtF,MAAM,GAAG,GAAG,MAAM,CAAC,EAAE,EAAE,sBAAsB,CAAC,CAAC;QAC/C,MAAM,CAAC,KAAK,CACV,GAAG,EACH,sFAAsF,CACvF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,MAAM,EAAE,GAAe,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;QACtF,MAAM,GAAG,GAAG,MAAM,CAAC,EAAE,EAAE,yBAAyB,CAAC,CAAC;QAClD,MAAM,CAAC,KAAK,CACV,GAAG,EACH,yFAAyF,CAC1F,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,EAAE,GAAe,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;QACtF,MAAM,GAAG,GAAG,MAAM,CAAC,EAAE,EAAE,yCAAyC,CAAC,CAAC;QAClE,MAAM,CAAC,KAAK,CACV,GAAG,EACH,yGAAyG,CAC1G,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,MAAM,EAAE,GAAe,EAAE,OAAO,EAAE,oCAAoC,EAAE,CAAC;QACzE,MAAM,GAAG,GAAG,MAAM,CAAC,EAAE,EAAE,qBAAqB,CAAC,CAAC;QAC9C,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,wDAAwD,CAAC,CAAC;IAC9E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACjE,MAAM,EAAE,GAAe,EAAE,OAAO,EAAE,oCAAoC,EAAE,CAAC;QACzE,MAAM,GAAG,GAAG,MAAM,CAAC,EAAE,EAAE,mCAAmC,CAAC,CAAC;QAC5D,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,sEAAsE,CAAC,CAAC;IAC5F,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Shared formatting utilities used across chart components.
3
+ */
4
+ /**
5
+ * Format a numeric value for display.
6
+ *
7
+ * When `compact` is true, large numbers are abbreviated (e.g. 1.2K).
8
+ * Otherwise values ≥ 100 show no decimals, smaller values show up to 2.
9
+ */
10
+ export declare function formatValue(value: number, compact?: boolean): string;
11
+ /**
12
+ * Format a numeric value with fixed decimal places.
13
+ *
14
+ * Integers get no decimals, values ≥ 100 get 1 decimal, others get 2.
15
+ * Unlike {@link formatValue} this uses `toFixed` so trailing zeros are
16
+ * preserved (useful in tabular data where column alignment matters).
17
+ */
18
+ export declare function formatFixedValue(value: number): string;
19
+ /**
20
+ * Format a git ref for human-readable display.
21
+ *
22
+ * Strips common prefixes (`refs/heads/`, `refs/tags/`, `refs/pull/…/merge`)
23
+ * and returns a short label. Returns `"—"` for undefined/empty refs.
24
+ */
25
+ export declare function formatRef(ref: string | undefined): string;
26
+ /**
27
+ * Format a percentage change with sign.
28
+ *
29
+ * Positive values get a `+` prefix, negative values keep their `-`.
30
+ */
31
+ export declare function formatPct(pct: number): string;
32
+ /**
33
+ * Format a run timestamp for compact UI display.
34
+ *
35
+ * Returns the original input when it is not a valid date string.
36
+ */
37
+ export declare function formatTimestamp(iso: string): string;
38
+ /**
39
+ * Format a commit SHA as a short display-friendly hash.
40
+ *
41
+ * Returns an en dash when no commit is available.
42
+ */
43
+ export declare function shortCommit(commit?: string): string;
44
+ /**
45
+ * Format metric direction semantics for human-readable UI copy.
46
+ */
47
+ export declare function formatDirection(direction: string): string;
48
+ //# sourceMappingURL=format-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-utils.d.ts","sourceRoot":"","sources":["../src/format-utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,UAAQ,GAAG,MAAM,CAKlE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAItD;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAQzD;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG7C;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CASnD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAUzD"}