diff --git a/.gitignore b/.gitignore
index 6240da8..48cfc27 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
dist/
# generated types
.astro/
+public/snapshot
# dependencies
node_modules/
diff --git a/astro.config.mjs b/astro.config.mjs
index 4605f7a..b7e7ab3 100644
--- a/astro.config.mjs
+++ b/astro.config.mjs
@@ -12,6 +12,12 @@ export default defineConfig({
site: "https://bomb.sh/",
base: "/docs",
outDir: "./dist/docs/",
+ server: {
+ headers: {
+ 'Cross-Origin-Embedder-Policy': 'require-corp',
+ 'Cross-Origin-Opener-Policy': 'same-origin'
+ }
+ },
integrations: [
starlight({
title: "Bombshell",
diff --git a/package.json b/package.json
index be532aa..2ab6054 100644
--- a/package.json
+++ b/package.json
@@ -4,10 +4,13 @@
"version": "0.0.1",
"scripts": {
"dev": "astro dev",
+ "dev:snapshot": "",
"start": "astro dev",
+ "prebuild": "node run snapshot",
"build": "astro build",
"preview": "astro preview",
- "astro": "astro"
+ "astro": "astro",
+ "snapshot": "node ./scripts/snapshot.ts"
},
"dependencies": {
"@astrojs/starlight": "^0.37.1",
@@ -17,9 +20,17 @@
"@types/node": "^22.19.3",
"astro": "^5.16.6",
"expressive-code-twoslash": "^0.5.3",
+ "@webcontainer/api": "^1.6.1",
+ "@webcontainer/snapshot": "^0.1.0",
+ "@xterm/addon-fit": "^0.11.0",
+ "@xterm/addon-web-links": "^0.12.0",
+ "@xterm/xterm": "^6.0.0",
"sharp": "^0.33.5",
"starlight-sidebar-topics": "^0.6.2"
},
+ "devDependencies": {
+ "tinyexec": "^1.0.2"
+ },
"pnpm": {
"onlyBuiltDependencies": [
"esbuild",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 93c4054..73e0129 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -23,6 +23,21 @@ importers:
'@types/node':
specifier: ^22.19.3
version: 22.19.3
+ '@webcontainer/api':
+ specifier: ^1.6.1
+ version: 1.6.1
+ '@webcontainer/snapshot':
+ specifier: ^0.1.0
+ version: 0.1.0
+ '@xterm/addon-fit':
+ specifier: ^0.11.0
+ version: 0.11.0
+ '@xterm/addon-web-links':
+ specifier: ^0.12.0
+ version: 0.12.0
+ '@xterm/xterm':
+ specifier: ^6.0.0
+ version: 6.0.0
astro:
specifier: ^5.16.6
version: 5.16.6(@types/node@22.19.3)(rollup@4.55.1)(typescript@5.8.2)
@@ -35,6 +50,10 @@ importers:
starlight-sidebar-topics:
specifier: ^0.6.2
version: 0.6.2(@astrojs/starlight@0.37.1(astro@5.16.6(@types/node@22.19.3)(rollup@4.55.1)(typescript@5.8.2)))
+ devDependencies:
+ tinyexec:
+ specifier: ^1.0.2
+ version: 1.0.2
packages:
@@ -526,6 +545,10 @@ packages:
'@mdx-js/mdx@3.1.1':
resolution: {integrity: sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==}
+ '@msgpack/msgpack@3.1.3':
+ resolution: {integrity: sha512-47XIizs9XZXvuJgoaJUIE2lFoID8ugvc0jzSHP+Ptfk8nTbnR8g788wv48N03Kx0UkAv559HWRQ3yzOgzlRNUA==}
+ engines: {node: '>= 18'}
+
'@oslojs/encoding@1.1.0':
resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==}
@@ -773,6 +796,22 @@ packages:
'@ungap/structured-clone@1.3.0':
resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==}
+ '@webcontainer/api@1.6.1':
+ resolution: {integrity: sha512-2RS2KiIw32BY1Icf6M1DvqSmcon9XICZCDgS29QJb2NmF12ZY2V5Ia+949hMKB3Wno+P/Y8W+sPP59PZeXSELg==}
+
+ '@webcontainer/snapshot@0.1.0':
+ resolution: {integrity: sha512-PTIGQ3osUpTbK/dqB8RYbcZGv8IK+DJACx709z5sFbeIlngB3hUFpTEYFYs1SbUvr/AEQqvd0/bhc4ectrPRRw==}
+ engines: {node: '>=16'}
+
+ '@xterm/addon-fit@0.11.0':
+ resolution: {integrity: sha512-jYcgT6xtVYhnhgxh3QgYDnnNMYTcf8ElbxxFzX0IZo+vabQqSPAjC3c1wJrKB5E19VwQei89QCiZZP86DCPF7g==}
+
+ '@xterm/addon-web-links@0.12.0':
+ resolution: {integrity: sha512-4Smom3RPyVp7ZMYOYDoC/9eGJJJqYhnPLGGqJ6wOBfB8VxPViJNSKdgRYb8NpaM6YSelEKbA2SStD7lGyqaobw==}
+
+ '@xterm/xterm@6.0.0':
+ resolution: {integrity: sha512-TQwDdQGtwwDt+2cgKDLn0IRaSxYu1tSUjgKarSDkUM0ZNiSRXFpjxEsvc/Zgc5kq5omJ+V0a8/kIM2WD3sMOYg==}
+
acorn-jsx@5.3.2:
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
peerDependencies:
@@ -2479,6 +2518,8 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@msgpack/msgpack@3.1.3': {}
+
'@oslojs/encoding@1.1.0': {}
'@pagefind/darwin-arm64@1.4.0':
@@ -2676,6 +2717,18 @@ snapshots:
'@ungap/structured-clone@1.3.0': {}
+ '@webcontainer/api@1.6.1': {}
+
+ '@webcontainer/snapshot@0.1.0':
+ dependencies:
+ '@msgpack/msgpack': 3.1.3
+
+ '@xterm/addon-fit@0.11.0': {}
+
+ '@xterm/addon-web-links@0.12.0': {}
+
+ '@xterm/xterm@6.0.0': {}
+
acorn-jsx@5.3.2(acorn@8.15.0):
dependencies:
acorn: 8.15.0
diff --git a/scripts/snapshot.ts b/scripts/snapshot.ts
new file mode 100644
index 0000000..7acb123
--- /dev/null
+++ b/scripts/snapshot.ts
@@ -0,0 +1,45 @@
+import fs from 'node:fs/promises';
+import { fileURLToPath } from 'node:url';
+import { snapshot } from '@webcontainer/snapshot';
+import {x} from 'tinyexec';
+import { createHash } from "node:crypto";
+
+const PACKAGE_JSON = {
+ name: 'example',
+ type: 'module',
+ version: '0.0.0',
+ dependencies: {
+ "@bomb.sh/args": "latest",
+ "@clack/core": "1.0.0-alpha.0",
+ "@clack/prompts": "1.0.0-alpha.0"
+ }
+}
+const IGNORE_FILES = ['*.md', '*.d.*', '*.map', 'LICENSE', 'license'];
+const rootDir = new URL('../', import.meta.url);
+const snapshotDir = new URL(`./snapshot-${hash()}/`, rootDir);
+const outFile = new URL('./public/snapshot', rootDir);
+
+async function run() {
+ await fs.mkdir(snapshotDir, { recursive: true });
+ await fs.writeFile(new URL('package.json', snapshotDir), JSON.stringify(PACKAGE_JSON));
+ await x('npm', ['install'], {
+ nodeOptions: {
+ cwd: fileURLToPath(snapshotDir),
+ }
+ })
+ for await (const file of fs.glob(IGNORE_FILES.map(file => `**/${file}`), { cwd: fileURLToPath(snapshotDir) })) {
+ await fs.rm(new URL(file, snapshotDir));
+ }
+ const output = await snapshot(fileURLToPath(snapshotDir));
+ await fs.writeFile(outFile, output);
+ await fs.rm(snapshotDir, { recursive: true, force: true });
+ console.log('snapshot generated');
+}
+
+run();
+
+function hash() {
+ return createHash("shake256", { outputLength: 8 })
+ .update(Date.now().toString())
+ .digest("hex");
+}
diff --git a/src/components/WebContainer/Terminal.astro b/src/components/WebContainer/Terminal.astro
new file mode 100644
index 0000000..8758b3c
--- /dev/null
+++ b/src/components/WebContainer/Terminal.astro
@@ -0,0 +1,69 @@
+
+