@continuous-excellence/ze-great-dashboard-aws 0.31.55 → 0.31.57

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 (4) hide show
  1. package/dist/cli.js +336 -211
  2. package/dist/index.js +336 -211
  3. package/dist/lambda.mjs +255 -106
  4. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -577,6 +577,12 @@ var testCountSchema = z4.discriminatedUnion("status", [
577
577
  type: z4.literal("test-count"),
578
578
  status: z4.literal("reported"),
579
579
  total: z4.number().int().nonnegative(),
580
+ /** Public identity for browser-local comparisons, never observation time. */
581
+ run: z4.object({
582
+ id: z4.string().min(1),
583
+ attempt: z4.number().int().positive(),
584
+ updatedAt: z4.iso.datetime()
585
+ }).optional(),
580
586
  passed: z4.number().int().nonnegative().optional(),
581
587
  failed: z4.number().int().nonnegative().optional(),
582
588
  skipped: z4.number().int().nonnegative().optional()
@@ -669,8 +675,29 @@ var securityDetailsResponseSchema = z5.strictObject({
669
675
  ])
670
676
  });
671
677
 
678
+ // packages/shared/src/test-history.ts
679
+ import { z as z6 } from "zod";
680
+ var testHistorySampleSchema = z6.object({
681
+ id: z6.string().min(1),
682
+ attempt: z6.number().int().positive(),
683
+ updatedAt: z6.iso.datetime(),
684
+ total: z6.number().int().nonnegative()
685
+ });
686
+ var testHistorySchema = z6.object({
687
+ inspectedAt: z6.iso.datetime(),
688
+ inspectedRuns: z6.number().int().min(0).max(8),
689
+ complete: z6.boolean(),
690
+ samples: z6.array(testHistorySampleSchema).max(8),
691
+ retryAt: z6.iso.datetime().optional()
692
+ });
693
+ function retryAfterTime(value2, now) {
694
+ if (!value2) return void 0;
695
+ const at = /^\d+$/.test(value2) ? now + Number(value2) * 1e3 : Date.parse(value2);
696
+ return Number.isFinite(at) && at > now ? at : void 0;
697
+ }
698
+
672
699
  // packages/server/src/adapters/github-actions.ts
673
- import { z as z7 } from "zod";
700
+ import { z as z9 } from "zod";
674
701
 
675
702
  // packages/server/src/credentials.ts
676
703
  function environmentCredentials(env = process.env) {
@@ -851,6 +878,9 @@ function base64url(value2) {
851
878
  return Buffer.from(value2).toString("base64url");
852
879
  }
853
880
 
881
+ // packages/server/src/adapters/github-test-evidence.ts
882
+ import { z as z8 } from "zod";
883
+
854
884
  // node_modules/fflate/esm/browser.js
855
885
  var u8 = Uint8Array;
856
886
  var u16 = Uint16Array;
@@ -1290,10 +1320,10 @@ function strFromU8(dat, latin1) {
1290
1320
  return s;
1291
1321
  }
1292
1322
  }
1293
- var z64hs = function(d, b, l, z11, sc, su, off) {
1323
+ var z64hs = function(d, b, l, z13, sc, su, off) {
1294
1324
  var nsc = sc == 4294967295, nsu = su == 4294967295, noff = off == 4294967295, e = b + l;
1295
1325
  var nf = nsc + nsu + noff;
1296
- if (z11 && nf) {
1326
+ if (z13 && nf) {
1297
1327
  for (; b + 4 < e; b += 4 + b2(d, b + 2)) {
1298
1328
  if (b2(d, b) == 1) {
1299
1329
  return [
@@ -1304,7 +1334,7 @@ var z64hs = function(d, b, l, z11, sc, su, off) {
1304
1334
  ];
1305
1335
  }
1306
1336
  }
1307
- if (z11 < 2)
1337
+ if (z13 < 2)
1308
1338
  err(13);
1309
1339
  }
1310
1340
  return [sc, su, off, 0];
@@ -1468,18 +1498,18 @@ var Unzip = /* @__PURE__ */ (function() {
1468
1498
  })();
1469
1499
 
1470
1500
  // packages/server/src/workflow-artifact-summary.ts
1471
- import { z as z6 } from "zod";
1501
+ import { z as z7 } from "zod";
1472
1502
  var maxArtifactBytes = 64 * 1024;
1473
- var testResultsSummarySchema = z6.object({
1474
- schemaVersion: z6.literal(1),
1475
- runId: z6.number().int().positive(),
1476
- runAttempt: z6.number().int().positive(),
1477
- headSha: z6.string().min(1),
1478
- total: z6.number().int().nonnegative(),
1479
- passed: z6.number().int().nonnegative().optional(),
1480
- failed: z6.number().int().nonnegative().optional(),
1481
- skipped: z6.number().int().nonnegative().optional(),
1482
- metadata: z6.record(z6.string(), z6.unknown()).optional()
1503
+ var testResultsSummarySchema = z7.object({
1504
+ schemaVersion: z7.literal(1),
1505
+ runId: z7.number().int().positive(),
1506
+ runAttempt: z7.number().int().positive(),
1507
+ headSha: z7.string().min(1),
1508
+ total: z7.number().int().nonnegative(),
1509
+ passed: z7.number().int().nonnegative().optional(),
1510
+ failed: z7.number().int().nonnegative().optional(),
1511
+ skipped: z7.number().int().nonnegative().optional(),
1512
+ metadata: z7.record(z7.string(), z7.unknown()).optional()
1483
1513
  }).superRefine((summary, ctx) => {
1484
1514
  const outcomeTotal = (summary.passed ?? 0) + (summary.failed ?? 0) + (summary.skipped ?? 0);
1485
1515
  for (const key of ["passed", "failed", "skipped"]) {
@@ -1555,71 +1585,165 @@ function concat(chunks, length) {
1555
1585
  return result;
1556
1586
  }
1557
1587
 
1588
+ // packages/server/src/adapters/github-test-evidence.ts
1589
+ var artifactsSchema = z8.object({
1590
+ artifacts: z8.array(
1591
+ z8.object({ id: z8.number().int().positive(), name: z8.string().min(1), expired: z8.boolean() })
1592
+ )
1593
+ });
1594
+ function testArtifactHttpFailure(response) {
1595
+ const retry = retryAfterTime(response.headers.get("retry-after"), Date.now());
1596
+ return {
1597
+ kind: "failed",
1598
+ observedAt: observedAt(response.headers.get("date")),
1599
+ errorKind: upstreamErrorKind(response.status),
1600
+ httpStatus: response.status,
1601
+ ...retry === void 0 ? {} : { retryAt: new Date(retry).toISOString() }
1602
+ };
1603
+ }
1604
+ async function inspectGithubTestArtifact(args2, selected, config) {
1605
+ const { run: run2 } = selected;
1606
+ let at = selected.observedAt;
1607
+ const failed = (errorKind3) => ({
1608
+ kind: "failed",
1609
+ observedAt: at,
1610
+ errorKind: errorKind3
1611
+ });
1612
+ const get = (url) => args2.githubClient.get({
1613
+ source: args2.source,
1614
+ fetcher: args2.fetcher,
1615
+ url,
1616
+ requestHeaders: new Headers()
1617
+ });
1618
+ const observe = (response) => {
1619
+ const value2 = observedAt(response.headers.get("date"));
1620
+ if (Date.parse(value2) < Date.parse(at)) at = value2;
1621
+ };
1622
+ try {
1623
+ if (!run2.id) return failed("upstream-error");
1624
+ if (run2.status !== "completed") return { kind: "pending", observedAt: at };
1625
+ const url = new URL(
1626
+ `https://api.github.com/repos/${args2.source.repo}/actions/runs/${run2.id}/artifacts`
1627
+ );
1628
+ url.searchParams.set("name", config.artifact);
1629
+ url.searchParams.set("per_page", "100");
1630
+ const artifacts = await get(url.toString());
1631
+ if (!artifacts.ok) return testArtifactHttpFailure(artifacts);
1632
+ observe(artifacts);
1633
+ const matches = artifactsSchema.parse(await artifacts.json()).artifacts.filter((item) => item.name === config.artifact);
1634
+ if (!matches.length) return { kind: "absent", observedAt: at };
1635
+ const [artifact] = matches;
1636
+ if (matches.length !== 1 || !artifact) return failed("upstream-error");
1637
+ if (artifact.expired) return { kind: "expired", observedAt: at };
1638
+ const archive = await get(
1639
+ `https://api.github.com/repos/${args2.source.repo}/actions/artifacts/${artifact.id}/zip`
1640
+ );
1641
+ if (!archive.ok) return testArtifactHttpFailure(archive);
1642
+ observe(archive);
1643
+ const summary = testResultsSummarySchema.parse(
1644
+ JSON.parse(await readTestResultsArtifact(archive, config.entry))
1645
+ );
1646
+ if (summary.runId !== run2.id || summary.runAttempt !== run2.run_attempt || summary.headSha !== run2.head_sha)
1647
+ return failed("upstream-error");
1648
+ const updatedAt = z8.iso.datetime().safeParse(run2.updated_at);
1649
+ const tests = {
1650
+ type: "test-count",
1651
+ status: "reported",
1652
+ total: summary.total,
1653
+ ...updatedAt.success ? { run: { id: String(run2.id), attempt: summary.runAttempt, updatedAt: updatedAt.data } } : {},
1654
+ ...summary.passed === void 0 ? {} : { passed: summary.passed },
1655
+ ...summary.failed === void 0 ? {} : { failed: summary.failed },
1656
+ ...summary.skipped === void 0 ? {} : { skipped: summary.skipped }
1657
+ };
1658
+ return { kind: "reported", observedAt: at, tests };
1659
+ } catch (error) {
1660
+ return failed(error instanceof GithubAuthenticationError ? "unauthorized" : "upstream-error");
1661
+ }
1662
+ }
1663
+ function currentTestEvidence(inspection) {
1664
+ const { observedAt: at } = inspection;
1665
+ switch (inspection.kind) {
1666
+ case "reported":
1667
+ return { state: "ok", observedAt: at, signal: inspection.tests };
1668
+ case "pending":
1669
+ return { state: "ok", observedAt: at, signal: { type: "test-count", status: "pending" } };
1670
+ case "absent":
1671
+ return { state: "ok", observedAt: at, signal: { type: "test-count", status: "not-reported" } };
1672
+ case "expired":
1673
+ return {
1674
+ state: "error",
1675
+ observedAt: at,
1676
+ error: { kind: "upstream-error", message: publicErrorMessage("upstream-error") }
1677
+ };
1678
+ case "failed":
1679
+ return {
1680
+ state: "error",
1681
+ observedAt: at,
1682
+ error: { kind: inspection.errorKind, message: publicErrorMessage(inspection.errorKind) }
1683
+ };
1684
+ }
1685
+ }
1686
+
1558
1687
  // packages/server/src/adapters/github-actions.ts
1559
- var pipelinePanelSchema = z7.object({
1688
+ var pipelinePanelSchema = z9.object({
1560
1689
  test_results: testResultsArtifactSchema.optional(),
1561
- id: z7.string().min(1),
1562
- type: z7.literal("pipeline-status"),
1563
- source: z7.string().min(1),
1690
+ id: z9.string().min(1),
1691
+ type: z9.literal("pipeline-status"),
1692
+ source: z9.string().min(1),
1564
1693
  /** GitHub accepts a workflow filename or numeric workflow id in this URL segment. */
1565
- pipeline: z7.string().min(1)
1694
+ pipeline: z9.string().min(1)
1566
1695
  });
1567
- var pullRequestHealthPanelSchema = z7.object({
1568
- id: z7.string().min(1),
1569
- type: z7.literal("pull-request-health"),
1570
- source: z7.string().min(1),
1571
- base_branch: z7.string().min(1),
1572
- update_workflows: z7.array(
1573
- z7.object({
1574
- workflow: z7.string().min(1),
1575
- branch_prefixes: z7.array(z7.string().min(1)).min(1)
1696
+ var pullRequestHealthPanelSchema = z9.object({
1697
+ id: z9.string().min(1),
1698
+ type: z9.literal("pull-request-health"),
1699
+ source: z9.string().min(1),
1700
+ base_branch: z9.string().min(1),
1701
+ update_workflows: z9.array(
1702
+ z9.object({
1703
+ workflow: z9.string().min(1),
1704
+ branch_prefixes: z9.array(z9.string().min(1)).min(1)
1576
1705
  })
1577
1706
  ).min(1),
1578
- build_workflow: z7.string().min(1),
1707
+ build_workflow: z9.string().min(1),
1579
1708
  build_events: githubActionsBuildEventsSchema.optional()
1580
1709
  });
1581
- var runSchema = z7.object({
1582
- id: z7.number().int().positive().optional(),
1583
- run_attempt: z7.number().int().positive().optional(),
1584
- head_sha: z7.string().min(1).optional(),
1585
- status: z7.string(),
1586
- conclusion: z7.string().nullable(),
1587
- name: z7.string().min(1),
1588
- html_url: z7.url(),
1710
+ var runSchema = z9.object({
1711
+ id: z9.number().int().positive().optional(),
1712
+ run_attempt: z9.number().int().positive().optional(),
1713
+ head_sha: z9.string().min(1).optional(),
1714
+ status: z9.string(),
1715
+ conclusion: z9.string().nullable(),
1716
+ name: z9.string().min(1),
1717
+ html_url: z9.url(),
1589
1718
  /** The GitHub Actions trigger that started this run. */
1590
- event: z7.string().min(1).optional(),
1719
+ event: z9.string().min(1).optional(),
1591
1720
  /** The branch that produced this run; absent for some event types. */
1592
- head_branch: z7.string().min(1).nullable().optional(),
1721
+ head_branch: z9.string().min(1).nullable().optional(),
1593
1722
  // Timestamp quality should only remove timing advice, never make an otherwise useful run unreadable.
1594
- run_started_at: z7.string().nullable().optional(),
1595
- updated_at: z7.string().optional(),
1596
- created_at: z7.string().optional()
1723
+ run_started_at: z9.string().nullable().optional(),
1724
+ updated_at: z9.string().optional(),
1725
+ created_at: z9.string().optional()
1597
1726
  });
1598
- var artifactsSchema = z7.object({
1599
- artifacts: z7.array(
1600
- z7.object({ id: z7.number().int().positive(), name: z7.string().min(1), expired: z7.boolean() })
1601
- )
1602
- });
1603
- var runsSchema = z7.object({ workflow_runs: z7.array(runSchema) });
1604
- var jobsSchema = z7.object({
1605
- jobs: z7.array(
1606
- z7.object({
1607
- name: z7.string().min(1),
1608
- status: z7.string(),
1609
- steps: z7.array(z7.object({ name: z7.string().min(1), status: z7.string() })).optional()
1727
+ var runsSchema = z9.object({ workflow_runs: z9.array(runSchema) });
1728
+ var jobsSchema = z9.object({
1729
+ jobs: z9.array(
1730
+ z9.object({
1731
+ name: z9.string().min(1),
1732
+ status: z9.string(),
1733
+ steps: z9.array(z9.object({ name: z9.string().min(1), status: z9.string() })).optional()
1610
1734
  })
1611
1735
  )
1612
1736
  });
1613
- var pullRequestsSchema = z7.array(
1614
- z7.object({
1615
- number: z7.number().int().positive(),
1616
- html_url: z7.url(),
1617
- head: z7.object({ ref: z7.string().min(1) }),
1618
- base: z7.object({ ref: z7.string().min(1) })
1737
+ var pullRequestsSchema = z9.array(
1738
+ z9.object({
1739
+ number: z9.number().int().positive(),
1740
+ html_url: z9.url(),
1741
+ head: z9.object({ ref: z9.string().min(1) }),
1742
+ base: z9.object({ ref: z9.string().min(1) })
1619
1743
  })
1620
1744
  );
1621
1745
  function permittedGithubActionsCalls(panel, source, _credentials) {
1622
- const { panel: parsedPanel, source: parsedSource } = z7.object({ panel: pipelinePanelSchema, source: githubActionsSourceSchema }).parse({ panel, source });
1746
+ const { panel: parsedPanel, source: parsedSource } = z9.object({ panel: pipelinePanelSchema, source: githubActionsSourceSchema }).parse({ panel, source });
1623
1747
  const url = new URL(
1624
1748
  `https://api.github.com/repos/${parsedSource.repo}/actions/workflows/${encodeURIComponent(parsedPanel.pipeline)}/runs`
1625
1749
  );
@@ -1628,7 +1752,7 @@ function permittedGithubActionsCalls(panel, source, _credentials) {
1628
1752
  return [{ url: url.toString(), headers: new Headers() }];
1629
1753
  }
1630
1754
  function testCountCapabilities(panel, source) {
1631
- return z7.object({ panel: testCountPanelSchema, source: githubActionsSourceSchema }).parse({ panel, source });
1755
+ return z9.object({ panel: testCountPanelSchema, source: githubActionsSourceSchema }).parse({ panel, source });
1632
1756
  }
1633
1757
  async function fetchGithubActionsTestCount(args2) {
1634
1758
  const { panel, source } = testCountCapabilities(args2.panel, args2.source);
@@ -1646,13 +1770,15 @@ async function fetchGithubActionsTestCount(args2) {
1646
1770
  return testCountEnvelope(
1647
1771
  noRunEnvelope(panel.id, source, panel.pipeline, selected.response.headers.get("date"))
1648
1772
  );
1649
- const evidence = await readGithubRunTestEvidence(
1650
- { ...args2, source, githubClient },
1651
- {
1652
- run: selected.run,
1653
- observedAt: selected.observedAt
1654
- },
1655
- panel.test_results
1773
+ const evidence = currentTestEvidence(
1774
+ await inspectGithubTestArtifact(
1775
+ { ...args2, source, githubClient },
1776
+ {
1777
+ run: selected.run,
1778
+ observedAt: selected.observedAt
1779
+ },
1780
+ panel.test_results
1781
+ )
1656
1782
  );
1657
1783
  return testCountEnvelope({ ...evidence, panelId: panel.id, link: selected.run.html_url });
1658
1784
  } catch (error) {
@@ -1666,82 +1792,8 @@ async function fetchGithubActionsTestCount(args2) {
1666
1792
  );
1667
1793
  }
1668
1794
  }
1669
- async function readGithubRunTestEvidence(args2, selected, artifactConfig) {
1670
- const { run: run2, observedAt: runObservedAt } = selected;
1671
- const { source, githubClient } = args2;
1672
- const noValidators = new Headers();
1673
- let failureObservedAt = runObservedAt;
1674
- const evidenceError = (kind, at = failureObservedAt) => ({
1675
- state: "error",
1676
- observedAt: at,
1677
- error: { kind, message: publicErrorMessage(kind) }
1678
- });
1679
- const failedResponse = (response) => evidenceError(errorKind(response.status), observedAt2(response.headers.get("date")));
1680
- try {
1681
- if (!run2.id) return evidenceError("upstream-error");
1682
- if (run2.status !== "completed")
1683
- return {
1684
- state: "ok",
1685
- observedAt: runObservedAt,
1686
- signal: { type: "test-count", status: "pending" }
1687
- };
1688
- const artifactsResponse = await githubFetch(
1689
- githubArtifactsCall(source, run2.id, artifactConfig),
1690
- {
1691
- ...args2,
1692
- source,
1693
- requestHeaders: noValidators,
1694
- githubClient
1695
- }
1696
- );
1697
- if (!artifactsResponse.ok) return failedResponse(artifactsResponse);
1698
- const artifactObservedAt = observedAt2(artifactsResponse.headers.get("date"));
1699
- failureObservedAt = oldestObservation(runObservedAt, artifactObservedAt);
1700
- const artifacts = artifactsSchema.parse(await artifactsResponse.json()).artifacts;
1701
- const matches = artifacts.filter((artifact2) => artifact2.name === artifactConfig.artifact);
1702
- if (matches.length === 0)
1703
- return {
1704
- state: "ok",
1705
- observedAt: oldestObservation(runObservedAt, artifactObservedAt),
1706
- signal: { type: "test-count", status: "not-reported" }
1707
- };
1708
- const [artifact] = matches;
1709
- if (matches.length !== 1 || !artifact || artifact.expired)
1710
- return evidenceError("upstream-error");
1711
- const archiveResponse = await githubFetch(githubArtifactDownloadCall(source, artifact.id), {
1712
- ...args2,
1713
- source,
1714
- requestHeaders: noValidators,
1715
- githubClient
1716
- });
1717
- if (!archiveResponse.ok) return failedResponse(archiveResponse);
1718
- const archiveObservedAt = observedAt2(archiveResponse.headers.get("date"));
1719
- failureObservedAt = oldestObservation(runObservedAt, artifactObservedAt, archiveObservedAt);
1720
- const summary = testResultsSummarySchema.parse(
1721
- JSON.parse(await readTestResultsArtifact(archiveResponse, artifactConfig.entry))
1722
- );
1723
- if (summary.runId !== run2.id || summary.runAttempt !== run2.run_attempt || summary.headSha !== run2.head_sha)
1724
- throw new Error("Test-results manifest does not belong to the selected workflow run.");
1725
- return {
1726
- state: "ok",
1727
- observedAt: oldestObservation(runObservedAt, artifactObservedAt, archiveObservedAt),
1728
- signal: {
1729
- type: "test-count",
1730
- status: "reported",
1731
- total: summary.total,
1732
- ...summary.passed === void 0 ? {} : { passed: summary.passed },
1733
- ...summary.failed === void 0 ? {} : { failed: summary.failed },
1734
- ...summary.skipped === void 0 ? {} : { skipped: summary.skipped }
1735
- }
1736
- };
1737
- } catch (error) {
1738
- return evidenceError(
1739
- error instanceof GithubAuthenticationError ? "unauthorized" : "upstream-error"
1740
- );
1741
- }
1742
- }
1743
1795
  function pullRequestHealthCapabilities(panel) {
1744
- const { panel: parsed } = z7.object({ panel: pullRequestHealthPanelSchema }).parse({ panel });
1796
+ const { panel: parsed } = z9.object({ panel: pullRequestHealthPanelSchema }).parse({ panel });
1745
1797
  return {
1746
1798
  panel: parsed,
1747
1799
  configuredUpdateWorkflow(workflow) {
@@ -1843,10 +1895,12 @@ async function fetchGithubActionsPipeline(args2) {
1843
1895
  if (activity) signal.activity = activity;
1844
1896
  }
1845
1897
  if (parsedPanel.test_results) {
1846
- signal.testResults = await readGithubRunTestEvidence(
1847
- { ...args2, source: parsedSource, githubClient },
1848
- { run: run2, observedAt: selected.observedAt },
1849
- parsedPanel.test_results
1898
+ signal.testResults = currentTestEvidence(
1899
+ await inspectGithubTestArtifact(
1900
+ { ...args2, source: parsedSource, githubClient },
1901
+ { run: run2, observedAt: selected.observedAt },
1902
+ parsedPanel.test_results
1903
+ )
1850
1904
  );
1851
1905
  }
1852
1906
  const envelope = {
@@ -1965,18 +2019,6 @@ function githubJobsCall(source, runId) {
1965
2019
  url.searchParams.set("per_page", "100");
1966
2020
  return { url: url.toString(), headers: new Headers() };
1967
2021
  }
1968
- function githubArtifactsCall(source, runId, testResults) {
1969
- const url = new URL(`https://api.github.com/repos/${source.repo}/actions/runs/${runId}/artifacts`);
1970
- url.searchParams.set("name", testResults.artifact);
1971
- url.searchParams.set("per_page", "100");
1972
- return { url: url.toString(), headers: new Headers() };
1973
- }
1974
- function githubArtifactDownloadCall(source, artifactId) {
1975
- return {
1976
- url: `https://api.github.com/repos/${source.repo}/actions/artifacts/${artifactId}/zip`,
1977
- headers: new Headers()
1978
- };
1979
- }
1980
2022
  function noRunEnvelope(panelId, source, pipeline, date) {
1981
2023
  return {
1982
2024
  panelId,
@@ -2015,7 +2057,7 @@ function completedRunDuration(run2) {
2015
2057
  return Number.isFinite(durationMs) && durationMs >= 0 ? { durationMs } : {};
2016
2058
  }
2017
2059
  function timestamp(value2) {
2018
- if (!value2 || !z7.iso.datetime().safeParse(value2).success) return void 0;
2060
+ if (!value2 || !z9.iso.datetime().safeParse(value2).success) return void 0;
2019
2061
  return Number.isFinite(new Date(value2).valueOf()) ? value2 : void 0;
2020
2062
  }
2021
2063
  function normalizeStatus(status, conclusion) {
@@ -2032,7 +2074,7 @@ function errorEnvelope(panelId, kind, error, link, observedAt4 = (/* @__PURE__ *
2032
2074
  return upstreamErrorEnvelope({ panelId, kind, error, link, upstreamDate: observedAt4 });
2033
2075
  }
2034
2076
  function sourceLink(panel, source) {
2035
- const parsedPanel = z7.object({ pipeline: z7.string().min(1) }).parse(panel);
2077
+ const parsedPanel = z9.object({ pipeline: z9.string().min(1) }).parse(panel);
2036
2078
  const parsedSource = githubActionsSourceSchema.parse(source);
2037
2079
  return sourceLinkForWorkflow(parsedSource, parsedPanel.pipeline);
2038
2080
  }
@@ -2042,6 +2084,81 @@ function sourceLinkForWorkflow(source, pipeline) {
2042
2084
  function observedAt2(value2) {
2043
2085
  return observedAt(value2);
2044
2086
  }
2087
+ async function fetchGithubTestHistory(args2) {
2088
+ const source = githubActionsSourceSchema.parse(args2.source);
2089
+ const fetcher = (input, init) => args2.fetcher(input, { ...init, ...args2.signal ? { signal: args2.signal } : {} });
2090
+ const artifact = testResultsArtifactSchema.parse(args2.panel.test_results);
2091
+ const workflow = z9.string().min(1).parse(args2.panel.pipeline);
2092
+ const now = Date.now();
2093
+ const cutoff = now - 14 * 864e5;
2094
+ const history = {
2095
+ inspectedAt: new Date(now).toISOString(),
2096
+ inspectedRuns: 0,
2097
+ complete: true,
2098
+ samples: []
2099
+ };
2100
+ let stop = false;
2101
+ const recordFailure = (failure2) => {
2102
+ history.complete = false;
2103
+ if (failure2.errorKind === "unauthorized" || failure2.httpStatus === 429) stop = true;
2104
+ if (failure2.retryAt && (!history.retryAt || Date.parse(failure2.retryAt) > Date.parse(history.retryAt)))
2105
+ history.retryAt = failure2.retryAt;
2106
+ };
2107
+ try {
2108
+ const call = githubRunsCall(
2109
+ source,
2110
+ workflow,
2111
+ source.branch,
2112
+ void 0,
2113
+ 8,
2114
+ new Date(cutoff).toISOString()
2115
+ );
2116
+ const url = new URL(call.url);
2117
+ url.searchParams.set("status", "completed");
2118
+ const response = await githubFetch(
2119
+ { ...call, url: url.toString() },
2120
+ { ...args2, fetcher, source, requestHeaders: new Headers() }
2121
+ );
2122
+ if (!response.ok) recordFailure(testArtifactHttpFailure(response));
2123
+ else {
2124
+ const runs = runsSchema.parse(await response.json()).workflow_runs.slice(0, 8);
2125
+ for (const run2 of runs) {
2126
+ if (stop || args2.signal?.aborted) {
2127
+ history.complete = false;
2128
+ break;
2129
+ }
2130
+ if (run2.status !== "completed") continue;
2131
+ if (run2.updated_at && Date.parse(run2.updated_at) < cutoff) continue;
2132
+ history.inspectedRuns++;
2133
+ const inspection = await inspectGithubTestArtifact(
2134
+ { ...args2, fetcher, source },
2135
+ { run: run2, observedAt: observedAt2(response.headers.get("date")) },
2136
+ artifact
2137
+ );
2138
+ switch (inspection.kind) {
2139
+ case "failed":
2140
+ recordFailure(inspection);
2141
+ break;
2142
+ case "reported": {
2143
+ const { run: identity, total } = inspection.tests;
2144
+ if (identity) history.samples.push({ ...identity, total });
2145
+ else history.complete = false;
2146
+ break;
2147
+ }
2148
+ case "absent":
2149
+ case "expired":
2150
+ break;
2151
+ case "pending":
2152
+ history.complete = false;
2153
+ break;
2154
+ }
2155
+ }
2156
+ }
2157
+ } catch {
2158
+ history.complete = false;
2159
+ }
2160
+ return Response.json(history, { headers: { "cache-control": "no-store" } });
2161
+ }
2045
2162
 
2046
2163
  // packages/server/src/configuration-error.ts
2047
2164
  var ConfigurationError = class extends Error {
@@ -2095,37 +2212,37 @@ function correctiveConstraint(issue) {
2095
2212
 
2096
2213
  // packages/server/src/adapters/azure-devops.ts
2097
2214
  import { readFile } from "node:fs/promises";
2098
- import { z as z8 } from "zod";
2099
- var pipelinePanelSchema2 = z8.object({
2100
- id: z8.string().min(1),
2101
- type: z8.literal("pipeline-status"),
2102
- source: z8.string().min(1),
2103
- pipeline: z8.number().int().positive()
2215
+ import { z as z10 } from "zod";
2216
+ var pipelinePanelSchema2 = z10.object({
2217
+ id: z10.string().min(1),
2218
+ type: z10.literal("pipeline-status"),
2219
+ source: z10.string().min(1),
2220
+ pipeline: z10.number().int().positive()
2104
2221
  });
2105
- var buildSchema = z8.object({
2106
- id: z8.number().int().positive(),
2107
- buildNumber: z8.string().min(1),
2108
- status: z8.string().nullable().optional(),
2109
- result: z8.string().nullable().optional(),
2110
- sourceBranch: z8.string().min(1).nullable().optional(),
2111
- startTime: z8.string().nullable().optional(),
2112
- finishTime: z8.string().nullable().optional(),
2113
- lastChangedDate: z8.string().nullable().optional()
2222
+ var buildSchema = z10.object({
2223
+ id: z10.number().int().positive(),
2224
+ buildNumber: z10.string().min(1),
2225
+ status: z10.string().nullable().optional(),
2226
+ result: z10.string().nullable().optional(),
2227
+ sourceBranch: z10.string().min(1).nullable().optional(),
2228
+ startTime: z10.string().nullable().optional(),
2229
+ finishTime: z10.string().nullable().optional(),
2230
+ lastChangedDate: z10.string().nullable().optional()
2114
2231
  });
2115
- var buildsSchema = z8.object({ value: z8.array(buildSchema) });
2116
- var timelineSchema = z8.object({
2117
- records: z8.array(
2118
- z8.object({
2119
- id: z8.string().min(1),
2120
- parentId: z8.string().min(1).nullable().optional(),
2121
- type: z8.string().min(1),
2122
- name: z8.string().min(1),
2123
- state: z8.string().nullable().optional()
2232
+ var buildsSchema = z10.object({ value: z10.array(buildSchema) });
2233
+ var timelineSchema = z10.object({
2234
+ records: z10.array(
2235
+ z10.object({
2236
+ id: z10.string().min(1),
2237
+ parentId: z10.string().min(1).nullable().optional(),
2238
+ type: z10.string().min(1),
2239
+ name: z10.string().min(1),
2240
+ state: z10.string().nullable().optional()
2124
2241
  })
2125
2242
  )
2126
2243
  });
2127
2244
  function permittedAzureDevOpsCalls(panel, source) {
2128
- const { panel: parsedPanel, source: parsedSource } = z8.object({ panel: pipelinePanelSchema2, source: azureDevOpsSourceSchema }).parse({ panel, source });
2245
+ const { panel: parsedPanel, source: parsedSource } = z10.object({ panel: pipelinePanelSchema2, source: azureDevOpsSourceSchema }).parse({ panel, source });
2129
2246
  return [buildsCall(parsedPanel.pipeline, parsedSource)];
2130
2247
  }
2131
2248
  async function fetchAzureDevOpsPipeline(args2) {
@@ -2238,9 +2355,9 @@ async function fetchAzureDevOpsPipeline(args2) {
2238
2355
  };
2239
2356
  }
2240
2357
  }
2241
- var delegatedTokenFileSchema = z8.object({
2242
- accessToken: z8.string().min(1),
2243
- expiresAt: z8.string().min(1)
2358
+ var delegatedTokenFileSchema = z10.object({
2359
+ accessToken: z10.string().min(1),
2360
+ expiresAt: z10.string().min(1)
2244
2361
  });
2245
2362
  async function azureDevOpsAuthorization(source, credentials) {
2246
2363
  if (source.token_env) {
@@ -2321,7 +2438,7 @@ function completedBuildDuration(build) {
2321
2438
  return Number.isFinite(durationMs) && durationMs >= 0 ? { durationMs } : {};
2322
2439
  }
2323
2440
  function timestamp2(value2) {
2324
- if (!value2 || !z8.iso.datetime().safeParse(value2).success) return void 0;
2441
+ if (!value2 || !z10.iso.datetime().safeParse(value2).success) return void 0;
2325
2442
  return Number.isFinite(new Date(value2).valueOf()) ? value2 : void 0;
2326
2443
  }
2327
2444
  function copyValidators(requestHeaders, upstreamHeaders) {
@@ -2347,23 +2464,23 @@ function observedAt3(value2) {
2347
2464
  }
2348
2465
 
2349
2466
  // packages/server/src/adapters/gitlab-ci.ts
2350
- import { z as z9 } from "zod";
2351
- var pipelinePanelSchema3 = z9.object({
2352
- id: z9.string().min(1),
2353
- type: z9.literal("pipeline-status"),
2354
- source: z9.string().min(1)
2467
+ import { z as z11 } from "zod";
2468
+ var pipelinePanelSchema3 = z11.object({
2469
+ id: z11.string().min(1),
2470
+ type: z11.literal("pipeline-status"),
2471
+ source: z11.string().min(1)
2355
2472
  });
2356
- var pipelineSchema = z9.object({
2357
- id: z9.number().int().positive(),
2358
- name: z9.string().min(1).nullable().optional(),
2359
- status: z9.string(),
2360
- ref: z9.string().min(1).nullable().optional(),
2361
- created_at: z9.string().nullable().optional(),
2362
- updated_at: z9.string().nullable().optional(),
2363
- web_url: z9.url()
2473
+ var pipelineSchema = z11.object({
2474
+ id: z11.number().int().positive(),
2475
+ name: z11.string().min(1).nullable().optional(),
2476
+ status: z11.string(),
2477
+ ref: z11.string().min(1).nullable().optional(),
2478
+ created_at: z11.string().nullable().optional(),
2479
+ updated_at: z11.string().nullable().optional(),
2480
+ web_url: z11.url()
2364
2481
  });
2365
2482
  function permittedGitlabCiCalls(panel, source) {
2366
- const { source: parsedSource } = z9.object({ panel: pipelinePanelSchema3, source: gitlabCiSourceSchema }).parse({ panel, source });
2483
+ const { source: parsedSource } = z11.object({ panel: pipelinePanelSchema3, source: gitlabCiSourceSchema }).parse({ panel, source });
2367
2484
  return [pipelinesCall(parsedSource)];
2368
2485
  }
2369
2486
  async function fetchGitlabCiPipeline(args2) {
@@ -2402,7 +2519,7 @@ async function fetchGitlabCiPipeline(args2) {
2402
2519
  );
2403
2520
  }
2404
2521
  try {
2405
- const pipeline = z9.array(pipelineSchema).parse(await upstream.json())[0];
2522
+ const pipeline = z11.array(pipelineSchema).parse(await upstream.json())[0];
2406
2523
  if (!pipeline) {
2407
2524
  const detail = source.branch ? `No pipelines found for ref "${source.branch}". Check the source's branch setting.` : "No pipelines found.";
2408
2525
  return failure(
@@ -2468,7 +2585,7 @@ function normalizeStatus3(status) {
2468
2585
  return "unknown";
2469
2586
  }
2470
2587
  function timestamp3(value2) {
2471
- if (!value2 || !z9.iso.datetime().safeParse(value2).success) return void 0;
2588
+ if (!value2 || !z11.iso.datetime().safeParse(value2).success) return void 0;
2472
2589
  return Number.isFinite(new Date(value2).valueOf()) ? value2 : void 0;
2473
2590
  }
2474
2591
  function failure(panelId, kind, error, link, date, failure2) {
@@ -2481,10 +2598,10 @@ function failure(panelId, kind, error, link, date, failure2) {
2481
2598
  }
2482
2599
 
2483
2600
  // packages/server/src/adapters/http-value.ts
2484
- import { z as z10 } from "zod";
2601
+ import { z as z12 } from "zod";
2485
2602
  function permittedHttpValueCalls(panel) {
2486
2603
  const grouped = httpValueGroupedPanelSchema.safeParse(panel);
2487
- const urls = grouped.success ? grouped.data.facts.map((fact) => fact.url) : [z10.object({ panel: httpValueScalarPanelSchema }).parse({ panel }).panel.url];
2604
+ const urls = grouped.success ? grouped.data.facts.map((fact) => fact.url) : [z12.object({ panel: httpValueScalarPanelSchema }).parse({ panel }).panel.url];
2488
2605
  return urls.map(permittedCall);
2489
2606
  }
2490
2607
  async function fetchHttpValue(args2) {
@@ -2583,6 +2700,9 @@ function readPanelAdapter(panel, source) {
2583
2700
  if (panel.type === "pipeline-status" && source?.type === "github-actions") {
2584
2701
  permittedGithubActionsCalls(panel, source);
2585
2702
  return {
2703
+ ...panel.test_results ? {
2704
+ testHistory: ({ source: _source, ...args2 }) => fetchGithubTestHistory({ ...args2, source })
2705
+ } : {},
2586
2706
  destination: () => "https://api.github.com",
2587
2707
  fetch: ({ source: _configuredSource, ...args2 }) => fetchGithubActionsPipeline({ ...args2, source })
2588
2708
  };
@@ -2590,6 +2710,9 @@ function readPanelAdapter(panel, source) {
2590
2710
  if (panel.type === "test-count" && source?.type === "github-actions") {
2591
2711
  testCountCapabilities(panel, source);
2592
2712
  return {
2713
+ ...panel.test_results ? {
2714
+ testHistory: ({ source: _source, ...args2 }) => fetchGithubTestHistory({ ...args2, source })
2715
+ } : {},
2593
2716
  destination: () => "https://api.github.com",
2594
2717
  fetch: ({ source: _configuredSource, ...args2 }) => fetchGithubActionsTestCount({ ...args2, source })
2595
2718
  };
@@ -2668,7 +2791,9 @@ function derive(config, rejectUnsupported) {
2668
2791
  return allowed;
2669
2792
  }
2670
2793
  function panelCapability(panel, source) {
2671
- if (readPanelAdapter(panel, source)) return { kind: "server", operations: ["read"] };
2794
+ const adapter = readPanelAdapter(panel, source);
2795
+ if (adapter)
2796
+ return { kind: "server", operations: adapter.testHistory ? ["read", "test-history"] : ["read"] };
2672
2797
  if (panel.type === "pull-request-health" && source?.type === "github-actions") {
2673
2798
  pullRequestHealthCapabilities(panel);
2674
2799
  return {