@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/lambda.mjs CHANGED
@@ -71654,6 +71654,12 @@ var testCountSchema = external_exports.discriminatedUnion("status", [
71654
71654
  type: external_exports.literal("test-count"),
71655
71655
  status: external_exports.literal("reported"),
71656
71656
  total: external_exports.number().int().nonnegative(),
71657
+ /** Public identity for browser-local comparisons, never observation time. */
71658
+ run: external_exports.object({
71659
+ id: external_exports.string().min(1),
71660
+ attempt: external_exports.number().int().positive(),
71661
+ updatedAt: external_exports.iso.datetime()
71662
+ }).optional(),
71657
71663
  passed: external_exports.number().int().nonnegative().optional(),
71658
71664
  failed: external_exports.number().int().nonnegative().optional(),
71659
71665
  skipped: external_exports.number().int().nonnegative().optional()
@@ -71819,6 +71825,27 @@ var securityDetailsResponseSchema = external_exports.strictObject({
71819
71825
  ])
71820
71826
  });
71821
71827
 
71828
+ // packages/shared/src/test-history.ts
71829
+ var testHistorySampleSchema = external_exports.object({
71830
+ id: external_exports.string().min(1),
71831
+ attempt: external_exports.number().int().positive(),
71832
+ updatedAt: external_exports.iso.datetime(),
71833
+ total: external_exports.number().int().nonnegative()
71834
+ });
71835
+ var testHistorySchema = external_exports.object({
71836
+ inspectedAt: external_exports.iso.datetime(),
71837
+ inspectedRuns: external_exports.number().int().min(0).max(8),
71838
+ complete: external_exports.boolean(),
71839
+ samples: external_exports.array(testHistorySampleSchema).max(8),
71840
+ retryAt: external_exports.iso.datetime().optional()
71841
+ });
71842
+ var testHistoryHeader = "X-Dashboard-Test-History";
71843
+ function retryAfterTime(value, now) {
71844
+ if (!value) return void 0;
71845
+ const at = /^\d+$/.test(value) ? now + Number(value) * 1e3 : Date.parse(value);
71846
+ return Number.isFinite(at) && at > now ? at : void 0;
71847
+ }
71848
+
71822
71849
  // packages/server/src/credentials.ts
71823
71850
  var import_client_secrets_manager = __toESM(require_dist_cjs16(), 1);
71824
71851
  var import_client_ssm = __toESM(require_dist_cjs17(), 1);
@@ -72764,6 +72791,105 @@ function concat(chunks, length) {
72764
72791
  return result;
72765
72792
  }
72766
72793
 
72794
+ // packages/server/src/adapters/github-test-evidence.ts
72795
+ var artifactsSchema = external_exports.object({
72796
+ artifacts: external_exports.array(
72797
+ external_exports.object({ id: external_exports.number().int().positive(), name: external_exports.string().min(1), expired: external_exports.boolean() })
72798
+ )
72799
+ });
72800
+ function testArtifactHttpFailure(response) {
72801
+ const retry = retryAfterTime(response.headers.get("retry-after"), Date.now());
72802
+ return {
72803
+ kind: "failed",
72804
+ observedAt: observedAt(response.headers.get("date")),
72805
+ errorKind: upstreamErrorKind(response.status),
72806
+ httpStatus: response.status,
72807
+ ...retry === void 0 ? {} : { retryAt: new Date(retry).toISOString() }
72808
+ };
72809
+ }
72810
+ async function inspectGithubTestArtifact(args, selected, config2) {
72811
+ const { run } = selected;
72812
+ let at = selected.observedAt;
72813
+ const failed = (errorKind3) => ({
72814
+ kind: "failed",
72815
+ observedAt: at,
72816
+ errorKind: errorKind3
72817
+ });
72818
+ const get2 = (url2) => args.githubClient.get({
72819
+ source: args.source,
72820
+ fetcher: args.fetcher,
72821
+ url: url2,
72822
+ requestHeaders: new Headers()
72823
+ });
72824
+ const observe = (response) => {
72825
+ const value = observedAt(response.headers.get("date"));
72826
+ if (Date.parse(value) < Date.parse(at)) at = value;
72827
+ };
72828
+ try {
72829
+ if (!run.id) return failed("upstream-error");
72830
+ if (run.status !== "completed") return { kind: "pending", observedAt: at };
72831
+ const url2 = new URL(
72832
+ `https://api.github.com/repos/${args.source.repo}/actions/runs/${run.id}/artifacts`
72833
+ );
72834
+ url2.searchParams.set("name", config2.artifact);
72835
+ url2.searchParams.set("per_page", "100");
72836
+ const artifacts = await get2(url2.toString());
72837
+ if (!artifacts.ok) return testArtifactHttpFailure(artifacts);
72838
+ observe(artifacts);
72839
+ const matches = artifactsSchema.parse(await artifacts.json()).artifacts.filter((item) => item.name === config2.artifact);
72840
+ if (!matches.length) return { kind: "absent", observedAt: at };
72841
+ const [artifact] = matches;
72842
+ if (matches.length !== 1 || !artifact) return failed("upstream-error");
72843
+ if (artifact.expired) return { kind: "expired", observedAt: at };
72844
+ const archive = await get2(
72845
+ `https://api.github.com/repos/${args.source.repo}/actions/artifacts/${artifact.id}/zip`
72846
+ );
72847
+ if (!archive.ok) return testArtifactHttpFailure(archive);
72848
+ observe(archive);
72849
+ const summary = testResultsSummarySchema.parse(
72850
+ JSON.parse(await readTestResultsArtifact(archive, config2.entry))
72851
+ );
72852
+ if (summary.runId !== run.id || summary.runAttempt !== run.run_attempt || summary.headSha !== run.head_sha)
72853
+ return failed("upstream-error");
72854
+ const updatedAt = external_exports.iso.datetime().safeParse(run.updated_at);
72855
+ const tests = {
72856
+ type: "test-count",
72857
+ status: "reported",
72858
+ total: summary.total,
72859
+ ...updatedAt.success ? { run: { id: String(run.id), attempt: summary.runAttempt, updatedAt: updatedAt.data } } : {},
72860
+ ...summary.passed === void 0 ? {} : { passed: summary.passed },
72861
+ ...summary.failed === void 0 ? {} : { failed: summary.failed },
72862
+ ...summary.skipped === void 0 ? {} : { skipped: summary.skipped }
72863
+ };
72864
+ return { kind: "reported", observedAt: at, tests };
72865
+ } catch (error63) {
72866
+ return failed(error63 instanceof GithubAuthenticationError ? "unauthorized" : "upstream-error");
72867
+ }
72868
+ }
72869
+ function currentTestEvidence(inspection) {
72870
+ const { observedAt: at } = inspection;
72871
+ switch (inspection.kind) {
72872
+ case "reported":
72873
+ return { state: "ok", observedAt: at, signal: inspection.tests };
72874
+ case "pending":
72875
+ return { state: "ok", observedAt: at, signal: { type: "test-count", status: "pending" } };
72876
+ case "absent":
72877
+ return { state: "ok", observedAt: at, signal: { type: "test-count", status: "not-reported" } };
72878
+ case "expired":
72879
+ return {
72880
+ state: "error",
72881
+ observedAt: at,
72882
+ error: { kind: "upstream-error", message: publicErrorMessage("upstream-error") }
72883
+ };
72884
+ case "failed":
72885
+ return {
72886
+ state: "error",
72887
+ observedAt: at,
72888
+ error: { kind: inspection.errorKind, message: publicErrorMessage(inspection.errorKind) }
72889
+ };
72890
+ }
72891
+ }
72892
+
72767
72893
  // packages/server/src/adapters/github-actions.ts
72768
72894
  var pipelinePanelSchema = external_exports.object({
72769
72895
  test_results: testResultsArtifactSchema.optional(),
@@ -72804,11 +72930,6 @@ var runSchema = external_exports.object({
72804
72930
  updated_at: external_exports.string().optional(),
72805
72931
  created_at: external_exports.string().optional()
72806
72932
  });
72807
- var artifactsSchema = external_exports.object({
72808
- artifacts: external_exports.array(
72809
- external_exports.object({ id: external_exports.number().int().positive(), name: external_exports.string().min(1), expired: external_exports.boolean() })
72810
- )
72811
- });
72812
72933
  var runsSchema = external_exports.object({ workflow_runs: external_exports.array(runSchema) });
72813
72934
  var jobsSchema = external_exports.object({
72814
72935
  jobs: external_exports.array(
@@ -72855,13 +72976,15 @@ async function fetchGithubActionsTestCount(args) {
72855
72976
  return testCountEnvelope(
72856
72977
  noRunEnvelope(panel.id, source, panel.pipeline, selected.response.headers.get("date"))
72857
72978
  );
72858
- const evidence = await readGithubRunTestEvidence(
72859
- { ...args, source, githubClient },
72860
- {
72861
- run: selected.run,
72862
- observedAt: selected.observedAt
72863
- },
72864
- panel.test_results
72979
+ const evidence = currentTestEvidence(
72980
+ await inspectGithubTestArtifact(
72981
+ { ...args, source, githubClient },
72982
+ {
72983
+ run: selected.run,
72984
+ observedAt: selected.observedAt
72985
+ },
72986
+ panel.test_results
72987
+ )
72865
72988
  );
72866
72989
  return testCountEnvelope({ ...evidence, panelId: panel.id, link: selected.run.html_url });
72867
72990
  } catch (error63) {
@@ -72875,80 +72998,6 @@ async function fetchGithubActionsTestCount(args) {
72875
72998
  );
72876
72999
  }
72877
73000
  }
72878
- async function readGithubRunTestEvidence(args, selected, artifactConfig) {
72879
- const { run, observedAt: runObservedAt } = selected;
72880
- const { source, githubClient } = args;
72881
- const noValidators = new Headers();
72882
- let failureObservedAt = runObservedAt;
72883
- const evidenceError = (kind, at = failureObservedAt) => ({
72884
- state: "error",
72885
- observedAt: at,
72886
- error: { kind, message: publicErrorMessage(kind) }
72887
- });
72888
- const failedResponse = (response) => evidenceError(errorKind(response.status), observedAt2(response.headers.get("date")));
72889
- try {
72890
- if (!run.id) return evidenceError("upstream-error");
72891
- if (run.status !== "completed")
72892
- return {
72893
- state: "ok",
72894
- observedAt: runObservedAt,
72895
- signal: { type: "test-count", status: "pending" }
72896
- };
72897
- const artifactsResponse = await githubFetch(
72898
- githubArtifactsCall(source, run.id, artifactConfig),
72899
- {
72900
- ...args,
72901
- source,
72902
- requestHeaders: noValidators,
72903
- githubClient
72904
- }
72905
- );
72906
- if (!artifactsResponse.ok) return failedResponse(artifactsResponse);
72907
- const artifactObservedAt = observedAt2(artifactsResponse.headers.get("date"));
72908
- failureObservedAt = oldestObservation(runObservedAt, artifactObservedAt);
72909
- const artifacts = artifactsSchema.parse(await artifactsResponse.json()).artifacts;
72910
- const matches = artifacts.filter((artifact2) => artifact2.name === artifactConfig.artifact);
72911
- if (matches.length === 0)
72912
- return {
72913
- state: "ok",
72914
- observedAt: oldestObservation(runObservedAt, artifactObservedAt),
72915
- signal: { type: "test-count", status: "not-reported" }
72916
- };
72917
- const [artifact] = matches;
72918
- if (matches.length !== 1 || !artifact || artifact.expired)
72919
- return evidenceError("upstream-error");
72920
- const archiveResponse = await githubFetch(githubArtifactDownloadCall(source, artifact.id), {
72921
- ...args,
72922
- source,
72923
- requestHeaders: noValidators,
72924
- githubClient
72925
- });
72926
- if (!archiveResponse.ok) return failedResponse(archiveResponse);
72927
- const archiveObservedAt = observedAt2(archiveResponse.headers.get("date"));
72928
- failureObservedAt = oldestObservation(runObservedAt, artifactObservedAt, archiveObservedAt);
72929
- const summary = testResultsSummarySchema.parse(
72930
- JSON.parse(await readTestResultsArtifact(archiveResponse, artifactConfig.entry))
72931
- );
72932
- if (summary.runId !== run.id || summary.runAttempt !== run.run_attempt || summary.headSha !== run.head_sha)
72933
- throw new Error("Test-results manifest does not belong to the selected workflow run.");
72934
- return {
72935
- state: "ok",
72936
- observedAt: oldestObservation(runObservedAt, artifactObservedAt, archiveObservedAt),
72937
- signal: {
72938
- type: "test-count",
72939
- status: "reported",
72940
- total: summary.total,
72941
- ...summary.passed === void 0 ? {} : { passed: summary.passed },
72942
- ...summary.failed === void 0 ? {} : { failed: summary.failed },
72943
- ...summary.skipped === void 0 ? {} : { skipped: summary.skipped }
72944
- }
72945
- };
72946
- } catch (error63) {
72947
- return evidenceError(
72948
- error63 instanceof GithubAuthenticationError ? "unauthorized" : "upstream-error"
72949
- );
72950
- }
72951
- }
72952
73001
  function pullRequestHealthCapabilities(panel) {
72953
73002
  const { panel: parsed } = external_exports.object({ panel: pullRequestHealthPanelSchema }).parse({ panel });
72954
73003
  return {
@@ -73227,10 +73276,12 @@ async function fetchGithubActionsPipeline(args) {
73227
73276
  if (activity) signal.activity = activity;
73228
73277
  }
73229
73278
  if (parsedPanel.test_results) {
73230
- signal.testResults = await readGithubRunTestEvidence(
73231
- { ...args, source: parsedSource, githubClient },
73232
- { run, observedAt: selected.observedAt },
73233
- parsedPanel.test_results
73279
+ signal.testResults = currentTestEvidence(
73280
+ await inspectGithubTestArtifact(
73281
+ { ...args, source: parsedSource, githubClient },
73282
+ { run, observedAt: selected.observedAt },
73283
+ parsedPanel.test_results
73284
+ )
73234
73285
  );
73235
73286
  }
73236
73287
  const envelope = {
@@ -73349,18 +73400,6 @@ function githubJobsCall(source, runId) {
73349
73400
  url2.searchParams.set("per_page", "100");
73350
73401
  return { url: url2.toString(), headers: new Headers() };
73351
73402
  }
73352
- function githubArtifactsCall(source, runId, testResults) {
73353
- const url2 = new URL(`https://api.github.com/repos/${source.repo}/actions/runs/${runId}/artifacts`);
73354
- url2.searchParams.set("name", testResults.artifact);
73355
- url2.searchParams.set("per_page", "100");
73356
- return { url: url2.toString(), headers: new Headers() };
73357
- }
73358
- function githubArtifactDownloadCall(source, artifactId) {
73359
- return {
73360
- url: `https://api.github.com/repos/${source.repo}/actions/artifacts/${artifactId}/zip`,
73361
- headers: new Headers()
73362
- };
73363
- }
73364
73403
  function noRunEnvelope(panelId, source, pipeline, date6) {
73365
73404
  return {
73366
73405
  panelId,
@@ -73426,6 +73465,81 @@ function sourceLinkForWorkflow(source, pipeline) {
73426
73465
  function observedAt2(value) {
73427
73466
  return observedAt(value);
73428
73467
  }
73468
+ async function fetchGithubTestHistory(args) {
73469
+ const source = githubActionsSourceSchema.parse(args.source);
73470
+ const fetcher = (input2, init) => args.fetcher(input2, { ...init, ...args.signal ? { signal: args.signal } : {} });
73471
+ const artifact = testResultsArtifactSchema.parse(args.panel.test_results);
73472
+ const workflow = external_exports.string().min(1).parse(args.panel.pipeline);
73473
+ const now = Date.now();
73474
+ const cutoff = now - 14 * 864e5;
73475
+ const history = {
73476
+ inspectedAt: new Date(now).toISOString(),
73477
+ inspectedRuns: 0,
73478
+ complete: true,
73479
+ samples: []
73480
+ };
73481
+ let stop = false;
73482
+ const recordFailure = (failure3) => {
73483
+ history.complete = false;
73484
+ if (failure3.errorKind === "unauthorized" || failure3.httpStatus === 429) stop = true;
73485
+ if (failure3.retryAt && (!history.retryAt || Date.parse(failure3.retryAt) > Date.parse(history.retryAt)))
73486
+ history.retryAt = failure3.retryAt;
73487
+ };
73488
+ try {
73489
+ const call = githubRunsCall(
73490
+ source,
73491
+ workflow,
73492
+ source.branch,
73493
+ void 0,
73494
+ 8,
73495
+ new Date(cutoff).toISOString()
73496
+ );
73497
+ const url2 = new URL(call.url);
73498
+ url2.searchParams.set("status", "completed");
73499
+ const response = await githubFetch(
73500
+ { ...call, url: url2.toString() },
73501
+ { ...args, fetcher, source, requestHeaders: new Headers() }
73502
+ );
73503
+ if (!response.ok) recordFailure(testArtifactHttpFailure(response));
73504
+ else {
73505
+ const runs = runsSchema.parse(await response.json()).workflow_runs.slice(0, 8);
73506
+ for (const run of runs) {
73507
+ if (stop || args.signal?.aborted) {
73508
+ history.complete = false;
73509
+ break;
73510
+ }
73511
+ if (run.status !== "completed") continue;
73512
+ if (run.updated_at && Date.parse(run.updated_at) < cutoff) continue;
73513
+ history.inspectedRuns++;
73514
+ const inspection = await inspectGithubTestArtifact(
73515
+ { ...args, fetcher, source },
73516
+ { run, observedAt: observedAt2(response.headers.get("date")) },
73517
+ artifact
73518
+ );
73519
+ switch (inspection.kind) {
73520
+ case "failed":
73521
+ recordFailure(inspection);
73522
+ break;
73523
+ case "reported": {
73524
+ const { run: identity, total } = inspection.tests;
73525
+ if (identity) history.samples.push({ ...identity, total });
73526
+ else history.complete = false;
73527
+ break;
73528
+ }
73529
+ case "absent":
73530
+ case "expired":
73531
+ break;
73532
+ case "pending":
73533
+ history.complete = false;
73534
+ break;
73535
+ }
73536
+ }
73537
+ }
73538
+ } catch {
73539
+ history.complete = false;
73540
+ }
73541
+ return Response.json(history, { headers: { "cache-control": "no-store" } });
73542
+ }
73429
73543
 
73430
73544
  // packages/server/src/configuration-error.ts
73431
73545
  var ConfigurationError = class extends Error {
@@ -73983,6 +74097,9 @@ function readPanelAdapter(panel, source) {
73983
74097
  if (panel.type === "pipeline-status" && source?.type === "github-actions") {
73984
74098
  permittedGithubActionsCalls(panel, source);
73985
74099
  return {
74100
+ ...panel.test_results ? {
74101
+ testHistory: ({ source: _source, ...args }) => fetchGithubTestHistory({ ...args, source })
74102
+ } : {},
73986
74103
  destination: () => "https://api.github.com",
73987
74104
  fetch: ({ source: _configuredSource, ...args }) => fetchGithubActionsPipeline({ ...args, source })
73988
74105
  };
@@ -73990,6 +74107,9 @@ function readPanelAdapter(panel, source) {
73990
74107
  if (panel.type === "test-count" && source?.type === "github-actions") {
73991
74108
  testCountCapabilities(panel, source);
73992
74109
  return {
74110
+ ...panel.test_results ? {
74111
+ testHistory: ({ source: _source, ...args }) => fetchGithubTestHistory({ ...args, source })
74112
+ } : {},
73993
74113
  destination: () => "https://api.github.com",
73994
74114
  fetch: ({ source: _configuredSource, ...args }) => fetchGithubActionsTestCount({ ...args, source })
73995
74115
  };
@@ -74074,7 +74194,9 @@ function permitsPanelOperation(allowlist, board, panel, operation2) {
74074
74194
  return allowlist.get(`${board}/${panel}`)?.has(operation2) ?? false;
74075
74195
  }
74076
74196
  function panelCapability(panel, source) {
74077
- if (readPanelAdapter(panel, source)) return { kind: "server", operations: ["read"] };
74197
+ const adapter = readPanelAdapter(panel, source);
74198
+ if (adapter)
74199
+ return { kind: "server", operations: adapter.testHistory ? ["read", "test-history"] : ["read"] };
74078
74200
  if (panel.type === "pull-request-health" && source?.type === "github-actions") {
74079
74201
  pullRequestHealthCapabilities(panel);
74080
74202
  return {
@@ -76559,7 +76681,8 @@ function validateClaimsSet(protectedHeader, claimsSetBytes, options = {}) {
76559
76681
  throw new TypeError("Invalid clockTolerance option type");
76560
76682
  tolerance = clockTolerance;
76561
76683
  }
76562
- validateInput("clockTolerance option", tolerance);
76684
+ if (validateInput("clockTolerance option", tolerance), tolerance < 0)
76685
+ throw new TypeError("Invalid clockTolerance option input");
76563
76686
  const { currentDate } = options, now = validateInput("currentDate option", epoch(currentDate === void 0 ? /* @__PURE__ */ new Date() : currentDate)), iat = validateNumericDate(claimsSet, "iat", maxTokenAge !== void 0), nbf = validateNumericDate(claimsSet, "nbf");
76564
76687
  if (nbf !== void 0 && nbf > now + tolerance)
76565
76688
  throw new JWTClaimValidationFailed('"nbf" claim timestamp check failed', claimsSet, "nbf", checkFailed);
@@ -76645,7 +76768,7 @@ function isCloudflareWorkers() {
76645
76768
  return typeof WebSocketPair < "u" || typeof navigator < "u" && navigator.userAgent === "Cloudflare-Workers" || typeof EdgeRuntime < "u" && EdgeRuntime === "vercel";
76646
76769
  }
76647
76770
  var USER_AGENT2;
76648
- (typeof navigator > "u" || !navigator.userAgent?.startsWith?.("Mozilla/5.0 ")) && (USER_AGENT2 = "jose/v6.2.14");
76771
+ (typeof navigator > "u" || !navigator.userAgent?.startsWith?.("Mozilla/5.0 ")) && (USER_AGENT2 = "jose/v6.2.15");
76649
76772
  var customFetch = /* @__PURE__ */ Symbol();
76650
76773
  async function fetchJwks(url2, headers, signal, fetchImpl = fetch) {
76651
76774
  const response = await fetchImpl(url2, {
@@ -76671,6 +76794,8 @@ function isFreshFor(timestamp4, duration3) {
76671
76794
  function validateDuration(value, fallback2, option) {
76672
76795
  if (Number.isNaN(value))
76673
76796
  throw new TypeError(`"${option}" option must not be NaN`);
76797
+ if (typeof value == "number" && value < 0)
76798
+ throw new TypeError(`"${option}" option must not be negative`);
76674
76799
  return typeof value == "number" ? value : fallback2;
76675
76800
  }
76676
76801
  function createRemoteJWKSet(url2, options) {
@@ -77000,6 +77125,28 @@ ${(0, import_yaml.stringify)(outputConfig, { sortMapEntries: true })}`,
77000
77125
  { boardId: boardName, panelId, operation: "read", destination: fact.url }
77001
77126
  );
77002
77127
  });
77128
+ app.get("/api/panel/:board/:panelId/test-history", async (c5) => {
77129
+ const boardName = c5.req.param("board");
77130
+ const panelId = c5.req.param("panelId");
77131
+ const panel = deps.boardConfig?.boards[boardName]?.panels.find(
77132
+ (candidate) => candidate.id === panelId
77133
+ );
77134
+ const source = panel?.source ? deps.boardConfig?.sources[panel.source] : void 0;
77135
+ if (!panel || !source || !permitsPanelOperation(allowlist, boardName, panelId, "test-history"))
77136
+ return rejected(c5, { boardId: boardName, panelId, operation: "test-history" });
77137
+ const adapter = readPanelAdapter(panel, source);
77138
+ if (!adapter?.testHistory)
77139
+ return rejected(c5, { boardId: boardName, panelId, operation: "test-history" });
77140
+ return adapter.testHistory({
77141
+ panel,
77142
+ source,
77143
+ signal: c5.req.raw.signal,
77144
+ requestHeaders: new Headers(),
77145
+ fetcher: deps.fetcher ?? globalThis.fetch,
77146
+ credentials,
77147
+ githubClient
77148
+ });
77149
+ });
77003
77150
  app.get("/api/panel/:board/:panelId", async (c5) => {
77004
77151
  const boardName = c5.req.param("board");
77005
77152
  const panelId = c5.req.param("panelId");
@@ -77022,7 +77169,7 @@ ${(0, import_yaml.stringify)(outputConfig, { sortMapEntries: true })}`,
77022
77169
  credentials,
77023
77170
  githubClient
77024
77171
  });
77025
- return observation(c5, result, {
77172
+ const response = await observation(c5, result, {
77026
77173
  boardId: boardName,
77027
77174
  panelId,
77028
77175
  operation: "read",
@@ -77030,6 +77177,8 @@ ${(0, import_yaml.stringify)(outputConfig, { sortMapEntries: true })}`,
77030
77177
  ...source ? { sourceType: source.type } : {},
77031
77178
  destination: adapter.destination(panel, source)
77032
77179
  });
77180
+ if (adapter.testHistory) response.headers.set(testHistoryHeader, "supported");
77181
+ return response;
77033
77182
  }
77034
77183
  return c5.notFound();
77035
77184
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@continuous-excellence/ze-great-dashboard-aws",
3
- "version": "0.31.55",
3
+ "version": "0.31.57",
4
4
  "type": "module",
5
5
  "description": "AWS server runtime and CloudFormation deployment tooling for Ze Great Dashboard.",
6
6
  "keywords": [