fidelity-kit 2.0.0 → 2.2.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.
- package/README.md +6 -0
- package/dist/core/schema.d.ts +1 -0
- package/dist/core/schema.d.ts.map +1 -1
- package/dist/core/schema.js +2 -0
- package/dist/core/schema.js.map +1 -1
- package/dist/live-reload.d.ts +12 -0
- package/dist/live-reload.d.ts.map +1 -0
- package/dist/live-reload.js +108 -0
- package/dist/live-reload.js.map +1 -0
- package/dist/live-reload.test.d.ts +2 -0
- package/dist/live-reload.test.d.ts.map +1 -0
- package/dist/live-reload.test.js +112 -0
- package/dist/live-reload.test.js.map +1 -0
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +15 -1
- package/dist/run.js.map +1 -1
- package/dist/server.d.ts +5 -2
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +14 -4
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
- package/viewer/assets/index-D3r8erGw.js +10 -0
- package/viewer/assets/index-OJNXD4i8.css +2 -0
- package/viewer/assets/routes-BXthYnUn.js +54 -0
- package/viewer/index.html +2 -2
- package/viewer/assets/ViewControls-CTFRFrir.js +0 -54
- package/viewer/assets/_-D3hbSo9M.js +0 -1
- package/viewer/assets/index-DBPzD7F6.js +0 -11
- package/viewer/assets/index-bVr7mAbR.css +0 -2
- package/viewer/assets/routes-OgzZznNP.js +0 -1
package/README.md
CHANGED
|
@@ -21,6 +21,12 @@ npx fidelity-kit dev results
|
|
|
21
21
|
|
|
22
22
|
Open the URL printed by the command (usually <http://localhost:3000>). `dev` processes new or changed images before starting and serves files without browser caching, so a reload shows your latest render. See the [working example](https://github.com/bhouston/fidelity-kit/tree/main/examples/demo) for a complete suite.
|
|
23
23
|
|
|
24
|
+
## See it in action
|
|
25
|
+
|
|
26
|
+
[Material Fidelity](https://material-fidelity.ben3d.ca) uses fidelity-kit to compare renderer output side by side, with visual deltas and PSNR metrics. Open the live site to explore the results.
|
|
27
|
+
|
|
28
|
+
[](https://material-fidelity.ben3d.ca)
|
|
29
|
+
|
|
24
30
|
## Adopt it in your suite
|
|
25
31
|
|
|
26
32
|
Create a `results` directory with a `fidelity.json` file. Put each scene in its own folder, with one AVIF image per renderer under each output name:
|
package/dist/core/schema.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export declare const configSchema: z.ZodObject<{
|
|
|
7
7
|
id: z.ZodString;
|
|
8
8
|
label: z.ZodOptional<z.ZodString>;
|
|
9
9
|
reference: z.ZodOptional<z.ZodBoolean>;
|
|
10
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
10
11
|
category: z.ZodOptional<z.ZodString>;
|
|
11
12
|
}, z.core.$strip>>;
|
|
12
13
|
outputs: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/core/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB,2FAA2F;AAC3F,eAAO,MAAM,YAAY
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/core/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB,2FAA2F;AAC3F,eAAO,MAAM,YAAY;;;;;;;;;;;;;;iBA8BvB,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAE1D,qCAAqC;AACrC,eAAO,MAAM,eAAe;;;iBAAoF,CAAC"}
|
package/dist/core/schema.js
CHANGED
|
@@ -16,6 +16,8 @@ export const configSchema = z.object({
|
|
|
16
16
|
id,
|
|
17
17
|
label: z.string().optional(),
|
|
18
18
|
reference: z.boolean().optional(),
|
|
19
|
+
/** `false` hides the renderer by default; viewers can still toggle it on. */
|
|
20
|
+
enabled: z.boolean().optional(),
|
|
19
21
|
category: z.string().optional(),
|
|
20
22
|
}))
|
|
21
23
|
.refine((r) => r.some((x) => x.reference), 'at least one renderer needs "reference": true')
|
package/dist/core/schema.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/core/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,MAAM,EAAE,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;AACtD,MAAM,SAAS,GAAG,CAA2B,KAAU,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,MAAM,CAAC;AAExH,2FAA2F;AAC3F,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,IAAI,EAAE,CAAC;SACJ,MAAM,EAAE;SACR,MAAM,CACL,CAAC,IAAI,EAAE,EAAE,CACP,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QACzE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;QACrB,UAAU,CAAC,IAAI,CAAC,EAClB,8EAA8E,CAC/E;SACA,QAAQ,EAAE;IACb,SAAS,EAAE,CAAC;SACT,KAAK,CACJ,CAAC,CAAC,MAAM,CAAC;QACP,EAAE;QACF,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC5B,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;QACjC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;KAChC,CAAC,CACH;SACA,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,+CAA+C,CAAC;SAC1F,MAAM,CAAC,SAAS,EAAE,6BAA6B,CAAC;IACnD,OAAO,EAAE,CAAC;SACP,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;SACrD,GAAG,CAAC,CAAC,EAAE,iCAAiC,CAAC;SACzC,MAAM,CAAC,SAAS,EAAE,2BAA2B,CAAC;SAC9C,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;CAC/B,CAAC,CAAC;AAGH,qCAAqC;AACrC,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/core/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,MAAM,EAAE,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;AACtD,MAAM,SAAS,GAAG,CAA2B,KAAU,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,MAAM,CAAC;AAExH,2FAA2F;AAC3F,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,IAAI,EAAE,CAAC;SACJ,MAAM,EAAE;SACR,MAAM,CACL,CAAC,IAAI,EAAE,EAAE,CACP,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QACzE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;QACrB,UAAU,CAAC,IAAI,CAAC,EAClB,8EAA8E,CAC/E;SACA,QAAQ,EAAE;IACb,SAAS,EAAE,CAAC;SACT,KAAK,CACJ,CAAC,CAAC,MAAM,CAAC;QACP,EAAE;QACF,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC5B,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;QACjC,6EAA6E;QAC7E,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;QAC/B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;KAChC,CAAC,CACH;SACA,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,+CAA+C,CAAC;SAC1F,MAAM,CAAC,SAAS,EAAE,6BAA6B,CAAC;IACnD,OAAO,EAAE,CAAC;SACP,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;SACrD,GAAG,CAAC,CAAC,EAAE,iCAAiC,CAAC;SACzC,MAAM,CAAC,SAAS,EAAE,2BAA2B,CAAC;SAC9C,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;CAC/B,CAAC,CAAC;AAGH,qCAAqC;AACrC,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const liveReloadPath = "/data/events";
|
|
2
|
+
/** One trailing debounce shared by all clients; revisions catch updates missed during reconnects. */
|
|
3
|
+
export declare function createLiveReload(debounceMs?: number): {
|
|
4
|
+
revision: () => string;
|
|
5
|
+
notify(): void;
|
|
6
|
+
response(req: Request): Response;
|
|
7
|
+
close(): void;
|
|
8
|
+
};
|
|
9
|
+
export type LiveReload = ReturnType<typeof createLiveReload>;
|
|
10
|
+
/** Observe published results (including external processing) and viewer README content. */
|
|
11
|
+
export declare function watchLiveReload(root: string, liveReload: LiveReload): Promise<import("chokidar").FSWatcher>;
|
|
12
|
+
//# sourceMappingURL=live-reload.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live-reload.d.ts","sourceRoot":"","sources":["../src/live-reload.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,cAAc,iBAAiB,CAAC;AAE7C,qGAAqG;AACrG,wBAAgB,gBAAgB,CAAC,UAAU,SAAO;;;kBAoBhC,OAAO,GAAG,QAAQ;;EA4CnC;AAED,MAAM,MAAM,UAAU,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE7D,2FAA2F;AAC3F,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,yCAyBzE"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { relative, resolve, sep } from 'node:path';
|
|
3
|
+
import { watch } from 'chokidar';
|
|
4
|
+
export const liveReloadPath = '/data/events';
|
|
5
|
+
/** One trailing debounce shared by all clients; revisions catch updates missed during reconnects. */
|
|
6
|
+
export function createLiveReload(debounceMs = 5000) {
|
|
7
|
+
const boot = randomUUID();
|
|
8
|
+
let version = 0;
|
|
9
|
+
let timer;
|
|
10
|
+
let closed = false;
|
|
11
|
+
const clients = new Set();
|
|
12
|
+
const revision = () => `${boot}:${version}`;
|
|
13
|
+
const frame = (event) => `event: ${event}\ndata: ${revision()}\n\n`;
|
|
14
|
+
return {
|
|
15
|
+
revision,
|
|
16
|
+
notify() {
|
|
17
|
+
if (closed)
|
|
18
|
+
return;
|
|
19
|
+
if (timer)
|
|
20
|
+
clearTimeout(timer);
|
|
21
|
+
timer = setTimeout(() => {
|
|
22
|
+
timer = undefined;
|
|
23
|
+
version++;
|
|
24
|
+
for (const client of clients)
|
|
25
|
+
client.send(frame('change'));
|
|
26
|
+
}, debounceMs);
|
|
27
|
+
timer.unref();
|
|
28
|
+
},
|
|
29
|
+
response(req) {
|
|
30
|
+
const headers = {
|
|
31
|
+
'Content-Type': 'text/event-stream',
|
|
32
|
+
'Cache-Control': 'no-store',
|
|
33
|
+
'X-Accel-Buffering': 'no',
|
|
34
|
+
};
|
|
35
|
+
if (closed)
|
|
36
|
+
return new Response(null, { status: 503, headers });
|
|
37
|
+
if (req.method === 'HEAD')
|
|
38
|
+
return new Response(null, { headers });
|
|
39
|
+
let dispose;
|
|
40
|
+
const body = new ReadableStream({
|
|
41
|
+
start(controller) {
|
|
42
|
+
const encoder = new TextEncoder();
|
|
43
|
+
const client = {
|
|
44
|
+
send(message) {
|
|
45
|
+
// A stalled reader reconnects instead of accumulating an unbounded queue.
|
|
46
|
+
if ((controller.desiredSize ?? 0) <= 0)
|
|
47
|
+
return client.close();
|
|
48
|
+
controller.enqueue(encoder.encode(message));
|
|
49
|
+
},
|
|
50
|
+
close() {
|
|
51
|
+
dispose?.();
|
|
52
|
+
controller.close();
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
const heartbeat = setInterval(() => client.send(': keepalive\n\n'), 15000);
|
|
56
|
+
heartbeat.unref();
|
|
57
|
+
dispose = () => {
|
|
58
|
+
clearInterval(heartbeat);
|
|
59
|
+
clients.delete(client);
|
|
60
|
+
};
|
|
61
|
+
clients.add(client);
|
|
62
|
+
client.send(frame('ready'));
|
|
63
|
+
},
|
|
64
|
+
cancel() {
|
|
65
|
+
dispose?.();
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
return new Response(body, { headers });
|
|
69
|
+
},
|
|
70
|
+
close() {
|
|
71
|
+
closed = true;
|
|
72
|
+
if (timer)
|
|
73
|
+
clearTimeout(timer);
|
|
74
|
+
for (const client of clients)
|
|
75
|
+
client.close();
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/** Observe published results (including external processing) and viewer README content. */
|
|
80
|
+
export async function watchLiveReload(root, liveReload) {
|
|
81
|
+
const base = resolve(root);
|
|
82
|
+
const relevant = (path) => {
|
|
83
|
+
const rel = relative(base, path).split(sep).join('/');
|
|
84
|
+
return rel === 'index.json' || rel === 'README.md' || rel.endsWith('/README.md');
|
|
85
|
+
};
|
|
86
|
+
const watcher = watch(base, {
|
|
87
|
+
ignoreInitial: true,
|
|
88
|
+
awaitWriteFinish: { stabilityThreshold: 500, pollInterval: 100 },
|
|
89
|
+
ignored: (path, stats) => !!stats?.isFile() && !relevant(path),
|
|
90
|
+
});
|
|
91
|
+
watcher.on('all', (event, path) => {
|
|
92
|
+
if (event === 'unlinkDir' || relevant(path))
|
|
93
|
+
liveReload.notify();
|
|
94
|
+
});
|
|
95
|
+
watcher.on('error', (error) => console.error('Live reload watch error:', error));
|
|
96
|
+
try {
|
|
97
|
+
await new Promise((resolveReady, reject) => {
|
|
98
|
+
watcher.once('ready', resolveReady);
|
|
99
|
+
watcher.once('error', reject);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
await watcher.close();
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
106
|
+
return watcher;
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=live-reload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live-reload.js","sourceRoot":"","sources":["../src/live-reload.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live-reload.test.d.ts","sourceRoot":"","sources":["../src/live-reload.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { afterEach, expect, test, vi } from 'vitest';
|
|
5
|
+
import { createLiveReload, watchLiveReload } from './live-reload.js';
|
|
6
|
+
import { createHandler, serve } from './server.js';
|
|
7
|
+
afterEach(() => vi.useRealTimers());
|
|
8
|
+
const decode = (value) => new TextDecoder().decode(value);
|
|
9
|
+
test('broadcasts one update to all clients five seconds after the last publication', async () => {
|
|
10
|
+
vi.useFakeTimers();
|
|
11
|
+
const live = createLiveReload();
|
|
12
|
+
const a = live.response(new Request('http://x/data/events')).body.getReader();
|
|
13
|
+
const b = live.response(new Request('http://x/data/events')).body.getReader();
|
|
14
|
+
try {
|
|
15
|
+
const revision = live.revision();
|
|
16
|
+
expect(decode((await a.read()).value)).toContain(`event: ready\ndata: ${revision}`);
|
|
17
|
+
await b.read();
|
|
18
|
+
live.notify();
|
|
19
|
+
await vi.advanceTimersByTimeAsync(4000);
|
|
20
|
+
live.notify();
|
|
21
|
+
await vi.advanceTimersByTimeAsync(4999);
|
|
22
|
+
expect(live.revision()).toBe(revision);
|
|
23
|
+
await vi.advanceTimersByTimeAsync(1);
|
|
24
|
+
expect(live.revision()).not.toBe(revision);
|
|
25
|
+
expect(decode((await a.read()).value)).toContain(`event: change\ndata: ${live.revision()}`);
|
|
26
|
+
expect(decode((await b.read()).value)).toContain('event: change');
|
|
27
|
+
await a.cancel();
|
|
28
|
+
live.notify();
|
|
29
|
+
await vi.advanceTimersByTimeAsync(5000);
|
|
30
|
+
expect(decode((await b.read()).value)).toContain('event: change');
|
|
31
|
+
}
|
|
32
|
+
finally {
|
|
33
|
+
live.close();
|
|
34
|
+
}
|
|
35
|
+
expect((await b.read()).done).toBe(true);
|
|
36
|
+
});
|
|
37
|
+
test('handshake carries current revision after reconnect and shutdown cancels pending notifications', async () => {
|
|
38
|
+
vi.useFakeTimers();
|
|
39
|
+
const live = createLiveReload();
|
|
40
|
+
live.notify();
|
|
41
|
+
await vi.advanceTimersByTimeAsync(5000);
|
|
42
|
+
const response = live.response(new Request('http://x/data/events'));
|
|
43
|
+
expect(response.headers.get('Content-Type')).toBe('text/event-stream');
|
|
44
|
+
expect(response.headers.get('Cache-Control')).toBe('no-store');
|
|
45
|
+
const reader = response.body.getReader();
|
|
46
|
+
expect(decode((await reader.read()).value)).toContain(live.revision());
|
|
47
|
+
const revision = live.revision();
|
|
48
|
+
live.notify();
|
|
49
|
+
live.close();
|
|
50
|
+
await vi.advanceTimersByTimeAsync(5000);
|
|
51
|
+
expect(live.revision()).toBe(revision);
|
|
52
|
+
expect((await reader.read()).done).toBe(true);
|
|
53
|
+
});
|
|
54
|
+
test('dev advertises the channel, serve does not, and HTTP disconnects clean up streams', async () => {
|
|
55
|
+
const root = await mkdtemp(join(tmpdir(), 'fk-live-http-'));
|
|
56
|
+
await writeFile(join(root, 'index.json'), '{}');
|
|
57
|
+
const live = createLiveReload(20);
|
|
58
|
+
const handler = createHandler(root, { dev: true, liveReload: live });
|
|
59
|
+
const server = await serve(handler, 0, '127.0.0.1');
|
|
60
|
+
try {
|
|
61
|
+
const address = server.address();
|
|
62
|
+
if (!address || typeof address === 'string')
|
|
63
|
+
throw new Error('Expected TCP address');
|
|
64
|
+
const url = `http://127.0.0.1:${address.port}`;
|
|
65
|
+
const index = await fetch(`${url}/data/index.json`);
|
|
66
|
+
expect(index.headers.get('X-Fidelity-Events')).toBe('data/events');
|
|
67
|
+
expect(index.headers.get('X-Fidelity-Revision')).toBe(live.revision());
|
|
68
|
+
await index.text();
|
|
69
|
+
const head = await fetch(`${url}/data/events`, { method: 'HEAD' });
|
|
70
|
+
expect(head.headers.get('Content-Type')).toBe('text/event-stream');
|
|
71
|
+
expect(await head.text()).toBe('');
|
|
72
|
+
const abort = new AbortController();
|
|
73
|
+
const response = await fetch(`${url}/data/events`, { signal: abort.signal });
|
|
74
|
+
const reader = response.body.getReader();
|
|
75
|
+
expect(decode((await reader.read()).value)).toContain('event: ready');
|
|
76
|
+
live.notify();
|
|
77
|
+
expect(decode((await reader.read()).value)).toContain('event: change');
|
|
78
|
+
abort.abort();
|
|
79
|
+
await reader.cancel().catch(() => { });
|
|
80
|
+
const ordinary = createHandler(root, { liveReload: live });
|
|
81
|
+
const normalIndex = await ordinary(new Request('http://x/data/index.json'));
|
|
82
|
+
expect(normalIndex.headers.get('X-Fidelity-Events')).toBeNull();
|
|
83
|
+
await normalIndex.text();
|
|
84
|
+
expect((await ordinary(new Request('http://x/data/events'))).status).toBe(404);
|
|
85
|
+
}
|
|
86
|
+
finally {
|
|
87
|
+
live.close();
|
|
88
|
+
server.closeAllConnections();
|
|
89
|
+
await new Promise((resolve) => server.close(() => resolve()));
|
|
90
|
+
await rm(root, { recursive: true, force: true });
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
test('watches external index and README publications but ignores temporary and input files', async () => {
|
|
94
|
+
const root = await mkdtemp(join(tmpdir(), 'fk-live-watch-'));
|
|
95
|
+
const live = createLiveReload();
|
|
96
|
+
const notify = vi.spyOn(live, 'notify');
|
|
97
|
+
const watcher = await watchLiveReload(root, live);
|
|
98
|
+
try {
|
|
99
|
+
await writeFile(join(root, 'index.json.tmp'), '{}');
|
|
100
|
+
await writeFile(join(root, 'renderer.png'), 'image');
|
|
101
|
+
await writeFile(join(root, 'index.json'), '{}');
|
|
102
|
+
await vi.waitFor(() => expect(notify).toHaveBeenCalledTimes(1), { timeout: 4000 });
|
|
103
|
+
await writeFile(join(root, 'README.md'), '# Updated');
|
|
104
|
+
await vi.waitFor(() => expect(notify).toHaveBeenCalledTimes(2), { timeout: 4000 });
|
|
105
|
+
}
|
|
106
|
+
finally {
|
|
107
|
+
await watcher.close();
|
|
108
|
+
live.close();
|
|
109
|
+
await rm(root, { recursive: true, force: true });
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
//# sourceMappingURL=live-reload.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live-reload.test.js","sourceRoot":"","sources":["../src/live-reload.test.ts"],"names":[],"mappings":"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"}
|
package/dist/run.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,uEAAuE;AACvE,wBAAsB,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,iBA0DpD"}
|
package/dist/run.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createLiveReload, watchLiveReload } from './live-reload.js';
|
|
1
2
|
import { existsSync } from 'node:fs';
|
|
2
3
|
import { resolve } from 'node:path';
|
|
3
4
|
import { processSuite } from './core/index.js';
|
|
@@ -34,10 +35,23 @@ export async function run(argv, dev) {
|
|
|
34
35
|
console.error(`FAILED ${f.file}: ${f.error}`);
|
|
35
36
|
}, { concurrency: argv.concurrency, process: argv.process, onProgress: progress.update });
|
|
36
37
|
}
|
|
37
|
-
const
|
|
38
|
+
const liveReload = dev ? createLiveReload() : undefined;
|
|
39
|
+
let liveWatcher;
|
|
40
|
+
const server = await (async () => {
|
|
41
|
+
if (liveReload)
|
|
42
|
+
liveWatcher = await watchLiveReload(root, liveReload);
|
|
43
|
+
return serve(createHandler(root, { cache, dev, liveReload }), argv.port, argv.host);
|
|
44
|
+
})().catch(async (error) => {
|
|
45
|
+
liveReload?.close();
|
|
46
|
+
await liveWatcher?.close();
|
|
38
47
|
await watcher?.close();
|
|
39
48
|
throw error;
|
|
40
49
|
});
|
|
50
|
+
server.once('close', () => {
|
|
51
|
+
liveReload?.close();
|
|
52
|
+
void liveWatcher?.close();
|
|
53
|
+
void watcher?.close();
|
|
54
|
+
});
|
|
41
55
|
const address = server.address();
|
|
42
56
|
if (!address || typeof address === 'string')
|
|
43
57
|
throw new Error('Could not determine the viewer port');
|
package/dist/run.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type Server } from 'node:http';
|
|
2
2
|
import { isDataFile } from './core/paths.js';
|
|
3
|
+
import { type LiveReload } from './live-reload.js';
|
|
3
4
|
/** The prebuilt viewer SPA (built by `pnpm build` into packages/cli/viewer, shipped in the npm package). */
|
|
4
5
|
export declare const viewerDir: string;
|
|
5
6
|
export declare function assertViewerBuilt(): void;
|
|
@@ -21,14 +22,16 @@ export interface HandlerOptions {
|
|
|
21
22
|
* hashed: `/data/image-hashes.json` is an empty `{}` (a 404 would log a console error in the browser), `?v=` is ignored and `image-hashes.json` is not even loaded.
|
|
22
23
|
*/
|
|
23
24
|
dev?: boolean;
|
|
25
|
+
/** Dev-only result change channel. */
|
|
26
|
+
liveReload?: LiveReload;
|
|
24
27
|
}
|
|
25
28
|
/**
|
|
26
|
-
* `/data/*` = the suite (allowlisted files); everything else = the viewer SPA (
|
|
29
|
+
* `/data/*` = the suite (allowlisted files); everything else = the viewer SPA (the detail page is `/?scene=`, so no path fallback is needed).
|
|
27
30
|
* Serve mode: images are shared-cacheable per `cache`; `index.json`, READMEs and `index.html` always revalidate (cheap
|
|
28
31
|
* 304s) so a re-run of `process` shows up immediately; hashed `/assets/*` are immutable. Dev mode: nothing is cached.
|
|
29
32
|
* Serve mode also keeps a lazy content-hash map (pre-populated from `<root>/image-hashes.json`), lists it at
|
|
30
33
|
* `/data/image-hashes.json`, and serves `image?v=<hash>` as immutable only when `<hash>` is the file's current hash.
|
|
31
34
|
*/
|
|
32
|
-
export declare function createHandler(root: string, { assets, cache, dev }?: HandlerOptions): (req: Request) => Promise<Response>;
|
|
35
|
+
export declare function createHandler(root: string, { assets, cache, dev, liveReload }?: HandlerOptions): (req: Request) => Promise<Response>;
|
|
33
36
|
export declare function serve(handler: (req: Request) => Promise<Response>, port: number | undefined, host: string): Promise<Server>;
|
|
34
37
|
//# sourceMappingURL=server.d.ts.map
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,WAAW,CAAC;AAgBtD,OAAO,EAAE,UAAU,EAAe,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,WAAW,CAAC;AAgBtD,OAAO,EAAE,UAAU,EAAe,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAkB,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnE,4GAA4G;AAC5G,eAAO,MAAM,SAAS,QAAuD,CAAC;AAE9E,wBAAgB,iBAAiB,SAEhC;AAED,OAAO,EAAE,UAAU,EAAE,CAAC;AAEtB,MAAM,WAAW,WAAW;IAC1B,2EAA2E;IAC3E,MAAM,EAAE,MAAM,CAAC;IACf,qHAAqH;IACrH,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AACD,eAAO,MAAM,kBAAkB,EAAE,WAA0D,CAAC;AAE5F,MAAM,WAAW,cAAc;IAC7B,qCAAqC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uCAAuC;IACvC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB;;;OAGG;IACH,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,sCAAsC;IACtC,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,EAAE,MAAkB,EAAE,KAA0B,EAAE,GAAW,EAAE,UAAU,EAAE,GAAE,cAAmB,SA8B7E,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC,CAqC/C;AAED,wBAAsB,KAAK,CACzB,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,EAC5C,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,CAAC,CASjB"}
|
package/dist/server.js
CHANGED
|
@@ -7,6 +7,7 @@ import { relative, resolve as resolvePath, sep } from 'node:path';
|
|
|
7
7
|
import { realpath } from 'node:fs/promises';
|
|
8
8
|
import { fileResponse, freshFileResponse, HashStore, IMMUTABLE, notModified, readHashFile, resolveInside, } from './core/index.js';
|
|
9
9
|
import { isDataFile, isImageFile } from './core/paths.js';
|
|
10
|
+
import { liveReloadPath } from './live-reload.js';
|
|
10
11
|
/** The prebuilt viewer SPA (built by `pnpm build` into packages/cli/viewer, shipped in the npm package). */
|
|
11
12
|
export const viewerDir = fileURLToPath(new URL('../viewer', import.meta.url));
|
|
12
13
|
export function assertViewerBuilt() {
|
|
@@ -16,13 +17,13 @@ export function assertViewerBuilt() {
|
|
|
16
17
|
export { isDataFile };
|
|
17
18
|
export const defaultCachePolicy = { maxAge: 300, staleWhileRevalidate: 86400 };
|
|
18
19
|
/**
|
|
19
|
-
* `/data/*` = the suite (allowlisted files); everything else = the viewer SPA (
|
|
20
|
+
* `/data/*` = the suite (allowlisted files); everything else = the viewer SPA (the detail page is `/?scene=`, so no path fallback is needed).
|
|
20
21
|
* Serve mode: images are shared-cacheable per `cache`; `index.json`, READMEs and `index.html` always revalidate (cheap
|
|
21
22
|
* 304s) so a re-run of `process` shows up immediately; hashed `/assets/*` are immutable. Dev mode: nothing is cached.
|
|
22
23
|
* Serve mode also keeps a lazy content-hash map (pre-populated from `<root>/image-hashes.json`), lists it at
|
|
23
24
|
* `/data/image-hashes.json`, and serves `image?v=<hash>` as immutable only when `<hash>` is the file's current hash.
|
|
24
25
|
*/
|
|
25
|
-
export function createHandler(root, { assets = viewerDir, cache = defaultCachePolicy, dev = false } = {}) {
|
|
26
|
+
export function createHandler(root, { assets = viewerDir, cache = defaultCachePolicy, dev = false, liveReload } = {}) {
|
|
26
27
|
const imageCache = `public, max-age=${cache.maxAge}, stale-while-revalidate=${cache.staleWhileRevalidate}, stale-if-error=${cache.staleWhileRevalidate}`;
|
|
27
28
|
const store = new HashStore();
|
|
28
29
|
const bootId = Date.now().toString(36); // keeps ETags of the hash listing from colliding across restarts
|
|
@@ -54,6 +55,8 @@ export function createHandler(root, { assets = viewerDir, cache = defaultCachePo
|
|
|
54
55
|
status: 404,
|
|
55
56
|
headers: { 'Cache-Control': dev ? 'no-store' : 'no-cache' },
|
|
56
57
|
});
|
|
58
|
+
if (path === liveReloadPath)
|
|
59
|
+
return dev && liveReload ? liveReload.response(req) : notFound;
|
|
57
60
|
if (path.startsWith('/data/')) {
|
|
58
61
|
const rel = path.slice('/data/'.length);
|
|
59
62
|
if (rel === 'image-hashes.json')
|
|
@@ -68,7 +71,14 @@ export function createHandler(root, { assets = viewerDir, cache = defaultCachePo
|
|
|
68
71
|
return notFound;
|
|
69
72
|
await loaded;
|
|
70
73
|
const isImage = isImageFile(rel);
|
|
71
|
-
|
|
74
|
+
// Snapshot before reading so an update during the fetch is caught by the SSE handshake.
|
|
75
|
+
const revision = liveReload?.revision();
|
|
76
|
+
const response = await send(req, full, isImage ? imageCache : undefined, isImage ? new URL(req.url).searchParams.get('v') : null);
|
|
77
|
+
if (dev && liveReload && rel === 'index.json' && response.ok) {
|
|
78
|
+
response.headers.set('X-Fidelity-Events', liveReloadPath.slice(1));
|
|
79
|
+
response.headers.set('X-Fidelity-Revision', revision);
|
|
80
|
+
}
|
|
81
|
+
return response;
|
|
72
82
|
}
|
|
73
83
|
const rel = path === '/' ? 'index.html' : path.slice(1);
|
|
74
84
|
const full = resolveInside(assets, rel);
|
|
@@ -94,7 +104,7 @@ function listen(handler, port, host) {
|
|
|
94
104
|
if (typeof v === 'string')
|
|
95
105
|
headers.set(k, v);
|
|
96
106
|
const res = nreq.method === 'GET' || nreq.method === 'HEAD'
|
|
97
|
-
? await handler(new Request(`http://${headers.get('host') ?? 'localhost'}${nreq.url}`, { headers })).catch((e) => new Response(String(e), { status: 500 }))
|
|
107
|
+
? await handler(new Request(`http://${headers.get('host') ?? 'localhost'}${nreq.url}`, { headers, method: nreq.method })).catch((e) => new Response(String(e), { status: 500 }))
|
|
98
108
|
: new Response('Method not allowed', { status: 405 });
|
|
99
109
|
nres.writeHead(res.status, Object.fromEntries(res.headers));
|
|
100
110
|
if (nreq.method === 'HEAD' || !res.body)
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAe,MAAM,WAAW,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,OAAO,IAAI,WAAW,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,SAAS,EACT,SAAS,EACT,WAAW,EACX,YAAY,EACZ,aAAa,GACd,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|