create-browserpod-quickstart 0.9.3

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/index.js ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { createProject } from './src/index.js';
4
+
5
+ createProject().catch((error) => {
6
+ console.error('An unexpected error occurred:', error);
7
+ process.exit(1);
8
+ });
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "create-browserpod-quickstart",
3
+ "version": "0.9.3",
4
+ "description": "Create a new BrowserPod project quickly",
5
+ "type": "module",
6
+ "main": "index.js",
7
+ "bin": {
8
+ "create-browserpod-quickstart": "index.js"
9
+ },
10
+ "engines": {
11
+ "node": "^18.0.0 || >=20.0.0"
12
+ },
13
+ "files": [
14
+ "index.js",
15
+ "src/**/*",
16
+ "templates/**/*"
17
+ ],
18
+ "keywords": [
19
+ "browserpod",
20
+ "template",
21
+ "quickstart",
22
+ "create",
23
+ "cli"
24
+ ],
25
+ "author": "Leaning Technologies",
26
+ "license": "MIT",
27
+ "dependencies": {
28
+ "prompts": "^2.4.2",
29
+ "fs-extra": "^11.2.0",
30
+ "chalk": "^5.3.0"
31
+ },
32
+ "devDependencies": {
33
+ "@types/fs-extra": "^11.0.4",
34
+ "@types/prompts": "^2.4.9"
35
+ },
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "https://github.com/leaningtech/browserpod-meta.git",
39
+ "directory": "packages/browserpod-quickstart"
40
+ },
41
+ "homepage": "https://browserpod.io",
42
+ "bugs": {
43
+ "url": "https://github.com/leaningtech/browserpod-meta/issues"
44
+ }
45
+ }
package/src/index.js ADDED
@@ -0,0 +1,117 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import prompts from 'prompts';
4
+ import chalk from 'chalk';
5
+ import { fileURLToPath } from 'url';
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+
10
+ const templates = [
11
+ {
12
+ name: 'vite-basic',
13
+ display: 'Basic',
14
+ description: 'A simple project running a basic script'
15
+ },
16
+ {
17
+ name: 'vite-web',
18
+ display: 'Web Server',
19
+ description: 'A simple project running a web server'
20
+ }
21
+ ];
22
+
23
+ async function validateProjectName(name) {
24
+ if (!name || name.trim().length === 0) {
25
+ return 'Project name is required';
26
+ }
27
+
28
+ if (!/^[a-z0-9-_]+$/i.test(name)) {
29
+ return 'Project name can only contain letters, numbers, hyphens, and underscores';
30
+ }
31
+
32
+ if (fs.existsSync(name)) {
33
+ return `Directory "${name}" already exists`;
34
+ }
35
+
36
+ return true;
37
+ }
38
+
39
+ async function copyFilesAndDirectories(src, dest, projectName, apiKey) {
40
+ const items = await fs.readdir(src);
41
+
42
+ for (const item of items) {
43
+ const srcPath = path.join(src, item);
44
+ const destPath = path.join(dest, item);
45
+ const stat = await fs.stat(srcPath);
46
+
47
+ if (stat.isDirectory()) {
48
+ await fs.ensureDir(destPath);
49
+ await copyFilesAndDirectories(srcPath, destPath, projectName, apiKey);
50
+ } else {
51
+ let content = await fs.readFile(srcPath, 'utf8');
52
+
53
+ // Replace template variables
54
+ content = content.replace(/\{\{PROJECT_NAME\}\}/g, projectName);
55
+ content = content.replace(/\{\{API_KEY\}\}/g, apiKey || '');
56
+
57
+ await fs.writeFile(destPath, content, 'utf8');
58
+ }
59
+ }
60
+ }
61
+
62
+ async function createProject() {
63
+ console.log(chalk.blue.bold('🚀 Create Browserpod Quickstart\n'));
64
+
65
+ const response = await prompts([
66
+ {
67
+ type: 'select',
68
+ name: 'template',
69
+ message: 'Select a template:',
70
+ choices: templates.map(t => ({
71
+ title: `${t.display} - ${t.description}`,
72
+ value: t.name
73
+ }))
74
+ },
75
+ {
76
+ type: 'text',
77
+ name: 'projectName',
78
+ message: 'Project name:',
79
+ validate: validateProjectName
80
+ },
81
+ {
82
+ type: 'password',
83
+ name: 'apiKey',
84
+ message: 'Browserpod API key (optional):',
85
+ hint: 'You can add this later in the .env file'
86
+ }
87
+ ]);
88
+
89
+ if (!response.template || !response.projectName) {
90
+ console.log(chalk.red('Setup cancelled'));
91
+ process.exit(1);
92
+ }
93
+
94
+ const { template, projectName, apiKey } = response;
95
+ const templatePath = path.join(__dirname, '..', 'templates', template);
96
+ const targetPath = path.resolve(projectName);
97
+
98
+ console.log(chalk.blue(`\n📁 Creating project in ${targetPath}...`));
99
+
100
+ try {
101
+ await fs.ensureDir(targetPath);
102
+ await copyFilesAndDirectories(templatePath, targetPath, projectName, apiKey);
103
+
104
+ console.log(chalk.green.bold('✅ Project created successfully!\n'));
105
+ console.log(chalk.yellow('Next steps:'));
106
+ console.log(` cd ${projectName}`);
107
+ console.log(' npm install');
108
+ console.log(' npm run dev');
109
+ console.log(chalk.gray('\nHappy coding! 🎉'));
110
+
111
+ } catch (error) {
112
+ console.error(chalk.red('Error creating project:'), error.message);
113
+ process.exit(1);
114
+ }
115
+ }
116
+
117
+ export { createProject };
@@ -0,0 +1,10 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>Hello BrowserPod</title>
6
+ </head>
7
+ <body>
8
+ <script type="module" src="/src/main.js"></script>
9
+ </body>
10
+ </html>
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "{{PROJECT_NAME}}",
3
+ "version": "0.0.0",
4
+ "type": "module",
5
+ "scripts": {
6
+ "dev": "vite",
7
+ "build": "vite build",
8
+ "preview": "vite preview"
9
+ },
10
+ "devDependencies": {
11
+ "vite": "^7.2.4"
12
+ },
13
+ "dependencies": {
14
+ "@leaningtech/browserpod": "latest"
15
+ }
16
+ }
@@ -0,0 +1,30 @@
1
+ import { BrowserPod } from '@leaningtech/browserpod'
2
+
3
+ // Initialize the Pod.
4
+ // VITE_BP_APIKEY is an environmental variable containing your Api Key.
5
+ // You can define it by creating a file called `.env` in the project directory
6
+ // with the content `VITE_BP_APIKEY=your-key`.
7
+ // To get an Api Key, visit https://console.browserpod.io .
8
+ const pod = await BrowserPod.boot({apiKey:import.meta.env.VITE_BP_APIKEY});
9
+
10
+ // Create an HTML element to use as our Terminal
11
+ const terminalElem = document.createElement("pre");
12
+ document.body.appendChild(terminalElem);
13
+ // Create a Terminal
14
+ const terminal = await pod.createDefaultTerminal(terminalElem);
15
+
16
+ // A simple script that we want to execute inside the Pod
17
+ const script = `
18
+ const fs = require("node:fs");
19
+ console.log("hello from node", process.version);
20
+ const rootContents = fs.readdirSync("/");
21
+ console.log(rootContents);
22
+ process.exit(0);
23
+ `;
24
+ // Write the script into the Pod's filesystem
25
+ const scriptFile = await pod.createFile("/script.js", "utf-8");
26
+ await scriptFile.write(script);
27
+ await scriptFile.close();
28
+ // Run the script
29
+ await pod.run("node", ["script.js"], {terminal:terminal});
30
+ console.log("done!");
@@ -0,0 +1,11 @@
1
+ import { defineConfig } from 'vite';
2
+
3
+ // https://vitejs.dev/config/
4
+ export default defineConfig({
5
+ server: {
6
+ headers: {
7
+ 'Cross-Origin-Embedder-Policy': 'require-corp',
8
+ 'Cross-Origin-Opener-Policy': 'same-origin'
9
+ }
10
+ }
11
+ });
@@ -0,0 +1,13 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>Hello BrowserPod</title>
6
+ </head>
7
+ <body>
8
+ <div id="url">Waiting for portal...</div>
9
+ <iframe id="portal"></iframe>
10
+ <div class="console" id="console"></div>
11
+ <script type="module" src="/src/main.js"></script>
12
+ </body>
13
+ </html>
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "{{PROJECT_NAME}}",
3
+ "version": "0.0.0",
4
+ "type": "module",
5
+ "scripts": {
6
+ "dev": "vite",
7
+ "build": "vite build",
8
+ "preview": "vite preview"
9
+ },
10
+ "devDependencies": {
11
+ "vite": "^7.2.4"
12
+ },
13
+ "dependencies": {
14
+ "@leaningtech/browserpod": "latest"
15
+ }
16
+ }
@@ -0,0 +1,11 @@
1
+ const express = require('express')
2
+ const app = express()
3
+ const port = 3000
4
+
5
+ app.get('/', (req, res) => {
6
+ res.send('Hello World!')
7
+ })
8
+
9
+ app.listen(port, () => {
10
+ console.log(`Example app listening on port ${port}`)
11
+ })
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "expressjs-tutorial",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "main.js",
6
+ "scripts": {
7
+ },
8
+ "author": "",
9
+ "license": "MIT",
10
+ "dependencies": {
11
+ "express": "^5.1.0"
12
+ }
13
+ }
@@ -0,0 +1,32 @@
1
+ import { BrowserPod } from '@leaningtech/browserpod'
2
+ import { copyFile } from './utils'
3
+
4
+ // Initialize the Pod.
5
+ // VITE_BP_APIKEY is an environmental variable containing your Api Key.
6
+ // You can define it by creating a file called `.env` in the project directory
7
+ // with the content `VITE_BP_APIKEY=your-key`.
8
+ // To get an Api Key, visit https://console.browserpod.io .
9
+ const pod = await BrowserPod.boot({apiKey:import.meta.env.VITE_BP_APIKEY});
10
+
11
+ // Create a Terminal
12
+ const terminalElem = document.getElementById("console");
13
+ document.body.appendChild(terminalElem);
14
+ const terminal = await pod.createDefaultTerminal(terminalElem);
15
+
16
+ // Hook the portal to preview the web page in an iframe
17
+ const portalIframe = document.getElementById("portal");
18
+ const urlDiv = document.getElementById("url");
19
+ pod.onPortal(({ url, port }) => {
20
+ urlDiv.innerHTML = `Portal available at <a href="${url}">${url}</a> for local server listening on port ${port}`;
21
+ portalIframe.src = url;
22
+ });
23
+
24
+ // Copy our project files
25
+ await pod.createDirectory("/project");
26
+ await copyFile(pod, "project/main.js");
27
+ await copyFile(pod, "project/package.json");
28
+
29
+ // Install dependencies
30
+ await pod.run("npm", ["install"], {echo:true, terminal:terminal, cwd: "/project"});
31
+ // Run the web server
32
+ await pod.run("node", ["main.js"], {echo:true, terminal:terminal, cwd: "/project"});
@@ -0,0 +1,7 @@
1
+ export async function copyFile(pod, path) {
2
+ const f = await pod.createFile("/"+path, "binary");
3
+ const resp = await fetch(path);
4
+ const buf = await resp.arrayBuffer();
5
+ await f.write(buf);
6
+ await f.close();
7
+ }
@@ -0,0 +1,11 @@
1
+ import { defineConfig } from 'vite';
2
+
3
+ // https://vitejs.dev/config/
4
+ export default defineConfig({
5
+ server: {
6
+ headers: {
7
+ 'Cross-Origin-Embedder-Policy': 'require-corp',
8
+ 'Cross-Origin-Opener-Policy': 'same-origin'
9
+ }
10
+ }
11
+ });