artifacty 0.14.0 → 0.16.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.
@@ -5,6 +5,17 @@ import { html } from "@codemirror/lang-html";
5
5
  import { json } from "@codemirror/lang-json";
6
6
  import { markdown } from "@codemirror/lang-markdown";
7
7
 
8
+ const viewerMessages = {
9
+ filter: "Filter", filterColumn: "Filter column {column}", ruleFilter: "Filter by rule id",
10
+ rowsShown: "{visible} of {total} rows shown", resultsShown: "{visible} of {total} results shown"
11
+ };
12
+ try {
13
+ Object.assign(viewerMessages, JSON.parse(document.getElementById("artifacty-viewer-i18n")?.textContent || "{}"));
14
+ } catch { /* Keep English fallback when optional configuration is unavailable. */ }
15
+ function viewerText(key, params = {}) {
16
+ return viewerMessages[key].replace(/\{(\w+)\}/g, (match, name) => String(params[name] ?? match));
17
+ }
18
+
8
19
  const viewerTheme = EditorView.theme({
9
20
  "&": {
10
21
  minHeight: "50vh"
@@ -235,8 +246,8 @@ function enhanceCsvViewer(section) {
235
246
  const input = document.createElement("input");
236
247
  input.type = "text";
237
248
  input.className = "csv-filter-input";
238
- input.placeholder = "Filter";
239
- input.setAttribute("aria-label", `Filter column ${index + 1}`);
249
+ input.placeholder = viewerText("filter");
250
+ input.setAttribute("aria-label", viewerText("filterColumn", { column: index + 1 }));
240
251
  input.addEventListener("input", apply);
241
252
  cell.append(input);
242
253
  filterRow.append(cell);
@@ -289,7 +300,7 @@ function enhanceCsvViewer(section) {
289
300
  tbody.append(fragment);
290
301
 
291
302
  status.hidden = false;
292
- status.textContent = `${visible.length} of ${rows.length} rows shown`;
303
+ status.textContent = viewerText("rowsShown", { visible: visible.length, total: rows.length });
293
304
  }
294
305
 
295
306
  apply();
@@ -335,8 +346,8 @@ function enhanceSarifViewer(section) {
335
346
  const ruleInput = document.createElement("input");
336
347
  ruleInput.type = "text";
337
348
  ruleInput.className = "sarif-rule-filter";
338
- ruleInput.placeholder = "Filter by rule id";
339
- ruleInput.setAttribute("aria-label", "Filter by rule id");
349
+ ruleInput.placeholder = viewerText("ruleFilter");
350
+ ruleInput.setAttribute("aria-label", viewerText("ruleFilter"));
340
351
  ruleInput.addEventListener("input", apply);
341
352
 
342
353
  controls.append(chipsWrap, ruleInput);
@@ -437,7 +448,7 @@ function enhanceSarifViewer(section) {
437
448
  tbody.append(fragment);
438
449
 
439
450
  status.hidden = false;
440
- status.textContent = `${visible.length} of ${rows.length} results shown`;
451
+ status.textContent = viewerText("resultsShown", { visible: visible.length, total: rows.length });
441
452
  }
442
453
 
443
454
  apply();
@@ -352,7 +352,9 @@ function isPidRunning(pid) {
352
352
  async function fetchHealth(url) {
353
353
  try {
354
354
  const response = await fetch(`${url}/health`, {
355
- signal: AbortSignal.timeout(500)
355
+ // Match the updater health deadline so brief CPU or I/O contention
356
+ // does not report a live background server as stopped.
357
+ signal: AbortSignal.timeout(2000)
356
358
  });
357
359
  return { ok: response.ok, status: response.status };
358
360
  } catch {
package/src/lib/events.js CHANGED
@@ -81,9 +81,9 @@ export function eventFromAudit(auditRow = {}) {
81
81
  * True when `event` is visible to `access`. Mirrors storage.js's
82
82
  * canReadArtifactMeta: a falsy `access` means an internal/trusted caller
83
83
  * (or single-user mode) and always sees everything; otherwise a
84
- * private-visibility event is only visible to its owner or an admin.
85
- * Events with no recorded visibility (not tied to a private artifact, or
86
- * predating this field) are always visible.
84
+ * public events allow anonymous readers, team events require a user, and
85
+ * private events require their owner or an admin. Legacy events without a
86
+ * visibility field use team semantics.
87
87
  */
88
88
  export function eventVisibleTo(event, access) {
89
89
  if (!event) {
@@ -95,7 +95,7 @@ export function eventVisibleTo(event, access) {
95
95
  if (access.role === "admin") {
96
96
  return true;
97
97
  }
98
- if (event.visibility !== "private") {
98
+ if (event.visibility === "public" || (event.visibility !== "private" && Boolean(access.userId))) {
99
99
  return true;
100
100
  }
101
101
  return Boolean(access.userId) && access.userId === event.ownerUserId;