From 35d84968bb42677cdfbbac022cc3c1d60ee7a74c Mon Sep 17 00:00:00 2001 From: Pan YANG Date: Sat, 3 Jan 2026 11:17:07 +0800 Subject: [PATCH 1/5] config(wrangler): restructure environment-specific routing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Move aicodingstack.io route to env.production section - Add env.staging section with staging.aicodingstack.io route - Properly organize environment-specific configurations 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .github/workflows/cleanup-preview.yml | 34 ++++++ .github/workflows/deploy-preview.yml | 154 +++++++++++++++--------- .github/workflows/deploy-production.yml | 56 +++------ .github/workflows/deploy-staging.yml | 56 +++++++++ wrangler.toml | 20 ++- 5 files changed, 222 insertions(+), 98 deletions(-) create mode 100644 .github/workflows/cleanup-preview.yml create mode 100644 .github/workflows/deploy-staging.yml diff --git a/.github/workflows/cleanup-preview.yml b/.github/workflows/cleanup-preview.yml new file mode 100644 index 0000000..318a2bb --- /dev/null +++ b/.github/workflows/cleanup-preview.yml @@ -0,0 +1,34 @@ +name: Cleanup Preview + +on: + pull_request: + types: [closed] + +jobs: + cleanup: + name: Delete Preview Deployment + runs-on: ubuntu-latest + permissions: + pull-requests: write + + steps: + - name: Delete Preview Deployment + uses: cloudflare/wrangler-action@v3 + with: + apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} + accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + command: delete --name aicodingstack-pr-${{ github.event.pull_request.number }} --force + continue-on-error: true + + - name: Comment Cleanup Status + uses: actions/github-script@v7 + with: + script: | + const prNumber = context.payload.pull_request.number; + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + body: `### Preview deployment cleaned up\n\nThe preview deployment for PR #${prNumber} has been removed.` + }); diff --git a/.github/workflows/deploy-preview.yml b/.github/workflows/deploy-preview.yml index 55bdf5c..310ac5b 100644 --- a/.github/workflows/deploy-preview.yml +++ b/.github/workflows/deploy-preview.yml @@ -2,23 +2,52 @@ name: Deploy Preview on: pull_request: - branches: [main] + push: + branches-ignore: [main, develop] concurrency: - group: preview-${{ github.ref }} + group: preview-${{ github.event.pull_request.number || github.ref_name }} cancel-in-progress: true jobs: - deploy-preview: - name: Deploy Preview to Cloudflare Pages + deploy: + name: Deploy Preview to Cloudflare Workers runs-on: ubuntu-latest permissions: contents: read pull-requests: write + deployments: write + steps: - name: Checkout code uses: actions/checkout@v6 + - name: Compute preview identifiers + id: preview_meta + run: | + if [[ "${{ github.event_name }}" == "pull_request" ]]; then + CF_BRANCH="pr-${{ github.event.pull_request.number }}" + CONTEXT_LABEL="PR #${{ github.event.pull_request.number }}" + else + RAW_BRANCH="${{ github.ref_name }}" + SLUG="$(echo "$RAW_BRANCH" | tr '[:upper:]' '[:lower:]' | sed -E 's#[^a-z0-9]+#-#g; s#(^-+|-+$)##g' | cut -c1-40)" + if [[ -z "$SLUG" ]]; then + SLUG="branch" + fi + CF_BRANCH="br-$SLUG" + CONTEXT_LABEL="Branch $RAW_BRANCH" + fi + + WORKER_NAME="aicodingstack-$CF_BRANCH" + PREVIEW_URL="https://${WORKER_NAME}.pr-preview.workers.dev" + + { + echo "cf_branch=$CF_BRANCH" + echo "worker_name=$WORKER_NAME" + echo "preview_url=$PREVIEW_URL" + echo "context_label=$CONTEXT_LABEL" + } >> "$GITHUB_OUTPUT" + - name: Setup Node.js uses: actions/setup-node@v6 with: @@ -28,61 +57,72 @@ jobs: - name: Install dependencies run: npm ci - - name: Run validation tests - run: npm run test:validate - - - name: Generate manifests and metadata - run: | - npm run generate:manifests - npm run generate:metadata + - name: Run CI tests + run: npm run test:ci - name: Build with OpenNext run: npm run build env: - BUILD_TIME: ${{ github.event.pull_request.updated_at }} - - # TODO: Configure Cloudflare Pages deployment - # You'll need to add these secrets to your repository: - # - CLOUDFLARE_API_TOKEN - # - CLOUDFLARE_ACCOUNT_ID - # - # Uncomment the steps below after adding the secrets: - # - # - name: Deploy to Cloudflare Pages (Preview) - # id: deploy - # uses: cloudflare/wrangler-action@v3 - # with: - # apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} - # accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} - # command: pages deploy .open-next --project-name=aicodingstack --branch=preview-${{ github.event.pull_request.number }} - # - # - name: Comment preview URL - # uses: actions/github-script@v7 - # with: - # script: | - # const previewUrl = '${{ steps.deploy.outputs.deployment-url }}'; - # const comment = `## 🚀 Preview Deployment - # - # Preview is ready! - # - # **Preview URL:** ${previewUrl} - # - # ### Build Details - # - **Commit:** ${context.sha.substring(0, 7)} - # - **Build Time:** ${{ github.event.pull_request.updated_at }} - # - # The preview will be automatically deleted when this PR is merged or closed.`; - # - # github.rest.issues.createComment({ - # issue_number: context.issue.number, - # owner: context.repo.owner, - # repo: context.repo.repo, - # body: comment - # }); - - - name: Preview deployment placeholder + BUILD_TIME: ${{ github.event.pull_request.updated_at || github.event.head_commit.timestamp }} + + - name: Deploy Preview + uses: cloudflare/wrangler-action@v3 + with: + apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} + accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + command: deploy --branch ${{ steps.preview_meta.outputs.cf_branch }} + + - name: Comment Preview URL + if: github.event_name == 'pull_request' + uses: actions/github-script@v7 + env: + PREVIEW_URL: ${{ steps.preview_meta.outputs.preview_url }} + with: + script: | + const prNumber = context.payload.pull_request.number; + const previewUrl = process.env.PREVIEW_URL; + const commitSha = context.sha.substring(0, 7); + + // Find existing bot comment + const { data: comments } = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + }); + + const botComment = comments.find(c => + c.user.type === 'Bot' && c.body.includes('Preview deployment') + ); + + const body = `### Preview deployment + + | Status | URL | + |--------|-----| + | Ready | [${previewUrl}](${previewUrl}) | + + **Commit:** \`${commitSha}\` + **Updated:** ${new Date().toISOString()}`; + + if (botComment) { + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: botComment.id, + body + }); + } else { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + body + }); + } + + - name: Deployment summary run: | - echo "⚠️ Preview deployment not yet configured" - echo "To enable preview deployments:" - echo "1. Add CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID to repository secrets" - echo "2. Uncomment the deployment steps in .github/workflows/deploy-preview.yml" + echo "### Preview Deployment" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "- **Context:** ${{ steps.preview_meta.outputs.context_label }}" >> $GITHUB_STEP_SUMMARY + echo "- **URL:** ${{ steps.preview_meta.outputs.preview_url }}" >> $GITHUB_STEP_SUMMARY + echo "- **Commit:** ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/deploy-production.yml b/.github/workflows/deploy-production.yml index 6312e31..e608542 100644 --- a/.github/workflows/deploy-production.yml +++ b/.github/workflows/deploy-production.yml @@ -5,16 +5,20 @@ on: branches: [main] concurrency: - group: production + group: production-deploy cancel-in-progress: false jobs: deploy-production: - name: Deploy to Cloudflare Pages + name: Deploy to Cloudflare Workers runs-on: ubuntu-latest + permissions: + contents: read + deployments: write environment: name: production url: https://aicodingstack.io + steps: - name: Checkout code uses: actions/checkout@v6 @@ -28,45 +32,25 @@ jobs: - name: Install dependencies run: npm ci - - name: Run validation tests - run: npm run test:validate - - - name: Generate manifests and metadata - run: | - npm run generate:manifests - npm run generate:metadata + - name: Run CI tests + run: npm run test:ci - name: Build with OpenNext run: npm run build env: BUILD_TIME: ${{ github.event.head_commit.timestamp }} - # TODO: Configure Cloudflare Pages deployment - # You'll need to add these secrets to your repository: - # - CLOUDFLARE_API_TOKEN - # - CLOUDFLARE_ACCOUNT_ID - # - # Uncomment the steps below after adding the secrets: - # - # - name: Deploy to Cloudflare Pages (Production) - # uses: cloudflare/wrangler-action@v3 - # with: - # apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} - # accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} - # command: pages deploy .open-next --project-name=aicodingstack --branch=main - # - # - name: Notify deployment success - # run: | - # echo "✅ Production deployment successful!" - # echo "🌐 Site: https://aicodingstack.io" - # echo "📝 Commit: ${{ github.sha }}" + - name: Deploy to Production + uses: cloudflare/wrangler-action@v3 + with: + apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} + accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + command: deploy --env production - - name: Production deployment placeholder + - name: Deployment summary run: | - echo "⚠️ Production deployment not yet configured" - echo "To enable production deployments:" - echo "1. Add CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID to repository secrets" - echo "2. Uncomment the deployment steps in .github/workflows/deploy-production.yml" - echo "" - echo "Manual deployment command:" - echo "npm run deploy" + echo "### Production Deployment" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "- **URL:** https://aicodingstack.io" >> $GITHUB_STEP_SUMMARY + echo "- **Commit:** ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY + echo "- **Time:** $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml new file mode 100644 index 0000000..df09a97 --- /dev/null +++ b/.github/workflows/deploy-staging.yml @@ -0,0 +1,56 @@ +name: Deploy Staging + +on: + push: + branches: [develop] + +concurrency: + group: staging-deploy + cancel-in-progress: true + +jobs: + deploy-staging: + name: Deploy to Cloudflare Workers (Staging) + runs-on: ubuntu-latest + permissions: + contents: read + deployments: write + environment: + name: staging + url: https://staging.aicodingstack.io + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: '22' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Run CI tests + run: npm run test:ci + + - name: Build with OpenNext + run: npm run build + env: + BUILD_TIME: ${{ github.event.head_commit.timestamp }} + + - name: Deploy to Staging + uses: cloudflare/wrangler-action@v3 + with: + apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} + accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + command: deploy --env staging + + - name: Deployment summary + run: | + echo "### Staging Deployment" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "- **URL:** https://staging.aicodingstack.io" >> $GITHUB_STEP_SUMMARY + echo "- **Commit:** ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY + echo "- **Time:** $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY diff --git a/wrangler.toml b/wrangler.toml index 64b838a..ab0db19 100644 --- a/wrangler.toml +++ b/wrangler.toml @@ -6,10 +6,6 @@ compatibility_flags = [ "global_fetch_strictly_public", ] -[[routes]] -pattern = "aicodingstack.io" -custom_domain = true - [assets] binding = "ASSETS" directory = ".open-next/assets" @@ -24,4 +20,18 @@ head_sampling_rate = 0.1 mode = "smart" [limits] -cpu_ms = 50 \ No newline at end of file +cpu_ms = 50 + +# ============ Production ============ +[env.production] +name = "aicodingstack" +[[env.production.routes]] +pattern = "aicodingstack.io" +custom_domain = true + +# ============ Staging ============ +[env.staging] +name = "aicodingstack-staging" +[[env.staging.routes]] +pattern = "staging.aicodingstack.io" +custom_domain = true \ No newline at end of file From 21ea0ce5769572b0e912cc779ae611734f04c582 Mon Sep 17 00:00:00 2001 From: Pan YANG Date: Sat, 3 Jan 2026 11:17:15 +0800 Subject: [PATCH 2/5] chore(gitignore): extend Claude settings ignore pattern MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Change from .claude/settings.local.json to .claude/settings.local.*.json - Supports more variants of local settings files 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 9d0705c..19da239 100644 --- a/.gitignore +++ b/.gitignore @@ -47,7 +47,7 @@ next-env.d.ts !.env.example # claude settings -.claude/settings.local.json +.claude/settings.local.*.json # python cache __pycache__/ From 11b118a6720db155a55d9e53ad4c5059761dc5d6 Mon Sep 17 00:00:00 2001 From: Pan YANG Date: Sat, 3 Jan 2026 11:20:39 +0800 Subject: [PATCH 3/5] chore(gitignore): fix Claude settings ignore pattern MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove unnecessary dot separator, change from .claude/settings.local.*.json to .claude/settings.local*.json 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 19da239..2f7be8d 100644 --- a/.gitignore +++ b/.gitignore @@ -47,7 +47,7 @@ next-env.d.ts !.env.example # claude settings -.claude/settings.local.*.json +.claude/settings.local*.json # python cache __pycache__/ From 64984360671dcd9240fc2d5491d7aa833fff1b66 Mon Sep 17 00:00:00 2001 From: Pan YANG Date: Sat, 3 Jan 2026 11:23:08 +0800 Subject: [PATCH 4/5] chore(deps): update package-lock.json MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Refresh lock file from npm install - Remove stale peer: true annotations from multiple packages 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- package-lock.json | 40 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/package-lock.json b/package-lock.json index c037e41..e7f995b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8418,8 +8418,7 @@ "resolved": "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-4.0.18.tgz", "integrity": "sha512-EF77RqROHL+4LhMGW5NTeKqfUd/e4OOv6EDFQ/UQQiFyWuqkEKyEz0NDILxOFxWUEVdjT2GQ2cC7t12B6pESwg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@cspell/dict-dart": { "version": "2.3.1", @@ -8580,16 +8579,14 @@ "resolved": "https://registry.npmjs.org/@cspell/dict-html/-/dict-html-4.0.13.tgz", "integrity": "sha512-vHzk2xfqQYPvoXtQtywa6ekIonPrUEwe2uftjry3UNRNl89TtzLJVSkiymKJ3WMb+W/DwKXKIb1tKzcIS8ccIg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@cspell/dict-html-symbol-entities": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/@cspell/dict-html-symbol-entities/-/dict-html-symbol-entities-4.0.4.tgz", "integrity": "sha512-afea+0rGPDeOV9gdO06UW183Qg6wRhWVkgCFwiO3bDupAoyXRuvupbb5nUyqSTsLXIKL8u8uXQlJ9pkz07oVXw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@cspell/dict-id-id": { "version": "1.0.7", @@ -8822,8 +8819,7 @@ "resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-3.2.3.tgz", "integrity": "sha512-zXh1wYsNljQZfWWdSPYwQhpwiuW0KPW1dSd8idjMRvSD0aSvWWHoWlrMsmZeRl4qM4QCEAjua8+cjflm41cQBg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@cspell/dict-vue": { "version": "3.0.5", @@ -10020,7 +10016,6 @@ "integrity": "sha512-0TTacJyZ9mDmY+VefuthVshaNIyCGZHJG2fMnGaDttCt8HmjUF7SizlHJpaCDoGnN635nK1wpzfpx/Xx5S4WnQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@mdx-js/mdx": "^3.0.0", "source-map": "^0.7.0" @@ -10081,7 +10076,6 @@ "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.1.tgz", "integrity": "sha512-f++rKLQgUVYDAtECQ6fn/is15GkEH9+nZPM3MS0RcxVqoTfawHvDlSCH7JbMhAM6uJ32v3eXLvLmLvjGu7PTQw==", "license": "MIT", - "peer": true, "dependencies": { "@types/mdx": "^2.0.0" }, @@ -10278,7 +10272,6 @@ "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz", "integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==", "license": "MIT", - "peer": true, "engines": { "node": "^14.21.3 || >=16" }, @@ -13731,7 +13724,6 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz", "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==", "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -13742,7 +13734,6 @@ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "devOptional": true, "license": "MIT", - "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -13908,7 +13899,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -19093,7 +19083,6 @@ "resolved": "https://registry.npmjs.org/next/-/next-15.5.9.tgz", "integrity": "sha512-agNLK89seZEtC5zUHwtut0+tNrc0Xw4FT/Dg+B/VLEo9pAcS9rtTKpek3V6kVcVwsB2YlqMaHdfZL4eLEVYuCg==", "license": "MIT", - "peer": true, "dependencies": { "@next/env": "15.5.9", "@swc/helpers": "0.5.15", @@ -19216,6 +19205,17 @@ } } }, + "node_modules/next-intl/node_modules/@swc/helpers": { + "version": "0.5.18", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.18.tgz", + "integrity": "sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ==", + "license": "Apache-2.0", + "optional": true, + "peer": true, + "dependencies": { + "tslib": "^2.8.0" + } + }, "node_modules/next/node_modules/postcss": { "version": "8.4.31", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", @@ -19612,7 +19612,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -19641,7 +19640,6 @@ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", "license": "MIT", - "peer": true, "dependencies": { "@types/use-sync-external-store": "^0.0.6", "use-sync-external-store": "^1.4.0" @@ -19834,8 +19832,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/redux-thunk": { "version": "3.1.0", @@ -20945,7 +20942,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "devOptional": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -20974,7 +20970,6 @@ "resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.24.tgz", "integrity": "sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==", "license": "MIT", - "peer": true, "dependencies": { "pathe": "^2.0.3" } @@ -21291,7 +21286,6 @@ "integrity": "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -22051,7 +22045,6 @@ "integrity": "sha512-s3mHDSWwHTduyY8kpHOsl27ZJ4ziDBJlc18PfBvNMqNnhO7yBeemlxH7bo7yQyU1foJrIZ6IENHDDg0Z9N8zQA==", "hasInstallScript": true, "license": "Apache-2.0", - "peer": true, "bin": { "workerd": "bin/workerd" }, @@ -22071,7 +22064,6 @@ "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.56.0.tgz", "integrity": "sha512-Nqi8duQeRbA+31QrD6QlWHW3IZVnuuRxMy7DEg46deUzywivmaRV/euBN5KKXDPtA24VyhYsK7I0tkb7P5DM2w==", "license": "MIT OR Apache-2.0", - "peer": true, "dependencies": { "@cloudflare/kv-asset-handler": "0.4.1", "@cloudflare/unenv-preset": "2.7.13", From 6100784b9623084990c7e3beb45a8f4e01a8c0f9 Mon Sep 17 00:00:00 2001 From: Pan YANG Date: Sat, 3 Jan 2026 11:57:00 +0800 Subject: [PATCH 5/5] feat(deploy): enable Cloudflare Workers preview URLs with alias MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add preview_urls = true to wrangler.toml - Update deploy-preview.yml to use versions upload --preview-alias - Implement new Cloudflare preview URL format with alias support 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .github/workflows/deploy-preview.yml | 11 ++++++++--- wrangler.toml | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy-preview.yml b/.github/workflows/deploy-preview.yml index 310ac5b..c60f54b 100644 --- a/.github/workflows/deploy-preview.yml +++ b/.github/workflows/deploy-preview.yml @@ -38,12 +38,17 @@ jobs: CONTEXT_LABEL="Branch $RAW_BRANCH" fi - WORKER_NAME="aicodingstack-$CF_BRANCH" - PREVIEW_URL="https://${WORKER_NAME}.pr-preview.workers.dev" + # Cloudflare Preview URLs (aliased) format: + # -..workers.dev + # See: https://developers.cloudflare.com/workers/configuration/previews/ + PREVIEW_ALIAS="$CF_BRANCH" + WORKER_NAME="aicodingstack" + PREVIEW_URL="https://${PREVIEW_ALIAS}-${WORKER_NAME}.pr-preview.workers.dev" { echo "cf_branch=$CF_BRANCH" echo "worker_name=$WORKER_NAME" + echo "preview_alias=$PREVIEW_ALIAS" echo "preview_url=$PREVIEW_URL" echo "context_label=$CONTEXT_LABEL" } >> "$GITHUB_OUTPUT" @@ -70,7 +75,7 @@ jobs: with: apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} - command: deploy --branch ${{ steps.preview_meta.outputs.cf_branch }} + command: versions upload --preview-alias ${{ steps.preview_meta.outputs.preview_alias }} - name: Comment Preview URL if: github.event_name == 'pull_request' diff --git a/wrangler.toml b/wrangler.toml index ab0db19..4092e50 100644 --- a/wrangler.toml +++ b/wrangler.toml @@ -1,6 +1,7 @@ name = "aicodingstack" main = ".open-next/worker.js" compatibility_date = "2025-11-01" +preview_urls = true compatibility_flags = [ "nodejs_compat", "global_fetch_strictly_public",