@@ -345,10 +345,190 @@ jobs:
345345 path : performance-results.json
346346 retention-days : 90
347347
348+ deploy-cloudflare-release :
349+ name : Deploy Release to Cloudflare R2
350+ runs-on : ubuntu-latest
351+ needs : [test-deno, build-npm]
352+ if : startsWith(github.ref, 'refs/tags/v')
353+
354+ steps :
355+ - name : Checkout code
356+ uses : actions/checkout@v4
357+
358+ - name : Setup Deno
359+ uses : denoland/setup-deno@v2
360+ with :
361+ deno-version : ${{ env.DENO_VERSION }}
362+
363+ - name : Download build artifacts
364+ uses : actions/download-artifact@v4
365+ with :
366+ name : libpng-wasm-deno-build
367+ path : ./
368+
369+ - name : Set release version
370+ id : release-version
371+ run : echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
372+
373+ - name : Calculate SHA-256
374+ id : sha
375+ run : |
376+ WASM_FILE="install/wasm/libpng-side.wasm"
377+ SHA=$(sha256sum "$WASM_FILE" | awk '{print $1}')
378+ echo "sha=${SHA}" >> $GITHUB_OUTPUT
379+ echo "${SHA}" > "${WASM_FILE}.sha256"
380+ echo "🔒 SHA-256: ${SHA}"
381+
382+ - name : Deploy versioned WASM to Cloudflare R2
383+ uses : cloudflare/wrangler-action@v3
384+ with :
385+ apiToken : ${{ secrets.CLOUDFLARE_API_TOKEN }}
386+ accountId : ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
387+ command : |
388+ VERSION="${{ steps.release-version.outputs.VERSION }}"
389+
390+ # Deploy to @version path (immutable)
391+ r2 object put discere-os-wasm-production/libpng/@${VERSION}/libpng-side.wasm \
392+ --file=install/wasm/libpng-side.wasm \
393+ --content-type=application/wasm \
394+ --cache-control="public, max-age=31536000, immutable"
395+
396+ r2 object put discere-os-wasm-production/libpng/@${VERSION}/libpng-side.wasm.sha256 \
397+ --file=install/wasm/libpng-side.wasm.sha256 \
398+ --content-type=text/plain \
399+ --cache-control="public, max-age=31536000, immutable"
400+
401+ r2 object put discere-os-wasm-production/libpng/@${VERSION}/libpng-release.js \
402+ --file=install/wasm/libpng-release.js \
403+ --content-type=application/javascript \
404+ --cache-control="public, max-age=31536000, immutable"
405+
406+ r2 object put discere-os-wasm-production/libpng/@${VERSION}/libpng-release.wasm \
407+ --file=install/wasm/libpng-release.wasm \
408+ --content-type=application/wasm \
409+ --cache-control="public, max-age=31536000, immutable"
410+
411+ - name : Deploy SHA path to Cloudflare R2
412+ uses : cloudflare/wrangler-action@v3
413+ with :
414+ apiToken : ${{ secrets.CLOUDFLARE_API_TOKEN }}
415+ accountId : ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
416+ command : |
417+ SHA="${{ steps.sha.outputs.sha }}"
418+ SHA_SHORT="${SHA:0:7}"
419+
420+ # Deploy to @sha-xxx path (content-addressable, immutable)
421+ r2 object put discere-os-wasm-production/libpng/@sha-${SHA_SHORT}/libpng-side.wasm \
422+ --file=install/wasm/libpng-side.wasm \
423+ --content-type=application/wasm \
424+ --cache-control="public, max-age=31536000, immutable"
425+
426+ r2 object put discere-os-wasm-production/libpng/@sha-${SHA_SHORT}/libpng-side.wasm.sha256 \
427+ --file=install/wasm/libpng-side.wasm.sha256 \
428+ --content-type=text/plain \
429+ --cache-control="public, max-age=31536000, immutable"
430+
431+ r2 object put discere-os-wasm-production/libpng/@sha-${SHA_SHORT}/libpng-release.js \
432+ --file=install/wasm/libpng-release.js \
433+ --content-type=application/javascript \
434+ --cache-control="public, max-age=31536000, immutable"
435+
436+ r2 object put discere-os-wasm-production/libpng/@sha-${SHA_SHORT}/libpng-release.wasm \
437+ --file=install/wasm/libpng-release.wasm \
438+ --content-type=application/wasm \
439+ --cache-control="public, max-age=31536000, immutable"
440+
441+ - name : Update latest pointer
442+ uses : cloudflare/wrangler-action@v3
443+ with :
444+ apiToken : ${{ secrets.CLOUDFLARE_API_TOKEN }}
445+ accountId : ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
446+ command : |
447+ VERSION="${{ steps.release-version.outputs.VERSION }}"
448+ echo "${VERSION}" > latest.txt
449+
450+ # Update @latest.txt pointer (short cache)
451+ r2 object put discere-os-wasm-production/libpng/@latest.txt \
452+ --file=latest.txt \
453+ --content-type=text/plain \
454+ --cache-control="public, max-age=300"
455+
456+ - name : Verify Cloudflare deployment
457+ run : |
458+ sleep 15 # Wait for R2 propagation
459+ curl -f "https://wasm.discere.cloud/libpng@${{ steps.release-version.outputs.VERSION }}/libpng-side.wasm" || exit 1
460+ echo "✅ Cloudflare R2 deployment verified"
461+
462+ deploy-cloudflare-snapshot :
463+ name : Deploy Snapshot to Cloudflare R2
464+ runs-on : ubuntu-latest
465+ needs : [test-deno]
466+ if : github.ref == 'refs/heads/wasm' && github.event_name == 'push'
467+
468+ steps :
469+ - name : Checkout code
470+ uses : actions/checkout@v4
471+
472+ - name : Setup Deno
473+ uses : denoland/setup-deno@v2
474+ with :
475+ deno-version : ${{ env.DENO_VERSION }}
476+
477+ - name : Download build artifacts
478+ uses : actions/download-artifact@v4
479+ with :
480+ name : libpng-wasm-deno-build
481+ path : ./
482+
483+ - name : Set snapshot version
484+ id : version
485+ run : echo "VERSION=sha-$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
486+
487+ - name : Calculate SHA-256
488+ id : sha
489+ run : |
490+ WASM_FILE="install/wasm/libpng-side.wasm"
491+ SHA=$(sha256sum "$WASM_FILE" | awk '{print $1}')
492+ echo "sha=${SHA}" >> $GITHUB_OUTPUT
493+ echo "${SHA}" > "${WASM_FILE}.sha256"
494+ echo "🔒 SHA-256: ${SHA}"
495+
496+ - name : Deploy snapshot WASM to Cloudflare R2
497+ uses : cloudflare/wrangler-action@v3
498+ with :
499+ apiToken : ${{ secrets.CLOUDFLARE_API_TOKEN }}
500+ accountId : ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
501+ command : |
502+ VERSION="${{ steps.version.outputs.VERSION }}"
503+
504+ # Deploy to @sha-xxx path (snapshot)
505+ r2 object put discere-os-wasm-production/libpng/@${VERSION}/libpng-side.wasm \
506+ --file=install/wasm/libpng-side.wasm \
507+ --content-type=application/wasm \
508+ --cache-control="public, max-age=31536000, immutable"
509+
510+ r2 object put discere-os-wasm-production/libpng/@${VERSION}/libpng-side.wasm.sha256 \
511+ --file=install/wasm/libpng-side.wasm.sha256 \
512+ --content-type=text/plain \
513+ --cache-control="public, max-age=31536000, immutable"
514+
515+ r2 object put discere-os-wasm-production/libpng/@${VERSION}/libpng-release.js \
516+ --file=install/wasm/libpng-release.js \
517+ --content-type=application/javascript \
518+ --cache-control="public, max-age=31536000, immutable"
519+
520+ r2 object put discere-os-wasm-production/libpng/@${VERSION}/libpng-release.wasm \
521+ --file=install/wasm/libpng-release.wasm \
522+ --content-type=application/wasm \
523+ --cache-control="public, max-age=31536000, immutable"
524+
525+ - name : Log deployment success
526+ run : echo "✅ Snapshot ${{ steps.version.outputs.VERSION }} deployed to Cloudflare R2"
527+
348528 release :
349529 name : Create Deno-Native Release
350530 if : github.event_name == 'release'
351- needs : [test-deno, build-npm, performance]
531+ needs : [test-deno, build-npm, performance, deploy-cloudflare-release ]
352532 runs-on : ubuntu-latest
353533
354534 steps :
@@ -417,6 +597,15 @@ jobs:
417597 import LibPNG from '@discere-os/libpng.wasm';
418598 ```
419599
600+ ### 🌐 CDN Access
601+ ```typescript
602+ // Latest version
603+ import LibPNG from "https://wasm.discere.cloud/libpng@latest/libpng-release.js";
604+
605+ // Specific version
606+ import LibPNG from "https://wasm.discere.cloud/libpng@v1.6.44/libpng-release.js";
607+ ```
608+
420609 ### 📋 Contents
421610 - `deno/`: Native Deno files with zero configuration
422611 - `npm/`: Generated Node.js package via dnt
0 commit comments