@tutorialkit-rb/cli 0.1.7 → 0.1.9
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/index.js +47 -38
- package/package.json +1 -1
- package/template/bin/build-pack +29 -7
- package/template/package.json +5 -5
- package/template/ruby-wasm/bin/pack-gems +6 -21
- package/template/ruby-wasm/package.json +1 -4
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ import "yargs-parser";
|
|
|
14
14
|
// package.json
|
|
15
15
|
var package_default = {
|
|
16
16
|
name: "@tutorialkit-rb/cli",
|
|
17
|
-
version: "0.1.
|
|
17
|
+
version: "0.1.9",
|
|
18
18
|
description: "Interactive tutorials powered by WebContainer API",
|
|
19
19
|
author: "StackBlitz Inc.",
|
|
20
20
|
type: "module",
|
|
@@ -675,30 +675,32 @@ import path4 from "node:path";
|
|
|
675
675
|
import * as prompts3 from "@clack/prompts";
|
|
676
676
|
import chalk4 from "chalk";
|
|
677
677
|
|
|
678
|
-
// src/commands/create/hosting-config/
|
|
679
|
-
var
|
|
678
|
+
// src/commands/create/hosting-config/Dockerfile.txt?raw
|
|
679
|
+
var Dockerfile_default = `# Minimal nginx image to serve pre-built static files
|
|
680
|
+
# Build happens in GitHub Actions (with WASM caching), not here
|
|
680
681
|
|
|
681
|
-
|
|
682
|
-
var netlify_toml_default = '[[headers]]\n for = "/*"\n [headers.values]\n Cross-Origin-Embedder-Policy = "require-corp"\n Cross-Origin-Opener-Policy = "same-origin"\n';
|
|
682
|
+
FROM nginx:alpine
|
|
683
683
|
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
]
|
|
701
|
-
|
|
684
|
+
# Copy pre-built site from GitHub Actions
|
|
685
|
+
COPY dist /usr/share/nginx/html
|
|
686
|
+
|
|
687
|
+
# Add required headers for WebContainers (SharedArrayBuffer support)
|
|
688
|
+
RUN echo 'add_header Cross-Origin-Embedder-Policy "require-corp";' > /etc/nginx/conf.d/custom-headers.conf \\
|
|
689
|
+
&& echo 'add_header Cross-Origin-Opener-Policy "same-origin";' >> /etc/nginx/conf.d/custom-headers.conf \\
|
|
690
|
+
&& echo 'add_header Cross-Origin-Resource-Policy "cross-origin";' >> /etc/nginx/conf.d/custom-headers.conf
|
|
691
|
+
|
|
692
|
+
EXPOSE 80
|
|
693
|
+
CMD ["nginx", "-g", "daemon off;"]
|
|
694
|
+
`;
|
|
695
|
+
|
|
696
|
+
// src/commands/create/hosting-config/deploy_flyio_yml.txt?raw
|
|
697
|
+
var deploy_flyio_yml_default = "name: Build and Deploy\n\non:\n push:\n branches: [main]\n workflow_dispatch:\n\nconcurrency:\n group: deploy\n cancel-in-progress: false\n\njobs:\n build:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n\n - uses: actions-rust-lang/setup-rust-toolchain@v1\n with:\n toolchain: 1.74.0\n\n - name: Install wasi-vfs\n env:\n WASI_VFS_VERSION: 0.5.4\n run: |\n curl -LO \"https://github.com/kateinoigakukun/wasi-vfs/releases/download/v${WASI_VFS_VERSION}/wasi-vfs-cli-x86_64-unknown-linux-gnu.zip\"\n unzip wasi-vfs-cli-x86_64-unknown-linux-gnu.zip\n mv wasi-vfs /usr/local/bin/wasi-vfs\n\n - uses: ruby/setup-ruby@v1\n env:\n BUNDLE_GEMFILE: ruby-wasm/Gemfile\n BUNDLE_PATH: ruby-wasm/vendor\n with:\n ruby-version: 3.3\n bundler-cache: true\n\n - uses: actions/setup-node@v4\n with:\n node-version: 20\n cache: npm\n\n - name: Cache ruby.wasm build artifacts\n uses: actions/cache@v4\n with:\n path: |\n ruby-wasm/build\n ruby-wasm/rubies\n key: ${{ runner.os }}-ruby-wasm-${{ hashFiles('ruby-wasm/Gemfile.lock') }}\n restore-keys: |\n ${{ runner.os }}-ruby-wasm-\n\n - name: Build ruby.wasm\n run: npm run build:wasm\n\n - name: Build tutorial\n run: |\n npm install\n npm run build\n\n - name: Setup flyctl\n if: github.ref == 'refs/heads/main' || github.event_name == 'workflow_dispatch'\n uses: superfly/flyctl-actions/setup-flyctl@master\n\n - name: Deploy to Fly.io\n if: github.ref == 'refs/heads/main' || github.event_name == 'workflow_dispatch'\n run: flyctl deploy --local-only\n env:\n FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}\n";
|
|
698
|
+
|
|
699
|
+
// src/commands/create/hosting-config/fly_toml.txt?raw
|
|
700
|
+
var fly_toml_default = "# Fly.io configuration\n# Update 'app' to your Fly.io app name after running: fly apps create <name>\napp = 'my-tutorial'\nprimary_region = 'sjc'\n\n[build]\n\n[http_service]\n internal_port = 80\n force_https = true\n auto_stop_machines = 'stop'\n auto_start_machines = true\n min_machines_running = 0\n processes = ['app']\n\n[[vm]]\n size = 'shared-cpu-1x'\n";
|
|
701
|
+
|
|
702
|
+
// src/commands/create/hosting-config/netlify_toml.txt?raw
|
|
703
|
+
var netlify_toml_default = '[build]\n publish = "./dist"\n command = "# no build needed \u2014 CI handles the build"\n\n[[headers]]\n for = "/*"\n [headers.values]\n Cross-Origin-Embedder-Policy = "require-corp"\n Cross-Origin-Opener-Policy = "same-origin"\n';
|
|
702
704
|
|
|
703
705
|
// src/commands/create/generate-hosting-config.ts
|
|
704
706
|
async function generateHostingConfig(dest, flags) {
|
|
@@ -707,9 +709,11 @@ async function generateHostingConfig(dest, flags) {
|
|
|
707
709
|
provider = await prompts3.select({
|
|
708
710
|
message: "Select hosting providers for automatic configuration:",
|
|
709
711
|
options: [
|
|
710
|
-
{ value: "Vercel", label: "Vercel" },
|
|
711
712
|
{ value: "Netlify", label: "Netlify" },
|
|
712
|
-
{ value: "
|
|
713
|
+
{ value: "Fly.io", label: "Fly.io" },
|
|
714
|
+
// TODO: re-enable when full deployment pipelines are added
|
|
715
|
+
// { value: 'Vercel', label: 'Vercel' },
|
|
716
|
+
// { value: 'Cloudflare', label: 'Cloudflare' },
|
|
713
717
|
{ value: "skip", label: "Skip hosting configuration" }
|
|
714
718
|
],
|
|
715
719
|
initialValue: DEFAULT_VALUES.provider
|
|
@@ -731,20 +735,20 @@ async function generateHostingConfig(dest, flags) {
|
|
|
731
735
|
}
|
|
732
736
|
let config;
|
|
733
737
|
let filename;
|
|
738
|
+
let extraFiles;
|
|
734
739
|
switch (provider.toLowerCase()) {
|
|
735
|
-
case "vercel": {
|
|
736
|
-
config = typeof vercel_default === "string" ? vercel_default : JSON.stringify(vercel_default, null, 2);
|
|
737
|
-
filename = "vercel.json";
|
|
738
|
-
break;
|
|
739
|
-
}
|
|
740
740
|
case "netlify": {
|
|
741
741
|
config = netlify_toml_default;
|
|
742
742
|
filename = "netlify.toml";
|
|
743
743
|
break;
|
|
744
744
|
}
|
|
745
|
-
case "
|
|
746
|
-
config =
|
|
747
|
-
filename = "
|
|
745
|
+
case "fly.io": {
|
|
746
|
+
config = fly_toml_default;
|
|
747
|
+
filename = "fly.toml";
|
|
748
|
+
extraFiles = [
|
|
749
|
+
{ filename: "Dockerfile", content: Dockerfile_default },
|
|
750
|
+
{ filename: path4.join(".github", "workflows", "deploy.yml"), content: deploy_flyio_yml_default }
|
|
751
|
+
];
|
|
748
752
|
break;
|
|
749
753
|
}
|
|
750
754
|
}
|
|
@@ -756,7 +760,16 @@ async function generateHostingConfig(dest, flags) {
|
|
|
756
760
|
task: async () => {
|
|
757
761
|
const filepath = path4.join(resolvedDest, filename);
|
|
758
762
|
fs3.writeFileSync(filepath, config);
|
|
759
|
-
|
|
763
|
+
const added = [filepath];
|
|
764
|
+
if (extraFiles) {
|
|
765
|
+
for (const extra of extraFiles) {
|
|
766
|
+
const extraPath = path4.join(resolvedDest, extra.filename);
|
|
767
|
+
fs3.mkdirSync(path4.dirname(extraPath), { recursive: true });
|
|
768
|
+
fs3.writeFileSync(extraPath, extra.content);
|
|
769
|
+
added.push(extraPath);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
return added.map((f) => `Added ${f}`).join("\n");
|
|
760
773
|
}
|
|
761
774
|
});
|
|
762
775
|
}
|
|
@@ -1122,10 +1135,6 @@ function updatePackageJson(dest, projectName, flags, provider) {
|
|
|
1122
1135
|
pkgJson.name = projectName;
|
|
1123
1136
|
updateWorkspaceVersions(pkgJson.dependencies, TUTORIALKIT_VERSION);
|
|
1124
1137
|
updateWorkspaceVersions(pkgJson.devDependencies, TUTORIALKIT_VERSION);
|
|
1125
|
-
if (provider.toLowerCase() === "cloudflare") {
|
|
1126
|
-
pkgJson.scripts = pkgJson.scripts || {};
|
|
1127
|
-
pkgJson.scripts.postbuild = "cp _headers ./dist/";
|
|
1128
|
-
}
|
|
1129
1138
|
fs7.writeFileSync(pkgPath, JSON.stringify(pkgJson, null, 2));
|
|
1130
1139
|
try {
|
|
1131
1140
|
const pkgLockPath = path8.resolve(dest, "package-lock.json");
|
package/package.json
CHANGED
package/template/bin/build-pack
CHANGED
|
@@ -7,7 +7,7 @@ set -e
|
|
|
7
7
|
#
|
|
8
8
|
# This is the fast path (~30s) compared to the monolithic `bin/build-wasm`
|
|
9
9
|
# (~5-20min). Requires a pre-built base binary (from bin/build-ruby-base
|
|
10
|
-
# or
|
|
10
|
+
# or downloaded from GitHub Releases).
|
|
11
11
|
#
|
|
12
12
|
# Usage: ./bin/build-pack
|
|
13
13
|
|
|
@@ -38,12 +38,34 @@ if [ -f "$RUBY_WASM_DIR/dist/ruby-base.wasm" ]; then
|
|
|
38
38
|
echo " Found: local build (dist/ruby-base.wasm)"
|
|
39
39
|
fi
|
|
40
40
|
|
|
41
|
-
# 2.
|
|
41
|
+
# 2. GitHub Releases fallback
|
|
42
42
|
if [ -z "$BASE_WASM" ]; then
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
echo " Not found locally, downloading from GitHub Releases..."
|
|
44
|
+
DOWNLOAD_DIR="$RUBY_WASM_DIR/dist"
|
|
45
|
+
mkdir -p "$DOWNLOAD_DIR"
|
|
46
|
+
DOWNLOAD_PATH="$DOWNLOAD_DIR/ruby-base.wasm"
|
|
47
|
+
|
|
48
|
+
REPO="Bakaface/tutorialkit.rb"
|
|
49
|
+
|
|
50
|
+
if command -v gh &> /dev/null; then
|
|
51
|
+
TAG=$(gh release list --repo "$REPO" --json tagName --jq '[.[] | select(.tagName | startswith("ruby-base-"))][0].tagName' 2>/dev/null)
|
|
52
|
+
|
|
53
|
+
if [ -n "$TAG" ]; then
|
|
54
|
+
echo " Release: $TAG"
|
|
55
|
+
gh release download "$TAG" --repo "$REPO" --pattern "ruby-base.wasm" --dir "$DOWNLOAD_DIR" --clobber 2>/dev/null
|
|
56
|
+
|
|
57
|
+
# Also download rbconfig if not present locally
|
|
58
|
+
RBCONFIG_DIR="$RUBY_WASM_DIR/rbconfig/wasm32-wasi"
|
|
59
|
+
if [ ! -f "$RBCONFIG_DIR/rbconfig.rb" ]; then
|
|
60
|
+
mkdir -p "$RBCONFIG_DIR"
|
|
61
|
+
gh release download "$TAG" --repo "$REPO" --pattern "rbconfig.rb" --dir "$RBCONFIG_DIR" --clobber 2>/dev/null
|
|
62
|
+
fi
|
|
63
|
+
fi
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
if [ -f "$DOWNLOAD_PATH" ]; then
|
|
67
|
+
BASE_WASM="$DOWNLOAD_PATH"
|
|
68
|
+
echo " Downloaded from GitHub Releases"
|
|
47
69
|
fi
|
|
48
70
|
fi
|
|
49
71
|
|
|
@@ -51,7 +73,7 @@ if [ -z "$BASE_WASM" ]; then
|
|
|
51
73
|
echo
|
|
52
74
|
echo "Error: No base WASM binary found."
|
|
53
75
|
echo "Either run 'bin/build-ruby-base' to build one,"
|
|
54
|
-
echo "or
|
|
76
|
+
echo "or ensure a ruby-base release exists on GitHub."
|
|
55
77
|
exit 1
|
|
56
78
|
fi
|
|
57
79
|
|
package/template/package.json
CHANGED
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
"@codemirror/lang-yaml": "^6.1.2",
|
|
23
23
|
"@codemirror/legacy-modes": "^6.5.1",
|
|
24
24
|
"@nanostores/react": "0.7.2",
|
|
25
|
-
"@tutorialkit-rb/react": "0.1.
|
|
26
|
-
"@tutorialkit-rb/runtime": "0.1.
|
|
25
|
+
"@tutorialkit-rb/react": "0.1.9",
|
|
26
|
+
"@tutorialkit-rb/runtime": "0.1.9",
|
|
27
27
|
"nanostores": "^0.10.3",
|
|
28
28
|
"react": "^18.3.1",
|
|
29
29
|
"react-dom": "^18.3.1"
|
|
@@ -31,9 +31,9 @@
|
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@astrojs/check": "^0.7.0",
|
|
33
33
|
"@astrojs/react": "^3.6.0",
|
|
34
|
-
"@tutorialkit-rb/astro": "0.1.
|
|
35
|
-
"@tutorialkit-rb/theme": "0.1.
|
|
36
|
-
"@tutorialkit-rb/types": "0.1.
|
|
34
|
+
"@tutorialkit-rb/astro": "0.1.9",
|
|
35
|
+
"@tutorialkit-rb/theme": "0.1.9",
|
|
36
|
+
"@tutorialkit-rb/types": "0.1.9",
|
|
37
37
|
"@types/mdast": "^4.0.4",
|
|
38
38
|
"@types/node": "^20.14.6",
|
|
39
39
|
"@types/react": "^18.3.3",
|
|
@@ -78,28 +78,18 @@ def find_rbconfig
|
|
|
78
78
|
shipped = File.join(SCRIPT_DIR, "rbconfig", "wasm32-wasi", "rbconfig.rb")
|
|
79
79
|
return shipped if File.exist?(shipped)
|
|
80
80
|
|
|
81
|
-
# 2.
|
|
82
|
-
npm_pkg = File.join(SCRIPT_DIR, "node_modules", "@tutorialkit-rb", "ruby-3.3",
|
|
83
|
-
"rbconfig", "wasm32-wasi", "rbconfig.rb")
|
|
84
|
-
return npm_pkg if File.exist?(npm_pkg)
|
|
85
|
-
|
|
86
|
-
# 3. Fallback: generated by a previous base binary build
|
|
81
|
+
# 2. Fallback: generated by a previous base binary build
|
|
87
82
|
Dir.glob(File.join(SCRIPT_DIR, "rubies", "*/usr/local/lib/ruby/*/wasm32-wasi/rbconfig.rb")).first
|
|
88
83
|
end
|
|
89
84
|
|
|
90
85
|
def find_base_wasm
|
|
91
|
-
#
|
|
86
|
+
# Locally-built or downloaded binary (from bin/build-ruby-base or GitHub Releases)
|
|
92
87
|
local = File.join(SCRIPT_DIR, "dist", "ruby-base.wasm")
|
|
93
88
|
return local if File.exist?(local)
|
|
94
89
|
|
|
95
|
-
# 2. From @tutorialkit-rb/ruby-3.3 npm package
|
|
96
|
-
npm_pkg = File.join(SCRIPT_DIR, "node_modules", "@tutorialkit-rb", "ruby-3.3",
|
|
97
|
-
"dist", "ruby-base.wasm")
|
|
98
|
-
return npm_pkg if File.exist?(npm_pkg)
|
|
99
|
-
|
|
100
90
|
$stderr.puts "Error: No base WASM binary found."
|
|
101
91
|
$stderr.puts "Either run 'bin/build-ruby-base' to build a custom binary,"
|
|
102
|
-
$stderr.puts "or
|
|
92
|
+
$stderr.puts "or run 'bin/build-pack' which downloads from GitHub Releases."
|
|
103
93
|
exit 1
|
|
104
94
|
end
|
|
105
95
|
|
|
@@ -111,12 +101,7 @@ def find_usr_dir
|
|
|
111
101
|
return path if Dir.exist?(path)
|
|
112
102
|
end
|
|
113
103
|
|
|
114
|
-
# 2.
|
|
115
|
-
npm_pkg = File.join(SCRIPT_DIR, "node_modules", "@tutorialkit-rb", "ruby-3.3",
|
|
116
|
-
"rubies", "usr")
|
|
117
|
-
return npm_pkg if Dir.exist?(npm_pkg)
|
|
118
|
-
|
|
119
|
-
# 3. Fallback: glob for the rubies/ directory left by rbwasm
|
|
104
|
+
# 2. Fallback: glob for the rubies/ directory left by rbwasm
|
|
120
105
|
candidates = Dir.glob(File.join(SCRIPT_DIR, "rubies", "ruby-3.3-wasm32-unknown-wasip1-full-*", "usr"))
|
|
121
106
|
return candidates.first if candidates.any?
|
|
122
107
|
|
|
@@ -133,7 +118,7 @@ rbconfig_path = find_rbconfig
|
|
|
133
118
|
unless rbconfig_path
|
|
134
119
|
$stderr.puts "Error: Could not find rbconfig.rb for cross-compilation"
|
|
135
120
|
$stderr.puts "Expected at: rbconfig/wasm32-wasi/rbconfig.rb"
|
|
136
|
-
$stderr.puts "Or
|
|
121
|
+
$stderr.puts "Or run 'bin/build-ruby-base' to generate one."
|
|
137
122
|
exit 1
|
|
138
123
|
end
|
|
139
124
|
puts "rbconfig: #{rbconfig_path}"
|
|
@@ -149,7 +134,7 @@ if usr_dir
|
|
|
149
134
|
else
|
|
150
135
|
$stderr.puts "Warning: Could not find usr/ directory for /usr mapping."
|
|
151
136
|
$stderr.puts " The packed binary may be missing Ruby stdlib at /usr."
|
|
152
|
-
$stderr.puts " Run 'bin/build-ruby-base'
|
|
137
|
+
$stderr.puts " Run 'bin/build-ruby-base' to generate it."
|
|
153
138
|
end
|
|
154
139
|
puts
|
|
155
140
|
|