Files
vibe-kanban/frontend/package.json
Louis Knight-Webb 7f9f1433af Store binaries in Cloudflare R2 instead of bundling in npm package (Vibe Kanban) (#1554)
* All changes are complete. Let me provide a summary of what was implemented:

## Summary

I've implemented the Cloudflare R2 binary storage feature. Here are the changes:

### Files Created
- **`npx-cli/bin/download.js`** - New module that handles downloading binaries from R2 with:
  - SHA-256 checksum verification
  - Progress reporting
  - Redirect handling
  - Local caching in `~/.vibe-kanban/bin/{version}/{platform}/`

### Files Modified

1. **`npx-cli/bin/cli.js`**
   - Converted to async for on-demand downloads
   - Downloads binaries from R2 instead of using bundled files
   - Non-blocking update check shows notice if newer version available
   - Caches binaries locally per version/platform

2. **`npx-cli/package.json`**
   - Removed `"dist"` from `files` array (package now ~15KB instead of ~150MB)

3. **`.github/workflows/pre-release.yml`**
   - Added new `upload-to-r2` job that:
     - Downloads all platform packages from artifacts
     - Generates manifest.json with SHA-256 checksums for each binary
     - Uploads binaries to R2 at `binaries/v{version}/{platform}/{binary}.zip`
     - Updates global manifest with latest version
   - Modified `create-prerelease` job to:
     - Depend on `upload-to-r2` instead of `package-npx-cli`
     - Inject R2 public URL into download.js via `sed`
     - No longer download/bundle binaries in the npm package

### Required GitHub Secrets

You'll need to add these secrets to your repository:
- `R2_BINARIES_ACCESS_KEY_ID`
- `R2_BINARIES_SECRET_ACCESS_KEY`
- `R2_BINARIES_ENDPOINT` (e.g., `https://<account_id>.r2.cloudflarestorage.com`)
- `R2_BINARIES_BUCKET`
- `R2_BINARIES_PUBLIC_URL` (the public URL for your R2 bucket, e.g., custom domain or public R2 URL)

### R2 Bucket Structure
```
binaries/
  manifest.json                    # {"latest": "0.0.135"}
  v0.0.135/
    manifest.json                  # Per-version manifest with checksums
    linux-x64/
      vibe-kanban.zip
      vibe-kanban-mcp.zip
      vibe-kanban-review.zip
    ...
```

* Done! I've updated the implementation to use full tags (with timestamps) instead of just version numbers. Here's a summary of what changed:

## Changes Made

1. **`npx-cli/bin/download.js`**:
   - Added `BINARY_TAG` constant (placeholder `__BINARY_TAG__`)
   - Changed `ensureBinary()` to use `BINARY_TAG` instead of accepting version as parameter
   - Cache paths now use the tag: `~/.vibe-kanban/bin/{tag}/{platform}/`

2. **`npx-cli/bin/cli.js`**:
   - Updated to import `BINARY_TAG` from download.js
   - Cache directory now uses `BINARY_TAG` instead of `CLI_VERSION`
   - Updated `ensureBinary()` call to not pass version

3. **`.github/workflows/pre-release.yml`**:
   - `upload-to-r2` job now uses `new_tag` instead of `new_version` for R2 paths
   - Binaries are stored at `binaries/{tag}/{platform}/{binary}.zip`
   - Global manifest stores the full tag: `{"latest": "v0.0.135-20251215122030"}`
   - `create-prerelease` job now injects both `__R2_PUBLIC_URL__` and `__BINARY_TAG__`

This allows multiple pre-releases to coexist in R2 (e.g., `v0.0.135-20251215122030` and `v0.0.135-20251215100000`), making rollbacks easy.

* chore: bump version to 0.0.136

---------

Co-authored-by: GitHub Action <action@github.com>
2025-12-15 23:48:27 +00:00

105 lines
3.5 KiB
JSON

{
"name": "vibe-kanban",
"private": true,
"version": "0.0.136",
"type": "module",
"scripts": {
"dev": "VITE_OPEN=${VITE_OPEN:-false} vite",
"build": "tsc && vite build",
"check": "tsc --noEmit",
"preview": "vite preview",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"lint:fix": "eslint . --ext ts,tsx --fix",
"lint:i18n": "LINT_I18N=true eslint . --ext ts,tsx --max-warnings 0",
"format": "prettier --write \"src/**/*.{ts,tsx,js,jsx,json,css,md}\"",
"format:check": "prettier --check \"src/**/*.{ts,tsx,js,jsx,json,css,md}\""
},
"dependencies": {
"@codemirror/lang-json": "^6.0.2",
"@codemirror/language": "^6.11.2",
"@codemirror/lint": "^6.8.5",
"@codemirror/view": "^6.38.1",
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/utilities": "^3.2.2",
"@ebay/nice-modal-react": "^1.2.13",
"@git-diff-view/file": "^0.0.30",
"@git-diff-view/react": "^0.0.30",
"@lexical/code": "^0.36.2",
"@lexical/link": "^0.36.2",
"@lexical/list": "^0.36.2",
"@lexical/markdown": "^0.36.2",
"@lexical/react": "^0.36.2",
"@lexical/rich-text": "^0.36.2",
"@radix-ui/react-dropdown-menu": "^2.1.15",
"@radix-ui/react-label": "^2.1.7",
"@radix-ui/react-select": "^2.2.5",
"@radix-ui/react-slot": "^1.2.3",
"@radix-ui/react-switch": "^1.0.3",
"@radix-ui/react-toggle-group": "^1.1.11",
"@radix-ui/react-tooltip": "^1.2.7",
"@rjsf/shadcn": "6.1.1",
"@sentry/react": "^9.34.0",
"@sentry/vite-plugin": "^3.5.0",
"@tanstack/electric-db-collection": "^0.2.6",
"@tanstack/react-db": "^0.1.50",
"@tanstack/react-form": "^1.23.8",
"@tanstack/react-query": "^5.85.5",
"@uiw/react-codemirror": "^4.25.1",
"@virtuoso.dev/message-list": "^1.13.3",
"class-variance-authority": "^0.7.0",
"click-to-react-component": "^1.1.2",
"clsx": "^2.0.0",
"embla-carousel-react": "^8.6.0",
"fancy-ansi": "^0.1.3",
"framer-motion": "^12.23.24",
"i18next": "^25.5.2",
"i18next-browser-languagedetector": "^8.2.0",
"lexical": "^0.36.2",
"lodash": "^4.17.21",
"lucide-react": "^0.539.0",
"posthog-js": "^1.276.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-dropzone": "^14.3.8",
"react-hotkeys-hook": "^5.1.0",
"react-i18next": "^15.7.3",
"react-resizable-panels": "^3.0.6",
"react-router-dom": "^6.8.1",
"react-virtuoso": "^4.14.0",
"rfc6902": "^5.1.2",
"simple-icons": "^15.16.0",
"tailwind-merge": "^2.2.0",
"tailwindcss-animate": "^1.0.7",
"vibe-kanban-web-companion": "^0.0.4",
"wa-sqlite": "^1.0.0",
"zustand": "^4.5.4"
},
"devDependencies": {
"@rjsf/core": "6.1.1",
"@rjsf/utils": "6.1.1",
"@rjsf/validator-ajv8": "6.1.1",
"@tailwindcss/container-queries": "^0.1.1",
"@types/lodash": "^4.17.20",
"@types/react": "^18.2.43",
"@types/react-dom": "^18.2.17",
"@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.21.0",
"@vitejs/plugin-react": "^4.2.1",
"autoprefixer": "^10.4.16",
"eslint": "^8.55.0",
"eslint-config-prettier": "^10.1.5",
"eslint-plugin-check-file": "^2.8.0",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-i18next": "^6.1.3",
"eslint-plugin-prettier": "^5.5.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.5",
"eslint-plugin-unused-imports": "^4.1.4",
"postcss": "^8.4.32",
"prettier": "^3.6.1",
"tailwindcss": "^3.4.0",
"typescript": "^5.9.2",
"vite": "^5.0.8"
}
}