@vibeo/renderer 0.1.0 → 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.
package/dist/bundler.d.ts CHANGED
@@ -7,4 +7,9 @@ import type { BundleResult } from "./types.js";
7
7
  * and mounts it with ReactDOM.createRoot.
8
8
  */
9
9
  export declare function bundle(entryPoint: string): Promise<BundleResult>;
10
+ /**
11
+ * Bundle the user's React entry point for the visual editor.
12
+ * Same pattern as bundle() but renders <Editor> instead of <Player>.
13
+ */
14
+ export declare function bundleForEditor(entryPoint: string, port?: number): Promise<BundleResult>;
10
15
  //# sourceMappingURL=bundler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bundler.d.ts","sourceRoot":"","sources":["../src/bundler.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C;;;;;;GAMG;AACH,wBAAsB,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAqItE"}
1
+ {"version":3,"file":"bundler.d.ts","sourceRoot":"","sources":["../src/bundler.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AA0D/C;;;;;;GAMG;AACH,wBAAsB,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAyItE;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACnC,UAAU,EAAE,MAAM,EAClB,IAAI,GAAE,MAAa,GAClB,OAAO,CAAC,YAAY,CAAC,CA6HvB"}
package/dist/bundler.js CHANGED
@@ -1,6 +1,54 @@
1
1
  import { mkdtemp, rm } from "node:fs/promises";
2
- import { join, dirname } from "node:path";
2
+ import { join, dirname, resolve } from "node:path";
3
3
  import { tmpdir } from "node:os";
4
+ import { existsSync } from "node:fs";
5
+ /**
6
+ * Find the monorepo root by walking up from the entry file until we find
7
+ * the packages/ directory. Returns null if not found.
8
+ */
9
+ function findMonorepoRoot(startDir) {
10
+ let dir = startDir;
11
+ for (let i = 0; i < 10; i++) {
12
+ if (existsSync(join(dir, "packages", "core", "src", "index.ts"))) {
13
+ return dir;
14
+ }
15
+ const parent = dirname(dir);
16
+ if (parent === dir)
17
+ break;
18
+ dir = parent;
19
+ }
20
+ return null;
21
+ }
22
+ /**
23
+ * Bun.build plugin that resolves all @vibeo/* bare-specifier imports to
24
+ * their source .ts/.tsx files. This prevents the bundler from pulling in
25
+ * BOTH the compiled dist/ AND the source for the same package, which
26
+ * would duplicate React contexts and break provider/consumer pairing.
27
+ */
28
+ function vibeoSourcePlugin(monoRoot) {
29
+ const pkgMap = {};
30
+ for (const name of [
31
+ "core",
32
+ "player",
33
+ "audio",
34
+ "effects",
35
+ "extras",
36
+ "editor",
37
+ ]) {
38
+ pkgMap[`@vibeo/${name}`] = resolve(monoRoot, "packages", name, "src", "index.ts");
39
+ }
40
+ return {
41
+ name: "vibeo-source-resolver",
42
+ setup(build) {
43
+ build.onResolve({ filter: /^@vibeo\// }, (args) => {
44
+ const src = pkgMap[args.path];
45
+ if (src)
46
+ return { path: src };
47
+ return undefined;
48
+ });
49
+ },
50
+ };
51
+ }
4
52
  /**
5
53
  * Bundle the user's React entry point using Bun.build,
6
54
  * then serve it via a local HTTP server for the headless browser to load.
@@ -71,6 +119,8 @@ root.render(React.createElement(PreviewApp));
71
119
  window.vibeo_ready = true;
72
120
  `);
73
121
  try {
122
+ const monoRoot = findMonorepoRoot(entryDir);
123
+ const plugins = monoRoot ? [vibeoSourcePlugin(monoRoot)] : [];
74
124
  const result = await Bun.build({
75
125
  entrypoints: [bootstrapPath],
76
126
  outdir: outDir,
@@ -78,6 +128,7 @@ window.vibeo_ready = true;
78
128
  format: "esm",
79
129
  minify: false,
80
130
  splitting: false,
131
+ plugins,
81
132
  define: {
82
133
  "process.env.NODE_ENV": JSON.stringify("production"),
83
134
  },
@@ -132,4 +183,119 @@ window.vibeo_ready = true;
132
183
  await rm(bootstrapPath, { force: true });
133
184
  }
134
185
  }
186
+ /**
187
+ * Bundle the user's React entry point for the visual editor.
188
+ * Same pattern as bundle() but renders <Editor> instead of <Player>.
189
+ */
190
+ export async function bundleForEditor(entryPoint, port = 3001) {
191
+ const outDir = await mkdtemp(join(tmpdir(), "vibeo-editor-bundle-"));
192
+ const entryDir = dirname(entryPoint);
193
+ const bootstrapPath = join(entryDir, "__vibeo_editor_entry.tsx");
194
+ await Bun.write(bootstrapPath, `import React from "react";
195
+ import { createRoot } from "react-dom/client";
196
+ import { Root } from ${JSON.stringify(entryPoint)};
197
+ import { Editor } from "@vibeo/editor";
198
+ import { VibeoRoot, useCompositionContext } from "@vibeo/core";
199
+
200
+ function EditorShell() {
201
+ const { compositions } = useCompositionContext();
202
+
203
+ const entries = [];
204
+ for (const [, comp] of compositions) {
205
+ entries.push({
206
+ id: comp.id,
207
+ name: comp.id,
208
+ component: comp.component,
209
+ width: comp.width,
210
+ height: comp.height,
211
+ fps: comp.fps,
212
+ durationInFrames: comp.durationInFrames,
213
+ });
214
+ }
215
+
216
+ if (entries.length === 0) {
217
+ return React.createElement("div", {
218
+ style: { color: "#888", fontFamily: "sans-serif", padding: 40 }
219
+ }, "Loading compositions...");
220
+ }
221
+
222
+ return React.createElement(Editor, { compositions: entries });
223
+ }
224
+
225
+ function EditorApp() {
226
+ return React.createElement(VibeoRoot, null,
227
+ React.createElement(Root),
228
+ React.createElement(EditorShell),
229
+ );
230
+ }
231
+
232
+ const container = document.getElementById("root");
233
+ const root = createRoot(container);
234
+ root.render(React.createElement(EditorApp));
235
+
236
+ window.vibeo_ready = true;
237
+ `);
238
+ try {
239
+ const monoRoot = findMonorepoRoot(entryDir);
240
+ const plugins = monoRoot ? [vibeoSourcePlugin(monoRoot)] : [];
241
+ const result = await Bun.build({
242
+ entrypoints: [bootstrapPath],
243
+ outdir: outDir,
244
+ target: "browser",
245
+ format: "esm",
246
+ minify: false,
247
+ splitting: false,
248
+ plugins,
249
+ define: {
250
+ "process.env.NODE_ENV": JSON.stringify("production"),
251
+ },
252
+ });
253
+ if (!result.success) {
254
+ const messages = result.logs.map((l) => l.message).join("\n");
255
+ throw new Error(`Editor bundle failed:\n${messages}`);
256
+ }
257
+ const bundleName = result.outputs[0]?.path.split("/").pop() ?? "__vibeo_editor_entry.js";
258
+ const html = `<!DOCTYPE html>
259
+ <html>
260
+ <head>
261
+ <meta charset="utf-8" />
262
+ <title>Vibeo Editor</title>
263
+ <style>
264
+ * { margin: 0; padding: 0; box-sizing: border-box; }
265
+ html, body, #root { width: 100%; height: 100%; overflow: hidden; }
266
+ </style>
267
+ </head>
268
+ <body>
269
+ <div id="root"></div>
270
+ <script type="module" src="/${bundleName}"></script>
271
+ </body>
272
+ </html>`;
273
+ await Bun.write(join(outDir, "index.html"), html);
274
+ const server = Bun.serve({
275
+ port,
276
+ async fetch(req) {
277
+ const url = new URL(req.url);
278
+ const filePath = join(outDir, url.pathname === "/" ? "index.html" : url.pathname);
279
+ const file = Bun.file(filePath);
280
+ if (await file.exists()) {
281
+ return new Response(file);
282
+ }
283
+ return new Response("Not found", { status: 404 });
284
+ },
285
+ });
286
+ const serverPort = server.port ?? port;
287
+ const cleanup = async () => {
288
+ server.stop(true);
289
+ await rm(outDir, { recursive: true, force: true });
290
+ };
291
+ return {
292
+ outDir,
293
+ url: `http://localhost:${serverPort}`,
294
+ cleanup,
295
+ };
296
+ }
297
+ finally {
298
+ await rm(bootstrapPath, { force: true });
299
+ }
300
+ }
135
301
  //# sourceMappingURL=bundler.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"bundler.js","sourceRoot":"","sources":["../src/bundler.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bundler.js","sourceRoot":"","sources":["../src/bundler.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export type { RenderConfig, RenderProgress, Codec, ImageFormat, FrameRange, StitchOptions, AudioMuxOptions, BundleResult, } from "./types.js";
2
2
  export { launchBrowser, closeBrowser, createPage } from "./browser.js";
3
- export { bundle } from "./bundler.js";
3
+ export { bundle, bundleForEditor } from "./bundler.js";
4
4
  export { seekToFrame, loadBundle } from "./seek-to-frame.js";
5
5
  export { captureFrame } from "./capture-frame.js";
6
6
  export { parseFrameRange, getRealFrameRange, validateFrameRange } from "./frame-range.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,YAAY,EACZ,cAAc,EACd,KAAK,EACL,WAAW,EACX,UAAU,EACV,aAAa,EACb,eAAe,EACf,YAAY,GACb,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAGvE,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAGtC,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAG7D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGlD,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAG1F,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGhD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,YAAY,EACZ,cAAc,EACd,KAAK,EACL,WAAW,EACX,UAAU,EACV,aAAa,EACb,eAAe,EACf,YAAY,GACb,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAGvE,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAGvD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAG7D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGlD,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAG1F,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGhD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC"}
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // Browser lifecycle
2
2
  export { launchBrowser, closeBrowser, createPage } from "./browser.js";
3
3
  // Bundler
4
- export { bundle } from "./bundler.js";
4
+ export { bundle, bundleForEditor } from "./bundler.js";
5
5
  // Frame navigation
6
6
  export { seekToFrame, loadBundle } from "./seek-to-frame.js";
7
7
  // Frame capture
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAYA,oBAAoB;AACpB,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAEvE,UAAU;AACV,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC,mBAAmB;AACnB,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAE7D,gBAAgB;AAChB,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,wBAAwB;AACxB,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAE1F,mBAAmB;AACnB,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,qBAAqB;AACrB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,4BAA4B;AAC5B,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAYA,oBAAoB;AACpB,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAEvE,UAAU;AACV,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEvD,mBAAmB;AACnB,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAE7D,gBAAgB;AAChB,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,wBAAwB;AACxB,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAE1F,mBAAmB;AACnB,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,qBAAqB;AACrB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,4BAA4B;AAC5B,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibeo/renderer",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
package/src/bundler.ts CHANGED
@@ -1,8 +1,64 @@
1
1
  import { mkdtemp, rm } from "node:fs/promises";
2
- import { join, dirname } from "node:path";
2
+ import { join, dirname, resolve } from "node:path";
3
3
  import { tmpdir } from "node:os";
4
4
  import type { BundleResult } from "./types.js";
5
5
 
6
+ import { existsSync } from "node:fs";
7
+
8
+ /**
9
+ * Find the monorepo root by walking up from the entry file until we find
10
+ * the packages/ directory. Returns null if not found.
11
+ */
12
+ function findMonorepoRoot(startDir: string): string | null {
13
+ let dir = startDir;
14
+ for (let i = 0; i < 10; i++) {
15
+ if (existsSync(join(dir, "packages", "core", "src", "index.ts"))) {
16
+ return dir;
17
+ }
18
+ const parent = dirname(dir);
19
+ if (parent === dir) break;
20
+ dir = parent;
21
+ }
22
+ return null;
23
+ }
24
+
25
+ /**
26
+ * Bun.build plugin that resolves all @vibeo/* bare-specifier imports to
27
+ * their source .ts/.tsx files. This prevents the bundler from pulling in
28
+ * BOTH the compiled dist/ AND the source for the same package, which
29
+ * would duplicate React contexts and break provider/consumer pairing.
30
+ */
31
+ function vibeoSourcePlugin(monoRoot: string): import("bun").BunPlugin {
32
+ const pkgMap: Record<string, string> = {};
33
+ for (const name of [
34
+ "core",
35
+ "player",
36
+ "audio",
37
+ "effects",
38
+ "extras",
39
+ "editor",
40
+ ]) {
41
+ pkgMap[`@vibeo/${name}`] = resolve(
42
+ monoRoot,
43
+ "packages",
44
+ name,
45
+ "src",
46
+ "index.ts",
47
+ );
48
+ }
49
+
50
+ return {
51
+ name: "vibeo-source-resolver",
52
+ setup(build) {
53
+ build.onResolve({ filter: /^@vibeo\// }, (args) => {
54
+ const src = pkgMap[args.path];
55
+ if (src) return { path: src };
56
+ return undefined;
57
+ });
58
+ },
59
+ };
60
+ }
61
+
6
62
  /**
7
63
  * Bundle the user's React entry point using Bun.build,
8
64
  * then serve it via a local HTTP server for the headless browser to load.
@@ -78,6 +134,9 @@ window.vibeo_ready = true;
78
134
  );
79
135
 
80
136
  try {
137
+ const monoRoot = findMonorepoRoot(entryDir);
138
+ const plugins = monoRoot ? [vibeoSourcePlugin(monoRoot)] : [];
139
+
81
140
  const result = await Bun.build({
82
141
  entrypoints: [bootstrapPath],
83
142
  outdir: outDir,
@@ -85,6 +144,7 @@ window.vibeo_ready = true;
85
144
  format: "esm",
86
145
  minify: false,
87
146
  splitting: false,
147
+ plugins,
88
148
  define: {
89
149
  "process.env.NODE_ENV": JSON.stringify("production"),
90
150
  },
@@ -144,3 +204,137 @@ window.vibeo_ready = true;
144
204
  await rm(bootstrapPath, { force: true });
145
205
  }
146
206
  }
207
+
208
+ /**
209
+ * Bundle the user's React entry point for the visual editor.
210
+ * Same pattern as bundle() but renders <Editor> instead of <Player>.
211
+ */
212
+ export async function bundleForEditor(
213
+ entryPoint: string,
214
+ port: number = 3001,
215
+ ): Promise<BundleResult> {
216
+ const outDir = await mkdtemp(join(tmpdir(), "vibeo-editor-bundle-"));
217
+
218
+ const entryDir = dirname(entryPoint);
219
+ const bootstrapPath = join(entryDir, "__vibeo_editor_entry.tsx");
220
+ await Bun.write(
221
+ bootstrapPath,
222
+ `import React from "react";
223
+ import { createRoot } from "react-dom/client";
224
+ import { Root } from ${JSON.stringify(entryPoint)};
225
+ import { Editor } from "@vibeo/editor";
226
+ import { VibeoRoot, useCompositionContext } from "@vibeo/core";
227
+
228
+ function EditorShell() {
229
+ const { compositions } = useCompositionContext();
230
+
231
+ const entries = [];
232
+ for (const [, comp] of compositions) {
233
+ entries.push({
234
+ id: comp.id,
235
+ name: comp.id,
236
+ component: comp.component,
237
+ width: comp.width,
238
+ height: comp.height,
239
+ fps: comp.fps,
240
+ durationInFrames: comp.durationInFrames,
241
+ });
242
+ }
243
+
244
+ if (entries.length === 0) {
245
+ return React.createElement("div", {
246
+ style: { color: "#888", fontFamily: "sans-serif", padding: 40 }
247
+ }, "Loading compositions...");
248
+ }
249
+
250
+ return React.createElement(Editor, { compositions: entries });
251
+ }
252
+
253
+ function EditorApp() {
254
+ return React.createElement(VibeoRoot, null,
255
+ React.createElement(Root),
256
+ React.createElement(EditorShell),
257
+ );
258
+ }
259
+
260
+ const container = document.getElementById("root");
261
+ const root = createRoot(container);
262
+ root.render(React.createElement(EditorApp));
263
+
264
+ window.vibeo_ready = true;
265
+ `,
266
+ );
267
+
268
+ try {
269
+ const monoRoot = findMonorepoRoot(entryDir);
270
+ const plugins = monoRoot ? [vibeoSourcePlugin(monoRoot)] : [];
271
+
272
+ const result = await Bun.build({
273
+ entrypoints: [bootstrapPath],
274
+ outdir: outDir,
275
+ target: "browser",
276
+ format: "esm",
277
+ minify: false,
278
+ splitting: false,
279
+ plugins,
280
+ define: {
281
+ "process.env.NODE_ENV": JSON.stringify("production"),
282
+ },
283
+ });
284
+
285
+ if (!result.success) {
286
+ const messages = result.logs.map((l) => l.message).join("\n");
287
+ throw new Error(`Editor bundle failed:\n${messages}`);
288
+ }
289
+
290
+ const bundleName =
291
+ result.outputs[0]?.path.split("/").pop() ?? "__vibeo_editor_entry.js";
292
+ const html = `<!DOCTYPE html>
293
+ <html>
294
+ <head>
295
+ <meta charset="utf-8" />
296
+ <title>Vibeo Editor</title>
297
+ <style>
298
+ * { margin: 0; padding: 0; box-sizing: border-box; }
299
+ html, body, #root { width: 100%; height: 100%; overflow: hidden; }
300
+ </style>
301
+ </head>
302
+ <body>
303
+ <div id="root"></div>
304
+ <script type="module" src="/${bundleName}"></script>
305
+ </body>
306
+ </html>`;
307
+
308
+ await Bun.write(join(outDir, "index.html"), html);
309
+
310
+ const server = Bun.serve({
311
+ port,
312
+ async fetch(req) {
313
+ const url = new URL(req.url);
314
+ const filePath = join(
315
+ outDir,
316
+ url.pathname === "/" ? "index.html" : url.pathname,
317
+ );
318
+ const file = Bun.file(filePath);
319
+ if (await file.exists()) {
320
+ return new Response(file);
321
+ }
322
+ return new Response("Not found", { status: 404 });
323
+ },
324
+ });
325
+ const serverPort = server.port ?? port;
326
+
327
+ const cleanup = async () => {
328
+ server.stop(true);
329
+ await rm(outDir, { recursive: true, force: true });
330
+ };
331
+
332
+ return {
333
+ outDir,
334
+ url: `http://localhost:${serverPort}`,
335
+ cleanup,
336
+ };
337
+ } finally {
338
+ await rm(bootstrapPath, { force: true });
339
+ }
340
+ }
package/src/index.ts CHANGED
@@ -14,7 +14,7 @@ export type {
14
14
  export { launchBrowser, closeBrowser, createPage } from "./browser.js";
15
15
 
16
16
  // Bundler
17
- export { bundle } from "./bundler.js";
17
+ export { bundle, bundleForEditor } from "./bundler.js";
18
18
 
19
19
  // Frame navigation
20
20
  export { seekToFrame, loadBundle } from "./seek-to-frame.js";