at main 380 lines 9.5 kB view raw
1#!/usr/bin/env bash 2set -euo pipefail 3 4SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 5cd "$SCRIPT_DIR" 6 7PKG_NAME="@weaver.sh/editor" 8PKG_VERSION="0.1.1" 9 10# Targets to build 11TARGETS=(bundler web nodejs deno) 12 13COMMAND="${1:-build}" 14shift || true 15 16# Feature variants 17declare -A VARIANTS=( 18 ["core"]="" 19 ["collab"]="collab" 20) 21 22build() { 23 local target="$1" 24 local variant="$2" 25 local features="$3" 26 local out_dir="pkg/${variant}/${target}" 27 28 echo "Building ${variant}/${target}..." 29 30 local feature_args="--no-default-features" 31 if [[ -n "$features" ]]; then 32 feature_args="$feature_args --features $features" 33 fi 34 35 wasm-pack build \ 36 --out-name weaver_editor \ 37 --out-dir "$out_dir" \ 38 --target "$target" \ 39 $feature_args 40 41 # Report size 42 local wasm_file="${out_dir}/weaver_editor_bg.wasm" 43 if [[ -f "$wasm_file" ]]; then 44 local size=$(ls -lh "$wasm_file" | awk '{print $5}') 45 echo "${size}" 46 fi 47} 48 49generate_package_json() { 50 local variant="$1" 51 local out_dir="pkg/${variant}" 52 local pkg_suffix="" 53 local description="" 54 55 if [[ "$variant" == "collab" ]]; then 56 pkg_suffix="-collab" 57 description="Weaver markdown editor with collaborative editing (Loro CRDT + iroh P2P)" 58 else 59 pkg_suffix="-core" 60 description="Weaver markdown editor (local editing, lightweight)" 61 fi 62 63 # Worker export only for collab variant 64 local worker_export="" 65 local worker_files="" 66 if [[ "$variant" == "collab" ]]; then 67 worker_export=', 68 "./worker": { 69 "import": "./worker/editor_worker.js" 70 }' 71 worker_files=', 72 "worker/"' 73 fi 74 75 cat > "${out_dir}/package.json" << EOF 76{ 77 "name": "${PKG_NAME}${pkg_suffix}", 78 "version": "${PKG_VERSION}", 79 "description": "${description}", 80 "license": "MPL-2.0", 81 "repository": { 82 "type": "git", 83 "url": "https://tangled.org/nonbinary.computer/weaver" 84 }, 85 "keywords": ["atproto", "markdown", "editor", "wasm", "weaver"], 86 "main": "index.js", 87 "module": "index.js", 88 "types": "index.d.ts", 89 "exports": { 90 ".": { 91 "import": "./index.js", 92 "types": "./index.d.ts" 93 }, 94 "./types": { 95 "import": "./types.js", 96 "types": "./types.d.ts" 97 }, 98 "./wasm/bundler": { 99 "import": "./bundler/weaver_editor.js", 100 "types": "./bundler/weaver_editor.d.ts" 101 }, 102 "./wasm/web": { 103 "import": "./web/weaver_editor.js", 104 "types": "./web/weaver_editor.d.ts" 105 }, 106 "./wasm/nodejs": { 107 "import": "./nodejs/weaver_editor.js", 108 "require": "./nodejs/weaver_editor.js", 109 "types": "./nodejs/weaver_editor.d.ts" 110 }, 111 "./wasm/deno": { 112 "import": "./deno/weaver_editor.js", 113 "types": "./deno/weaver_editor.d.ts" 114 }, 115 "./weaver-editor.css": "./weaver-editor.css"${worker_export} 116 }, 117 "files": [ 118 "index.js", 119 "index.d.ts", 120 "types.js", 121 "types.d.ts", 122 "weaver-editor.css", 123 "bundler/", 124 "web/", 125 "nodejs/", 126 "deno/", 127 "README.md"${worker_files} 128 ] 129} 130EOF 131} 132 133generate_readme() { 134 local variant="$1" 135 local out_dir="pkg/${variant}" 136 137 cat > "${out_dir}/README.md" << 'EOF' 138# @weaver.sh/editor 139 140WASM-based markdown editor for weaver.sh. 141 142## Installation 143 144```bash 145npm install @weaver.sh/editor-core # Local editing only 146npm install @weaver.sh/editor-collab # With collaborative editing 147``` 148 149## Usage 150 151### With a bundler (webpack, vite, etc.) 152 153```javascript 154import init, { JsEditor } from '@weaver.sh/editor-core'; 155 156await init(); 157 158const editor = JsEditor.fromMarkdown('# Hello\n\nWorld'); 159console.log(editor.getMarkdown()); 160``` 161 162### Direct browser usage (no bundler) 163 164```html 165<script type="module"> 166 import init, { JsEditor } from '@weaver.sh/editor-core/web'; 167 await init(); 168 // ... 169</script> 170``` 171 172### Node.js 173 174```javascript 175const { JsEditor } = require('@weaver.sh/editor-core/nodejs'); 176``` 177 178## API 179 180See the TypeScript definitions for full API documentation. 181 182### Core 183 184- `JsEditor.new()` - Create empty editor 185- `JsEditor.fromMarkdown(content)` - Create from markdown 186- `JsEditor.fromSnapshot(entry)` - Create from EntryJson snapshot 187- `editor.getMarkdown()` - Get markdown content 188- `editor.getSnapshot()` - Get EntryJson for drafts 189- `editor.toEntry()` - Get validated EntryJson for publishing 190- `editor.executeAction(action)` - Execute an EditorAction 191- `editor.setTitle(title)` / `editor.setPath(path)` / `editor.setTags(tags)` 192 193### Images 194 195- `editor.addPendingImage(image)` - Track pending upload 196- `editor.finalizeImage(localId, finalized)` - Mark upload complete 197- `editor.getPendingImages()` - Get images awaiting upload 198- `editor.getStagingUris()` - Get staging record URIs for cleanup 199 200### Collab (editor-collab only) 201 202- `JsCollabEditor` - Collaborative editor with Loro CRDT 203- `editor.exportUpdates()` / `editor.importUpdates(bytes)` 204- `editor.addPeer(nodeId)` / `editor.removePeer(nodeId)` 205EOF 206} 207 208build_worker() { 209 echo "Building editor worker WASM..." 210 211 # Build the worker binary from weaver-editor-crdt 212 # Must be in workspace root for cargo to find the crate 213 local workspace_root="$(cd ../.. && pwd)" 214 215 export RUSTFLAGS='--cfg getrandom_backend="wasm_js"' 216 217 (cd "$workspace_root" && cargo build \ 218 -p weaver-editor-crdt \ 219 --bin editor_worker \ 220 --target wasm32-unknown-unknown \ 221 --release \ 222 --features collab) 223 224 # Create worker output directory 225 local worker_out="pkg/collab/worker" 226 mkdir -p "$worker_out" 227 228 # Run wasm-bindgen with no-modules target for web worker compatibility 229 wasm-bindgen \ 230 "$workspace_root/target/wasm32-unknown-unknown/release/editor_worker.wasm" \ 231 --out-dir "$worker_out" \ 232 --target no-modules \ 233 --no-typescript 234 235 # Report size 236 local wasm_file="${worker_out}/editor_worker_bg.wasm" 237 if [[ -f "$wasm_file" ]]; then 238 local size=$(ls -lh "$wasm_file" | awk '{print $5}') 239 echo " → Worker WASM: ${size}" 240 fi 241} 242 243build_typescript() { 244 echo "Building TypeScript wrapper..." 245 246 # Install deps if needed 247 if [[ ! -d "ts/node_modules" ]]; then 248 (cd ts && npm install) 249 fi 250 251 # Link WASM output so TypeScript can find it during compilation 252 # Use collab/bundler as source - it has all exports (JsCollabEditor + JsEditor) 253 # Core variant users who import collab will get runtime error, which is expected 254 rm -rf ts/bundler 255 ln -s ../pkg/collab/bundler ts/bundler 256 257 # Compile TypeScript 258 (cd ts && npm run build) 259 260 # Copy to pkg variants 261 for variant in "${!VARIANTS[@]}"; do 262 local out_dir="pkg/${variant}" 263 264 # Copy compiled JS/TS 265 cp -r ts/dist/* "${out_dir}/" 266 267 # Copy CSS 268 cp ts/weaver-editor.css "${out_dir}/" 269 done 270 271 echo " → TypeScript wrapper built" 272} 273 274do_build() { 275 # Clean previous builds 276 rm -rf pkg 277 278 # Build all combinations 279 for variant in "${!VARIANTS[@]}"; do 280 features="${VARIANTS[$variant]}" 281 282 for target in "${TARGETS[@]}"; do 283 build "$target" "$variant" "$features" 284 done 285 286 generate_package_json "$variant" 287 generate_readme "$variant" 288 289 # Clean up wasm-pack artifacts we don't need 290 find "pkg/${variant}" -name ".gitignore" -delete 291 find "pkg/${variant}" -name "package.json" -path "*/bundler/*" -delete 292 find "pkg/${variant}" -name "package.json" -path "*/web/*" -delete 293 find "pkg/${variant}" -name "package.json" -path "*/nodejs/*" -delete 294 find "pkg/${variant}" -name "package.json" -path "*/deno/*" -delete 295 done 296 297 # Build worker WASM for collab variant 298 build_worker 299 300 # Build TypeScript wrapper 301 build_typescript 302 303 echo "" 304 echo "Build complete!" 305 echo "" 306 echo "Editor WASM:" 307 ls -lh pkg/core/web/*.wasm pkg/collab/web/*.wasm 2>/dev/null || true 308 echo "" 309 echo "Worker WASM (collab only):" 310 ls -lh pkg/collab/worker/*.wasm 2>/dev/null || true 311 echo "" 312 echo "Packages:" 313 echo " pkg/core/ - @weaver.sh/editor-core (local editing)" 314 echo " pkg/collab/ - @weaver.sh/editor-collab (with CRDT collab)" 315} 316 317do_pack() { 318 echo "Packing..." 319 for variant in "${!VARIANTS[@]}"; do 320 echo " ${variant}..." 321 (cd "pkg/${variant}" && npm pack) 322 done 323 echo "" 324 echo "Tarballs created:" 325 ls -lh pkg/*/*.tgz 2>/dev/null || true 326} 327 328do_publish() { 329 local tag="${1:-}" 330 local tag_arg="" 331 if [[ -n "$tag" ]]; then 332 tag_arg="--tag $tag" 333 fi 334 335 echo "Publishing..." 336 for variant in "${!VARIANTS[@]}"; do 337 echo " ${variant}..." 338 (cd "pkg/${variant}" && npm publish --access public $tag_arg) 339 done 340 echo "" 341 echo "Published!" 342} 343 344usage() { 345 echo "Usage: $0 [command]" 346 echo "" 347 echo "Commands:" 348 echo " build Build all variants and targets (default)" 349 echo " pack Create npm tarballs" 350 echo " publish Publish to npm registry" 351 echo " all Build, pack, and publish" 352 echo "" 353 echo "Options for publish:" 354 echo " --tag <tag> Publish with a specific tag (e.g., 'next', 'beta')" 355} 356 357case "$COMMAND" in 358 build) 359 do_build 360 ;; 361 pack) 362 do_pack 363 ;; 364 publish) 365 do_publish "$@" 366 ;; 367 all) 368 do_build 369 do_pack 370 do_publish "$@" 371 ;; 372 -h|--help|help) 373 usage 374 ;; 375 *) 376 echo "Unknown command: $COMMAND" 377 usage 378 exit 1 379 ;; 380esac