@crvy/rprtr 0.0.7 → 0.0.9

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.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.0.9] - 2026-06-05
9
+
10
+ ### Fixed
11
+
12
+ - Remove file watcher that interfered with live updates
13
+ ## [0.0.8] - 2026-06-05
14
+
15
+ ### Fixed
16
+
17
+ - Broadcast test-begin events to UI and allow running→terminal status transitions
8
18
  ## [0.0.7] - 2026-06-05
9
19
 
10
20
  ### Ci
@@ -11,10 +11,10 @@ import {
11
11
  finalizeRunEvent,
12
12
  resolveBaselineTargets,
13
13
  safeParse
14
- } from "./chunk-JGS2VWQP.js";
14
+ } from "./chunk-EJRLZZ22.js";
15
15
 
16
16
  // src/server/app.ts
17
- import { dirname as dirname3, join as join4 } from "path";
17
+ import { dirname as dirname3, join as join3 } from "path";
18
18
  import { fileURLToPath } from "url";
19
19
  import pLimit from "p-limit";
20
20
 
@@ -178,7 +178,9 @@ function broadcastToBrowsers(wsClients, msg) {
178
178
  // src/server/handlers.ts
179
179
  function handleTestBegin(ctx, data) {
180
180
  const test = applyTestBeginEvent(ctx, data);
181
+ ctx.reportData.isRunning = true;
181
182
  console.log(` \u25B6 [${test.browser ?? "?"}] ${test.title}`);
183
+ broadcastToBrowsers(ctx.wsClients, { type: "test-begin", data });
182
184
  }
183
185
  function handleTestEnd(ctx, data) {
184
186
  const result = applyTestEndEvent(ctx, data);
@@ -208,123 +210,15 @@ function handleSync(ctx) {
208
210
  broadcastToBrowsers(ctx.wsClients, { type: "sync", data: ctx.reportData });
209
211
  }
210
212
 
211
- // src/server/report-watch.ts
212
- import { readdir as readdir2, stat as stat2 } from "fs/promises";
213
- import { join as join2 } from "path";
214
- var OFFLINE_REPORT_FILE_PATTERN2 = /^crvy-rprtr(?:-\d+)?\.json$/;
215
- function createDebouncedRefresh(reload, delayMs = 50) {
216
- let timer = null;
217
- return () => {
218
- if (timer !== null) {
219
- clearTimeout(timer);
220
- }
221
- timer = setTimeout(() => {
222
- timer = null;
223
- void reload();
224
- }, delayMs);
225
- };
226
- }
227
- function isFileNotFound2(error) {
228
- return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
229
- }
230
- async function describeFile(filePath, label) {
231
- try {
232
- const fileStats = await stat2(filePath);
233
- return `${label}:${fileStats.size}:${fileStats.mtimeMs}`;
234
- } catch (error) {
235
- if (isFileNotFound2(error)) {
236
- return null;
237
- }
238
- throw error;
239
- }
240
- }
241
- async function createOfflineFingerprint(offlineReportDir) {
242
- if (!await isDirectory(offlineReportDir)) {
243
- return "offline:missing";
244
- }
245
- try {
246
- const entries = await readdir2(offlineReportDir, { withFileTypes: true });
247
- const relevantEntries = entries.filter(
248
- (entry) => entry.isFile() && (entry.name === "report.json" || OFFLINE_REPORT_FILE_PATTERN2.test(entry.name))
249
- ).sort((left, right) => left.name.localeCompare(right.name));
250
- const parts = await Promise.all(
251
- relevantEntries.map((entry) => describeFile(join2(offlineReportDir, entry.name), entry.name))
252
- );
253
- return `offline:${parts.filter((part) => part !== null).join("|")}`;
254
- } catch (error) {
255
- const errorMsg = error instanceof Error ? error.message : String(error);
256
- console.warn(`[Server] Unable to scan ${offlineReportDir}: ${errorMsg}`);
257
- return "offline:error";
258
- }
259
- }
260
- async function createScreenshotFingerprint(screenshotDir, relativePath = "") {
261
- const directoryPath = relativePath === "" ? screenshotDir : join2(screenshotDir, relativePath);
262
- if (!await isDirectory(directoryPath)) {
263
- return relativePath === "" ? ["screenshots:missing"] : [];
264
- }
265
- try {
266
- const entries = await readdir2(directoryPath, { withFileTypes: true });
267
- const parts = await Promise.all(
268
- entries.sort((left, right) => left.name.localeCompare(right.name)).map((entry) => {
269
- const entryRelativePath = relativePath === "" ? entry.name : join2(relativePath, entry.name);
270
- if (entry.isDirectory()) {
271
- return createScreenshotFingerprint(screenshotDir, entryRelativePath);
272
- }
273
- return describeFile(join2(screenshotDir, entryRelativePath), entryRelativePath);
274
- })
275
- );
276
- return parts.flat().filter((part) => part !== null);
277
- } catch (error) {
278
- if (isFileNotFound2(error)) {
279
- return relativePath === "" ? ["screenshots:missing"] : [];
280
- }
281
- const errorMsg = error instanceof Error ? error.message : String(error);
282
- console.warn(`[Server] Unable to scan ${directoryPath}: ${errorMsg}`);
283
- return relativePath === "" ? ["screenshots:error"] : [];
284
- }
285
- }
286
- async function createArtifactsFingerprint(options) {
287
- const [offlineFingerprint, screenshotFingerprint] = await Promise.all([
288
- createOfflineFingerprint(options.offlineReportDir),
289
- createScreenshotFingerprint(options.screenshotDir)
290
- ]);
291
- return `${offlineFingerprint}::${screenshotFingerprint.join("|")}`;
292
- }
293
- async function watchReportArtifacts(options) {
294
- let fingerprint = await createArtifactsFingerprint(options);
295
- let isPolling = false;
296
- const interval = setInterval(() => {
297
- if (isPolling) {
298
- return;
299
- }
300
- isPolling = true;
301
- void createArtifactsFingerprint(options).then((nextFingerprint) => {
302
- if (nextFingerprint === fingerprint) {
303
- return;
304
- }
305
- fingerprint = nextFingerprint;
306
- options.scheduleRefresh();
307
- }).catch((error) => {
308
- const errorMsg = error instanceof Error ? error.message : String(error);
309
- console.warn(`[Server] Artifact refresh poll failed: ${errorMsg}`);
310
- }).finally(() => {
311
- isPolling = false;
312
- });
313
- }, 100);
314
- return () => {
315
- clearInterval(interval);
316
- };
317
- }
318
-
319
213
  // src/server/routes.ts
320
214
  import { existsSync } from "fs";
321
- import { dirname as dirname2, join as join3 } from "path";
215
+ import { dirname as dirname2, join as join2 } from "path";
322
216
  var LIVE_UPDATES_WEBSOCKET_PATH = "/";
323
217
  function isWebSocketUpgradeRequest(req) {
324
218
  return new URL(req.url).pathname === LIVE_UPDATES_WEBSOCKET_PATH && req.headers.get("upgrade")?.toLowerCase() === "websocket";
325
219
  }
326
220
  async function handleRoot(ctx) {
327
- const html = await respondWithFile(join3(ctx.staticDir, "index.html"), "text/html");
221
+ const html = await respondWithFile(join2(ctx.staticDir, "index.html"), "text/html");
328
222
  return html ?? new Response("Not Found", { status: 404 });
329
223
  }
330
224
  async function handleAppCss() {
@@ -343,7 +237,7 @@ function handleApiReport(ctx) {
343
237
  }
344
238
  var APPROVAL_TARGET_ERROR = "Could not resolve approval target";
345
239
  function actualPathFromUrl(ctx, actualUrl) {
346
- return actualUrl.startsWith("/screenshots/") ? join3(ctx.reportData.screenshotDir, actualUrl.slice("/screenshots/".length)) : actualUrl;
240
+ return actualUrl.startsWith("/screenshots/") ? join2(ctx.reportData.screenshotDir, actualUrl.slice("/screenshots/".length)) : actualUrl;
347
241
  }
348
242
  function reporterTitlePath(test) {
349
243
  const testFile = test.location?.file;
@@ -487,7 +381,7 @@ async function handleScreenshots(ctx, req) {
487
381
  }
488
382
  async function handleDist(ctx, req) {
489
383
  const path = new URL(req.url).pathname.slice("/dist/".length);
490
- const filePath = join3(ctx.staticDir, path);
384
+ const filePath = join2(ctx.staticDir, path);
491
385
  const contentType = filePath.endsWith(".css") ? "text/css" : filePath.endsWith(".js") ? "application/javascript" : filePath.endsWith(".svelte") ? "text/plain" : "application/octet-stream";
492
386
  const file = await respondWithFile(filePath, contentType);
493
387
  return file ?? new Response("Not Found", { status: 404 });
@@ -590,10 +484,6 @@ async function loadOfflineReports(offlineReportDir, reportData) {
590
484
  screenshotsBaseUrl: "/screenshots/"
591
485
  });
592
486
  }
593
- function resetReloadableReportData(reportData) {
594
- reportData.tests = {};
595
- reportData.isUpdateMode = false;
596
- }
597
487
  async function handleParsedWebSocketMessage(ctx, msg) {
598
488
  switch (msg.type) {
599
489
  case "test-begin": {
@@ -645,16 +535,16 @@ async function resolveStaticDir(staticDir) {
645
535
  const currentDir = dirname3(fileURLToPath(import.meta.url));
646
536
  const candidates = staticDir === void 0 ? [
647
537
  currentDir,
648
- join4(currentDir, "dist"),
649
- join4(currentDir, "..", "dist"),
650
- join4(currentDir, "..", "..", "dist"),
651
- join4(currentDir, ".."),
652
- join4(currentDir, "..", "..")
653
- ] : [staticDir, join4(staticDir, "dist")];
538
+ join3(currentDir, "dist"),
539
+ join3(currentDir, "..", "dist"),
540
+ join3(currentDir, "..", "..", "dist"),
541
+ join3(currentDir, ".."),
542
+ join3(currentDir, "..", "..")
543
+ ] : [staticDir, join3(staticDir, "dist")];
654
544
  const resolvedCandidates = await Promise.all(
655
545
  candidates.map(async (candidate) => ({
656
546
  candidate,
657
- exists: await fileExists(join4(candidate, "index.html"))
547
+ exists: await fileExists(join3(candidate, "index.html"))
658
548
  }))
659
549
  );
660
550
  const resolved = resolvedCandidates.find(({ exists }) => exists);
@@ -665,7 +555,7 @@ async function resolveStaticDir(staticDir) {
665
555
  }
666
556
  async function resolveReportPath(reportPath) {
667
557
  if (await isDirectory(reportPath)) {
668
- return { reportFile: join4(reportPath, "report.json"), offlineReportDir: reportPath };
558
+ return { reportFile: join3(reportPath, "report.json"), offlineReportDir: reportPath };
669
559
  }
670
560
  return { reportFile: reportPath, offlineReportDir: dirname3(reportPath) };
671
561
  }
@@ -698,22 +588,13 @@ async function createServerApp(options = {}) {
698
588
  const getHandlerContext = () => createHandlerContext(reportData, wsClients, currentRunIds, saveReport);
699
589
  const handleRequest = (req) => handleHttpRequest(routesContext, req);
700
590
  const handleWebSocketMessage = createWebSocketMessageHandler(getHandlerContext);
701
- const reloadFromDisk = async () => {
702
- resetReloadableReportData(reportData);
703
- await loadReport(reportFile, reportData);
704
- await loadOfflineReports(offlineReportDir, reportData);
705
- broadcastToBrowsers(wsClients, { type: "sync", data: reportData });
706
- };
707
- await reloadFromDisk();
708
- const close = await watchReportArtifacts({
709
- offlineReportDir,
710
- screenshotDir: reportData.screenshotDir,
711
- scheduleRefresh: createDebouncedRefresh(reloadFromDisk)
712
- });
591
+ await loadReport(reportFile, reportData);
592
+ await loadOfflineReports(offlineReportDir, reportData);
713
593
  return {
714
594
  port,
715
595
  wsClients,
716
- close,
596
+ close: () => {
597
+ },
717
598
  handleRequest,
718
599
  handleWebSocketMessage
719
600
  };
package/dist/cli.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  startServer
4
- } from "./chunk-OMDYTNWY.js";
5
- import "./chunk-JGS2VWQP.js";
4
+ } from "./chunk-TS64TROX.js";
5
+ import "./chunk-EJRLZZ22.js";
6
6
 
7
7
  // src/cli.ts
8
8
  import { join } from "path";
@@ -0,0 +1,3 @@
1
+ export declare const log: (...args: unknown[]) => void;
2
+ export declare const logError: (...args: unknown[]) => void;
3
+ //# sourceMappingURL=debug-log.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debug-log.d.ts","sourceRoot":"","sources":["../src/debug-log.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,GAAG,GAAI,GAAG,MAAM,OAAO,EAAE,KAAG,IAExC,CAAA;AACD,eAAO,MAAM,QAAQ,GAAI,GAAG,MAAM,OAAO,EAAE,KAAG,IAE7C,CAAA"}
package/dist/index.css CHANGED
@@ -24,7 +24,6 @@
24
24
  --color-white: #fff;
25
25
  --spacing: 0.25rem;
26
26
  --container-xl: 36rem;
27
- --container-2xl: 42rem;
28
27
  --text-xs: 0.75rem;
29
28
  --text-xs--line-height: calc(1 / 0.75);
30
29
  --text-sm: 0.875rem;
@@ -391,9 +390,6 @@
391
390
  .w-full {
392
391
  width: 100%;
393
392
  }
394
- .max-w-2xl {
395
- max-width: var(--container-2xl);
396
- }
397
393
  .max-w-full {
398
394
  max-width: 100%;
399
395
  }
@@ -541,12 +537,6 @@
541
537
  .border-edge {
542
538
  border-color: var(--color-edge);
543
539
  }
544
- .border-edge\/70 {
545
- border-color: var(--color-edge);
546
- @supports (color: color-mix(in lab, red, red)) {
547
- border-color: color-mix(in oklab, var(--color-edge) 70%, transparent);
548
- }
549
- }
550
540
  .border-error {
551
541
  border-color: var(--color-error);
552
542
  }
@@ -559,12 +549,6 @@
559
549
  border-color: color-mix(in oklab, var(--color-green-500) 60%, transparent);
560
550
  }
561
551
  }
562
- .border-info\/40 {
563
- border-color: var(--color-info);
564
- @supports (color: color-mix(in lab, red, red)) {
565
- border-color: color-mix(in oklab, var(--color-info) 40%, transparent);
566
- }
567
- }
568
552
  .border-purple-500\/60 {
569
553
  border-color: color-mix(in srgb, oklch(62.7% 0.265 303.9) 60%, transparent);
570
554
  @supports (color: color-mix(in lab, red, red)) {
@@ -619,12 +603,6 @@
619
603
  .bg-info {
620
604
  background-color: var(--color-info);
621
605
  }
622
- .bg-info\/10 {
623
- background-color: var(--color-info);
624
- @supports (color: color-mix(in lab, red, red)) {
625
- background-color: color-mix(in oklab, var(--color-info) 10%, transparent);
626
- }
627
- }
628
606
  .bg-purple-500\/25 {
629
607
  background-color: color-mix(in srgb, oklch(62.7% 0.265 303.9) 25%, transparent);
630
608
  @supports (color: color-mix(in lab, red, red)) {