@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/cdp.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ export declare class CDPClient {
2
+ private ws;
3
+ private nextId;
4
+ private pending;
5
+ private listeners;
6
+ private constructor();
7
+ static connect(wsUrl: string): Promise<CDPClient>;
8
+ send(method: string, params?: Record<string, unknown>): Promise<unknown>;
9
+ on(event: string, handler: (params: unknown) => void): void;
10
+ off(event: string, handler: (params: unknown) => void): void;
11
+ once(event: string): Promise<unknown>;
12
+ close(): void;
13
+ }
14
+ //# sourceMappingURL=cdp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cdp.d.ts","sourceRoot":"","sources":["../src/cdp.ts"],"names":[],"mappings":"AAaA,qBAAa,SAAS;IACpB,OAAO,CAAC,EAAE,CAAY;IACtB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,OAAO,CAGX;IACJ,OAAO,CAAC,SAAS,CAAqD;IAEtE,OAAO;WA8BM,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAWjD,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;IAe9E,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI;IAS3D,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI;IAO5D,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAUrC,KAAK,IAAI,IAAI;CAOd"}
package/dist/cdp.js ADDED
@@ -0,0 +1,86 @@
1
+ import WebSocket from "ws";
2
+ export class CDPClient {
3
+ ws;
4
+ nextId = 1;
5
+ pending = new Map();
6
+ listeners = new Map();
7
+ constructor(ws) {
8
+ this.ws = ws;
9
+ ws.on("message", (raw) => {
10
+ const msg = JSON.parse(raw.toString());
11
+ if ("id" in msg && msg.id != null) {
12
+ const entry = this.pending.get(msg.id);
13
+ if (entry) {
14
+ this.pending.delete(msg.id);
15
+ if (msg.error) {
16
+ entry.reject(new Error(`CDP error: ${msg.error.message}`));
17
+ }
18
+ else {
19
+ entry.resolve(msg.result);
20
+ }
21
+ }
22
+ return;
23
+ }
24
+ if ("method" in msg) {
25
+ const handlers = this.listeners.get(msg.method);
26
+ if (handlers) {
27
+ for (const handler of handlers) {
28
+ handler(msg.params);
29
+ }
30
+ }
31
+ }
32
+ });
33
+ }
34
+ static async connect(wsUrl) {
35
+ const ws = new WebSocket(wsUrl, { perMessageDeflate: false });
36
+ await new Promise((resolve, reject) => {
37
+ ws.once("open", resolve);
38
+ ws.once("error", reject);
39
+ });
40
+ return new CDPClient(ws);
41
+ }
42
+ async send(method, params) {
43
+ const id = this.nextId++;
44
+ const message = JSON.stringify({ id, method, params });
45
+ return new Promise((resolve, reject) => {
46
+ this.pending.set(id, { resolve, reject });
47
+ this.ws.send(message, (err) => {
48
+ if (err) {
49
+ this.pending.delete(id);
50
+ reject(err);
51
+ }
52
+ });
53
+ });
54
+ }
55
+ on(event, handler) {
56
+ let handlers = this.listeners.get(event);
57
+ if (!handlers) {
58
+ handlers = new Set();
59
+ this.listeners.set(event, handlers);
60
+ }
61
+ handlers.add(handler);
62
+ }
63
+ off(event, handler) {
64
+ const handlers = this.listeners.get(event);
65
+ if (handlers) {
66
+ handlers.delete(handler);
67
+ }
68
+ }
69
+ once(event) {
70
+ return new Promise((resolve) => {
71
+ const handler = (params) => {
72
+ this.off(event, handler);
73
+ resolve(params);
74
+ };
75
+ this.on(event, handler);
76
+ });
77
+ }
78
+ close() {
79
+ this.ws.close();
80
+ for (const { reject } of this.pending.values()) {
81
+ reject(new Error("CDP connection closed"));
82
+ }
83
+ this.pending.clear();
84
+ }
85
+ }
86
+ //# sourceMappingURL=cdp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cdp.js","sourceRoot":"","sources":["../src/cdp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { type ChildProcess } from "node:child_process";
2
+ interface ChromiumInstance {
3
+ process: ChildProcess;
4
+ wsUrl: string;
5
+ close: () => void;
6
+ }
7
+ export declare function launchChromium(options: {
8
+ width: number;
9
+ height: number;
10
+ }): Promise<ChromiumInstance>;
11
+ export {};
12
+ //# sourceMappingURL=chromium.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chromium.d.ts","sourceRoot":"","sources":["../src/chromium.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAS,MAAM,oBAAoB,CAAC;AA6B9D,UAAU,gBAAgB;IACxB,OAAO,EAAE,YAAY,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,wBAAsB,cAAc,CAAC,OAAO,EAAE;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA0D5B"}
@@ -0,0 +1,75 @@
1
+ import { spawn } from "node:child_process";
2
+ import * as fs from "node:fs";
3
+ const CHROMIUM_PATHS = [
4
+ process.env.CHROMIUM_PATH,
5
+ "/usr/bin/chromium",
6
+ "/usr/bin/chromium-browser",
7
+ "/usr/bin/google-chrome-stable",
8
+ "/usr/bin/google-chrome",
9
+ "/usr/bin/brave-browser",
10
+ "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
11
+ "/Applications/Chromium.app/Contents/MacOS/Chromium",
12
+ "/Applications/Brave Browser.app/Contents/MacOS/Brave Browser",
13
+ "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
14
+ "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
15
+ ];
16
+ function findChromium() {
17
+ for (const candidate of CHROMIUM_PATHS) {
18
+ if (candidate && fs.existsSync(candidate)) {
19
+ return candidate;
20
+ }
21
+ }
22
+ throw new Error("Could not find Chromium. Install chromium or set the CHROMIUM_PATH environment variable.");
23
+ }
24
+ export async function launchChromium(options) {
25
+ const chromiumPath = findChromium();
26
+ const args = [
27
+ "--headless=new",
28
+ "--remote-debugging-port=0",
29
+ "--no-first-run",
30
+ "--no-default-browser-check",
31
+ "--disable-gpu",
32
+ "--disable-extensions",
33
+ "--disable-background-networking",
34
+ "--disable-sync",
35
+ "--disable-translate",
36
+ "--mute-audio",
37
+ "--run-all-compositor-stages-before-draw",
38
+ "--disable-new-content-rendering-timeout",
39
+ `--window-size=${options.width},${options.height}`,
40
+ ];
41
+ const child = spawn(chromiumPath, args, {
42
+ stdio: ["ignore", "ignore", "pipe"],
43
+ });
44
+ const wsUrl = await new Promise((resolve, reject) => {
45
+ const timeout = setTimeout(() => {
46
+ child.kill();
47
+ reject(new Error("Timed out waiting for Chromium DevTools WebSocket URL"));
48
+ }, 15_000);
49
+ let stderr = "";
50
+ child.stderr?.on("data", (chunk) => {
51
+ stderr += chunk.toString();
52
+ const match = /DevTools listening on (ws:\/\/.+)/.exec(stderr);
53
+ if (match) {
54
+ clearTimeout(timeout);
55
+ resolve(match[1]);
56
+ }
57
+ });
58
+ child.on("error", (err) => {
59
+ clearTimeout(timeout);
60
+ reject(err);
61
+ });
62
+ child.on("close", (code) => {
63
+ clearTimeout(timeout);
64
+ reject(new Error(`Chromium exited with code ${code} before DevTools was ready`));
65
+ });
66
+ });
67
+ return {
68
+ process: child,
69
+ wsUrl,
70
+ close() {
71
+ child.kill("SIGTERM");
72
+ },
73
+ };
74
+ }
75
+ //# sourceMappingURL=chromium.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chromium.js","sourceRoot":"","sources":["../src/chromium.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAE9B,MAAM,cAAc,GAAG;IACrB,OAAO,CAAC,GAAG,CAAC,aAAa;IACzB,mBAAmB;IACnB,2BAA2B;IAC3B,+BAA+B;IAC/B,wBAAwB;IACxB,wBAAwB;IACxB,8DAA8D;IAC9D,oDAAoD;IACpD,8DAA8D;IAC9D,4DAA4D;IAC5D,kEAAkE;CACnE,CAAC;AAEF,SAAS,YAAY;IACnB,KAAK,MAAM,SAAS,IAAI,cAAc,EAAE,CAAC;QACvC,IAAI,SAAS,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC1C,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC;IAED,MAAM,IAAI,KAAK,CACb,0FAA0F,CAC3F,CAAC;AACJ,CAAC;AAQD,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAGpC;IACC,MAAM,YAAY,GAAG,YAAY,EAAE,CAAC;IAEpC,MAAM,IAAI,GAAG;QACX,gBAAgB;QAChB,2BAA2B;QAC3B,gBAAgB;QAChB,4BAA4B;QAC5B,eAAe;QACf,sBAAsB;QACtB,iCAAiC;QACjC,gBAAgB;QAChB,qBAAqB;QACrB,cAAc;QACd,yCAAyC;QACzC,yCAAyC;QACzC,iBAAiB,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,MAAM,EAAE;KACnD,CAAC;IAEF,MAAM,KAAK,GAAG,KAAK,CAAC,YAAY,EAAE,IAAI,EAAE;QACtC,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC;KACpC,CAAC,CAAC;IAEH,MAAM,KAAK,GAAG,MAAM,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1D,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YAC9B,KAAK,CAAC,IAAI,EAAE,CAAC;YACb,MAAM,CAAC,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC,CAAC;QAC7E,CAAC,EAAE,MAAM,CAAC,CAAC;QAEX,IAAI,MAAM,GAAG,EAAE,CAAC;QAEhB,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YACzC,MAAM,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YAC3B,MAAM,KAAK,GAAG,mCAAmC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC/D,IAAI,KAAK,EAAE,CAAC;gBACV,YAAY,CAAC,OAAO,CAAC,CAAC;gBACtB,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YACpB,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACxB,YAAY,CAAC,OAAO,CAAC,CAAC;YACtB,MAAM,CAAC,GAAG,CAAC,CAAC;QACd,CAAC,CAAC,CAAC;QAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACzB,YAAY,CAAC,OAAO,CAAC,CAAC;YACtB,MAAM,CAAC,IAAI,KAAK,CAAC,6BAA6B,IAAI,4BAA4B,CAAC,CAAC,CAAC;QACnF,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,OAAO,EAAE,KAAK;QACd,KAAK;QACL,KAAK;YACH,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACxB,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Walkthrough } from "@walkrstudio/core";
2
+ export declare function buildEmbedHtml(frames: Buffer[], fps: number, walkthrough: Walkthrough): string;
3
+ //# sourceMappingURL=embed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embed.d.ts","sourceRoot":"","sources":["../src/embed.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAYrD,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,GAAG,MAAM,CA4hB9F"}