@walkrstudio/recorder 0.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.
Files changed (45) hide show
  1. package/dist/cdp.d.ts +14 -0
  2. package/dist/cdp.d.ts.map +1 -0
  3. package/dist/cdp.js +86 -0
  4. package/dist/cdp.js.map +1 -0
  5. package/dist/chromium.d.ts +12 -0
  6. package/dist/chromium.d.ts.map +1 -0
  7. package/dist/chromium.js +75 -0
  8. package/dist/chromium.js.map +1 -0
  9. package/dist/embed.d.ts +3 -0
  10. package/dist/embed.d.ts.map +1 -0
  11. package/dist/embed.js +548 -0
  12. package/dist/embed.js.map +1 -0
  13. package/dist/encoder.d.ts +6 -0
  14. package/dist/encoder.d.ts.map +1 -0
  15. package/dist/encoder.js +121 -0
  16. package/dist/encoder.js.map +1 -0
  17. package/dist/index.d.ts +6 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +5 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/realtime-recorder.d.ts +4 -0
  22. package/dist/realtime-recorder.d.ts.map +1 -0
  23. package/dist/realtime-recorder.js +109 -0
  24. package/dist/realtime-recorder.js.map +1 -0
  25. package/dist/recorder.d.ts +4 -0
  26. package/dist/recorder.d.ts.map +1 -0
  27. package/dist/recorder.js +180 -0
  28. package/dist/recorder.js.map +1 -0
  29. package/dist/recording-session.d.ts +26 -0
  30. package/dist/recording-session.d.ts.map +1 -0
  31. package/dist/recording-session.js +88 -0
  32. package/dist/recording-session.js.map +1 -0
  33. package/dist/static-server.d.ts +9 -0
  34. package/dist/static-server.d.ts.map +1 -0
  35. package/dist/static-server.js +212 -0
  36. package/dist/static-server.js.map +1 -0
  37. package/dist/streaming-encoder.d.ts +26 -0
  38. package/dist/streaming-encoder.d.ts.map +1 -0
  39. package/dist/streaming-encoder.js +89 -0
  40. package/dist/streaming-encoder.js.map +1 -0
  41. package/dist/types.d.ts +15 -0
  42. package/dist/types.d.ts.map +1 -0
  43. package/dist/types.js +2 -0
  44. package/dist/types.js.map +1 -0
  45. package/package.json +34 -0
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export { buildEmbedHtml } from "./embed.js";
2
+ export { encodeFrames } from "./encoder.js";
3
+ export { recordWalkthrough } from "./recorder.js";
4
+ export { StreamingEncoder } from "./streaming-encoder.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { Walkthrough } from "@walkrstudio/core";
2
+ import type { RecordOptions, RecordResult } from "./types.js";
3
+ export declare function recordRealtimeWalkthrough(walkthrough: Walkthrough, options?: RecordOptions): Promise<RecordResult>;
4
+ //# sourceMappingURL=realtime-recorder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-recorder.d.ts","sourceRoot":"","sources":["../src/realtime-recorder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAYrD,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE9D,wBAAsB,yBAAyB,CAC7C,WAAW,EAAE,WAAW,EACxB,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,YAAY,CAAC,CA+HvB"}
@@ -0,0 +1,109 @@
1
+ import * as path from "node:path";
2
+ import { encodeFrames } from "./encoder.js";
3
+ import { createRecordingSession, DEFAULT_FPS, DEFAULT_HEIGHT, DEFAULT_WIDTH, getDefaultOutput, isFiniteNumber, waitForConsoleMessage, } from "./recording-session.js";
4
+ import { StreamingEncoder } from "./streaming-encoder.js";
5
+ export async function recordRealtimeWalkthrough(walkthrough, options = {}) {
6
+ const width = isFiniteNumber(options.width)
7
+ ? Math.max(1, Math.round(options.width))
8
+ : DEFAULT_WIDTH;
9
+ const height = isFiniteNumber(options.height)
10
+ ? Math.max(1, Math.round(options.height))
11
+ : DEFAULT_HEIGHT;
12
+ const fps = isFiniteNumber(options.fps) ? Math.max(1, Math.round(options.fps)) : DEFAULT_FPS;
13
+ const format = options.format ?? "mp4";
14
+ const isEmbed = format === "embed";
15
+ const outputPath = path.resolve(options.output ?? getDefaultOutput(format));
16
+ const totalDurationMs = walkthrough.steps.reduce((sum, step) => sum + Math.max(0, step.duration), 0);
17
+ const expectedFrames = Math.ceil(totalDurationMs / (1000 / fps));
18
+ const session = await createRecordingSession(walkthrough, { width, height });
19
+ try {
20
+ const { cdp, server } = session;
21
+ // No browser API patching — real-time mode uses wall clock
22
+ // Set up console listener before navigating
23
+ const readyPromise = waitForConsoleMessage(cdp, "__WALKR_RECORD_READY__");
24
+ // Navigate to studio in record mode
25
+ await cdp.send("Page.navigate", {
26
+ url: `${server.url}?mode=record`,
27
+ });
28
+ await readyPromise;
29
+ // Set up completion listener
30
+ const completePromise = new Promise((resolve) => {
31
+ const handler = (params) => {
32
+ const event = params;
33
+ const text = event.args?.map((a) => a.value ?? "").join(" ") ?? "";
34
+ if (text.includes("__WALKR_RECORD_COMPLETE__")) {
35
+ cdp.off("Runtime.consoleAPICalled", handler);
36
+ resolve();
37
+ }
38
+ };
39
+ cdp.on("Runtime.consoleAPICalled", handler);
40
+ });
41
+ // For embed format, buffer frames. For video formats, stream to encoder.
42
+ const frames = [];
43
+ let encoder = null;
44
+ let frameCount = 0;
45
+ if (!isEmbed) {
46
+ encoder = new StreamingEncoder({
47
+ format: format,
48
+ fps,
49
+ width,
50
+ height,
51
+ outputPath,
52
+ expectedFrames,
53
+ });
54
+ }
55
+ // Start screencast — push-based frame delivery
56
+ await cdp.send("Page.startScreencast", {
57
+ format: "jpeg",
58
+ quality: 90,
59
+ maxWidth: width,
60
+ maxHeight: height,
61
+ everyNthFrame: 1,
62
+ });
63
+ // Handle incoming screencast frames with serialized writes
64
+ let writeChain = Promise.resolve();
65
+ cdp.on("Page.screencastFrame", (params) => {
66
+ const event = params;
67
+ // Ack immediately so Chrome keeps sending frames
68
+ void cdp.send("Page.screencastFrameAck", { sessionId: event.sessionId });
69
+ const frameBuffer = Buffer.from(event.data, "base64");
70
+ if (isEmbed) {
71
+ frames.push(frameBuffer);
72
+ }
73
+ else if (encoder) {
74
+ const enc = encoder;
75
+ writeChain = writeChain.then(() => enc.write(frameBuffer));
76
+ }
77
+ frameCount++;
78
+ options.onProgress?.(Math.min(100, (frameCount / expectedFrames) * 100));
79
+ });
80
+ // Trigger playback
81
+ await cdp.send("Runtime.evaluate", {
82
+ expression: "window.__walkrPlay()",
83
+ awaitPromise: false,
84
+ });
85
+ // Wait for walkthrough completion
86
+ await completePromise;
87
+ // Stop screencast and drain pending writes
88
+ await cdp.send("Page.stopScreencast");
89
+ await writeChain;
90
+ // Finalize
91
+ if (isEmbed) {
92
+ return await encodeFrames(frames, {
93
+ ...options,
94
+ width,
95
+ height,
96
+ fps,
97
+ walkthrough,
98
+ });
99
+ }
100
+ if (encoder) {
101
+ return await encoder.finish();
102
+ }
103
+ throw new Error("Unexpected state: no encoder and not embed format");
104
+ }
105
+ finally {
106
+ session.cleanup();
107
+ }
108
+ }
109
+ //# sourceMappingURL=realtime-recorder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-recorder.js","sourceRoot":"","sources":["../src/realtime-recorder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { Walkthrough } from "@walkrstudio/core";
2
+ import type { RecordOptions, RecordResult } from "./types.js";
3
+ export declare function recordWalkthrough(walkthrough: Walkthrough, options?: RecordOptions): Promise<RecordResult>;
4
+ //# sourceMappingURL=recorder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../src/recorder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAarD,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE9D,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,WAAW,EACxB,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,YAAY,CAAC,CAwMvB"}
@@ -0,0 +1,180 @@
1
+ import * as path from "node:path";
2
+ import { encodeFrames } from "./encoder.js";
3
+ import { recordRealtimeWalkthrough } from "./realtime-recorder.js";
4
+ import { createRecordingSession, DEFAULT_FPS, DEFAULT_HEIGHT, DEFAULT_WIDTH, getDefaultOutput, isFiniteNumber, waitForConsoleMessage, } from "./recording-session.js";
5
+ import { StreamingEncoder } from "./streaming-encoder.js";
6
+ export async function recordWalkthrough(walkthrough, options = {}) {
7
+ if (options.realtime) {
8
+ return recordRealtimeWalkthrough(walkthrough, options);
9
+ }
10
+ const width = isFiniteNumber(options.width)
11
+ ? Math.max(1, Math.round(options.width))
12
+ : DEFAULT_WIDTH;
13
+ const height = isFiniteNumber(options.height)
14
+ ? Math.max(1, Math.round(options.height))
15
+ : DEFAULT_HEIGHT;
16
+ const fps = isFiniteNumber(options.fps) ? Math.max(1, Math.round(options.fps)) : DEFAULT_FPS;
17
+ const frameIntervalMs = 1000 / fps;
18
+ const format = options.format ?? "mp4";
19
+ const isEmbed = format === "embed";
20
+ const outputPath = path.resolve(options.output ?? getDefaultOutput(format));
21
+ const session = await createRecordingSession(walkthrough, { width, height });
22
+ try {
23
+ const { cdp, server } = session;
24
+ // Patch browser APIs for virtual time compatibility.
25
+ // - WebSocket: block connections (pending WebSockets prevent virtual time advance)
26
+ // - requestAnimationFrame: replace with setTimeout (rAF doesn't fire during
27
+ // virtual time, but setTimeout does — the engine uses rAF for step timing)
28
+ await cdp.send("Page.addScriptToEvaluateOnNewDocument", {
29
+ source: `
30
+ window.WebSocket = class extends EventTarget {
31
+ static CONNECTING = 0;
32
+ static OPEN = 1;
33
+ static CLOSING = 2;
34
+ static CLOSED = 3;
35
+ CONNECTING = 0;
36
+ OPEN = 1;
37
+ CLOSING = 2;
38
+ CLOSED = 3;
39
+ readyState = 3;
40
+ bufferedAmount = 0;
41
+ extensions = '';
42
+ protocol = '';
43
+ binaryType = 'blob';
44
+ url = '';
45
+ constructor(url) {
46
+ super();
47
+ this.url = typeof url === 'string' ? url : '';
48
+ setTimeout(() => {
49
+ this.dispatchEvent(new CloseEvent('error'));
50
+ this.dispatchEvent(new CloseEvent('close', { code: 1006 }));
51
+ }, 0);
52
+ }
53
+ send() {}
54
+ close() {}
55
+ };
56
+
57
+ // Replace rAF with setTimeout so callbacks fire during virtual time.
58
+ // Chrome's virtual time advances setTimeout but not rAF.
59
+ // The delay matches the frame capture interval so exactly 1 rAF
60
+ // callback fires per frame budget — minimal overhead with best
61
+ // timing accuracy. setTimeout(0) doesn't work because
62
+ // maxVirtualTimeTaskStarvationCount batches same-time tasks.
63
+ window.requestAnimationFrame = function(cb) {
64
+ return setTimeout(() => cb(performance.now()), ${Math.round(frameIntervalMs)});
65
+ };
66
+ window.cancelAnimationFrame = function(id) {
67
+ clearTimeout(id);
68
+ };
69
+ `,
70
+ worldName: "",
71
+ runImmediately: true,
72
+ });
73
+ // Pause virtual time before navigation
74
+ await cdp.send("Emulation.setVirtualTimePolicy", {
75
+ policy: "pause",
76
+ });
77
+ // Set up console listener before navigating
78
+ const readyPromise = waitForConsoleMessage(cdp, "__WALKR_RECORD_READY__");
79
+ // Navigate to studio in record mode
80
+ await cdp.send("Page.navigate", {
81
+ url: `${server.url}?mode=record`,
82
+ });
83
+ // Grant load budget — let page load, fetch walkthrough.json, load iframe
84
+ await cdp.send("Emulation.setVirtualTimePolicy", {
85
+ policy: "pauseIfNetworkFetchesPending",
86
+ budget: 30000,
87
+ maxVirtualTimeTaskStarvationCount: 100000,
88
+ waitForNavigation: true,
89
+ });
90
+ // Wait for __WALKR_RECORD_READY__
91
+ await readyPromise;
92
+ // Trigger playback
93
+ let isComplete = false;
94
+ cdp.on("Runtime.consoleAPICalled", (params) => {
95
+ const event = params;
96
+ const text = event.args?.map((a) => a.value ?? "").join(" ") ?? "";
97
+ if (text.includes("__WALKR_RECORD_COMPLETE__")) {
98
+ isComplete = true;
99
+ }
100
+ });
101
+ await cdp.send("Runtime.evaluate", {
102
+ expression: "window.__walkrPlay()",
103
+ awaitPromise: false,
104
+ });
105
+ // Advance time in chunks until STEPPING fires (iframe loaded, first step executing)
106
+ await waitForConsoleMessage(cdp, "__WALKR_RECORD_STEPPING__");
107
+ // Pause virtual time to cancel the remaining load budget, then drain
108
+ // any stale virtualTimeBudgetExpired event from the cancelled budget.
109
+ await cdp.send("Emulation.setVirtualTimePolicy", { policy: "pause" });
110
+ await new Promise((r) => setTimeout(r, 0));
111
+ // Frame capture loop using virtual time
112
+ const totalDurationMs = walkthrough.steps.reduce((sum, step) => sum + Math.max(0, step.duration), 0);
113
+ const expectedFrames = Math.ceil(totalDurationMs / frameIntervalMs);
114
+ // For embed format, buffer all frames. For video formats, stream to encoder.
115
+ const frames = [];
116
+ let encoder = null;
117
+ if (!isEmbed) {
118
+ encoder = new StreamingEncoder({
119
+ format: format,
120
+ fps,
121
+ width,
122
+ height,
123
+ outputPath,
124
+ expectedFrames,
125
+ });
126
+ }
127
+ let capturedCount = 0;
128
+ while (!isComplete && capturedCount < expectedFrames) {
129
+ // Register listener BEFORE send — the response and event may arrive
130
+ // in the same TCP packet, so the event could be dispatched before
131
+ // the send promise resolves.
132
+ const budgetExpired = cdp.once("Emulation.virtualTimeBudgetExpired");
133
+ await cdp.send("Emulation.setVirtualTimePolicy", {
134
+ policy: "pauseIfNetworkFetchesPending",
135
+ budget: frameIntervalMs,
136
+ maxVirtualTimeTaskStarvationCount: 100000,
137
+ });
138
+ await budgetExpired;
139
+ // Switch to clean pause so the compositor can produce a frame.
140
+ // With pauseIfNetworkFetchesPending the compositor may block on
141
+ // pending requests, causing captureScreenshot to hang.
142
+ await cdp.send("Emulation.setVirtualTimePolicy", { policy: "pause" });
143
+ // Capture screenshot
144
+ const result = (await cdp.send("Page.captureScreenshot", {
145
+ format: "jpeg",
146
+ quality: 90,
147
+ }));
148
+ const frameBuffer = Buffer.from(result.data, "base64");
149
+ if (isEmbed) {
150
+ frames.push(frameBuffer);
151
+ }
152
+ else if (encoder) {
153
+ await encoder.write(frameBuffer);
154
+ }
155
+ capturedCount++;
156
+ // Report progress
157
+ options.onProgress?.(Math.min(100, (capturedCount / expectedFrames) * 100));
158
+ }
159
+ // Finalize
160
+ if (isEmbed) {
161
+ // Trim to exact expected frame count — virtual time rounding may produce extras
162
+ const finalFrames = frames.slice(0, expectedFrames);
163
+ return await encodeFrames(finalFrames, {
164
+ ...options,
165
+ width,
166
+ height,
167
+ fps,
168
+ walkthrough,
169
+ });
170
+ }
171
+ if (encoder) {
172
+ return await encoder.finish();
173
+ }
174
+ throw new Error("Unexpected state: no encoder and not embed format");
175
+ }
176
+ finally {
177
+ session.cleanup();
178
+ }
179
+ }
180
+ //# sourceMappingURL=recorder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recorder.js","sourceRoot":"","sources":["../src/recorder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { Walkthrough } from "@walkrstudio/core";
2
+ import { CDPClient } from "./cdp.js";
3
+ import type { RecordOptions } from "./types.js";
4
+ interface RecordingSession {
5
+ server: {
6
+ url: string;
7
+ close: () => void;
8
+ };
9
+ chromium: {
10
+ close: () => void;
11
+ };
12
+ cdp: CDPClient;
13
+ cleanup: () => void;
14
+ }
15
+ export declare const DEFAULT_WIDTH = 1920;
16
+ export declare const DEFAULT_HEIGHT = 1080;
17
+ export declare const DEFAULT_FPS = 30;
18
+ export declare const isFiniteNumber: (value: unknown) => value is number;
19
+ export declare const getDefaultOutput: (format: RecordOptions["format"]) => string;
20
+ export declare function createRecordingSession(walkthrough: Walkthrough, opts: {
21
+ width: number;
22
+ height: number;
23
+ }): Promise<RecordingSession>;
24
+ export declare function waitForConsoleMessage(cdp: CDPClient, message: string): Promise<void>;
25
+ export {};
26
+ //# sourceMappingURL=recording-session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recording-session.d.ts","sourceRoot":"","sources":["../src/recording-session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAGrC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAOhD,UAAU,gBAAgB;IACxB,MAAM,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC;IAC3C,QAAQ,EAAE;QAAE,KAAK,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC;IAChC,GAAG,EAAE,SAAS,CAAC;IACf,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,eAAO,MAAM,aAAa,OAAO,CAAC;AAClC,eAAO,MAAM,cAAc,OAAO,CAAC;AACnC,eAAO,MAAM,WAAW,KAAK,CAAC;AAE9B,eAAO,MAAM,cAAc,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MACJ,CAAC;AAEtD,eAAO,MAAM,gBAAgB,GAAI,QAAQ,aAAa,CAAC,QAAQ,CAAC,KAAG,MAKlE,CAAC;AAoBF,wBAAsB,sBAAsB,CAC1C,WAAW,EAAE,WAAW,EACxB,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACtC,OAAO,CAAC,gBAAgB,CAAC,CAwC3B;AAED,wBAAsB,qBAAqB,CAAC,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAwB1F"}
@@ -0,0 +1,88 @@
1
+ import { CDPClient } from "./cdp.js";
2
+ import { launchChromium } from "./chromium.js";
3
+ import { startStaticServer } from "./static-server.js";
4
+ export const DEFAULT_WIDTH = 1920;
5
+ export const DEFAULT_HEIGHT = 1080;
6
+ export const DEFAULT_FPS = 30;
7
+ export const isFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value);
8
+ export const getDefaultOutput = (format) => {
9
+ if (format === "gif")
10
+ return "output.gif";
11
+ if (format === "webm")
12
+ return "output.webm";
13
+ if (format === "embed")
14
+ return "output.html";
15
+ return "output.mp4";
16
+ };
17
+ async function getPageWsUrl(browserWsUrl) {
18
+ const url = new URL(browserWsUrl);
19
+ const httpUrl = `http://${url.host}/json/list`;
20
+ const res = await fetch(httpUrl);
21
+ if (!res.ok) {
22
+ throw new Error(`Failed to list CDP targets: ${res.status}`);
23
+ }
24
+ const targets = (await res.json());
25
+ const page = targets.find((t) => t.type === "page");
26
+ if (!page?.webSocketDebuggerUrl) {
27
+ throw new Error("No page target found in Chromium");
28
+ }
29
+ return page.webSocketDebuggerUrl;
30
+ }
31
+ export async function createRecordingSession(walkthrough, opts) {
32
+ const server = await startStaticServer(walkthrough);
33
+ let chromium = null;
34
+ let cdp = null;
35
+ try {
36
+ const browser = await launchChromium({ width: opts.width, height: opts.height });
37
+ chromium = browser;
38
+ const pageWsUrl = await getPageWsUrl(browser.wsUrl);
39
+ cdp = await CDPClient.connect(pageWsUrl);
40
+ await cdp.send("Page.enable");
41
+ await cdp.send("Runtime.enable");
42
+ await cdp.send("Emulation.setDeviceMetricsOverride", {
43
+ width: opts.width,
44
+ height: opts.height,
45
+ deviceScaleFactor: 1,
46
+ mobile: false,
47
+ });
48
+ const sessionCdp = cdp;
49
+ const sessionChromium = chromium;
50
+ return {
51
+ server,
52
+ chromium,
53
+ cdp,
54
+ cleanup() {
55
+ sessionCdp.close();
56
+ sessionChromium.close();
57
+ server.close();
58
+ },
59
+ };
60
+ }
61
+ catch (err) {
62
+ cdp?.close();
63
+ chromium?.close();
64
+ server.close();
65
+ throw err;
66
+ }
67
+ }
68
+ export async function waitForConsoleMessage(cdp, message) {
69
+ return new Promise((resolve, reject) => {
70
+ const timeout = setTimeout(() => {
71
+ cdp.off("Runtime.consoleAPICalled", handler);
72
+ reject(new Error(`Timed out waiting for console message: ${message}`));
73
+ }, 30_000);
74
+ const handler = (params) => {
75
+ const event = params;
76
+ if (event.type !== "log")
77
+ return;
78
+ const text = event.args?.map((a) => a.value ?? "").join(" ") ?? "";
79
+ if (text.includes(message)) {
80
+ clearTimeout(timeout);
81
+ cdp.off("Runtime.consoleAPICalled", handler);
82
+ resolve();
83
+ }
84
+ };
85
+ cdp.on("Runtime.consoleAPICalled", handler);
86
+ });
87
+ }
88
+ //# sourceMappingURL=recording-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recording-session.js","sourceRoot":"","sources":["../src/recording-session.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAevD,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,CAAC;AAClC,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC;AACnC,MAAM,CAAC,MAAM,WAAW,GAAG,EAAE,CAAC;AAE9B,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,KAAc,EAAmB,EAAE,CAChE,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAEtD,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,MAA+B,EAAU,EAAE;IAC1E,IAAI,MAAM,KAAK,KAAK;QAAE,OAAO,YAAY,CAAC;IAC1C,IAAI,MAAM,KAAK,MAAM;QAAE,OAAO,aAAa,CAAC;IAC5C,IAAI,MAAM,KAAK,OAAO;QAAE,OAAO,aAAa,CAAC;IAC7C,OAAO,YAAY,CAAC;AACtB,CAAC,CAAC;AAEF,KAAK,UAAU,YAAY,CAAC,YAAoB;IAC9C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC;IAClC,MAAM,OAAO,GAAG,UAAU,GAAG,CAAC,IAAI,YAAY,CAAC;IAE/C,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,CAAC;IACjC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,+BAA+B,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED,MAAM,OAAO,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAgB,CAAC;IAClD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC;IACpD,IAAI,CAAC,IAAI,EAAE,oBAAoB,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IAED,OAAO,IAAI,CAAC,oBAAoB,CAAC;AACnC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,WAAwB,EACxB,IAAuC;IAEvC,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,WAAW,CAAC,CAAC;IACpD,IAAI,QAAQ,GAAiC,IAAI,CAAC;IAClD,IAAI,GAAG,GAAqB,IAAI,CAAC;IAEjC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QACjF,QAAQ,GAAG,OAAO,CAAC;QAEnB,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACpD,GAAG,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACzC,MAAM,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC9B,MAAM,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAEjC,MAAM,GAAG,CAAC,IAAI,CAAC,oCAAoC,EAAE;YACnD,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,iBAAiB,EAAE,CAAC;YACpB,MAAM,EAAE,KAAK;SACd,CAAC,CAAC;QAEH,MAAM,UAAU,GAAG,GAAG,CAAC;QACvB,MAAM,eAAe,GAAG,QAAQ,CAAC;QAEjC,OAAO;YACL,MAAM;YACN,QAAQ;YACR,GAAG;YACH,OAAO;gBACL,UAAU,CAAC,KAAK,EAAE,CAAC;gBACnB,eAAe,CAAC,KAAK,EAAE,CAAC;gBACxB,MAAM,CAAC,KAAK,EAAE,CAAC;YACjB,CAAC;SACF,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,EAAE,KAAK,EAAE,CAAC;QACb,QAAQ,EAAE,KAAK,EAAE,CAAC;QAClB,MAAM,CAAC,KAAK,EAAE,CAAC;QACf,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,GAAc,EAAE,OAAe;IACzE,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC3C,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YAC9B,GAAG,CAAC,GAAG,CAAC,0BAA0B,EAAE,OAAO,CAAC,CAAC;YAC7C,MAAM,CAAC,IAAI,KAAK,CAAC,0CAA0C,OAAO,EAAE,CAAC,CAAC,CAAC;QACzE,CAAC,EAAE,MAAM,CAAC,CAAC;QAEX,MAAM,OAAO,GAAG,CAAC,MAAe,EAAQ,EAAE;YACxC,MAAM,KAAK,GAAG,MAGb,CAAC;YACF,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK;gBAAE,OAAO;YAEjC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;YACnE,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC3B,YAAY,CAAC,OAAO,CAAC,CAAC;gBACtB,GAAG,CAAC,GAAG,CAAC,0BAA0B,EAAE,OAAO,CAAC,CAAC;gBAC7C,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC,CAAC;QAEF,GAAG,CAAC,EAAE,CAAC,0BAA0B,EAAE,OAAO,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { Walkthrough } from "@walkrstudio/core";
2
+ interface StudioServer {
3
+ port: number;
4
+ url: string;
5
+ close: () => void;
6
+ }
7
+ export declare function startStaticServer(walkthrough: Walkthrough): Promise<StudioServer>;
8
+ export {};
9
+ //# sourceMappingURL=static-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static-server.d.ts","sourceRoot":"","sources":["../src/static-server.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD,UAAU,YAAY;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAoKD,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAuFvF"}