├── .editorconfig ├── .gitattributes ├── .github ├── dependabot.yml └── workflows │ ├── ci.yml │ └── release.yml ├── .gitignore ├── .vscode └── settings.json ├── Pipfile ├── Pipfile.lock ├── build_updated.sh ├── build_updated_test.sh ├── check_bun.py ├── check_nodejs.py ├── commit_changes.sh ├── commit_changes_test.sh ├── coverage.svg ├── examples ├── next │ ├── default-app-dir-standalone │ │ ├── .eslintrc.json │ │ ├── .gitignore │ │ ├── README.md │ │ ├── bun.lockb │ │ ├── dockerfile │ │ ├── next.config.js │ │ ├── package.json │ │ ├── postcss.config.js │ │ ├── public │ │ │ ├── next.svg │ │ │ └── vercel.svg │ │ ├── scripts │ │ │ └── build.sh │ │ ├── src │ │ │ └── app │ │ │ │ ├── favicon.ico │ │ │ │ ├── globals.css │ │ │ │ ├── layout.tsx │ │ │ │ └── page.tsx │ │ ├── tailwind.config.ts │ │ └── tsconfig.json │ └── default-app-dir │ │ ├── .eslintrc.json │ │ ├── .gitignore │ │ ├── README.md │ │ ├── bun.lockb │ │ ├── dockerfile │ │ ├── next.config.js │ │ ├── package.json │ │ ├── postcss.config.js │ │ ├── public │ │ ├── next.svg │ │ └── vercel.svg │ │ ├── src │ │ └── app │ │ │ ├── favicon.ico │ │ │ ├── globals.css │ │ │ ├── layout.tsx │ │ │ └── page.tsx │ │ ├── tailwind.config.ts │ │ └── tsconfig.json └── remix │ └── basic │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── app │ ├── entry.client.tsx │ ├── entry.server.tsx │ ├── root.tsx │ └── routes │ │ └── _index.tsx │ ├── bun.lockb │ ├── dockerfile │ ├── package.json │ ├── public │ └── favicon.ico │ ├── remix.config.js │ ├── remix.env.d.ts │ └── tsconfig.json ├── license ├── merge_lcov.sh ├── merge_lcov_test.sh ├── readme.md ├── src ├── base │ ├── 18 │ │ ├── alpine │ │ │ ├── docker-entrypoint.sh │ │ │ └── dockerfile │ │ ├── debian-slim │ │ │ ├── docker-entrypoint.sh │ │ │ └── dockerfile │ │ └── debian │ │ │ ├── docker-entrypoint.sh │ │ │ └── dockerfile │ ├── 20 │ │ ├── alpine │ │ │ ├── docker-entrypoint.sh │ │ │ └── dockerfile │ │ ├── debian-slim │ │ │ ├── docker-entrypoint.sh │ │ │ └── dockerfile │ │ └── debian │ │ │ ├── docker-entrypoint.sh │ │ │ └── dockerfile │ ├── 22 │ │ ├── alpine │ │ │ ├── docker-entrypoint.sh │ │ │ └── dockerfile │ │ ├── debian-slim │ │ │ ├── docker-entrypoint.sh │ │ │ └── dockerfile │ │ └── debian │ │ │ ├── docker-entrypoint.sh │ │ │ └── dockerfile │ └── 23 │ │ ├── alpine │ │ ├── docker-entrypoint.sh │ │ └── dockerfile │ │ ├── debian-slim │ │ ├── docker-entrypoint.sh │ │ └── dockerfile │ │ └── debian │ │ ├── docker-entrypoint.sh │ │ └── dockerfile └── git │ ├── 18 │ └── alpine │ │ ├── docker-entrypoint.sh │ │ └── dockerfile │ ├── 20 │ └── alpine │ │ ├── docker-entrypoint.sh │ │ └── dockerfile │ ├── 22 │ └── alpine │ │ ├── docker-entrypoint.sh │ │ └── dockerfile │ └── 23 │ └── alpine │ ├── docker-entrypoint.sh │ └── dockerfile ├── test_check_bun.py ├── test_check_nodejs.py └── versions.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 2 7 | indent_style = space 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "docker" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | - package-ecosystem: "github-actions" # See documentation for possible values 13 | directory: "/" # Location of package manifests 14 | schedule: 15 | interval: "weekly" 16 | - package-ecosystem: "npm" 17 | directory: "/examples" 18 | schedule: 19 | interval: "weekly" 20 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | workflow_call: 5 | push: 6 | branches: 7 | - main 8 | paths-ignore: 9 | - "**/coverage.svg" 10 | 11 | pull_request: 12 | branches: 13 | - main 14 | paths-ignore: 15 | - "**/coverage.svg" 16 | 17 | jobs: 18 | test: 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - name: Checkout code 23 | uses: actions/checkout@v4 24 | 25 | # - name: Set up bashcov 26 | # uses: infertux/bashcov/.github/actions/set-up-bashcov@master 27 | 28 | - name: Set up Python 29 | uses: actions/setup-python@v5 30 | with: 31 | python-version: "3.x" 32 | cache: "pipenv" 33 | 34 | - name: Install lcov 35 | run: sudo apt-get update && sudo apt-get install -y lcov 36 | 37 | - name: Install dependencies 38 | run: | 39 | pip install pipenv 40 | pipenv install --dev 41 | 42 | - name: Run tests with coverage 43 | run: | 44 | pipenv run pytest --cov --cov-report=lcov 45 | # bashcov ./commit_changes_test.sh 46 | # ./merge_lcov.sh src merged.lcov 47 | 48 | - name: Coverage Badge 49 | uses: ImBIOS/lcov-coverage-badge@v1 50 | with: 51 | file: ./coverage.lcov 52 | 53 | - name: Verify Changed files 54 | uses: tj-actions/verify-changed-files@v20 55 | id: verify-changed-files 56 | with: 57 | files: "coverage.svg" 58 | 59 | - name: Commit files 60 | if: steps.verify-changed-files.outputs.files_changed == 'true' 61 | run: | 62 | git config --local user.email "github-actions[bot]@users.noreply.github.com" 63 | git config --local user.name "github-actions[bot]" 64 | git add coverage.svg 65 | git commit -m "ci: update coverage.svg" 66 | 67 | - name: Push changes 68 | if: steps.verify-changed-files.outputs.files_changed == 'true' 69 | uses: ad-m/github-push-action@master 70 | with: 71 | github_token: ${{ secrets.github_token }} 72 | branch: ${{ github.ref }} 73 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | schedule: 5 | - cron: "0 0 * * *" # Every day at midnight 6 | workflow_dispatch: 7 | inputs: 8 | bun-versions: 9 | description: "Bun version, comma separated (e.g. 0.0.1,0.0.2,1.0.8-canary.20231104.1)" 10 | required: false 11 | default: "" 12 | nodejs-version: 13 | description: "Node.js version, comma separated (e.g. 14.7.4,17.3.8,18.4.5)" 14 | required: false 15 | default: "" 16 | distros: 17 | description: "Distro, comma separated (e.g. alpine,debian-slim,debian)" 18 | required: false 19 | default: "" 20 | # TODO: To be implemented 21 | # skip-check: 22 | # description: "Skip version check" 23 | # required: false 24 | # default: "true" 25 | 26 | env: 27 | REGISTRY: imbios 28 | PLATFORMS: linux/amd64,linux/arm64 29 | NODE_MAJOR_VERSIONS_TO_CHECK: 18,20,22,23 30 | NODE_VERSIONS_TO_BUILD: "" 31 | BUN_TAGS_TO_CHECK: canary,latest 32 | BUN_VERSIONS_TO_BUILD: "" 33 | DISTROS: alpine,debian-slim,debian 34 | 35 | jobs: 36 | test-job: 37 | uses: ./.github/workflows/ci.yml 38 | build-job: 39 | needs: test-job 40 | runs-on: ubuntu-latest 41 | steps: 42 | - name: Checkout code 43 | uses: actions/checkout@v4 44 | 45 | - name: Install jq 46 | run: sudo apt install jq 47 | 48 | - name: Set up Python 49 | uses: actions/setup-python@v5 50 | with: 51 | python-version: "3.12" 52 | cache: "pipenv" 53 | 54 | - name: Install pipenv 55 | run: pip install pipenv 56 | 57 | - name: Install dependencies using pipenv 58 | run: | 59 | pipenv install --dev 60 | 61 | - name: Check for new releases of nodejs and bun 62 | if: ${{ inputs.nodejs-version == '' && inputs.bun-versions == '' && inputs.distros == '' }} 63 | run: | 64 | set -e 65 | echo "NODE_VERSIONS_TO_BUILD=$(pipenv run python check_nodejs.py ${{ env.NODE_MAJOR_VERSIONS_TO_CHECK }})" >> $GITHUB_ENV 66 | echo "BUN_VERSIONS_TO_BUILD=$(pipenv run python check_bun.py ${{ env.BUN_TAGS_TO_CHECK }})" >> $GITHUB_ENV 67 | 68 | - name: Setup Docker Buildx 69 | uses: docker/setup-buildx-action@v3 70 | 71 | - name: Login to Docker Hub 72 | uses: docker/login-action@v3 73 | with: 74 | username: ${{ secrets.DOCKER_USERNAME }} 75 | password: ${{ secrets.DOCKER_TOKEN }} 76 | 77 | - uses: nick-fields/retry@v3 78 | name: Build and push Docker images 79 | with: 80 | timeout_minutes: 60 81 | max_attempts: 3 82 | retry_on: error 83 | command: ./build_updated.sh 84 | env: 85 | REGISTRY: ${{ env.REGISTRY }} 86 | PLATFORMS: ${{ env.PLATFORMS }} 87 | NODE_VERSIONS_TO_BUILD: ${{ env.NODE_VERSIONS_TO_BUILD || inputs.nodejs-version }} 88 | BUN_VERSIONS_TO_BUILD: ${{ env.BUN_VERSIONS_TO_BUILD || inputs.bun-versions }} 89 | DISTROS: ${{ env.DISTROS || inputs.distros }} 90 | 91 | - name: Commit changes 92 | run: ./commit_changes.sh 93 | env: 94 | BUN_VERSIONS_TO_BUILD: ${{ env.BUN_VERSIONS_TO_BUILD }} 95 | NODE_VERSIONS_TO_BUILD: ${{ env.NODE_VERSIONS_TO_BUILD }} 96 | DISTROS: ${{ env.DISTROS }} 97 | - name: Pull changes 98 | run: git pull -r 99 | - name: Push changes 100 | uses: ad-m/github-push-action@master 101 | with: 102 | github_token: ${{ secrets.GITHUB_TOKEN }} 103 | rerun-failed-jobs: 104 | runs-on: ubuntu-latest 105 | needs: [build-job] 106 | if: failure() 107 | steps: 108 | - name: Rerun failed jobs in the current workflow 109 | env: 110 | GH_TOKEN: ${{ github.token }} 111 | run: gh run rerun ${{ github.run_id }} --failed 112 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Pipfile 2 | .Pipfile.lock 3 | .venv/ 4 | .coverage 5 | *.lcov 6 | coverage.info 7 | coverage/ 8 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.codeActionsOnSave": { 3 | "source.organizeImports": "explicit", 4 | "source.fixAll": "explicit", 5 | "source.convertImportFormat": "explicit", 6 | "source.unusedImports": "explicit" 7 | }, 8 | "editor.formatOnSave": true 9 | } 10 | -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | url = "https://pypi.org/simple" 3 | verify_ssl = true 4 | name = "pypi" 5 | 6 | [packages] 7 | beautifulsoup4 = "*" 8 | packaging = "*" 9 | requests = "*" 10 | pytest = "*" 11 | pytest-mock = "*" 12 | pytest-cov = "*" 13 | responses = "*" 14 | 15 | [dev-packages] 16 | pytest = "*" 17 | pytest-mock = "*" 18 | pytest-cov = "*" 19 | 20 | [requires] 21 | python_version = "3.12" 22 | -------------------------------------------------------------------------------- /Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "83efb77fdc8daa30a5662ec37293a30fec8cd961e0d38fc2baf6c127e30f5a62" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3.12" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "beautifulsoup4": { 20 | "hashes": [ 21 | "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051", 22 | "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed" 23 | ], 24 | "index": "pypi", 25 | "markers": "python_full_version >= '3.6.0'", 26 | "version": "==4.12.3" 27 | }, 28 | "certifi": { 29 | "hashes": [ 30 | "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56", 31 | "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db" 32 | ], 33 | "markers": "python_version >= '3.6'", 34 | "version": "==2024.12.14" 35 | }, 36 | "charset-normalizer": { 37 | "hashes": [ 38 | "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537", 39 | "sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa", 40 | "sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a", 41 | "sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294", 42 | "sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b", 43 | "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd", 44 | "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601", 45 | "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd", 46 | "sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4", 47 | "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d", 48 | "sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2", 49 | "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313", 50 | "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd", 51 | "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa", 52 | "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8", 53 | "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1", 54 | "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2", 55 | "sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496", 56 | "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d", 57 | "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b", 58 | "sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e", 59 | "sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a", 60 | "sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4", 61 | "sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca", 62 | "sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78", 63 | "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408", 64 | "sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5", 65 | "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3", 66 | "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f", 67 | "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a", 68 | "sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765", 69 | "sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6", 70 | "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146", 71 | "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6", 72 | "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9", 73 | "sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd", 74 | "sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c", 75 | "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f", 76 | "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545", 77 | "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176", 78 | "sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770", 79 | "sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824", 80 | "sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f", 81 | "sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf", 82 | "sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487", 83 | "sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d", 84 | "sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd", 85 | "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b", 86 | "sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534", 87 | "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f", 88 | "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b", 89 | "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9", 90 | "sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd", 91 | "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125", 92 | "sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9", 93 | "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de", 94 | "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11", 95 | "sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d", 96 | "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35", 97 | "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f", 98 | "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda", 99 | "sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7", 100 | "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a", 101 | "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971", 102 | "sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8", 103 | "sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41", 104 | "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d", 105 | "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f", 106 | "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757", 107 | "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a", 108 | "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886", 109 | "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77", 110 | "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76", 111 | "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247", 112 | "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", 113 | "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb", 114 | "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7", 115 | "sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e", 116 | "sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6", 117 | "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037", 118 | "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1", 119 | "sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e", 120 | "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807", 121 | "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407", 122 | "sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c", 123 | "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12", 124 | "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3", 125 | "sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089", 126 | "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd", 127 | "sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e", 128 | "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00", 129 | "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616" 130 | ], 131 | "markers": "python_version >= '3.7'", 132 | "version": "==3.4.1" 133 | }, 134 | "coverage": { 135 | "extras": [ 136 | "toml" 137 | ], 138 | "hashes": [ 139 | "sha256:05fca8ba6a87aabdd2d30d0b6c838b50510b56cdcfc604d40760dae7153b73d9", 140 | "sha256:0aa9692b4fdd83a4647eeb7db46410ea1322b5ed94cd1715ef09d1d5922ba87f", 141 | "sha256:0c807ca74d5a5e64427c8805de15b9ca140bba13572d6d74e262f46f50b13273", 142 | "sha256:0d7a2bf79378d8fb8afaa994f91bfd8215134f8631d27eba3e0e2c13546ce994", 143 | "sha256:0f460286cb94036455e703c66988851d970fdfd8acc2a1122ab7f4f904e4029e", 144 | "sha256:204a8238afe787323a8b47d8be4df89772d5c1e4651b9ffa808552bdf20e1d50", 145 | "sha256:2396e8116db77789f819d2bc8a7e200232b7a282c66e0ae2d2cd84581a89757e", 146 | "sha256:254f1a3b1eef5f7ed23ef265eaa89c65c8c5b6b257327c149db1ca9d4a35f25e", 147 | "sha256:26bcf5c4df41cad1b19c84af71c22cbc9ea9a547fc973f1f2cc9a290002c8b3c", 148 | "sha256:27c6e64726b307782fa5cbe531e7647aee385a29b2107cd87ba7c0105a5d3853", 149 | "sha256:299e91b274c5c9cdb64cbdf1b3e4a8fe538a7a86acdd08fae52301b28ba297f8", 150 | "sha256:2bcfa46d7709b5a7ffe089075799b902020b62e7ee56ebaed2f4bdac04c508d8", 151 | "sha256:2ccf240eb719789cedbb9fd1338055de2761088202a9a0b73032857e53f612fe", 152 | "sha256:32ee6d8491fcfc82652a37109f69dee9a830e9379166cb73c16d8dc5c2915165", 153 | "sha256:3f7b444c42bbc533aaae6b5a2166fd1a797cdb5eb58ee51a92bee1eb94a1e1cb", 154 | "sha256:457574f4599d2b00f7f637a0700a6422243b3565509457b2dbd3f50703e11f59", 155 | "sha256:489a01f94aa581dbd961f306e37d75d4ba16104bbfa2b0edb21d29b73be83609", 156 | "sha256:4bcc276261505d82f0ad426870c3b12cb177752834a633e737ec5ee79bbdff18", 157 | "sha256:4e0de1e902669dccbf80b0415fb6b43d27edca2fbd48c74da378923b05316098", 158 | "sha256:4e4630c26b6084c9b3cb53b15bd488f30ceb50b73c35c5ad7871b869cb7365fd", 159 | "sha256:4eea95ef275de7abaef630c9b2c002ffbc01918b726a39f5a4353916ec72d2f3", 160 | "sha256:507a20fc863cae1d5720797761b42d2d87a04b3e5aeb682ef3b7332e90598f43", 161 | "sha256:54a5f0f43950a36312155dae55c505a76cd7f2b12d26abeebbe7a0b36dbc868d", 162 | "sha256:55b201b97286cf61f5e76063f9e2a1d8d2972fc2fcfd2c1272530172fd28c359", 163 | "sha256:59af35558ba08b758aec4d56182b222976330ef8d2feacbb93964f576a7e7a90", 164 | "sha256:5c912978f7fbf47ef99cec50c4401340436d200d41d714c7a4766f377c5b7b78", 165 | "sha256:656c82b8a0ead8bba147de9a89bda95064874c91a3ed43a00e687f23cc19d53a", 166 | "sha256:6713ba4b4ebc330f3def51df1d5d38fad60b66720948112f114968feb52d3f99", 167 | "sha256:675cefc4c06e3b4c876b85bfb7c59c5e2218167bbd4da5075cbe3b5790a28988", 168 | "sha256:6f93531882a5f68c28090f901b1d135de61b56331bba82028489bc51bdd818d2", 169 | "sha256:714f942b9c15c3a7a5fe6876ce30af831c2ad4ce902410b7466b662358c852c0", 170 | "sha256:79109c70cc0882e4d2d002fe69a24aa504dec0cc17169b3c7f41a1d341a73694", 171 | "sha256:7bbd8c8f1b115b892e34ba66a097b915d3871db7ce0e6b9901f462ff3a975377", 172 | "sha256:7ed2f37cfce1ce101e6dffdfd1c99e729dd2ffc291d02d3e2d0af8b53d13840d", 173 | "sha256:7fb105327c8f8f0682e29843e2ff96af9dcbe5bab8eeb4b398c6a33a16d80a23", 174 | "sha256:89d76815a26197c858f53c7f6a656686ec392b25991f9e409bcef020cd532312", 175 | "sha256:9a7cfb50515f87f7ed30bc882f68812fd98bc2852957df69f3003d22a2aa0abf", 176 | "sha256:9e1747bab246d6ff2c4f28b4d186b205adced9f7bd9dc362051cc37c4a0c7bd6", 177 | "sha256:9e80eba8801c386f72e0712a0453431259c45c3249f0009aff537a517b52942b", 178 | "sha256:a01ec4af7dfeb96ff0078ad9a48810bb0cc8abcb0115180c6013a6b26237626c", 179 | "sha256:a372c89c939d57abe09e08c0578c1d212e7a678135d53aa16eec4430adc5e690", 180 | "sha256:a3b204c11e2b2d883946fe1d97f89403aa1811df28ce0447439178cc7463448a", 181 | "sha256:a534738b47b0de1995f85f582d983d94031dffb48ab86c95bdf88dc62212142f", 182 | "sha256:a5e37dc41d57ceba70956fa2fc5b63c26dba863c946ace9705f8eca99daecdc4", 183 | "sha256:aa744da1820678b475e4ba3dfd994c321c5b13381d1041fe9c608620e6676e25", 184 | "sha256:ab32947f481f7e8c763fa2c92fd9f44eeb143e7610c4ca9ecd6a36adab4081bd", 185 | "sha256:abb02e2f5a3187b2ac4cd46b8ced85a0858230b577ccb2c62c81482ca7d18852", 186 | "sha256:b330368cb99ef72fcd2dc3ed260adf67b31499584dc8a20225e85bfe6f6cfed0", 187 | "sha256:bc67deb76bc3717f22e765ab3e07ee9c7a5e26b9019ca19a3b063d9f4b874244", 188 | "sha256:c0b1818063dc9e9d838c09e3a473c1422f517889436dd980f5d721899e66f315", 189 | "sha256:c56e097019e72c373bae32d946ecf9858fda841e48d82df7e81c63ac25554078", 190 | "sha256:c7827a5bc7bdb197b9e066cdf650b2887597ad124dd99777332776f7b7c7d0d0", 191 | "sha256:ccc2b70a7ed475c68ceb548bf69cec1e27305c1c2606a5eb7c3afff56a1b3b27", 192 | "sha256:d37a84878285b903c0fe21ac8794c6dab58150e9359f1aaebbeddd6412d53132", 193 | "sha256:e2f0280519e42b0a17550072861e0bc8a80a0870de260f9796157d3fca2733c5", 194 | "sha256:e4ae5ac5e0d1e4edfc9b4b57b4cbecd5bc266a6915c500f358817a8496739247", 195 | "sha256:e67926f51821b8e9deb6426ff3164870976fe414d033ad90ea75e7ed0c2e5022", 196 | "sha256:e78b270eadb5702938c3dbe9367f878249b5ef9a2fcc5360ac7bff694310d17b", 197 | "sha256:ea3c8f04b3e4af80e17bab607c386a830ffc2fb88a5484e1df756478cf70d1d3", 198 | "sha256:ec22b5e7fe7a0fa8509181c4aac1db48f3dd4d3a566131b313d1efc102892c18", 199 | "sha256:f4f620668dbc6f5e909a0946a877310fb3d57aea8198bde792aae369ee1c23b5", 200 | "sha256:fd34e7b3405f0cc7ab03d54a334c17a9e802897580d964bd8c2001f4b9fd488f" 201 | ], 202 | "markers": "python_version >= '3.9'", 203 | "version": "==7.6.10" 204 | }, 205 | "idna": { 206 | "hashes": [ 207 | "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", 208 | "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" 209 | ], 210 | "markers": "python_version >= '3.6'", 211 | "version": "==3.10" 212 | }, 213 | "iniconfig": { 214 | "hashes": [ 215 | "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", 216 | "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" 217 | ], 218 | "markers": "python_version >= '3.7'", 219 | "version": "==2.0.0" 220 | }, 221 | "packaging": { 222 | "hashes": [ 223 | "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", 224 | "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f" 225 | ], 226 | "index": "pypi", 227 | "markers": "python_version >= '3.8'", 228 | "version": "==24.2" 229 | }, 230 | "pluggy": { 231 | "hashes": [ 232 | "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", 233 | "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669" 234 | ], 235 | "markers": "python_version >= '3.8'", 236 | "version": "==1.5.0" 237 | }, 238 | "pytest": { 239 | "hashes": [ 240 | "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6", 241 | "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761" 242 | ], 243 | "index": "pypi", 244 | "markers": "python_version >= '3.8'", 245 | "version": "==8.3.4" 246 | }, 247 | "pytest-cov": { 248 | "hashes": [ 249 | "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35", 250 | "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0" 251 | ], 252 | "index": "pypi", 253 | "markers": "python_version >= '3.9'", 254 | "version": "==6.0.0" 255 | }, 256 | "pytest-mock": { 257 | "hashes": [ 258 | "sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f", 259 | "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0" 260 | ], 261 | "index": "pypi", 262 | "markers": "python_version >= '3.8'", 263 | "version": "==3.14.0" 264 | }, 265 | "pyyaml": { 266 | "hashes": [ 267 | "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", 268 | "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", 269 | "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", 270 | "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e", 271 | "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", 272 | "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", 273 | "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", 274 | "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", 275 | "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", 276 | "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", 277 | "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a", 278 | "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", 279 | "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", 280 | "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8", 281 | "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", 282 | "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19", 283 | "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", 284 | "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a", 285 | "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", 286 | "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", 287 | "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", 288 | "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631", 289 | "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", 290 | "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", 291 | "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", 292 | "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", 293 | "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", 294 | "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", 295 | "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", 296 | "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706", 297 | "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", 298 | "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", 299 | "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", 300 | "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083", 301 | "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", 302 | "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", 303 | "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", 304 | "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", 305 | "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725", 306 | "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", 307 | "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", 308 | "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", 309 | "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", 310 | "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", 311 | "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5", 312 | "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d", 313 | "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", 314 | "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", 315 | "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", 316 | "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", 317 | "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", 318 | "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", 319 | "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4" 320 | ], 321 | "markers": "python_version >= '3.8'", 322 | "version": "==6.0.2" 323 | }, 324 | "requests": { 325 | "hashes": [ 326 | "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", 327 | "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" 328 | ], 329 | "index": "pypi", 330 | "markers": "python_version >= '3.8'", 331 | "version": "==2.32.3" 332 | }, 333 | "responses": { 334 | "hashes": [ 335 | "sha256:9cac8f21e1193bb150ec557875377e41ed56248aed94e4567ed644db564bacf1", 336 | "sha256:eae7ce61a9603004e76c05691e7c389e59652d91e94b419623c12bbfb8e331d8" 337 | ], 338 | "index": "pypi", 339 | "markers": "python_version >= '3.8'", 340 | "version": "==0.25.6" 341 | }, 342 | "soupsieve": { 343 | "hashes": [ 344 | "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb", 345 | "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9" 346 | ], 347 | "markers": "python_version >= '3.8'", 348 | "version": "==2.6" 349 | }, 350 | "urllib3": { 351 | "hashes": [ 352 | "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", 353 | "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d" 354 | ], 355 | "markers": "python_version >= '3.9'", 356 | "version": "==2.3.0" 357 | } 358 | }, 359 | "develop": { 360 | "coverage": { 361 | "extras": [ 362 | "toml" 363 | ], 364 | "hashes": [ 365 | "sha256:05fca8ba6a87aabdd2d30d0b6c838b50510b56cdcfc604d40760dae7153b73d9", 366 | "sha256:0aa9692b4fdd83a4647eeb7db46410ea1322b5ed94cd1715ef09d1d5922ba87f", 367 | "sha256:0c807ca74d5a5e64427c8805de15b9ca140bba13572d6d74e262f46f50b13273", 368 | "sha256:0d7a2bf79378d8fb8afaa994f91bfd8215134f8631d27eba3e0e2c13546ce994", 369 | "sha256:0f460286cb94036455e703c66988851d970fdfd8acc2a1122ab7f4f904e4029e", 370 | "sha256:204a8238afe787323a8b47d8be4df89772d5c1e4651b9ffa808552bdf20e1d50", 371 | "sha256:2396e8116db77789f819d2bc8a7e200232b7a282c66e0ae2d2cd84581a89757e", 372 | "sha256:254f1a3b1eef5f7ed23ef265eaa89c65c8c5b6b257327c149db1ca9d4a35f25e", 373 | "sha256:26bcf5c4df41cad1b19c84af71c22cbc9ea9a547fc973f1f2cc9a290002c8b3c", 374 | "sha256:27c6e64726b307782fa5cbe531e7647aee385a29b2107cd87ba7c0105a5d3853", 375 | "sha256:299e91b274c5c9cdb64cbdf1b3e4a8fe538a7a86acdd08fae52301b28ba297f8", 376 | "sha256:2bcfa46d7709b5a7ffe089075799b902020b62e7ee56ebaed2f4bdac04c508d8", 377 | "sha256:2ccf240eb719789cedbb9fd1338055de2761088202a9a0b73032857e53f612fe", 378 | "sha256:32ee6d8491fcfc82652a37109f69dee9a830e9379166cb73c16d8dc5c2915165", 379 | "sha256:3f7b444c42bbc533aaae6b5a2166fd1a797cdb5eb58ee51a92bee1eb94a1e1cb", 380 | "sha256:457574f4599d2b00f7f637a0700a6422243b3565509457b2dbd3f50703e11f59", 381 | "sha256:489a01f94aa581dbd961f306e37d75d4ba16104bbfa2b0edb21d29b73be83609", 382 | "sha256:4bcc276261505d82f0ad426870c3b12cb177752834a633e737ec5ee79bbdff18", 383 | "sha256:4e0de1e902669dccbf80b0415fb6b43d27edca2fbd48c74da378923b05316098", 384 | "sha256:4e4630c26b6084c9b3cb53b15bd488f30ceb50b73c35c5ad7871b869cb7365fd", 385 | "sha256:4eea95ef275de7abaef630c9b2c002ffbc01918b726a39f5a4353916ec72d2f3", 386 | "sha256:507a20fc863cae1d5720797761b42d2d87a04b3e5aeb682ef3b7332e90598f43", 387 | "sha256:54a5f0f43950a36312155dae55c505a76cd7f2b12d26abeebbe7a0b36dbc868d", 388 | "sha256:55b201b97286cf61f5e76063f9e2a1d8d2972fc2fcfd2c1272530172fd28c359", 389 | "sha256:59af35558ba08b758aec4d56182b222976330ef8d2feacbb93964f576a7e7a90", 390 | "sha256:5c912978f7fbf47ef99cec50c4401340436d200d41d714c7a4766f377c5b7b78", 391 | "sha256:656c82b8a0ead8bba147de9a89bda95064874c91a3ed43a00e687f23cc19d53a", 392 | "sha256:6713ba4b4ebc330f3def51df1d5d38fad60b66720948112f114968feb52d3f99", 393 | "sha256:675cefc4c06e3b4c876b85bfb7c59c5e2218167bbd4da5075cbe3b5790a28988", 394 | "sha256:6f93531882a5f68c28090f901b1d135de61b56331bba82028489bc51bdd818d2", 395 | "sha256:714f942b9c15c3a7a5fe6876ce30af831c2ad4ce902410b7466b662358c852c0", 396 | "sha256:79109c70cc0882e4d2d002fe69a24aa504dec0cc17169b3c7f41a1d341a73694", 397 | "sha256:7bbd8c8f1b115b892e34ba66a097b915d3871db7ce0e6b9901f462ff3a975377", 398 | "sha256:7ed2f37cfce1ce101e6dffdfd1c99e729dd2ffc291d02d3e2d0af8b53d13840d", 399 | "sha256:7fb105327c8f8f0682e29843e2ff96af9dcbe5bab8eeb4b398c6a33a16d80a23", 400 | "sha256:89d76815a26197c858f53c7f6a656686ec392b25991f9e409bcef020cd532312", 401 | "sha256:9a7cfb50515f87f7ed30bc882f68812fd98bc2852957df69f3003d22a2aa0abf", 402 | "sha256:9e1747bab246d6ff2c4f28b4d186b205adced9f7bd9dc362051cc37c4a0c7bd6", 403 | "sha256:9e80eba8801c386f72e0712a0453431259c45c3249f0009aff537a517b52942b", 404 | "sha256:a01ec4af7dfeb96ff0078ad9a48810bb0cc8abcb0115180c6013a6b26237626c", 405 | "sha256:a372c89c939d57abe09e08c0578c1d212e7a678135d53aa16eec4430adc5e690", 406 | "sha256:a3b204c11e2b2d883946fe1d97f89403aa1811df28ce0447439178cc7463448a", 407 | "sha256:a534738b47b0de1995f85f582d983d94031dffb48ab86c95bdf88dc62212142f", 408 | "sha256:a5e37dc41d57ceba70956fa2fc5b63c26dba863c946ace9705f8eca99daecdc4", 409 | "sha256:aa744da1820678b475e4ba3dfd994c321c5b13381d1041fe9c608620e6676e25", 410 | "sha256:ab32947f481f7e8c763fa2c92fd9f44eeb143e7610c4ca9ecd6a36adab4081bd", 411 | "sha256:abb02e2f5a3187b2ac4cd46b8ced85a0858230b577ccb2c62c81482ca7d18852", 412 | "sha256:b330368cb99ef72fcd2dc3ed260adf67b31499584dc8a20225e85bfe6f6cfed0", 413 | "sha256:bc67deb76bc3717f22e765ab3e07ee9c7a5e26b9019ca19a3b063d9f4b874244", 414 | "sha256:c0b1818063dc9e9d838c09e3a473c1422f517889436dd980f5d721899e66f315", 415 | "sha256:c56e097019e72c373bae32d946ecf9858fda841e48d82df7e81c63ac25554078", 416 | "sha256:c7827a5bc7bdb197b9e066cdf650b2887597ad124dd99777332776f7b7c7d0d0", 417 | "sha256:ccc2b70a7ed475c68ceb548bf69cec1e27305c1c2606a5eb7c3afff56a1b3b27", 418 | "sha256:d37a84878285b903c0fe21ac8794c6dab58150e9359f1aaebbeddd6412d53132", 419 | "sha256:e2f0280519e42b0a17550072861e0bc8a80a0870de260f9796157d3fca2733c5", 420 | "sha256:e4ae5ac5e0d1e4edfc9b4b57b4cbecd5bc266a6915c500f358817a8496739247", 421 | "sha256:e67926f51821b8e9deb6426ff3164870976fe414d033ad90ea75e7ed0c2e5022", 422 | "sha256:e78b270eadb5702938c3dbe9367f878249b5ef9a2fcc5360ac7bff694310d17b", 423 | "sha256:ea3c8f04b3e4af80e17bab607c386a830ffc2fb88a5484e1df756478cf70d1d3", 424 | "sha256:ec22b5e7fe7a0fa8509181c4aac1db48f3dd4d3a566131b313d1efc102892c18", 425 | "sha256:f4f620668dbc6f5e909a0946a877310fb3d57aea8198bde792aae369ee1c23b5", 426 | "sha256:fd34e7b3405f0cc7ab03d54a334c17a9e802897580d964bd8c2001f4b9fd488f" 427 | ], 428 | "markers": "python_version >= '3.9'", 429 | "version": "==7.6.10" 430 | }, 431 | "iniconfig": { 432 | "hashes": [ 433 | "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", 434 | "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" 435 | ], 436 | "markers": "python_version >= '3.7'", 437 | "version": "==2.0.0" 438 | }, 439 | "packaging": { 440 | "hashes": [ 441 | "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", 442 | "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f" 443 | ], 444 | "index": "pypi", 445 | "markers": "python_version >= '3.8'", 446 | "version": "==24.2" 447 | }, 448 | "pluggy": { 449 | "hashes": [ 450 | "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", 451 | "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669" 452 | ], 453 | "markers": "python_version >= '3.8'", 454 | "version": "==1.5.0" 455 | }, 456 | "pytest": { 457 | "hashes": [ 458 | "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6", 459 | "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761" 460 | ], 461 | "index": "pypi", 462 | "markers": "python_version >= '3.8'", 463 | "version": "==8.3.4" 464 | }, 465 | "pytest-cov": { 466 | "hashes": [ 467 | "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35", 468 | "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0" 469 | ], 470 | "index": "pypi", 471 | "markers": "python_version >= '3.9'", 472 | "version": "==6.0.0" 473 | }, 474 | "pytest-mock": { 475 | "hashes": [ 476 | "sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f", 477 | "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0" 478 | ], 479 | "index": "pypi", 480 | "markers": "python_version >= '3.8'", 481 | "version": "==3.14.0" 482 | } 483 | } 484 | } 485 | -------------------------------------------------------------------------------- /build_updated.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Exit on error 4 | set -e 5 | 6 | # Logging function 7 | log() { 8 | echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')] $@" 9 | } 10 | 11 | # Function to validate version format 12 | validate_version() { 13 | local version=$1 14 | local regex="^[0-9]+\.[0-9]+\.[0-9]+(-canary\.[0-9]{8}\.[0-9]+)?$" 15 | if [[ ! $version =~ $regex ]]; then 16 | echo "Invalid version format: $version" 17 | exit 1 18 | fi 19 | } 20 | 21 | # Retry function 22 | retry() { 23 | local retries=${RETRIES:-3} 24 | local count=0 25 | until "$@"; do 26 | exit_code=$? 27 | count=$((count + 1)) 28 | if [ $count -lt $retries ]; then 29 | log "Retrying ($count/$retries)..." 30 | sleep 5 31 | else 32 | log "Failed after $count attempts." 33 | return $exit_code 34 | fi 35 | done 36 | return 0 37 | } 38 | 39 | # Convert comma-separated strings to arrays 40 | IFS=',' read -ra NODE_VERSIONS <<<"$NODE_VERSIONS_TO_BUILD" 41 | IFS=',' read -ra BUN_VERSIONS <<<"$BUN_VERSIONS_TO_BUILD" 42 | IFS=',' read -ra DISTROS <<<"$DISTROS" 43 | 44 | # If NODE_VERSIONS_TO_BUILD is empty, but BUN_VERSIONS_TO_BUILD is not, 45 | # build all versions from versions.json 46 | if [ -z "$NODE_VERSIONS_TO_BUILD" ]; then 47 | IFS=',' read -ra NODE_MAJOR_VERSIONS <<<"$NODE_MAJOR_VERSIONS_TO_CHECK" 48 | NODE_VERSIONS=() 49 | for node_major_version in "${NODE_MAJOR_VERSIONS[@]}"; do 50 | node_version=$(cat versions.json | jq -r ".nodejs.\"${node_major_version}\".version") 51 | if [ "$node_version" != "null" ]; then 52 | NODE_VERSIONS+=("${node_version//v/}") 53 | fi 54 | done 55 | fi 56 | 57 | log "Building Node versions: ${NODE_VERSIONS[*]}" 58 | 59 | # If BUN_VERSIONS_TO_BUILD is empty, but NODE_VERSIONS_TO_BUILD is not, 60 | # build all versions from versions.json 61 | if [ -z "$BUN_VERSIONS_TO_BUILD" ]; then 62 | BUN_VERSIONS=() 63 | for bun_version in $(cat versions.json | jq -r '.bun | keys[]'); do 64 | BUN_VERSIONS+=("${bun_version//v/}") 65 | done 66 | fi 67 | 68 | log "Building Bun versions: ${BUN_VERSIONS[*]}" 69 | 70 | # Validate versions 71 | for version in "${NODE_VERSIONS[@]}"; do 72 | validate_version "$version" 73 | done 74 | for version in "${BUN_VERSIONS[@]}"; do 75 | validate_version "$version" 76 | done 77 | 78 | # Read the JSON file 79 | json_data=$(cat versions.json) 80 | 81 | # Function to generate tags 82 | generate_tags() { 83 | local bun_version=$1 84 | local node_version=$2 85 | local distro=$3 86 | 87 | local node_major=${node_version%%.*} 88 | local node_minor=${node_version%.*} 89 | local bun_major=${bun_version%%.*} 90 | local bun_minor=${bun_version%.*} 91 | 92 | local is_canary=false 93 | if [[ $bun_version == *"-canary"* ]]; then 94 | is_canary=true 95 | bun_version="canary" 96 | fi 97 | 98 | echo "$REGISTRY/bun-node:${bun_version}-${node_version}-${distro}" 99 | 100 | if [ $is_canary == false ]; then 101 | echo "$REGISTRY/bun-node:${bun_minor}-${node_version}-${distro}" 102 | echo "$REGISTRY/bun-node:${bun_major}-${node_version}-${distro}" 103 | echo "$REGISTRY/bun-node:${bun_version}-${node_minor}-${distro}" 104 | echo "$REGISTRY/bun-node:${bun_version}-${node_major}-${distro}" 105 | elif [[ $bun_version == "canary" ]]; then 106 | echo "$REGISTRY/bun-node:canary-${node_minor}-${distro}" 107 | echo "$REGISTRY/bun-node:canary-${node_major}-${distro}" 108 | fi 109 | 110 | local codename=$(echo "${json_data}" | jq -r ".nodejs.\"${node_major}\".name") 111 | echo "$REGISTRY/bun-node:${bun_version}-${codename}-${distro}" 112 | 113 | if [[ $is_canary == false ]]; then 114 | echo "$REGISTRY/bun-node:latest-${node_version}-${distro}" 115 | echo "$REGISTRY/bun-node:latest-${node_major}-${distro}" 116 | echo "$REGISTRY/bun-node:latest-${codename}-${distro}" 117 | fi 118 | 119 | if [[ $is_canary == false && "$node_major" == "20" && $distro == "debian" ]]; then 120 | echo "$REGISTRY/bun-node:latest" 121 | fi 122 | 123 | if [[ $is_canary == false ]]; then 124 | echo "$REGISTRY/bun-node:${node_major}-${distro}" 125 | fi 126 | } 127 | 128 | # Build, tag, and push loop 129 | for bun_version in "${BUN_VERSIONS[@]}"; do 130 | for node_version in "${NODE_VERSIONS[@]}"; do 131 | for distro in "${DISTROS[@]}"; do 132 | tag_distro=$distro 133 | if [ "$distro" == "debian-slim" ]; then 134 | tag_distro="slim" 135 | fi 136 | 137 | tags=($(generate_tags "$bun_version" "$node_version" "$tag_distro")) 138 | 139 | node_major=${node_version%%.*} 140 | log "Building image for Bun version $bun_version, Node version $node_version, Distro $distro" 141 | image_name="$REGISTRY/bun-node:${bun_version}-${node_version}-${tag_distro}" 142 | 143 | for tag in "${tags[@]}"; do 144 | log "Tagging $image_name as $tag" 145 | retry docker buildx build --platform "$PLATFORMS" -t "$image_name" -t "$tag" "./src/base/${node_major}/${distro}" --push --provenance=mode=max 146 | 147 | if [ "$distro" == "alpine" ]; then 148 | log "Building and Tagging Alpine image with Git" 149 | retry docker buildx build --platform "$PLATFORMS" -t "$image_name-git" -t "$tag-git" "./src/git/${node_major}/${distro}" --push --provenance=mode=max 150 | fi 151 | done 152 | 153 | log "Updating versions.json file" 154 | bun_tag="latest" 155 | if [[ $bun_version == *"-canary"* ]]; then 156 | bun_tag="canary" 157 | fi 158 | json_data=$(echo "${json_data}" | jq ".nodejs.\"${node_major}\".version = \"v${node_version}\"" | jq ".bun.\"${bun_tag}\" = \"v${bun_version}\"") 159 | echo "${json_data}" >versions.json 160 | done 161 | done 162 | done 163 | -------------------------------------------------------------------------------- /build_updated_test.sh: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /check_bun.py: -------------------------------------------------------------------------------- 1 | """ 2 | Script to fetch the latest versions of the Bun package based on specified 3 | version types. 4 | 5 | Usage: 6 | python check_bun.py [version_type] 7 | 8 | Arguments: 9 | version_type: Comma-separated list of version types to fetch. Valid 10 | options: "latest", "canary". 11 | """ 12 | 13 | import argparse 14 | import json 15 | from typing import List, Dict, Optional, Tuple 16 | import requests 17 | from bs4 import BeautifulSoup 18 | from packaging import version 19 | 20 | 21 | def get_bun_latest_versions(version_types: List[str]) -> Dict[str, Optional[str]]: 22 | """ 23 | Fetches the latest Bun versions from the Bun NPM page based on specified version types. 24 | 25 | Args: 26 | version_types (List[str]): List of version types to fetch. 27 | 28 | Returns: 29 | Dict[str, Optional[str]]: Dictionary with version types as keys and latest version strings as values. 30 | """ 31 | url = "https://www.npmjs.com/package/bun?activeTab=versions" 32 | try: 33 | response = requests.get(url, timeout=5) 34 | response.raise_for_status() 35 | except requests.RequestException as e: 36 | raise RuntimeError("Failed to fetch Bun versions") from e 37 | 38 | soup = BeautifulSoup(response.content, "html.parser") 39 | versions = soup.find_all("a", class_="_132722c7 f5 black-60 lh-copy code") 40 | version_list = [ver.get_text().strip() for ver in versions] 41 | 42 | latest_versions = {"latest": None, "canary": None} 43 | 44 | for ver_str in version_list: 45 | parsed_version, is_canary = parse_version(ver_str) 46 | update_latest_versions( 47 | latest_versions, ver_str, parsed_version, is_canary, version_types 48 | ) 49 | 50 | return {k: v for k, v in latest_versions.items() if k in version_types} 51 | 52 | 53 | def parse_version(version_str: str) -> Tuple[version.Version, bool]: 54 | """ 55 | Parses a version string and identifies if it's a canary version. 56 | 57 | Args: 58 | version_str (str): The version string to parse. 59 | 60 | Returns: 61 | version.Version: The parsed version. 62 | bool: True if it's a canary version, False otherwise. 63 | """ 64 | version_parts = version_str.split("-", 1) 65 | parsed_version = version.parse(version_parts[0]) 66 | is_canary = "canary" in version_str 67 | return parsed_version, is_canary 68 | 69 | 70 | def update_latest_versions( 71 | latest_versions: Dict[str, Optional[str]], 72 | version_str: str, 73 | parsed_version: version.Version, 74 | is_canary: bool, 75 | version_types: List[str], 76 | ): 77 | """ 78 | Updates the dictionary of latest versions if a newer version is found. 79 | 80 | Args: 81 | latest_versions (Dict[str, Optional[str]]): Dictionary to store latest versions. 82 | version_str (str): The version string. 83 | parsed_version (version.Version): Parsed version object. 84 | is_canary (bool): Flag indicating if the version is a canary version. 85 | version_types (List[str]): List of version types to consider. 86 | """ 87 | type_key = "canary" if is_canary else "latest" 88 | if type_key in version_types: 89 | current_version = latest_versions[type_key] 90 | if current_version is None or parsed_version > version.parse( 91 | current_version.split("-", 1)[0] 92 | ): 93 | latest_versions[type_key] = version_str 94 | 95 | 96 | def main(): 97 | """ 98 | Fetches the latest Bun versions and compares them with the current versions. 99 | If there are any updated versions, it prints them. 100 | 101 | Args: 102 | version_type (str): Comma-separated list of version types to fetch: latest, canary 103 | 104 | Returns: 105 | None 106 | """ 107 | parser = argparse.ArgumentParser(description="Fetch the latest Bun versions.") 108 | parser.add_argument( 109 | "version_type", 110 | type=str, 111 | default="latest,canary", 112 | help="Comma-separated list of version types to fetch: latest, canary", 113 | ) 114 | args = parser.parse_args() 115 | version_types = args.version_type.split(",") 116 | 117 | try: 118 | latest_versions = get_bun_latest_versions(version_types) 119 | except RuntimeError as e: 120 | print(str(e)) 121 | return 122 | 123 | with open("versions.json", encoding="utf-8") as f: 124 | current_versions = json.load(f)["bun"] 125 | 126 | updated_versions = [ 127 | latest_versions[vt] 128 | for vt in version_types 129 | if latest_versions[vt] != current_versions.get(vt) 130 | ] 131 | 132 | if updated_versions: 133 | print(",".join(updated_versions)) 134 | 135 | 136 | if __name__ == "__main__": 137 | main() 138 | -------------------------------------------------------------------------------- /check_nodejs.py: -------------------------------------------------------------------------------- 1 | """ 2 | Fetches Node.js versions for specified major versions from the Node.js previous releases page. 3 | """ 4 | 5 | import argparse 6 | import json 7 | import sys 8 | import requests 9 | from bs4 import BeautifulSoup 10 | 11 | 12 | def get_nodejs_versions(major_versions): 13 | """ 14 | Fetches Node.js versions for specified major versions from the Node.js previous releases page. 15 | 16 | Args: 17 | major_versions (list): A list of major versions to filter for. 18 | 19 | Returns: 20 | list: A list of Node.js versions that match the specified major versions. 21 | """ 22 | url = "https://nodejs.org/en/about/previous-releases/" 23 | response = requests.get(url, timeout=5) 24 | soup = BeautifulSoup(response.content, "html.parser") 25 | 26 | # Find all version numbers on the page 27 | versions = soup.find_all("td", attrs={"data-label": "Version"}) 28 | version_list = [ 29 | version.get_text().strip().replace("Node.js ", "") for version in versions 30 | ] 31 | 32 | # Filter for specific major versions 33 | filtered_versions = [ 34 | version 35 | for version in version_list 36 | if any(version.startswith("v" + str(major) + ".") for major in major_versions) 37 | ] 38 | 39 | return filtered_versions 40 | 41 | 42 | def main(): 43 | """ 44 | Fetches Node.js versions for specified major versions from the Node.js previous releases page. 45 | 46 | Command-line Arguments: 47 | major_versions (str): A string of major versions separated by commas. 48 | """ 49 | parser = argparse.ArgumentParser( 50 | description="Fetch Node.js versions for specific major versions." 51 | ) 52 | parser.add_argument( 53 | "major_versions", 54 | type=str, 55 | help="Comma-separated list of major versions to fetch", 56 | ) 57 | 58 | args = parser.parse_args() 59 | 60 | # Convert comma-separated string to list of integers 61 | major_versions = [int(major) for major in args.major_versions.split(",")] 62 | 63 | # Get Node.js versions 64 | nodejs_versions = get_nodejs_versions(major_versions) 65 | 66 | # Read current versions from versions.json 67 | with open("versions.json", encoding="utf-8") as f: 68 | current_versions = json.load(f)["nodejs"] 69 | 70 | # Check for updates and set NODE_VERSIONS_TO_BUILD 71 | updated_versions = [] 72 | for version in nodejs_versions: 73 | major = version[1:].split(".")[0] 74 | if major in current_versions: 75 | if version != current_versions[major]["version"]: 76 | updated_versions.append(version) 77 | else: 78 | # Log a error if the major version is not found 79 | print( 80 | f"Error: Major version {major} not found in current versions.", 81 | file=sys.stderr, 82 | ) 83 | 84 | if updated_versions: 85 | print(",".join(version[1:] for version in updated_versions)) 86 | 87 | 88 | if __name__ == "__main__": 89 | main() 90 | -------------------------------------------------------------------------------- /commit_changes.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | # Extract versions from versions.json 6 | BUN_CANARY_VERSION=$(jq -r '.bun.canary' versions.json) 7 | BUN_LATEST_VERSION=$(jq -r '.bun.latest' versions.json) 8 | NODE_VERSIONS=$(jq -r '.nodejs | to_entries[] | "\(.value.name): \(.value.version)"' versions.json) 9 | 10 | # Generate the commit message 11 | COMMIT_MESSAGE="build: update image(s) version 12 | 13 | - bun: (canary) ${BUN_CANARY_VERSION}, (latest) ${BUN_LATEST_VERSION} 14 | - nodejs: 15 | ${NODE_VERSIONS} 16 | - distro: ${DISTROS}" 17 | 18 | # Configure git 19 | git config --local user.email "github-actions[bot]@users.noreply.github.com" 20 | git config --local user.name "github-actions[bot]" 21 | 22 | # Add changes and commit if there are any 23 | git add versions.json 24 | if ! git diff-index --quiet HEAD; then 25 | git commit -m "$COMMIT_MESSAGE" 26 | fi 27 | -------------------------------------------------------------------------------- /commit_changes_test.sh: -------------------------------------------------------------------------------- 1 | # #!/bin/bash 2 | 3 | # # Start bashcov for coverage tracking 4 | # bashcov start 5 | 6 | # # Set up test environment for versions.json 7 | # echo '{ 8 | # "bun": { 9 | # "canary": "1.0.0-canary", 10 | # "latest": "1.0.0" 11 | # }, 12 | # "nodejs": { 13 | # "v14": { "name": "v14", "version": "14.17.6" }, 14 | # "v16": { "name": "v16", "version": "16.8.0" } 15 | # } 16 | # }' >versions.json 17 | 18 | # # Run the original script (commit the changes) 19 | # ./commit_changes.sh 20 | 21 | # # Now, ensure the commit is undone completely 22 | # git reset --hard HEAD~1 # This will undo the most recent commit 23 | 24 | # # Confirm there's no staged change or modified file 25 | # git status # This should show no changes in the working directory 26 | 27 | # # Run bashcov report and other steps after reset 28 | # bashcov report 29 | 30 | # # Generate lcov report (bashcov will create the lcov report file) 31 | # bashcov report --lcov >lcov-report.lcov 32 | 33 | # # Optional: Check the generated lcov report 34 | # cat lcov-report.lcov 35 | -------------------------------------------------------------------------------- /coverage.svg: -------------------------------------------------------------------------------- 1 | Coverage: 90%Coverage90% -------------------------------------------------------------------------------- /examples/next/default-app-dir-standalone/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /examples/next/default-app-dir-standalone/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /examples/next/default-app-dir-standalone/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | # or 14 | bun dev 15 | ``` 16 | 17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 18 | 19 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. 20 | 21 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. 22 | 23 | ## Learn More 24 | 25 | To learn more about Next.js, take a look at the following resources: 26 | 27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 29 | 30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 31 | 32 | ## Deploy on Vercel 33 | 34 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 35 | 36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 37 | -------------------------------------------------------------------------------- /examples/next/default-app-dir-standalone/bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ImBIOS/bun-node/151bd0d6bcfed152baac8ffd523f28f4dd688df1/examples/next/default-app-dir-standalone/bun.lockb -------------------------------------------------------------------------------- /examples/next/default-app-dir-standalone/dockerfile: -------------------------------------------------------------------------------- 1 | # Use the official Node.js image as the base image 2 | FROM imbios/bun-node:latest 3 | 4 | # Set the working directory inside the container 5 | WORKDIR /app 6 | 7 | # Copy the package.json and bun.lockb files to the working directory 8 | COPY package.json bun.lockb ./ 9 | 10 | # Install the app dependencies 11 | RUN bun install 12 | 13 | # Copy the rest of the app files to the working directory 14 | COPY . . 15 | 16 | # Build the Remix app 17 | RUN bun run build 18 | 19 | # Expose the port on which the app will run 20 | EXPOSE 3000 21 | 22 | # Start the app 23 | CMD ["bun", "run", "start"] 24 | -------------------------------------------------------------------------------- /examples/next/default-app-dir-standalone/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: "standalone", 4 | }; 5 | 6 | module.exports = nextConfig; 7 | -------------------------------------------------------------------------------- /examples/next/default-app-dir-standalone/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "default-app-dir", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "./scripts/build.sh", 8 | "standalone": "bun .next/standalone/server.js", 9 | "start": "next start", 10 | "lint": "next lint" 11 | }, 12 | "dependencies": { 13 | "react": "^18", 14 | "react-dom": "^18", 15 | "next": "14.2.21" 16 | }, 17 | "devDependencies": { 18 | "typescript": "^5", 19 | "@types/node": "^20", 20 | "@types/react": "^18", 21 | "@types/react-dom": "^18", 22 | "autoprefixer": "^10.0.1", 23 | "postcss": "^8", 24 | "tailwindcss": "^3.3.0", 25 | "eslint": "^8", 26 | "eslint-config-next": "14.0.4" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /examples/next/default-app-dir-standalone/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /examples/next/default-app-dir-standalone/public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/next/default-app-dir-standalone/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/next/default-app-dir-standalone/scripts/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # Handle Ctrl+C 5 | trap 'kill $nextBuildPid $copyPublicPid $copyStaticPid 2>/dev/null' INT 6 | 7 | # Run Next.js build with passed arguments 8 | next build "$@" & 9 | nextBuildPid=$! 10 | wait $nextBuildPid 11 | 12 | # Copy files only if not in a CI environment 13 | if [ -z "$CI" ]; then 14 | cp -r ./public ./.next/standalone/public & 15 | copyPublicPid=$! 16 | 17 | cp -r ./.next/static ./.next/standalone/.next/static & 18 | copyStaticPid=$! 19 | 20 | wait $copyPublicPid $copyStaticPid 21 | fi 22 | -------------------------------------------------------------------------------- /examples/next/default-app-dir-standalone/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ImBIOS/bun-node/151bd0d6bcfed152baac8ffd523f28f4dd688df1/examples/next/default-app-dir-standalone/src/app/favicon.ico -------------------------------------------------------------------------------- /examples/next/default-app-dir-standalone/src/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | :root { 6 | --foreground-rgb: 0, 0, 0; 7 | --background-start-rgb: 214, 219, 220; 8 | --background-end-rgb: 255, 255, 255; 9 | } 10 | 11 | @media (prefers-color-scheme: dark) { 12 | :root { 13 | --foreground-rgb: 255, 255, 255; 14 | --background-start-rgb: 0, 0, 0; 15 | --background-end-rgb: 0, 0, 0; 16 | } 17 | } 18 | 19 | body { 20 | color: rgb(var(--foreground-rgb)); 21 | background: linear-gradient( 22 | to bottom, 23 | transparent, 24 | rgb(var(--background-end-rgb)) 25 | ) 26 | rgb(var(--background-start-rgb)); 27 | } 28 | -------------------------------------------------------------------------------- /examples/next/default-app-dir-standalone/src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from 'next' 2 | import { Inter } from 'next/font/google' 3 | import './globals.css' 4 | 5 | const inter = Inter({ subsets: ['latin'] }) 6 | 7 | export const metadata: Metadata = { 8 | title: 'Create Next App', 9 | description: 'Generated by create next app', 10 | } 11 | 12 | export default function RootLayout({ 13 | children, 14 | }: { 15 | children: React.ReactNode 16 | }) { 17 | return ( 18 | 19 | {children} 20 | 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /examples/next/default-app-dir-standalone/src/app/page.tsx: -------------------------------------------------------------------------------- 1 | import Image from 'next/image' 2 | 3 | export default function Home() { 4 | return ( 5 |
6 |
7 |

8 | Get started by editing  9 | src/app/page.tsx 10 |

11 |
12 | 18 | By{' '} 19 | Vercel Logo 27 | 28 |
29 |
30 | 31 |
32 | Next.js Logo 40 |
41 | 42 |
43 | 49 |

50 | Docs{' '} 51 | 52 | -> 53 | 54 |

55 |

56 | Find in-depth information about Next.js features and API. 57 |

58 |
59 | 60 | 66 |

67 | Learn{' '} 68 | 69 | -> 70 | 71 |

72 |

73 | Learn about Next.js in an interactive course with quizzes! 74 |

75 |
76 | 77 | 83 |

84 | Templates{' '} 85 | 86 | -> 87 | 88 |

89 |

90 | Explore starter templates for Next.js. 91 |

92 |
93 | 94 | 100 |

101 | Deploy{' '} 102 | 103 | -> 104 | 105 |

106 |

107 | Instantly deploy your Next.js site to a shareable URL with Vercel. 108 |

109 |
110 |
111 |
112 | ) 113 | } 114 | -------------------------------------------------------------------------------- /examples/next/default-app-dir-standalone/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'tailwindcss' 2 | 3 | const config: Config = { 4 | content: [ 5 | './src/pages/**/*.{js,ts,jsx,tsx,mdx}', 6 | './src/components/**/*.{js,ts,jsx,tsx,mdx}', 7 | './src/app/**/*.{js,ts,jsx,tsx,mdx}', 8 | ], 9 | theme: { 10 | extend: { 11 | backgroundImage: { 12 | 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', 13 | 'gradient-conic': 14 | 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))', 15 | }, 16 | }, 17 | }, 18 | plugins: [], 19 | } 20 | export default config 21 | -------------------------------------------------------------------------------- /examples/next/default-app-dir-standalone/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "noEmit": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "incremental": true, 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ], 21 | "paths": { 22 | "@/*": ["./src/*"] 23 | } 24 | }, 25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 26 | "exclude": ["node_modules"] 27 | } 28 | -------------------------------------------------------------------------------- /examples/next/default-app-dir/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /examples/next/default-app-dir/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /examples/next/default-app-dir/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | # or 14 | bun dev 15 | ``` 16 | 17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 18 | 19 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. 20 | 21 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. 22 | 23 | ## Learn More 24 | 25 | To learn more about Next.js, take a look at the following resources: 26 | 27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 29 | 30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 31 | 32 | ## Deploy on Vercel 33 | 34 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 35 | 36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 37 | -------------------------------------------------------------------------------- /examples/next/default-app-dir/bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ImBIOS/bun-node/151bd0d6bcfed152baac8ffd523f28f4dd688df1/examples/next/default-app-dir/bun.lockb -------------------------------------------------------------------------------- /examples/next/default-app-dir/dockerfile: -------------------------------------------------------------------------------- 1 | # Use the official Node.js image as the base image 2 | FROM imbios/bun-node:latest 3 | 4 | # Set the working directory inside the container 5 | WORKDIR /app 6 | 7 | # Copy the package.json and bun.lockb files to the working directory 8 | COPY package.json bun.lockb ./ 9 | 10 | # Install the app dependencies 11 | RUN bun install 12 | 13 | # Copy the rest of the app files to the working directory 14 | COPY . . 15 | 16 | # Build the Remix app 17 | RUN bun run build 18 | 19 | # Expose the port on which the app will run 20 | EXPOSE 3000 21 | 22 | # Start the app 23 | CMD ["bun", "run", "start"] 24 | 25 | -------------------------------------------------------------------------------- /examples/next/default-app-dir/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {} 3 | 4 | module.exports = nextConfig 5 | -------------------------------------------------------------------------------- /examples/next/default-app-dir/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "default-app-dir", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "react": "^18", 13 | "react-dom": "^18", 14 | "next": "14.2.21" 15 | }, 16 | "devDependencies": { 17 | "typescript": "^5", 18 | "@types/node": "^20", 19 | "@types/react": "^18", 20 | "@types/react-dom": "^18", 21 | "autoprefixer": "^10.0.1", 22 | "postcss": "^8", 23 | "tailwindcss": "^3.3.0", 24 | "eslint": "^8", 25 | "eslint-config-next": "14.0.4" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /examples/next/default-app-dir/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /examples/next/default-app-dir/public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/next/default-app-dir/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/next/default-app-dir/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ImBIOS/bun-node/151bd0d6bcfed152baac8ffd523f28f4dd688df1/examples/next/default-app-dir/src/app/favicon.ico -------------------------------------------------------------------------------- /examples/next/default-app-dir/src/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | :root { 6 | --foreground-rgb: 0, 0, 0; 7 | --background-start-rgb: 214, 219, 220; 8 | --background-end-rgb: 255, 255, 255; 9 | } 10 | 11 | @media (prefers-color-scheme: dark) { 12 | :root { 13 | --foreground-rgb: 255, 255, 255; 14 | --background-start-rgb: 0, 0, 0; 15 | --background-end-rgb: 0, 0, 0; 16 | } 17 | } 18 | 19 | body { 20 | color: rgb(var(--foreground-rgb)); 21 | background: linear-gradient( 22 | to bottom, 23 | transparent, 24 | rgb(var(--background-end-rgb)) 25 | ) 26 | rgb(var(--background-start-rgb)); 27 | } 28 | -------------------------------------------------------------------------------- /examples/next/default-app-dir/src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from 'next' 2 | import { Inter } from 'next/font/google' 3 | import './globals.css' 4 | 5 | const inter = Inter({ subsets: ['latin'] }) 6 | 7 | export const metadata: Metadata = { 8 | title: 'Create Next App', 9 | description: 'Generated by create next app', 10 | } 11 | 12 | export default function RootLayout({ 13 | children, 14 | }: { 15 | children: React.ReactNode 16 | }) { 17 | return ( 18 | 19 | {children} 20 | 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /examples/next/default-app-dir/src/app/page.tsx: -------------------------------------------------------------------------------- 1 | import Image from 'next/image' 2 | 3 | export default function Home() { 4 | return ( 5 |
6 |
7 |

8 | Get started by editing  9 | src/app/page.tsx 10 |

11 |
12 | 18 | By{' '} 19 | Vercel Logo 27 | 28 |
29 |
30 | 31 |
32 | Next.js Logo 40 |
41 | 42 |
43 | 49 |

50 | Docs{' '} 51 | 52 | -> 53 | 54 |

55 |

56 | Find in-depth information about Next.js features and API. 57 |

58 |
59 | 60 | 66 |

67 | Learn{' '} 68 | 69 | -> 70 | 71 |

72 |

73 | Learn about Next.js in an interactive course with quizzes! 74 |

75 |
76 | 77 | 83 |

84 | Templates{' '} 85 | 86 | -> 87 | 88 |

89 |

90 | Explore starter templates for Next.js. 91 |

92 |
93 | 94 | 100 |

101 | Deploy{' '} 102 | 103 | -> 104 | 105 |

106 |

107 | Instantly deploy your Next.js site to a shareable URL with Vercel. 108 |

109 |
110 |
111 |
112 | ) 113 | } 114 | -------------------------------------------------------------------------------- /examples/next/default-app-dir/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'tailwindcss' 2 | 3 | const config: Config = { 4 | content: [ 5 | './src/pages/**/*.{js,ts,jsx,tsx,mdx}', 6 | './src/components/**/*.{js,ts,jsx,tsx,mdx}', 7 | './src/app/**/*.{js,ts,jsx,tsx,mdx}', 8 | ], 9 | theme: { 10 | extend: { 11 | backgroundImage: { 12 | 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', 13 | 'gradient-conic': 14 | 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))', 15 | }, 16 | }, 17 | }, 18 | plugins: [], 19 | } 20 | export default config 21 | -------------------------------------------------------------------------------- /examples/next/default-app-dir/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "noEmit": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "incremental": true, 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ], 21 | "paths": { 22 | "@/*": ["./src/*"] 23 | } 24 | }, 25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 26 | "exclude": ["node_modules"] 27 | } 28 | -------------------------------------------------------------------------------- /examples/remix/basic/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | /** @type {import('eslint').Linter.Config} */ 2 | module.exports = { 3 | extends: ["@remix-run/eslint-config", "@remix-run/eslint-config/node"], 4 | }; 5 | -------------------------------------------------------------------------------- /examples/remix/basic/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /.cache 4 | /build 5 | /public/build 6 | .env 7 | -------------------------------------------------------------------------------- /examples/remix/basic/README.md: -------------------------------------------------------------------------------- 1 | # Welcome to Remix! 2 | 3 | - [Remix Docs](https://remix.run/docs) 4 | 5 | ## Development 6 | 7 | From your terminal: 8 | 9 | ```sh 10 | npm run dev 11 | ``` 12 | 13 | This starts your app in development mode, rebuilding assets on file changes. 14 | 15 | ## Deployment 16 | 17 | First, build your app for production: 18 | 19 | ```sh 20 | npm run build 21 | ``` 22 | 23 | Then run the app in production mode: 24 | 25 | ```sh 26 | npm start 27 | ``` 28 | 29 | Now you'll need to pick a host to deploy it to. 30 | 31 | ### DIY 32 | 33 | If you're familiar with deploying node applications, the built-in Remix app server is production-ready. 34 | 35 | Make sure to deploy the output of `remix build` 36 | 37 | - `build/` 38 | - `public/build/` 39 | -------------------------------------------------------------------------------- /examples/remix/basic/app/entry.client.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * By default, Remix will handle hydrating your app on the client for you. 3 | * You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨ 4 | * For more information, see https://remix.run/file-conventions/entry.client 5 | */ 6 | 7 | import { RemixBrowser } from "@remix-run/react"; 8 | import { startTransition, StrictMode } from "react"; 9 | import { hydrateRoot } from "react-dom/client"; 10 | 11 | startTransition(() => { 12 | hydrateRoot( 13 | document, 14 | 15 | 16 | 17 | ); 18 | }); 19 | -------------------------------------------------------------------------------- /examples/remix/basic/app/entry.server.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * By default, Remix will handle generating the HTTP Response for you. 3 | * You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨ 4 | * For more information, see https://remix.run/file-conventions/entry.server 5 | */ 6 | 7 | import { PassThrough } from "node:stream"; 8 | 9 | import type { AppLoadContext, EntryContext } from "@remix-run/node"; 10 | import { createReadableStreamFromReadable } from "@remix-run/node"; 11 | import { RemixServer } from "@remix-run/react"; 12 | import isbot from "isbot"; 13 | import { renderToPipeableStream } from "react-dom/server"; 14 | 15 | const ABORT_DELAY = 5_000; 16 | 17 | export default function handleRequest( 18 | request: Request, 19 | responseStatusCode: number, 20 | responseHeaders: Headers, 21 | remixContext: EntryContext, 22 | loadContext: AppLoadContext 23 | ) { 24 | return isbot(request.headers.get("user-agent")) 25 | ? handleBotRequest( 26 | request, 27 | responseStatusCode, 28 | responseHeaders, 29 | remixContext 30 | ) 31 | : handleBrowserRequest( 32 | request, 33 | responseStatusCode, 34 | responseHeaders, 35 | remixContext 36 | ); 37 | } 38 | 39 | function handleBotRequest( 40 | request: Request, 41 | responseStatusCode: number, 42 | responseHeaders: Headers, 43 | remixContext: EntryContext 44 | ) { 45 | return new Promise((resolve, reject) => { 46 | let shellRendered = false; 47 | const { pipe, abort } = renderToPipeableStream( 48 | , 53 | { 54 | onAllReady() { 55 | shellRendered = true; 56 | const body = new PassThrough(); 57 | const stream = createReadableStreamFromReadable(body); 58 | 59 | responseHeaders.set("Content-Type", "text/html"); 60 | 61 | resolve( 62 | new Response(stream, { 63 | headers: responseHeaders, 64 | status: responseStatusCode, 65 | }) 66 | ); 67 | 68 | pipe(body); 69 | }, 70 | onShellError(error: unknown) { 71 | reject(error); 72 | }, 73 | onError(error: unknown) { 74 | responseStatusCode = 500; 75 | // Log streaming rendering errors from inside the shell. Don't log 76 | // errors encountered during initial shell rendering since they'll 77 | // reject and get logged in handleDocumentRequest. 78 | if (shellRendered) { 79 | console.error(error); 80 | } 81 | }, 82 | } 83 | ); 84 | 85 | setTimeout(abort, ABORT_DELAY); 86 | }); 87 | } 88 | 89 | function handleBrowserRequest( 90 | request: Request, 91 | responseStatusCode: number, 92 | responseHeaders: Headers, 93 | remixContext: EntryContext 94 | ) { 95 | return new Promise((resolve, reject) => { 96 | let shellRendered = false; 97 | const { pipe, abort } = renderToPipeableStream( 98 | , 103 | { 104 | onShellReady() { 105 | shellRendered = true; 106 | const body = new PassThrough(); 107 | const stream = createReadableStreamFromReadable(body); 108 | 109 | responseHeaders.set("Content-Type", "text/html"); 110 | 111 | resolve( 112 | new Response(stream, { 113 | headers: responseHeaders, 114 | status: responseStatusCode, 115 | }) 116 | ); 117 | 118 | pipe(body); 119 | }, 120 | onShellError(error: unknown) { 121 | reject(error); 122 | }, 123 | onError(error: unknown) { 124 | responseStatusCode = 500; 125 | // Log streaming rendering errors from inside the shell. Don't log 126 | // errors encountered during initial shell rendering since they'll 127 | // reject and get logged in handleDocumentRequest. 128 | if (shellRendered) { 129 | console.error(error); 130 | } 131 | }, 132 | } 133 | ); 134 | 135 | setTimeout(abort, ABORT_DELAY); 136 | }); 137 | } 138 | -------------------------------------------------------------------------------- /examples/remix/basic/app/root.tsx: -------------------------------------------------------------------------------- 1 | import { cssBundleHref } from "@remix-run/css-bundle"; 2 | import type { LinksFunction } from "@remix-run/node"; 3 | import { 4 | Links, 5 | LiveReload, 6 | Meta, 7 | Outlet, 8 | Scripts, 9 | ScrollRestoration, 10 | } from "@remix-run/react"; 11 | 12 | export const links: LinksFunction = () => [ 13 | ...(cssBundleHref ? [{ rel: "stylesheet", href: cssBundleHref }] : []), 14 | ]; 15 | 16 | export default function App() { 17 | return ( 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /examples/remix/basic/app/routes/_index.tsx: -------------------------------------------------------------------------------- 1 | import type { MetaFunction } from "@remix-run/node"; 2 | 3 | export const meta: MetaFunction = () => { 4 | return [ 5 | { title: "New Remix App" }, 6 | { name: "description", content: "Welcome to Remix!" }, 7 | ]; 8 | }; 9 | 10 | export default function Index() { 11 | return ( 12 |
13 |

Welcome to Remix

14 | 39 |
40 | ); 41 | } 42 | -------------------------------------------------------------------------------- /examples/remix/basic/bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ImBIOS/bun-node/151bd0d6bcfed152baac8ffd523f28f4dd688df1/examples/remix/basic/bun.lockb -------------------------------------------------------------------------------- /examples/remix/basic/dockerfile: -------------------------------------------------------------------------------- 1 | # Use the official Node.js image as the base image 2 | FROM imbios/bun-node:latest 3 | 4 | # Set the working directory inside the container 5 | WORKDIR /app 6 | 7 | # Copy the package.json and bun.lockb files to the working directory 8 | COPY package.json bun.lockb ./ 9 | 10 | # Install the app dependencies 11 | RUN bun install 12 | 13 | # Copy the rest of the app files to the working directory 14 | COPY . . 15 | 16 | # Build the Remix app 17 | RUN bun run build 18 | 19 | # Expose the port on which the app will run 20 | EXPOSE 3000 21 | 22 | # Start the app 23 | CMD ["bun", "run", "start"] 24 | 25 | -------------------------------------------------------------------------------- /examples/remix/basic/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "basic-remix-test", 3 | "private": true, 4 | "sideEffects": false, 5 | "type": "module", 6 | "scripts": { 7 | "build": "remix build", 8 | "dev": "remix dev --manual", 9 | "start": "remix-serve ./build/index.js", 10 | "typecheck": "tsc" 11 | }, 12 | "dependencies": { 13 | "@remix-run/css-bundle": "^2.3.1", 14 | "@remix-run/node": "^2.3.1", 15 | "@remix-run/react": "^2.3.1", 16 | "@remix-run/serve": "^2.3.1", 17 | "isbot": "^3.6.8", 18 | "react": "^18.2.0", 19 | "react-dom": "^18.2.0" 20 | }, 21 | "devDependencies": { 22 | "@remix-run/dev": "^2.3.1", 23 | "@remix-run/eslint-config": "^2.3.1", 24 | "@types/react": "^18.2.20", 25 | "@types/react-dom": "^18.2.7", 26 | "eslint": "^8.38.0", 27 | "typescript": "^5.1.6" 28 | }, 29 | "engines": { 30 | "node": ">=18.0.0" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/remix/basic/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ImBIOS/bun-node/151bd0d6bcfed152baac8ffd523f28f4dd688df1/examples/remix/basic/public/favicon.ico -------------------------------------------------------------------------------- /examples/remix/basic/remix.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@remix-run/dev').AppConfig} */ 2 | export default { 3 | ignoredRouteFiles: ["**/.*"], 4 | // appDirectory: "app", 5 | // assetsBuildDirectory: "public/build", 6 | // publicPath: "/build/", 7 | // serverBuildPath: "build/index.js", 8 | }; 9 | -------------------------------------------------------------------------------- /examples/remix/basic/remix.env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /examples/remix/basic/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"], 3 | "compilerOptions": { 4 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 5 | "isolatedModules": true, 6 | "esModuleInterop": true, 7 | "jsx": "react-jsx", 8 | "moduleResolution": "Bundler", 9 | "resolveJsonModule": true, 10 | "target": "ES2022", 11 | "strict": true, 12 | "allowJs": true, 13 | "forceConsistentCasingInFileNames": true, 14 | "baseUrl": ".", 15 | "paths": { 16 | "~/*": ["./app/*"] 17 | }, 18 | 19 | // Remix takes care of building everything in `remix build`. 20 | "noEmit": true 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024-2025 Imamuzzaki Abu Salam 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /merge_lcov.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Check if the directory exists 4 | if [ ! -d "$1" ]; then 5 | echo "Directory $1 does not exist. Please provide a valid directory." 6 | exit 1 7 | fi 8 | 9 | # Find lcov.info and coverage.lcov files 10 | LCOV_INPUT_FILES=$(find . \( -name "lcov.info" -o -name "coverage.lcov" \)) 11 | 12 | # Check if any files were found 13 | if [ -z "$LCOV_INPUT_FILES" ]; then 14 | echo "No lcov.info or coverage.lcov files found in current directory recursively." 15 | exit 1 16 | fi 17 | 18 | # Initialize the lcov command 19 | LCOV_COMMAND="lcov" 20 | 21 | # Loop over each found file and append to the lcov command 22 | for FILE in $LCOV_INPUT_FILES; do 23 | LCOV_COMMAND="$LCOV_COMMAND -a \"$FILE\"" 24 | done 25 | 26 | # Run the lcov command with the specified output path 27 | $LCOV_COMMAND -o "$1/$2" 28 | -------------------------------------------------------------------------------- /merge_lcov_test.sh: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Bun and Node.js Docker Images: Optimize Your Development Workflow 🐇 🐳 🐢 🚀 2 | 3 | [![dockeri.co](https://dockerico.blankenship.io/image/imbios/bun-node)](https://hub.docker.com/r/imbios/bun-node) 4 | 5 | [![GitHub issues](https://img.shields.io/github/issues/ImBIOS/bun-node.svg "GitHub issues")](https://github.com/ImBIOS/bun-node) 6 | [![GitHub stars](https://img.shields.io/github/stars/ImBIOS/bun-node.svg "GitHub stars")](https://github.com/ImBIOS/bun-node) 7 | ![Test Coverage](https://github.com/ImBIOS/bun-node/raw/refs/heads/main/coverage.svg) 8 | ![CI Status](https://github.com/ImBIOS/bun-node/actions/workflows/ci.yml/badge.svg) 9 | ![Release Status](https://github.com/ImBIOS/bun-node/actions/workflows/release.yml/badge.svg) 10 | 11 | This repository offers pre-configured Docker images combining [Bun](https://bun.sh/), with [Node.js](https://nodejs.org/), the popular JavaScript runtime. Ideal for development, testing, and production environments. 12 | 13 | Use node.js as runtime, and bun as package manager, etc. The node.js in this docker image functions as fallback when bun is not implement the feature yet. 14 | 15 | ## Features 16 | 17 | - **Multiple Node.js Versions**: Supports Node.js versions which currently supported by [docker-node](https://github.com/nodejs/docker-node) 18 | - **Variety of Builds**: Available in Alpine, Debian, and Slim versions 19 | 20 | ## Quick Start 21 | 22 | ```bash 23 | docker pull imbios/bun-node 24 | ``` 25 | 26 | ## Build Types 27 | 28 | - **alpine**: Minimal build ideal for smaller footprint 29 | - **debian**: Standard build, balanced between size and features 30 | - **slim**: Debian-based but lighter, stripped of unnecessary files 31 | - Do you need `distroless` ? 32 | 33 | ## Advanced Image Tagging 34 | 35 | ```txt 36 | imbios/bun-node:--[optional -git] 37 | ``` 38 | 39 | - **bun-version**: Bun version (e.g. 1.0.0, 1.0.30, 1) or tag (e.g. latest or canary) 40 | - **node-version**: Node.js version (e.g. 18, 20.11, 21.7.1) or tag (e.g. hydrogen, iron, current) 41 | - **build-type**: Build type (e.g. alpine, debian, slim) 42 | - **optional -git**: Optional git tag, an alpine image with git installed 43 | 44 | ## Show Your Support 🌟 45 | 46 | If you find this Docker image useful, please consider giving it a ⭐ star on GitHub and Dockerhub! These stats tell me this code is useful for humanity and makes me prioritize maintenance. 47 | 48 | ## Contribution 49 | 50 | Feel free to contribute by submitting pull requests or by reporting issues. 51 | 52 | ## License 53 | 54 | This project is licensed under the MIT License. 55 | 56 | --- 57 | 58 | For custom configurations and support, visit [Project Wiki](https://github.com/ImBIOS/bun-node/wiki) or [Issues](https://github.com/ImBIOS/bun-node/issues). 59 | 60 | ## Keywords 61 | 62 | Docker, Node.js, Bun, Development, Deployment, Alpine, Debian, Slim 63 | -------------------------------------------------------------------------------- /src/base/18/alpine/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | if [ "${1#-}" != "${1}" ] || [ -z "$(command -v "${1}")" ] || { [ -f "${1}" ] && ! [ -x "${1}" ]; }; then 5 | set -- /usr/local/bin/bun "$@" 6 | fi 7 | 8 | exec "$@" 9 | -------------------------------------------------------------------------------- /src/base/18/alpine/dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.20 AS build 2 | 3 | # https://github.com/oven-sh/bun/releases 4 | ARG BUN_VERSION=latest 5 | 6 | RUN apk --no-cache add ca-certificates curl dirmngr gpg gpg-agent unzip \ 7 | && arch="$(apk --print-arch)" \ 8 | && case "${arch##*-}" in \ 9 | x86_64) build="x64-musl-baseline";; \ 10 | aarch64) build="aarch64-musl";; \ 11 | *) echo "error: unsupported architecture: $arch"; exit 1 ;; \ 12 | esac \ 13 | && version="$BUN_VERSION" \ 14 | && case "$version" in \ 15 | latest | canary | bun-v*) tag="$version"; ;; \ 16 | v*) tag="bun-$version"; ;; \ 17 | *) tag="bun-v$version"; ;; \ 18 | esac \ 19 | && case "$tag" in \ 20 | latest) release="latest/download"; ;; \ 21 | *) release="download/$tag"; ;; \ 22 | esac \ 23 | && curl "https://github.com/oven-sh/bun/releases/$release/bun-linux-$build.zip" \ 24 | -fsSLO \ 25 | --compressed \ 26 | --retry 5 \ 27 | || (echo "error: failed to download: $tag" && exit 1) \ 28 | && for key in \ 29 | "F3DCC08A8572C0749B3E18888EAB4D40A7B22B59" \ 30 | ; do \ 31 | gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" \ 32 | || gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key" ; \ 33 | done \ 34 | && curl "https://github.com/oven-sh/bun/releases/$release/SHASUMS256.txt.asc" \ 35 | -fsSLO \ 36 | --compressed \ 37 | --retry 5 \ 38 | && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \ 39 | || (echo "error: failed to verify: $tag" && exit 1) \ 40 | && grep " bun-linux-$build.zip\$" SHASUMS256.txt | sha256sum -c - \ 41 | || (echo "error: failed to verify: $tag" && exit 1) \ 42 | && unzip "bun-linux-$build.zip" \ 43 | && mv "bun-linux-$build/bun" /usr/local/bin/bun \ 44 | && rm -f "bun-linux-$build.zip" SHASUMS256.txt.asc SHASUMS256.txt \ 45 | && chmod +x /usr/local/bin/bun 46 | 47 | FROM node:18-alpine3.20 48 | 49 | # Disable the runtime transpiler cache by default inside Docker containers. 50 | # On ephemeral containers, the cache is not useful 51 | ARG BUN_RUNTIME_TRANSPILER_CACHE_PATH=0 52 | ENV BUN_RUNTIME_TRANSPILER_CACHE_PATH=${BUN_RUNTIME_TRANSPILER_CACHE_PATH} 53 | 54 | # Ensure `bun install -g` works 55 | ARG BUN_INSTALL_BIN=/usr/local/bin 56 | ENV BUN_INSTALL_BIN=${BUN_INSTALL_BIN} 57 | 58 | COPY --from=build /usr/local/bin/bun /usr/local/bin/ 59 | COPY docker-entrypoint.sh /usr/local/bin/ 60 | RUN mkdir -p /usr/local/bun-node-fallback-bin && ln -s /usr/local/bin/bun /usr/local/bun-node-fallback-bin/node 61 | ENV PATH "${PATH}:/usr/local/bun-node-fallback-bin" 62 | 63 | # Temporarily use the `build`-stage /tmp folder to access the glibc APKs: 64 | RUN --mount=type=bind,from=build,source=/tmp,target=/tmp \ 65 | addgroup -g 1001 bun \ 66 | && adduser -u 1001 -G bun -s /bin/sh -D bun \ 67 | && ln -s /usr/local/bin/bun /usr/local/bin/bunx \ 68 | && apk add libgcc libstdc++ \ 69 | && which bun \ 70 | && which bunx \ 71 | && bun --version 72 | 73 | WORKDIR /home/bun/app 74 | ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] 75 | CMD ["/usr/local/bin/bun"] 76 | -------------------------------------------------------------------------------- /src/base/18/debian-slim/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | if [ "${1#-}" != "${1}" ] || [ -z "$(command -v "${1}")" ] || { [ -f "${1}" ] && ! [ -x "${1}" ]; }; then 5 | set -- /usr/local/bin/bun "$@" 6 | fi 7 | 8 | exec "$@" 9 | -------------------------------------------------------------------------------- /src/base/18/debian-slim/dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:bookworm-slim AS build 2 | 3 | # https://github.com/oven-sh/bun/releases 4 | ARG BUN_VERSION=latest 5 | 6 | RUN apt-get update -qq \ 7 | && apt-get install -qq --no-install-recommends \ 8 | ca-certificates \ 9 | curl \ 10 | dirmngr \ 11 | gpg \ 12 | gpg-agent \ 13 | unzip \ 14 | && apt-get clean \ 15 | && rm -rf /var/lib/apt/lists/* \ 16 | && arch="$(dpkg --print-architecture)" \ 17 | && case "${arch##*-}" in \ 18 | amd64) build="x64-baseline";; \ 19 | arm64) build="aarch64";; \ 20 | *) echo "error: unsupported architecture: $arch"; exit 1 ;; \ 21 | esac \ 22 | && version="$BUN_VERSION" \ 23 | && case "$version" in \ 24 | latest | canary | bun-v*) tag="$version"; ;; \ 25 | v*) tag="bun-$version"; ;; \ 26 | *) tag="bun-v$version"; ;; \ 27 | esac \ 28 | && case "$tag" in \ 29 | latest) release="latest/download"; ;; \ 30 | *) release="download/$tag"; ;; \ 31 | esac \ 32 | && curl "https://github.com/oven-sh/bun/releases/$release/bun-linux-$build.zip" \ 33 | -fsSLO \ 34 | --compressed \ 35 | --retry 5 \ 36 | || (echo "error: failed to download: $tag" && exit 1) \ 37 | && for key in \ 38 | "F3DCC08A8572C0749B3E18888EAB4D40A7B22B59" \ 39 | ; do \ 40 | gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" \ 41 | || gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key" ; \ 42 | done \ 43 | && curl "https://github.com/oven-sh/bun/releases/$release/SHASUMS256.txt.asc" \ 44 | -fsSLO \ 45 | --compressed \ 46 | --retry 5 \ 47 | && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \ 48 | || (echo "error: failed to verify: $tag" && exit 1) \ 49 | && grep " bun-linux-$build.zip\$" SHASUMS256.txt | sha256sum -c - \ 50 | || (echo "error: failed to verify: $tag" && exit 1) \ 51 | && unzip "bun-linux-$build.zip" \ 52 | && mv "bun-linux-$build/bun" /usr/local/bin/bun \ 53 | && rm -f "bun-linux-$build.zip" SHASUMS256.txt.asc SHASUMS256.txt \ 54 | && chmod +x /usr/local/bin/bun \ 55 | && which bun \ 56 | && bun --version 57 | 58 | FROM node:18-bookworm-slim 59 | 60 | # Disable the runtime transpiler cache by default inside Docker containers. 61 | # On ephemeral containers, the cache is not useful 62 | ARG BUN_RUNTIME_TRANSPILER_CACHE_PATH=0 63 | ENV BUN_RUNTIME_TRANSPILER_CACHE_PATH=${BUN_RUNTIME_TRANSPILER_CACHE_PATH} 64 | 65 | # Ensure `bun install -g` works 66 | ARG BUN_INSTALL_BIN=/usr/local/bin 67 | ENV BUN_INSTALL_BIN=${BUN_INSTALL_BIN} 68 | 69 | COPY docker-entrypoint.sh /usr/local/bin 70 | COPY --from=build /usr/local/bin/bun /usr/local/bin/bun 71 | RUN mkdir -p /usr/local/bun-node-fallback-bin && ln -s /usr/local/bin/bun /usr/local/bun-node-fallback-bin/node 72 | ENV PATH "${PATH}:/usr/local/bun-node-fallback-bin" 73 | 74 | RUN groupadd bun \ 75 | --gid 1001 \ 76 | && useradd bun \ 77 | --uid 1001 \ 78 | --gid bun \ 79 | --shell /bin/sh \ 80 | --create-home \ 81 | && ln -s /usr/local/bin/bun /usr/local/bin/bunx \ 82 | && which bun \ 83 | && which bunx \ 84 | && bun --version 85 | 86 | WORKDIR /home/bun/app 87 | ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] 88 | CMD ["/usr/local/bin/bun"] 89 | -------------------------------------------------------------------------------- /src/base/18/debian/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | if [ "${1#-}" != "${1}" ] || [ -z "$(command -v "${1}")" ] || { [ -f "${1}" ] && ! [ -x "${1}" ]; }; then 5 | set -- /usr/local/bin/bun "$@" 6 | fi 7 | 8 | exec "$@" 9 | -------------------------------------------------------------------------------- /src/base/18/debian/dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:bookworm-slim AS build 2 | 3 | # https://github.com/oven-sh/bun/releases 4 | ARG BUN_VERSION=latest 5 | 6 | # Node.js includes python3 for node-gyp, see https://github.com/oven-sh/bun/issues/9807 7 | # Though, not on slim and alpine images. 8 | RUN apt-get update -qq \ 9 | && apt-get install -qq --no-install-recommends \ 10 | ca-certificates \ 11 | curl \ 12 | dirmngr \ 13 | gpg \ 14 | gpg-agent \ 15 | unzip \ 16 | python3 \ 17 | && apt-get clean \ 18 | && rm -rf /var/lib/apt/lists/* \ 19 | && arch="$(dpkg --print-architecture)" \ 20 | && case "${arch##*-}" in \ 21 | amd64) build="x64-baseline";; \ 22 | arm64) build="aarch64";; \ 23 | *) echo "error: unsupported architecture: $arch"; exit 1 ;; \ 24 | esac \ 25 | && version="$BUN_VERSION" \ 26 | && case "$version" in \ 27 | latest | canary | bun-v*) tag="$version"; ;; \ 28 | v*) tag="bun-$version"; ;; \ 29 | *) tag="bun-v$version"; ;; \ 30 | esac \ 31 | && case "$tag" in \ 32 | latest) release="latest/download"; ;; \ 33 | *) release="download/$tag"; ;; \ 34 | esac \ 35 | && curl "https://github.com/oven-sh/bun/releases/$release/bun-linux-$build.zip" \ 36 | -fsSLO \ 37 | --compressed \ 38 | --retry 5 \ 39 | || (echo "error: failed to download: $tag" && exit 1) \ 40 | && for key in \ 41 | "F3DCC08A8572C0749B3E18888EAB4D40A7B22B59" \ 42 | ; do \ 43 | gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" \ 44 | || gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key" ; \ 45 | done \ 46 | && curl "https://github.com/oven-sh/bun/releases/$release/SHASUMS256.txt.asc" \ 47 | -fsSLO \ 48 | --compressed \ 49 | --retry 5 \ 50 | && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \ 51 | || (echo "error: failed to verify: $tag" && exit 1) \ 52 | && grep " bun-linux-$build.zip\$" SHASUMS256.txt | sha256sum -c - \ 53 | || (echo "error: failed to verify: $tag" && exit 1) \ 54 | && unzip "bun-linux-$build.zip" \ 55 | && mv "bun-linux-$build/bun" /usr/local/bin/bun \ 56 | && rm -f "bun-linux-$build.zip" SHASUMS256.txt.asc SHASUMS256.txt \ 57 | && chmod +x /usr/local/bin/bun 58 | 59 | FROM node:18-bookworm 60 | 61 | COPY docker-entrypoint.sh /usr/local/bin 62 | COPY --from=build /usr/local/bin/bun /usr/local/bin/bun 63 | RUN mkdir -p /usr/local/bun-node-fallback-bin && ln -s /usr/local/bin/bun /usr/local/bun-node-fallback-bin/node 64 | ENV PATH "${PATH}:/usr/local/bun-node-fallback-bin" 65 | 66 | # Disable the runtime transpiler cache by default inside Docker containers. 67 | # On ephemeral containers, the cache is not useful 68 | ARG BUN_RUNTIME_TRANSPILER_CACHE_PATH=0 69 | ENV BUN_RUNTIME_TRANSPILER_CACHE_PATH=${BUN_RUNTIME_TRANSPILER_CACHE_PATH} 70 | 71 | # Ensure `bun install -g` works 72 | ARG BUN_INSTALL_BIN=/usr/local/bin 73 | ENV BUN_INSTALL_BIN=${BUN_INSTALL_BIN} 74 | 75 | RUN groupadd bun \ 76 | --gid 1001 \ 77 | && useradd bun \ 78 | --uid 1001 \ 79 | --gid bun \ 80 | --shell /bin/sh \ 81 | --create-home \ 82 | && ln -s /usr/local/bin/bun /usr/local/bin/bunx \ 83 | && which bun \ 84 | && which bunx \ 85 | && bun --version 86 | 87 | WORKDIR /home/bun/app 88 | ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] 89 | CMD ["/usr/local/bin/bun"] 90 | -------------------------------------------------------------------------------- /src/base/20/alpine/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | if [ "${1#-}" != "${1}" ] || [ -z "$(command -v "${1}")" ] || { [ -f "${1}" ] && ! [ -x "${1}" ]; }; then 5 | set -- /usr/local/bin/bun "$@" 6 | fi 7 | 8 | exec "$@" 9 | -------------------------------------------------------------------------------- /src/base/20/alpine/dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.20 AS build 2 | 3 | # https://github.com/oven-sh/bun/releases 4 | ARG BUN_VERSION=latest 5 | 6 | RUN apk --no-cache add ca-certificates curl dirmngr gpg gpg-agent unzip \ 7 | && arch="$(apk --print-arch)" \ 8 | && case "${arch##*-}" in \ 9 | x86_64) build="x64-musl-baseline";; \ 10 | aarch64) build="aarch64-musl";; \ 11 | *) echo "error: unsupported architecture: $arch"; exit 1 ;; \ 12 | esac \ 13 | && version="$BUN_VERSION" \ 14 | && case "$version" in \ 15 | latest | canary | bun-v*) tag="$version"; ;; \ 16 | v*) tag="bun-$version"; ;; \ 17 | *) tag="bun-v$version"; ;; \ 18 | esac \ 19 | && case "$tag" in \ 20 | latest) release="latest/download"; ;; \ 21 | *) release="download/$tag"; ;; \ 22 | esac \ 23 | && curl "https://github.com/oven-sh/bun/releases/$release/bun-linux-$build.zip" \ 24 | -fsSLO \ 25 | --compressed \ 26 | --retry 5 \ 27 | || (echo "error: failed to download: $tag" && exit 1) \ 28 | && for key in \ 29 | "F3DCC08A8572C0749B3E18888EAB4D40A7B22B59" \ 30 | ; do \ 31 | gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" \ 32 | || gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key" ; \ 33 | done \ 34 | && curl "https://github.com/oven-sh/bun/releases/$release/SHASUMS256.txt.asc" \ 35 | -fsSLO \ 36 | --compressed \ 37 | --retry 5 \ 38 | && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \ 39 | || (echo "error: failed to verify: $tag" && exit 1) \ 40 | && grep " bun-linux-$build.zip\$" SHASUMS256.txt | sha256sum -c - \ 41 | || (echo "error: failed to verify: $tag" && exit 1) \ 42 | && unzip "bun-linux-$build.zip" \ 43 | && mv "bun-linux-$build/bun" /usr/local/bin/bun \ 44 | && rm -f "bun-linux-$build.zip" SHASUMS256.txt.asc SHASUMS256.txt \ 45 | && chmod +x /usr/local/bin/bun 46 | 47 | FROM node:20-alpine3.20 48 | 49 | # Disable the runtime transpiler cache by default inside Docker containers. 50 | # On ephemeral containers, the cache is not useful 51 | ARG BUN_RUNTIME_TRANSPILER_CACHE_PATH=0 52 | ENV BUN_RUNTIME_TRANSPILER_CACHE_PATH=${BUN_RUNTIME_TRANSPILER_CACHE_PATH} 53 | 54 | # Ensure `bun install -g` works 55 | ARG BUN_INSTALL_BIN=/usr/local/bin 56 | ENV BUN_INSTALL_BIN=${BUN_INSTALL_BIN} 57 | 58 | COPY --from=build /usr/local/bin/bun /usr/local/bin/ 59 | COPY docker-entrypoint.sh /usr/local/bin/ 60 | RUN mkdir -p /usr/local/bun-node-fallback-bin && ln -s /usr/local/bin/bun /usr/local/bun-node-fallback-bin/node 61 | ENV PATH "${PATH}:/usr/local/bun-node-fallback-bin" 62 | 63 | # Temporarily use the `build`-stage /tmp folder to access the glibc APKs: 64 | RUN --mount=type=bind,from=build,source=/tmp,target=/tmp \ 65 | addgroup -g 1001 bun \ 66 | && adduser -u 1001 -G bun -s /bin/sh -D bun \ 67 | && ln -s /usr/local/bin/bun /usr/local/bin/bunx \ 68 | && apk add libgcc libstdc++ \ 69 | && which bun \ 70 | && which bunx \ 71 | && bun --version 72 | 73 | WORKDIR /home/bun/app 74 | ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] 75 | CMD ["/usr/local/bin/bun"] 76 | -------------------------------------------------------------------------------- /src/base/20/debian-slim/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | if [ "${1#-}" != "${1}" ] || [ -z "$(command -v "${1}")" ] || { [ -f "${1}" ] && ! [ -x "${1}" ]; }; then 5 | set -- /usr/local/bin/bun "$@" 6 | fi 7 | 8 | exec "$@" 9 | -------------------------------------------------------------------------------- /src/base/20/debian-slim/dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:bookworm-slim AS build 2 | 3 | # https://github.com/oven-sh/bun/releases 4 | ARG BUN_VERSION=latest 5 | 6 | RUN apt-get update -qq \ 7 | && apt-get install -qq --no-install-recommends \ 8 | ca-certificates \ 9 | curl \ 10 | dirmngr \ 11 | gpg \ 12 | gpg-agent \ 13 | unzip \ 14 | && apt-get clean \ 15 | && rm -rf /var/lib/apt/lists/* \ 16 | && arch="$(dpkg --print-architecture)" \ 17 | && case "${arch##*-}" in \ 18 | amd64) build="x64-baseline";; \ 19 | arm64) build="aarch64";; \ 20 | *) echo "error: unsupported architecture: $arch"; exit 1 ;; \ 21 | esac \ 22 | && version="$BUN_VERSION" \ 23 | && case "$version" in \ 24 | latest | canary | bun-v*) tag="$version"; ;; \ 25 | v*) tag="bun-$version"; ;; \ 26 | *) tag="bun-v$version"; ;; \ 27 | esac \ 28 | && case "$tag" in \ 29 | latest) release="latest/download"; ;; \ 30 | *) release="download/$tag"; ;; \ 31 | esac \ 32 | && curl "https://github.com/oven-sh/bun/releases/$release/bun-linux-$build.zip" \ 33 | -fsSLO \ 34 | --compressed \ 35 | --retry 5 \ 36 | || (echo "error: failed to download: $tag" && exit 1) \ 37 | && for key in \ 38 | "F3DCC08A8572C0749B3E18888EAB4D40A7B22B59" \ 39 | ; do \ 40 | gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" \ 41 | || gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key" ; \ 42 | done \ 43 | && curl "https://github.com/oven-sh/bun/releases/$release/SHASUMS256.txt.asc" \ 44 | -fsSLO \ 45 | --compressed \ 46 | --retry 5 \ 47 | && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \ 48 | || (echo "error: failed to verify: $tag" && exit 1) \ 49 | && grep " bun-linux-$build.zip\$" SHASUMS256.txt | sha256sum -c - \ 50 | || (echo "error: failed to verify: $tag" && exit 1) \ 51 | && unzip "bun-linux-$build.zip" \ 52 | && mv "bun-linux-$build/bun" /usr/local/bin/bun \ 53 | && rm -f "bun-linux-$build.zip" SHASUMS256.txt.asc SHASUMS256.txt \ 54 | && chmod +x /usr/local/bin/bun \ 55 | && which bun \ 56 | && bun --version 57 | 58 | FROM node:20-bookworm-slim 59 | 60 | # Disable the runtime transpiler cache by default inside Docker containers. 61 | # On ephemeral containers, the cache is not useful 62 | ARG BUN_RUNTIME_TRANSPILER_CACHE_PATH=0 63 | ENV BUN_RUNTIME_TRANSPILER_CACHE_PATH=${BUN_RUNTIME_TRANSPILER_CACHE_PATH} 64 | 65 | # Ensure `bun install -g` works 66 | ARG BUN_INSTALL_BIN=/usr/local/bin 67 | ENV BUN_INSTALL_BIN=${BUN_INSTALL_BIN} 68 | 69 | COPY docker-entrypoint.sh /usr/local/bin 70 | COPY --from=build /usr/local/bin/bun /usr/local/bin/bun 71 | RUN mkdir -p /usr/local/bun-node-fallback-bin && ln -s /usr/local/bin/bun /usr/local/bun-node-fallback-bin/node 72 | ENV PATH "${PATH}:/usr/local/bun-node-fallback-bin" 73 | 74 | RUN groupadd bun \ 75 | --gid 1001 \ 76 | && useradd bun \ 77 | --uid 1001 \ 78 | --gid bun \ 79 | --shell /bin/sh \ 80 | --create-home \ 81 | && ln -s /usr/local/bin/bun /usr/local/bin/bunx \ 82 | && which bun \ 83 | && which bunx \ 84 | && bun --version 85 | 86 | WORKDIR /home/bun/app 87 | ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] 88 | CMD ["/usr/local/bin/bun"] 89 | -------------------------------------------------------------------------------- /src/base/20/debian/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | if [ "${1#-}" != "${1}" ] || [ -z "$(command -v "${1}")" ] || { [ -f "${1}" ] && ! [ -x "${1}" ]; }; then 5 | set -- /usr/local/bin/bun "$@" 6 | fi 7 | 8 | exec "$@" 9 | -------------------------------------------------------------------------------- /src/base/20/debian/dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:bookworm-slim AS build 2 | 3 | # https://github.com/oven-sh/bun/releases 4 | ARG BUN_VERSION=latest 5 | 6 | # Node.js includes python3 for node-gyp, see https://github.com/oven-sh/bun/issues/9807 7 | # Though, not on slim and alpine images. 8 | RUN apt-get update -qq \ 9 | && apt-get install -qq --no-install-recommends \ 10 | ca-certificates \ 11 | curl \ 12 | dirmngr \ 13 | gpg \ 14 | gpg-agent \ 15 | unzip \ 16 | python3 \ 17 | && apt-get clean \ 18 | && rm -rf /var/lib/apt/lists/* \ 19 | && arch="$(dpkg --print-architecture)" \ 20 | && case "${arch##*-}" in \ 21 | amd64) build="x64-baseline";; \ 22 | arm64) build="aarch64";; \ 23 | *) echo "error: unsupported architecture: $arch"; exit 1 ;; \ 24 | esac \ 25 | && version="$BUN_VERSION" \ 26 | && case "$version" in \ 27 | latest | canary | bun-v*) tag="$version"; ;; \ 28 | v*) tag="bun-$version"; ;; \ 29 | *) tag="bun-v$version"; ;; \ 30 | esac \ 31 | && case "$tag" in \ 32 | latest) release="latest/download"; ;; \ 33 | *) release="download/$tag"; ;; \ 34 | esac \ 35 | && curl "https://github.com/oven-sh/bun/releases/$release/bun-linux-$build.zip" \ 36 | -fsSLO \ 37 | --compressed \ 38 | --retry 5 \ 39 | || (echo "error: failed to download: $tag" && exit 1) \ 40 | && for key in \ 41 | "F3DCC08A8572C0749B3E18888EAB4D40A7B22B59" \ 42 | ; do \ 43 | gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" \ 44 | || gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key" ; \ 45 | done \ 46 | && curl "https://github.com/oven-sh/bun/releases/$release/SHASUMS256.txt.asc" \ 47 | -fsSLO \ 48 | --compressed \ 49 | --retry 5 \ 50 | && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \ 51 | || (echo "error: failed to verify: $tag" && exit 1) \ 52 | && grep " bun-linux-$build.zip\$" SHASUMS256.txt | sha256sum -c - \ 53 | || (echo "error: failed to verify: $tag" && exit 1) \ 54 | && unzip "bun-linux-$build.zip" \ 55 | && mv "bun-linux-$build/bun" /usr/local/bin/bun \ 56 | && rm -f "bun-linux-$build.zip" SHASUMS256.txt.asc SHASUMS256.txt \ 57 | && chmod +x /usr/local/bin/bun 58 | 59 | FROM node:20-bookworm 60 | 61 | COPY docker-entrypoint.sh /usr/local/bin 62 | COPY --from=build /usr/local/bin/bun /usr/local/bin/bun 63 | RUN mkdir -p /usr/local/bun-node-fallback-bin && ln -s /usr/local/bin/bun /usr/local/bun-node-fallback-bin/node 64 | ENV PATH "${PATH}:/usr/local/bun-node-fallback-bin" 65 | 66 | # Disable the runtime transpiler cache by default inside Docker containers. 67 | # On ephemeral containers, the cache is not useful 68 | ARG BUN_RUNTIME_TRANSPILER_CACHE_PATH=0 69 | ENV BUN_RUNTIME_TRANSPILER_CACHE_PATH=${BUN_RUNTIME_TRANSPILER_CACHE_PATH} 70 | 71 | # Ensure `bun install -g` works 72 | ARG BUN_INSTALL_BIN=/usr/local/bin 73 | ENV BUN_INSTALL_BIN=${BUN_INSTALL_BIN} 74 | 75 | RUN groupadd bun \ 76 | --gid 1001 \ 77 | && useradd bun \ 78 | --uid 1001 \ 79 | --gid bun \ 80 | --shell /bin/sh \ 81 | --create-home \ 82 | && ln -s /usr/local/bin/bun /usr/local/bin/bunx \ 83 | && which bun \ 84 | && which bunx \ 85 | && bun --version 86 | 87 | WORKDIR /home/bun/app 88 | ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] 89 | CMD ["/usr/local/bin/bun"] 90 | -------------------------------------------------------------------------------- /src/base/22/alpine/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | if [ "${1#-}" != "${1}" ] || [ -z "$(command -v "${1}")" ] || { [ -f "${1}" ] && ! [ -x "${1}" ]; }; then 5 | set -- /usr/local/bin/bun "$@" 6 | fi 7 | 8 | exec "$@" 9 | -------------------------------------------------------------------------------- /src/base/22/alpine/dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.20 AS build 2 | 3 | # https://github.com/oven-sh/bun/releases 4 | ARG BUN_VERSION=latest 5 | 6 | RUN apk --no-cache add ca-certificates curl dirmngr gpg gpg-agent unzip \ 7 | && arch="$(apk --print-arch)" \ 8 | && case "${arch##*-}" in \ 9 | x86_64) build="x64-musl-baseline";; \ 10 | aarch64) build="aarch64-musl";; \ 11 | *) echo "error: unsupported architecture: $arch"; exit 1 ;; \ 12 | esac \ 13 | && version="$BUN_VERSION" \ 14 | && case "$version" in \ 15 | latest | canary | bun-v*) tag="$version"; ;; \ 16 | v*) tag="bun-$version"; ;; \ 17 | *) tag="bun-v$version"; ;; \ 18 | esac \ 19 | && case "$tag" in \ 20 | latest) release="latest/download"; ;; \ 21 | *) release="download/$tag"; ;; \ 22 | esac \ 23 | && curl "https://github.com/oven-sh/bun/releases/$release/bun-linux-$build.zip" \ 24 | -fsSLO \ 25 | --compressed \ 26 | --retry 5 \ 27 | || (echo "error: failed to download: $tag" && exit 1) \ 28 | && for key in \ 29 | "F3DCC08A8572C0749B3E18888EAB4D40A7B22B59" \ 30 | ; do \ 31 | gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" \ 32 | || gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key" ; \ 33 | done \ 34 | && curl "https://github.com/oven-sh/bun/releases/$release/SHASUMS256.txt.asc" \ 35 | -fsSLO \ 36 | --compressed \ 37 | --retry 5 \ 38 | && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \ 39 | || (echo "error: failed to verify: $tag" && exit 1) \ 40 | && grep " bun-linux-$build.zip\$" SHASUMS256.txt | sha256sum -c - \ 41 | || (echo "error: failed to verify: $tag" && exit 1) \ 42 | && unzip "bun-linux-$build.zip" \ 43 | && mv "bun-linux-$build/bun" /usr/local/bin/bun \ 44 | && rm -f "bun-linux-$build.zip" SHASUMS256.txt.asc SHASUMS256.txt \ 45 | && chmod +x /usr/local/bin/bun 46 | 47 | FROM node:22-alpine3.20 48 | 49 | # Disable the runtime transpiler cache by default inside Docker containers. 50 | # On ephemeral containers, the cache is not useful 51 | ARG BUN_RUNTIME_TRANSPILER_CACHE_PATH=0 52 | ENV BUN_RUNTIME_TRANSPILER_CACHE_PATH=${BUN_RUNTIME_TRANSPILER_CACHE_PATH} 53 | 54 | # Ensure `bun install -g` works 55 | ARG BUN_INSTALL_BIN=/usr/local/bin 56 | ENV BUN_INSTALL_BIN=${BUN_INSTALL_BIN} 57 | 58 | COPY --from=build /usr/local/bin/bun /usr/local/bin/ 59 | COPY docker-entrypoint.sh /usr/local/bin/ 60 | RUN mkdir -p /usr/local/bun-node-fallback-bin && ln -s /usr/local/bin/bun /usr/local/bun-node-fallback-bin/node 61 | ENV PATH "${PATH}:/usr/local/bun-node-fallback-bin" 62 | 63 | # Temporarily use the `build`-stage /tmp folder to access the glibc APKs: 64 | RUN --mount=type=bind,from=build,source=/tmp,target=/tmp \ 65 | addgroup -g 1001 bun \ 66 | && adduser -u 1001 -G bun -s /bin/sh -D bun \ 67 | && ln -s /usr/local/bin/bun /usr/local/bin/bunx \ 68 | && apk add libgcc libstdc++ \ 69 | && which bun \ 70 | && which bunx \ 71 | && bun --version 72 | 73 | WORKDIR /home/bun/app 74 | ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] 75 | CMD ["/usr/local/bin/bun"] 76 | -------------------------------------------------------------------------------- /src/base/22/debian-slim/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | if [ "${1#-}" != "${1}" ] || [ -z "$(command -v "${1}")" ] || { [ -f "${1}" ] && ! [ -x "${1}" ]; }; then 5 | set -- /usr/local/bin/bun "$@" 6 | fi 7 | 8 | exec "$@" 9 | -------------------------------------------------------------------------------- /src/base/22/debian-slim/dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:bookworm-slim AS build 2 | 3 | # https://github.com/oven-sh/bun/releases 4 | ARG BUN_VERSION=latest 5 | 6 | RUN apt-get update -qq \ 7 | && apt-get install -qq --no-install-recommends \ 8 | ca-certificates \ 9 | curl \ 10 | dirmngr \ 11 | gpg \ 12 | gpg-agent \ 13 | unzip \ 14 | && apt-get clean \ 15 | && rm -rf /var/lib/apt/lists/* \ 16 | && arch="$(dpkg --print-architecture)" \ 17 | && case "${arch##*-}" in \ 18 | amd64) build="x64-baseline";; \ 19 | arm64) build="aarch64";; \ 20 | *) echo "error: unsupported architecture: $arch"; exit 1 ;; \ 21 | esac \ 22 | && version="$BUN_VERSION" \ 23 | && case "$version" in \ 24 | latest | canary | bun-v*) tag="$version"; ;; \ 25 | v*) tag="bun-$version"; ;; \ 26 | *) tag="bun-v$version"; ;; \ 27 | esac \ 28 | && case "$tag" in \ 29 | latest) release="latest/download"; ;; \ 30 | *) release="download/$tag"; ;; \ 31 | esac \ 32 | && curl "https://github.com/oven-sh/bun/releases/$release/bun-linux-$build.zip" \ 33 | -fsSLO \ 34 | --compressed \ 35 | --retry 5 \ 36 | || (echo "error: failed to download: $tag" && exit 1) \ 37 | && for key in \ 38 | "F3DCC08A8572C0749B3E18888EAB4D40A7B22B59" \ 39 | ; do \ 40 | gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" \ 41 | || gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key" ; \ 42 | done \ 43 | && curl "https://github.com/oven-sh/bun/releases/$release/SHASUMS256.txt.asc" \ 44 | -fsSLO \ 45 | --compressed \ 46 | --retry 5 \ 47 | && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \ 48 | || (echo "error: failed to verify: $tag" && exit 1) \ 49 | && grep " bun-linux-$build.zip\$" SHASUMS256.txt | sha256sum -c - \ 50 | || (echo "error: failed to verify: $tag" && exit 1) \ 51 | && unzip "bun-linux-$build.zip" \ 52 | && mv "bun-linux-$build/bun" /usr/local/bin/bun \ 53 | && rm -f "bun-linux-$build.zip" SHASUMS256.txt.asc SHASUMS256.txt \ 54 | && chmod +x /usr/local/bin/bun \ 55 | && which bun \ 56 | && bun --version 57 | 58 | FROM node:22-bookworm-slim 59 | 60 | # Disable the runtime transpiler cache by default inside Docker containers. 61 | # On ephemeral containers, the cache is not useful 62 | ARG BUN_RUNTIME_TRANSPILER_CACHE_PATH=0 63 | ENV BUN_RUNTIME_TRANSPILER_CACHE_PATH=${BUN_RUNTIME_TRANSPILER_CACHE_PATH} 64 | 65 | # Ensure `bun install -g` works 66 | ARG BUN_INSTALL_BIN=/usr/local/bin 67 | ENV BUN_INSTALL_BIN=${BUN_INSTALL_BIN} 68 | 69 | COPY docker-entrypoint.sh /usr/local/bin 70 | COPY --from=build /usr/local/bin/bun /usr/local/bin/bun 71 | RUN mkdir -p /usr/local/bun-node-fallback-bin && ln -s /usr/local/bin/bun /usr/local/bun-node-fallback-bin/node 72 | ENV PATH "${PATH}:/usr/local/bun-node-fallback-bin" 73 | 74 | RUN groupadd bun \ 75 | --gid 1001 \ 76 | && useradd bun \ 77 | --uid 1001 \ 78 | --gid bun \ 79 | --shell /bin/sh \ 80 | --create-home \ 81 | && ln -s /usr/local/bin/bun /usr/local/bin/bunx \ 82 | && which bun \ 83 | && which bunx \ 84 | && bun --version 85 | 86 | WORKDIR /home/bun/app 87 | ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] 88 | CMD ["/usr/local/bin/bun"] 89 | -------------------------------------------------------------------------------- /src/base/22/debian/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | if [ "${1#-}" != "${1}" ] || [ -z "$(command -v "${1}")" ] || { [ -f "${1}" ] && ! [ -x "${1}" ]; }; then 5 | set -- /usr/local/bin/bun "$@" 6 | fi 7 | 8 | exec "$@" 9 | -------------------------------------------------------------------------------- /src/base/22/debian/dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:bookworm-slim AS build 2 | 3 | # https://github.com/oven-sh/bun/releases 4 | ARG BUN_VERSION=latest 5 | 6 | # Node.js includes python3 for node-gyp, see https://github.com/oven-sh/bun/issues/9807 7 | # Though, not on slim and alpine images. 8 | RUN apt-get update -qq \ 9 | && apt-get install -qq --no-install-recommends \ 10 | ca-certificates \ 11 | curl \ 12 | dirmngr \ 13 | gpg \ 14 | gpg-agent \ 15 | unzip \ 16 | python3 \ 17 | && apt-get clean \ 18 | && rm -rf /var/lib/apt/lists/* \ 19 | && arch="$(dpkg --print-architecture)" \ 20 | && case "${arch##*-}" in \ 21 | amd64) build="x64-baseline";; \ 22 | arm64) build="aarch64";; \ 23 | *) echo "error: unsupported architecture: $arch"; exit 1 ;; \ 24 | esac \ 25 | && version="$BUN_VERSION" \ 26 | && case "$version" in \ 27 | latest | canary | bun-v*) tag="$version"; ;; \ 28 | v*) tag="bun-$version"; ;; \ 29 | *) tag="bun-v$version"; ;; \ 30 | esac \ 31 | && case "$tag" in \ 32 | latest) release="latest/download"; ;; \ 33 | *) release="download/$tag"; ;; \ 34 | esac \ 35 | && curl "https://github.com/oven-sh/bun/releases/$release/bun-linux-$build.zip" \ 36 | -fsSLO \ 37 | --compressed \ 38 | --retry 5 \ 39 | || (echo "error: failed to download: $tag" && exit 1) \ 40 | && for key in \ 41 | "F3DCC08A8572C0749B3E18888EAB4D40A7B22B59" \ 42 | ; do \ 43 | gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" \ 44 | || gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key" ; \ 45 | done \ 46 | && curl "https://github.com/oven-sh/bun/releases/$release/SHASUMS256.txt.asc" \ 47 | -fsSLO \ 48 | --compressed \ 49 | --retry 5 \ 50 | && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \ 51 | || (echo "error: failed to verify: $tag" && exit 1) \ 52 | && grep " bun-linux-$build.zip\$" SHASUMS256.txt | sha256sum -c - \ 53 | || (echo "error: failed to verify: $tag" && exit 1) \ 54 | && unzip "bun-linux-$build.zip" \ 55 | && mv "bun-linux-$build/bun" /usr/local/bin/bun \ 56 | && rm -f "bun-linux-$build.zip" SHASUMS256.txt.asc SHASUMS256.txt \ 57 | && chmod +x /usr/local/bin/bun 58 | 59 | FROM node:22-bookworm 60 | 61 | COPY docker-entrypoint.sh /usr/local/bin 62 | COPY --from=build /usr/local/bin/bun /usr/local/bin/bun 63 | RUN mkdir -p /usr/local/bun-node-fallback-bin && ln -s /usr/local/bin/bun /usr/local/bun-node-fallback-bin/node 64 | ENV PATH "${PATH}:/usr/local/bun-node-fallback-bin" 65 | 66 | # Disable the runtime transpiler cache by default inside Docker containers. 67 | # On ephemeral containers, the cache is not useful 68 | ARG BUN_RUNTIME_TRANSPILER_CACHE_PATH=0 69 | ENV BUN_RUNTIME_TRANSPILER_CACHE_PATH=${BUN_RUNTIME_TRANSPILER_CACHE_PATH} 70 | 71 | # Ensure `bun install -g` works 72 | ARG BUN_INSTALL_BIN=/usr/local/bin 73 | ENV BUN_INSTALL_BIN=${BUN_INSTALL_BIN} 74 | 75 | RUN groupadd bun \ 76 | --gid 1001 \ 77 | && useradd bun \ 78 | --uid 1001 \ 79 | --gid bun \ 80 | --shell /bin/sh \ 81 | --create-home \ 82 | && ln -s /usr/local/bin/bun /usr/local/bin/bunx \ 83 | && which bun \ 84 | && which bunx \ 85 | && bun --version 86 | 87 | WORKDIR /home/bun/app 88 | ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] 89 | CMD ["/usr/local/bin/bun"] 90 | -------------------------------------------------------------------------------- /src/base/23/alpine/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | if [ "${1#-}" != "${1}" ] || [ -z "$(command -v "${1}")" ] || { [ -f "${1}" ] && ! [ -x "${1}" ]; }; then 5 | set -- /usr/local/bin/bun "$@" 6 | fi 7 | 8 | exec "$@" 9 | -------------------------------------------------------------------------------- /src/base/23/alpine/dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.20 AS build 2 | 3 | # https://github.com/oven-sh/bun/releases 4 | ARG BUN_VERSION=latest 5 | 6 | RUN apk --no-cache add ca-certificates curl dirmngr gpg gpg-agent unzip \ 7 | && arch="$(apk --print-arch)" \ 8 | && case "${arch##*-}" in \ 9 | x86_64) build="x64-musl-baseline";; \ 10 | aarch64) build="aarch64-musl";; \ 11 | *) echo "error: unsupported architecture: $arch"; exit 1 ;; \ 12 | esac \ 13 | && version="$BUN_VERSION" \ 14 | && case "$version" in \ 15 | latest | canary | bun-v*) tag="$version"; ;; \ 16 | v*) tag="bun-$version"; ;; \ 17 | *) tag="bun-v$version"; ;; \ 18 | esac \ 19 | && case "$tag" in \ 20 | latest) release="latest/download"; ;; \ 21 | *) release="download/$tag"; ;; \ 22 | esac \ 23 | && curl "https://github.com/oven-sh/bun/releases/$release/bun-linux-$build.zip" \ 24 | -fsSLO \ 25 | --compressed \ 26 | --retry 5 \ 27 | || (echo "error: failed to download: $tag" && exit 1) \ 28 | && for key in \ 29 | "F3DCC08A8572C0749B3E18888EAB4D40A7B22B59" \ 30 | ; do \ 31 | gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" \ 32 | || gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key" ; \ 33 | done \ 34 | && curl "https://github.com/oven-sh/bun/releases/$release/SHASUMS256.txt.asc" \ 35 | -fsSLO \ 36 | --compressed \ 37 | --retry 5 \ 38 | && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \ 39 | || (echo "error: failed to verify: $tag" && exit 1) \ 40 | && grep " bun-linux-$build.zip\$" SHASUMS256.txt | sha256sum -c - \ 41 | || (echo "error: failed to verify: $tag" && exit 1) \ 42 | && unzip "bun-linux-$build.zip" \ 43 | && mv "bun-linux-$build/bun" /usr/local/bin/bun \ 44 | && rm -f "bun-linux-$build.zip" SHASUMS256.txt.asc SHASUMS256.txt \ 45 | && chmod +x /usr/local/bin/bun 46 | 47 | FROM node:23-alpine3.20 48 | 49 | # Disable the runtime transpiler cache by default inside Docker containers. 50 | # On ephemeral containers, the cache is not useful 51 | ARG BUN_RUNTIME_TRANSPILER_CACHE_PATH=0 52 | ENV BUN_RUNTIME_TRANSPILER_CACHE_PATH=${BUN_RUNTIME_TRANSPILER_CACHE_PATH} 53 | 54 | # Ensure `bun install -g` works 55 | ARG BUN_INSTALL_BIN=/usr/local/bin 56 | ENV BUN_INSTALL_BIN=${BUN_INSTALL_BIN} 57 | 58 | COPY --from=build /usr/local/bin/bun /usr/local/bin/ 59 | COPY docker-entrypoint.sh /usr/local/bin/ 60 | RUN mkdir -p /usr/local/bun-node-fallback-bin && ln -s /usr/local/bin/bun /usr/local/bun-node-fallback-bin/node 61 | ENV PATH "${PATH}:/usr/local/bun-node-fallback-bin" 62 | 63 | # Temporarily use the `build`-stage /tmp folder to access the glibc APKs: 64 | RUN --mount=type=bind,from=build,source=/tmp,target=/tmp \ 65 | addgroup -g 1001 bun \ 66 | && adduser -u 1001 -G bun -s /bin/sh -D bun \ 67 | && ln -s /usr/local/bin/bun /usr/local/bin/bunx \ 68 | && apk add libgcc libstdc++ \ 69 | && which bun \ 70 | && which bunx \ 71 | && bun --version 72 | 73 | WORKDIR /home/bun/app 74 | ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] 75 | CMD ["/usr/local/bin/bun"] 76 | -------------------------------------------------------------------------------- /src/base/23/debian-slim/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | if [ "${1#-}" != "${1}" ] || [ -z "$(command -v "${1}")" ] || { [ -f "${1}" ] && ! [ -x "${1}" ]; }; then 5 | set -- /usr/local/bin/bun "$@" 6 | fi 7 | 8 | exec "$@" 9 | -------------------------------------------------------------------------------- /src/base/23/debian-slim/dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:bookworm-slim AS build 2 | 3 | # https://github.com/oven-sh/bun/releases 4 | ARG BUN_VERSION=latest 5 | 6 | RUN apt-get update -qq \ 7 | && apt-get install -qq --no-install-recommends \ 8 | ca-certificates \ 9 | curl \ 10 | dirmngr \ 11 | gpg \ 12 | gpg-agent \ 13 | unzip \ 14 | && apt-get clean \ 15 | && rm -rf /var/lib/apt/lists/* \ 16 | && arch="$(dpkg --print-architecture)" \ 17 | && case "${arch##*-}" in \ 18 | amd64) build="x64-baseline";; \ 19 | arm64) build="aarch64";; \ 20 | *) echo "error: unsupported architecture: $arch"; exit 1 ;; \ 21 | esac \ 22 | && version="$BUN_VERSION" \ 23 | && case "$version" in \ 24 | latest | canary | bun-v*) tag="$version"; ;; \ 25 | v*) tag="bun-$version"; ;; \ 26 | *) tag="bun-v$version"; ;; \ 27 | esac \ 28 | && case "$tag" in \ 29 | latest) release="latest/download"; ;; \ 30 | *) release="download/$tag"; ;; \ 31 | esac \ 32 | && curl "https://github.com/oven-sh/bun/releases/$release/bun-linux-$build.zip" \ 33 | -fsSLO \ 34 | --compressed \ 35 | --retry 5 \ 36 | || (echo "error: failed to download: $tag" && exit 1) \ 37 | && for key in \ 38 | "F3DCC08A8572C0749B3E18888EAB4D40A7B22B59" \ 39 | ; do \ 40 | gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" \ 41 | || gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key" ; \ 42 | done \ 43 | && curl "https://github.com/oven-sh/bun/releases/$release/SHASUMS256.txt.asc" \ 44 | -fsSLO \ 45 | --compressed \ 46 | --retry 5 \ 47 | && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \ 48 | || (echo "error: failed to verify: $tag" && exit 1) \ 49 | && grep " bun-linux-$build.zip\$" SHASUMS256.txt | sha256sum -c - \ 50 | || (echo "error: failed to verify: $tag" && exit 1) \ 51 | && unzip "bun-linux-$build.zip" \ 52 | && mv "bun-linux-$build/bun" /usr/local/bin/bun \ 53 | && rm -f "bun-linux-$build.zip" SHASUMS256.txt.asc SHASUMS256.txt \ 54 | && chmod +x /usr/local/bin/bun \ 55 | && which bun \ 56 | && bun --version 57 | 58 | FROM node:23-bookworm-slim 59 | 60 | # Disable the runtime transpiler cache by default inside Docker containers. 61 | # On ephemeral containers, the cache is not useful 62 | ARG BUN_RUNTIME_TRANSPILER_CACHE_PATH=0 63 | ENV BUN_RUNTIME_TRANSPILER_CACHE_PATH=${BUN_RUNTIME_TRANSPILER_CACHE_PATH} 64 | 65 | # Ensure `bun install -g` works 66 | ARG BUN_INSTALL_BIN=/usr/local/bin 67 | ENV BUN_INSTALL_BIN=${BUN_INSTALL_BIN} 68 | 69 | COPY docker-entrypoint.sh /usr/local/bin 70 | COPY --from=build /usr/local/bin/bun /usr/local/bin/bun 71 | RUN mkdir -p /usr/local/bun-node-fallback-bin && ln -s /usr/local/bin/bun /usr/local/bun-node-fallback-bin/node 72 | ENV PATH "${PATH}:/usr/local/bun-node-fallback-bin" 73 | 74 | RUN groupadd bun \ 75 | --gid 1001 \ 76 | && useradd bun \ 77 | --uid 1001 \ 78 | --gid bun \ 79 | --shell /bin/sh \ 80 | --create-home \ 81 | && ln -s /usr/local/bin/bun /usr/local/bin/bunx \ 82 | && which bun \ 83 | && which bunx \ 84 | && bun --version 85 | 86 | WORKDIR /home/bun/app 87 | ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] 88 | CMD ["/usr/local/bin/bun"] 89 | -------------------------------------------------------------------------------- /src/base/23/debian/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | if [ "${1#-}" != "${1}" ] || [ -z "$(command -v "${1}")" ] || { [ -f "${1}" ] && ! [ -x "${1}" ]; }; then 5 | set -- /usr/local/bin/bun "$@" 6 | fi 7 | 8 | exec "$@" 9 | -------------------------------------------------------------------------------- /src/base/23/debian/dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:bookworm-slim AS build 2 | 3 | # https://github.com/oven-sh/bun/releases 4 | ARG BUN_VERSION=latest 5 | 6 | # Node.js includes python3 for node-gyp, see https://github.com/oven-sh/bun/issues/9807 7 | # Though, not on slim and alpine images. 8 | RUN apt-get update -qq \ 9 | && apt-get install -qq --no-install-recommends \ 10 | ca-certificates \ 11 | curl \ 12 | dirmngr \ 13 | gpg \ 14 | gpg-agent \ 15 | unzip \ 16 | python3 \ 17 | && apt-get clean \ 18 | && rm -rf /var/lib/apt/lists/* \ 19 | && arch="$(dpkg --print-architecture)" \ 20 | && case "${arch##*-}" in \ 21 | amd64) build="x64-baseline";; \ 22 | arm64) build="aarch64";; \ 23 | *) echo "error: unsupported architecture: $arch"; exit 1 ;; \ 24 | esac \ 25 | && version="$BUN_VERSION" \ 26 | && case "$version" in \ 27 | latest | canary | bun-v*) tag="$version"; ;; \ 28 | v*) tag="bun-$version"; ;; \ 29 | *) tag="bun-v$version"; ;; \ 30 | esac \ 31 | && case "$tag" in \ 32 | latest) release="latest/download"; ;; \ 33 | *) release="download/$tag"; ;; \ 34 | esac \ 35 | && curl "https://github.com/oven-sh/bun/releases/$release/bun-linux-$build.zip" \ 36 | -fsSLO \ 37 | --compressed \ 38 | --retry 5 \ 39 | || (echo "error: failed to download: $tag" && exit 1) \ 40 | && for key in \ 41 | "F3DCC08A8572C0749B3E18888EAB4D40A7B22B59" \ 42 | ; do \ 43 | gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" \ 44 | || gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key" ; \ 45 | done \ 46 | && curl "https://github.com/oven-sh/bun/releases/$release/SHASUMS256.txt.asc" \ 47 | -fsSLO \ 48 | --compressed \ 49 | --retry 5 \ 50 | && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \ 51 | || (echo "error: failed to verify: $tag" && exit 1) \ 52 | && grep " bun-linux-$build.zip\$" SHASUMS256.txt | sha256sum -c - \ 53 | || (echo "error: failed to verify: $tag" && exit 1) \ 54 | && unzip "bun-linux-$build.zip" \ 55 | && mv "bun-linux-$build/bun" /usr/local/bin/bun \ 56 | && rm -f "bun-linux-$build.zip" SHASUMS256.txt.asc SHASUMS256.txt \ 57 | && chmod +x /usr/local/bin/bun 58 | 59 | FROM node:23-bookworm 60 | 61 | COPY docker-entrypoint.sh /usr/local/bin 62 | COPY --from=build /usr/local/bin/bun /usr/local/bin/bun 63 | RUN mkdir -p /usr/local/bun-node-fallback-bin && ln -s /usr/local/bin/bun /usr/local/bun-node-fallback-bin/node 64 | ENV PATH "${PATH}:/usr/local/bun-node-fallback-bin" 65 | 66 | # Disable the runtime transpiler cache by default inside Docker containers. 67 | # On ephemeral containers, the cache is not useful 68 | ARG BUN_RUNTIME_TRANSPILER_CACHE_PATH=0 69 | ENV BUN_RUNTIME_TRANSPILER_CACHE_PATH=${BUN_RUNTIME_TRANSPILER_CACHE_PATH} 70 | 71 | # Ensure `bun install -g` works 72 | ARG BUN_INSTALL_BIN=/usr/local/bin 73 | ENV BUN_INSTALL_BIN=${BUN_INSTALL_BIN} 74 | 75 | RUN groupadd bun \ 76 | --gid 1001 \ 77 | && useradd bun \ 78 | --uid 1001 \ 79 | --gid bun \ 80 | --shell /bin/sh \ 81 | --create-home \ 82 | && ln -s /usr/local/bin/bun /usr/local/bin/bunx \ 83 | && which bun \ 84 | && which bunx \ 85 | && bun --version 86 | 87 | WORKDIR /home/bun/app 88 | ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] 89 | CMD ["/usr/local/bin/bun"] 90 | -------------------------------------------------------------------------------- /src/git/18/alpine/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | if [ "${1#-}" != "${1}" ] || [ -z "$(command -v "${1}")" ] || { [ -f "${1}" ] && ! [ -x "${1}" ]; }; then 5 | set -- /usr/local/bin/bun "$@" 6 | fi 7 | 8 | exec "$@" 9 | -------------------------------------------------------------------------------- /src/git/18/alpine/dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.20 AS build 2 | 3 | # https://github.com/oven-sh/bun/releases 4 | ARG BUN_VERSION=latest 5 | 6 | RUN apk --no-cache add ca-certificates curl dirmngr gpg gpg-agent unzip \ 7 | && arch="$(apk --print-arch)" \ 8 | && case "${arch##*-}" in \ 9 | x86_64) build="x64-musl-baseline";; \ 10 | aarch64) build="aarch64-musl";; \ 11 | *) echo "error: unsupported architecture: $arch"; exit 1 ;; \ 12 | esac \ 13 | && version="$BUN_VERSION" \ 14 | && case "$version" in \ 15 | latest | canary | bun-v*) tag="$version"; ;; \ 16 | v*) tag="bun-$version"; ;; \ 17 | *) tag="bun-v$version"; ;; \ 18 | esac \ 19 | && case "$tag" in \ 20 | latest) release="latest/download"; ;; \ 21 | *) release="download/$tag"; ;; \ 22 | esac \ 23 | && curl "https://github.com/oven-sh/bun/releases/$release/bun-linux-$build.zip" \ 24 | -fsSLO \ 25 | --compressed \ 26 | --retry 5 \ 27 | || (echo "error: failed to download: $tag" && exit 1) \ 28 | && for key in \ 29 | "F3DCC08A8572C0749B3E18888EAB4D40A7B22B59" \ 30 | ; do \ 31 | gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" \ 32 | || gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key" ; \ 33 | done \ 34 | && curl "https://github.com/oven-sh/bun/releases/$release/SHASUMS256.txt.asc" \ 35 | -fsSLO \ 36 | --compressed \ 37 | --retry 5 \ 38 | && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \ 39 | || (echo "error: failed to verify: $tag" && exit 1) \ 40 | && grep " bun-linux-$build.zip\$" SHASUMS256.txt | sha256sum -c - \ 41 | || (echo "error: failed to verify: $tag" && exit 1) \ 42 | && unzip "bun-linux-$build.zip" \ 43 | && mv "bun-linux-$build/bun" /usr/local/bin/bun \ 44 | && rm -f "bun-linux-$build.zip" SHASUMS256.txt.asc SHASUMS256.txt \ 45 | && chmod +x /usr/local/bin/bun 46 | 47 | FROM node:18-alpine3.20 48 | 49 | # Disable the runtime transpiler cache by default inside Docker containers. 50 | # On ephemeral containers, the cache is not useful 51 | ARG BUN_RUNTIME_TRANSPILER_CACHE_PATH=0 52 | ENV BUN_RUNTIME_TRANSPILER_CACHE_PATH=${BUN_RUNTIME_TRANSPILER_CACHE_PATH} 53 | 54 | # Ensure `bun install -g` works 55 | ARG BUN_INSTALL_BIN=/usr/local/bin 56 | ENV BUN_INSTALL_BIN=${BUN_INSTALL_BIN} 57 | 58 | COPY --from=build /usr/local/bin/bun /usr/local/bin/ 59 | COPY docker-entrypoint.sh /usr/local/bin/ 60 | RUN mkdir -p /usr/local/bun-node-fallback-bin && ln -s /usr/local/bin/bun /usr/local/bun-node-fallback-bin/node 61 | ENV PATH "${PATH}:/usr/local/bun-node-fallback-bin" 62 | 63 | # Temporarily use the `build`-stage /tmp folder to access the glibc APKs: 64 | RUN --mount=type=bind,from=build,source=/tmp,target=/tmp \ 65 | addgroup -g 1001 bun \ 66 | && adduser -u 1001 -G bun -s /bin/sh -D bun \ 67 | && ln -s /usr/local/bin/bun /usr/local/bin/bunx \ 68 | && apk add libgcc libstdc++ \ 69 | && which bun \ 70 | && which bunx \ 71 | && bun --version 72 | 73 | # Add git 74 | RUN apk fix && \ 75 | apk --no-cache --update add git git-lfs gpg less openssh patch && \ 76 | git lfs install 77 | 78 | WORKDIR /home/bun/app 79 | ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] 80 | CMD ["/usr/local/bin/bun"] 81 | -------------------------------------------------------------------------------- /src/git/20/alpine/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | if [ "${1#-}" != "${1}" ] || [ -z "$(command -v "${1}")" ] || { [ -f "${1}" ] && ! [ -x "${1}" ]; }; then 5 | set -- /usr/local/bin/bun "$@" 6 | fi 7 | 8 | exec "$@" 9 | -------------------------------------------------------------------------------- /src/git/20/alpine/dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.20 AS build 2 | 3 | # https://github.com/oven-sh/bun/releases 4 | ARG BUN_VERSION=latest 5 | 6 | RUN apk --no-cache add ca-certificates curl dirmngr gpg gpg-agent unzip \ 7 | && arch="$(apk --print-arch)" \ 8 | && case "${arch##*-}" in \ 9 | x86_64) build="x64-musl-baseline";; \ 10 | aarch64) build="aarch64-musl";; \ 11 | *) echo "error: unsupported architecture: $arch"; exit 1 ;; \ 12 | esac \ 13 | && version="$BUN_VERSION" \ 14 | && case "$version" in \ 15 | latest | canary | bun-v*) tag="$version"; ;; \ 16 | v*) tag="bun-$version"; ;; \ 17 | *) tag="bun-v$version"; ;; \ 18 | esac \ 19 | && case "$tag" in \ 20 | latest) release="latest/download"; ;; \ 21 | *) release="download/$tag"; ;; \ 22 | esac \ 23 | && curl "https://github.com/oven-sh/bun/releases/$release/bun-linux-$build.zip" \ 24 | -fsSLO \ 25 | --compressed \ 26 | --retry 5 \ 27 | || (echo "error: failed to download: $tag" && exit 1) \ 28 | && for key in \ 29 | "F3DCC08A8572C0749B3E18888EAB4D40A7B22B59" \ 30 | ; do \ 31 | gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" \ 32 | || gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key" ; \ 33 | done \ 34 | && curl "https://github.com/oven-sh/bun/releases/$release/SHASUMS256.txt.asc" \ 35 | -fsSLO \ 36 | --compressed \ 37 | --retry 5 \ 38 | && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \ 39 | || (echo "error: failed to verify: $tag" && exit 1) \ 40 | && grep " bun-linux-$build.zip\$" SHASUMS256.txt | sha256sum -c - \ 41 | || (echo "error: failed to verify: $tag" && exit 1) \ 42 | && unzip "bun-linux-$build.zip" \ 43 | && mv "bun-linux-$build/bun" /usr/local/bin/bun \ 44 | && rm -f "bun-linux-$build.zip" SHASUMS256.txt.asc SHASUMS256.txt \ 45 | && chmod +x /usr/local/bin/bun 46 | 47 | FROM node:20-alpine3.20 48 | 49 | # Disable the runtime transpiler cache by default inside Docker containers. 50 | # On ephemeral containers, the cache is not useful 51 | ARG BUN_RUNTIME_TRANSPILER_CACHE_PATH=0 52 | ENV BUN_RUNTIME_TRANSPILER_CACHE_PATH=${BUN_RUNTIME_TRANSPILER_CACHE_PATH} 53 | 54 | # Ensure `bun install -g` works 55 | ARG BUN_INSTALL_BIN=/usr/local/bin 56 | ENV BUN_INSTALL_BIN=${BUN_INSTALL_BIN} 57 | 58 | COPY --from=build /usr/local/bin/bun /usr/local/bin/ 59 | COPY docker-entrypoint.sh /usr/local/bin/ 60 | RUN mkdir -p /usr/local/bun-node-fallback-bin && ln -s /usr/local/bin/bun /usr/local/bun-node-fallback-bin/node 61 | ENV PATH "${PATH}:/usr/local/bun-node-fallback-bin" 62 | 63 | # Temporarily use the `build`-stage /tmp folder to access the glibc APKs: 64 | RUN --mount=type=bind,from=build,source=/tmp,target=/tmp \ 65 | addgroup -g 1001 bun \ 66 | && adduser -u 1001 -G bun -s /bin/sh -D bun \ 67 | && ln -s /usr/local/bin/bun /usr/local/bin/bunx \ 68 | && apk add libgcc libstdc++ \ 69 | && which bun \ 70 | && which bunx \ 71 | && bun --version 72 | 73 | # Add git 74 | RUN apk fix && \ 75 | apk --no-cache --update add git git-lfs gpg less openssh patch && \ 76 | git lfs install 77 | 78 | WORKDIR /home/bun/app 79 | ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] 80 | CMD ["/usr/local/bin/bun"] 81 | -------------------------------------------------------------------------------- /src/git/22/alpine/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | if [ "${1#-}" != "${1}" ] || [ -z "$(command -v "${1}")" ] || { [ -f "${1}" ] && ! [ -x "${1}" ]; }; then 5 | set -- /usr/local/bin/bun "$@" 6 | fi 7 | 8 | exec "$@" 9 | -------------------------------------------------------------------------------- /src/git/22/alpine/dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.20 AS build 2 | 3 | # https://github.com/oven-sh/bun/releases 4 | ARG BUN_VERSION=latest 5 | 6 | RUN apk --no-cache add ca-certificates curl dirmngr gpg gpg-agent unzip \ 7 | && arch="$(apk --print-arch)" \ 8 | && case "${arch##*-}" in \ 9 | x86_64) build="x64-musl-baseline";; \ 10 | aarch64) build="aarch64-musl";; \ 11 | *) echo "error: unsupported architecture: $arch"; exit 1 ;; \ 12 | esac \ 13 | && version="$BUN_VERSION" \ 14 | && case "$version" in \ 15 | latest | canary | bun-v*) tag="$version"; ;; \ 16 | v*) tag="bun-$version"; ;; \ 17 | *) tag="bun-v$version"; ;; \ 18 | esac \ 19 | && case "$tag" in \ 20 | latest) release="latest/download"; ;; \ 21 | *) release="download/$tag"; ;; \ 22 | esac \ 23 | && curl "https://github.com/oven-sh/bun/releases/$release/bun-linux-$build.zip" \ 24 | -fsSLO \ 25 | --compressed \ 26 | --retry 5 \ 27 | || (echo "error: failed to download: $tag" && exit 1) \ 28 | && for key in \ 29 | "F3DCC08A8572C0749B3E18888EAB4D40A7B22B59" \ 30 | ; do \ 31 | gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" \ 32 | || gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key" ; \ 33 | done \ 34 | && curl "https://github.com/oven-sh/bun/releases/$release/SHASUMS256.txt.asc" \ 35 | -fsSLO \ 36 | --compressed \ 37 | --retry 5 \ 38 | && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \ 39 | || (echo "error: failed to verify: $tag" && exit 1) \ 40 | && grep " bun-linux-$build.zip\$" SHASUMS256.txt | sha256sum -c - \ 41 | || (echo "error: failed to verify: $tag" && exit 1) \ 42 | && unzip "bun-linux-$build.zip" \ 43 | && mv "bun-linux-$build/bun" /usr/local/bin/bun \ 44 | && rm -f "bun-linux-$build.zip" SHASUMS256.txt.asc SHASUMS256.txt \ 45 | && chmod +x /usr/local/bin/bun 46 | 47 | FROM node:22-alpine3.20 48 | 49 | # Disable the runtime transpiler cache by default inside Docker containers. 50 | # On ephemeral containers, the cache is not useful 51 | ARG BUN_RUNTIME_TRANSPILER_CACHE_PATH=0 52 | ENV BUN_RUNTIME_TRANSPILER_CACHE_PATH=${BUN_RUNTIME_TRANSPILER_CACHE_PATH} 53 | 54 | # Ensure `bun install -g` works 55 | ARG BUN_INSTALL_BIN=/usr/local/bin 56 | ENV BUN_INSTALL_BIN=${BUN_INSTALL_BIN} 57 | 58 | COPY --from=build /usr/local/bin/bun /usr/local/bin/ 59 | COPY docker-entrypoint.sh /usr/local/bin/ 60 | RUN mkdir -p /usr/local/bun-node-fallback-bin && ln -s /usr/local/bin/bun /usr/local/bun-node-fallback-bin/node 61 | ENV PATH "${PATH}:/usr/local/bun-node-fallback-bin" 62 | 63 | # Temporarily use the `build`-stage /tmp folder to access the glibc APKs: 64 | RUN --mount=type=bind,from=build,source=/tmp,target=/tmp \ 65 | addgroup -g 1001 bun \ 66 | && adduser -u 1001 -G bun -s /bin/sh -D bun \ 67 | && ln -s /usr/local/bin/bun /usr/local/bin/bunx \ 68 | && apk add libgcc libstdc++ \ 69 | && which bun \ 70 | && which bunx \ 71 | && bun --version 72 | 73 | # Add git 74 | RUN apk fix && \ 75 | apk --no-cache --update add git git-lfs gpg less openssh patch && \ 76 | git lfs install 77 | 78 | WORKDIR /home/bun/app 79 | ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] 80 | CMD ["/usr/local/bin/bun"] 81 | -------------------------------------------------------------------------------- /src/git/23/alpine/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | if [ "${1#-}" != "${1}" ] || [ -z "$(command -v "${1}")" ] || { [ -f "${1}" ] && ! [ -x "${1}" ]; }; then 5 | set -- /usr/local/bin/bun "$@" 6 | fi 7 | 8 | exec "$@" 9 | -------------------------------------------------------------------------------- /src/git/23/alpine/dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.20 AS build 2 | 3 | # https://github.com/oven-sh/bun/releases 4 | ARG BUN_VERSION=latest 5 | 6 | RUN apk --no-cache add ca-certificates curl dirmngr gpg gpg-agent unzip \ 7 | && arch="$(apk --print-arch)" \ 8 | && case "${arch##*-}" in \ 9 | x86_64) build="x64-musl-baseline";; \ 10 | aarch64) build="aarch64-musl";; \ 11 | *) echo "error: unsupported architecture: $arch"; exit 1 ;; \ 12 | esac \ 13 | && version="$BUN_VERSION" \ 14 | && case "$version" in \ 15 | latest | canary | bun-v*) tag="$version"; ;; \ 16 | v*) tag="bun-$version"; ;; \ 17 | *) tag="bun-v$version"; ;; \ 18 | esac \ 19 | && case "$tag" in \ 20 | latest) release="latest/download"; ;; \ 21 | *) release="download/$tag"; ;; \ 22 | esac \ 23 | && curl "https://github.com/oven-sh/bun/releases/$release/bun-linux-$build.zip" \ 24 | -fsSLO \ 25 | --compressed \ 26 | --retry 5 \ 27 | || (echo "error: failed to download: $tag" && exit 1) \ 28 | && for key in \ 29 | "F3DCC08A8572C0749B3E18888EAB4D40A7B22B59" \ 30 | ; do \ 31 | gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" \ 32 | || gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key" ; \ 33 | done \ 34 | && curl "https://github.com/oven-sh/bun/releases/$release/SHASUMS256.txt.asc" \ 35 | -fsSLO \ 36 | --compressed \ 37 | --retry 5 \ 38 | && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \ 39 | || (echo "error: failed to verify: $tag" && exit 1) \ 40 | && grep " bun-linux-$build.zip\$" SHASUMS256.txt | sha256sum -c - \ 41 | || (echo "error: failed to verify: $tag" && exit 1) \ 42 | && unzip "bun-linux-$build.zip" \ 43 | && mv "bun-linux-$build/bun" /usr/local/bin/bun \ 44 | && rm -f "bun-linux-$build.zip" SHASUMS256.txt.asc SHASUMS256.txt \ 45 | && chmod +x /usr/local/bin/bun 46 | 47 | FROM node:23-alpine3.20 48 | 49 | # Disable the runtime transpiler cache by default inside Docker containers. 50 | # On ephemeral containers, the cache is not useful 51 | ARG BUN_RUNTIME_TRANSPILER_CACHE_PATH=0 52 | ENV BUN_RUNTIME_TRANSPILER_CACHE_PATH=${BUN_RUNTIME_TRANSPILER_CACHE_PATH} 53 | 54 | # Ensure `bun install -g` works 55 | ARG BUN_INSTALL_BIN=/usr/local/bin 56 | ENV BUN_INSTALL_BIN=${BUN_INSTALL_BIN} 57 | 58 | COPY --from=build /usr/local/bin/bun /usr/local/bin/ 59 | COPY docker-entrypoint.sh /usr/local/bin/ 60 | RUN mkdir -p /usr/local/bun-node-fallback-bin && ln -s /usr/local/bin/bun /usr/local/bun-node-fallback-bin/node 61 | ENV PATH "${PATH}:/usr/local/bun-node-fallback-bin" 62 | 63 | # Temporarily use the `build`-stage /tmp folder to access the glibc APKs: 64 | RUN --mount=type=bind,from=build,source=/tmp,target=/tmp \ 65 | addgroup -g 1001 bun \ 66 | && adduser -u 1001 -G bun -s /bin/sh -D bun \ 67 | && ln -s /usr/local/bin/bun /usr/local/bin/bunx \ 68 | && apk add libgcc libstdc++ \ 69 | && which bun \ 70 | && which bunx \ 71 | && bun --version 72 | 73 | # Add git 74 | RUN apk fix && \ 75 | apk --no-cache --update add git git-lfs gpg less openssh patch && \ 76 | git lfs install 77 | 78 | WORKDIR /home/bun/app 79 | ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] 80 | CMD ["/usr/local/bin/bun"] 81 | -------------------------------------------------------------------------------- /test_check_bun.py: -------------------------------------------------------------------------------- 1 | import json 2 | from unittest.mock import mock_open, patch 3 | 4 | import pytest 5 | from bs4 import BeautifulSoup 6 | from packaging import version 7 | 8 | from check_bun import ( 9 | get_bun_latest_versions, 10 | main, 11 | parse_version, 12 | update_latest_versions, 13 | ) 14 | 15 | 16 | @pytest.fixture 17 | def mock_html(): 18 | """Mock HTML content for the Bun NPM page.""" 19 | return """ 20 | 1.0.0 21 | 1.1.0 22 | 1.1.1-canary 23 | """ 24 | 25 | 26 | @pytest.fixture 27 | def mock_versions_json(): 28 | """Mock content for the versions.json file.""" 29 | return json.dumps({"bun": {"latest": "1.0.0", "canary": "1.1.0-canary"}}) 30 | 31 | 32 | @patch("check_bun.requests.get") 33 | @patch("check_bun.BeautifulSoup") 34 | def test_get_bun_latest_versions(mock_bs, mock_requests, mock_html): 35 | """Test fetching latest Bun versions.""" 36 | mock_requests.return_value.content = mock_html 37 | mock_requests.return_value.raise_for_status = lambda: None 38 | mock_bs.return_value.find_all.return_value = [ 39 | BeautifulSoup(mock_html, "html.parser").find_all("a")[0], 40 | BeautifulSoup(mock_html, "html.parser").find_all("a")[1], 41 | BeautifulSoup(mock_html, "html.parser").find_all("a")[2], 42 | ] 43 | result = get_bun_latest_versions(["latest", "canary"]) 44 | assert result["latest"] == "1.1.0" 45 | assert result["canary"] == "1.1.1-canary" 46 | 47 | 48 | def test_parse_version(): 49 | """Test parsing version strings.""" 50 | parsed_version, is_canary = parse_version("1.1.1-canary") 51 | assert parsed_version.public == "1.1.1" 52 | assert is_canary 53 | 54 | parsed_version, is_canary = parse_version("1.1.0") 55 | assert parsed_version.public == "1.1.0" 56 | assert not is_canary 57 | 58 | 59 | def test_update_latest_versions(): 60 | """Test updating the latest version dictionary.""" 61 | latest_versions = {"latest": None, "canary": None} 62 | update_latest_versions( 63 | latest_versions, "1.1.1", version.parse("1.1.1"), False, ["latest", "canary"] 64 | ) 65 | assert latest_versions["latest"] == "1.1.1" 66 | 67 | update_latest_versions( 68 | latest_versions, 69 | "1.1.1-canary", 70 | version.parse("1.1.1"), 71 | True, 72 | ["latest", "canary"], 73 | ) 74 | assert latest_versions["canary"] == "1.1.1-canary" 75 | 76 | # Ensure no updates if the version is older 77 | update_latest_versions( 78 | latest_versions, "1.0.0", version.parse("1.0.0"), False, ["latest", "canary"] 79 | ) 80 | assert latest_versions["latest"] == "1.1.1" 81 | 82 | 83 | @patch( 84 | "builtins.open", 85 | new_callable=mock_open, 86 | read_data='{"bun": {"latest": "1.0.0", "canary": "1.1.0-canary"}}', 87 | ) 88 | @patch("check_bun.get_bun_latest_versions") 89 | def test_main(mock_get_bun_latest_versions, mock_file): 90 | """Test the main function.""" 91 | mock_get_bun_latest_versions.return_value = { 92 | "latest": "1.1.0", 93 | "canary": "1.1.1-canary", 94 | } 95 | with patch("sys.argv", ["check_bun.py", "latest,canary"]), patch( 96 | "builtins.print" 97 | ) as mock_print: 98 | main() 99 | mock_print.assert_called_once_with("1.1.0,1.1.1-canary") 100 | -------------------------------------------------------------------------------- /test_check_nodejs.py: -------------------------------------------------------------------------------- 1 | import json 2 | from unittest.mock import MagicMock, mock_open, patch 3 | 4 | import pytest 5 | import responses 6 | from bs4 import BeautifulSoup 7 | 8 | from check_nodejs import get_nodejs_versions, main 9 | 10 | 11 | def mock_previous_releases_html(): 12 | return """ 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
Node.js v16.20.0
Node.js v14.21.3
Node.js v12.22.12
Node.js v10.24.1
27 | """ 28 | 29 | 30 | def test_get_nodejs_versions(): 31 | """Test fetching Node.js versions with valid major versions.""" 32 | with patch("check_nodejs.requests.get") as mock_get: 33 | mock_get.return_value.content = mock_previous_releases_html() 34 | 35 | result = get_nodejs_versions([16, 14]) 36 | expected = ["v16.20.0", "v14.21.3"] 37 | 38 | assert result == expected 39 | 40 | 41 | def test_get_nodejs_versions_no_match(): 42 | """Test fetching Node.js versions with no matching major versions.""" 43 | with patch("check_nodejs.requests.get") as mock_get: 44 | mock_get.return_value.content = mock_previous_releases_html() 45 | 46 | result = get_nodejs_versions([8]) 47 | expected = [] 48 | 49 | assert result == expected 50 | 51 | 52 | def test_get_nodejs_versions_empty_page(): 53 | """Test fetching Node.js versions when the HTML page is empty.""" 54 | with patch("check_nodejs.requests.get") as mock_get: 55 | mock_get.return_value.content = "" 56 | 57 | result = get_nodejs_versions([16]) 58 | expected = [] 59 | 60 | assert result == expected 61 | 62 | 63 | def test_main(monkeypatch): 64 | """Test the main function including JSON handling and updates.""" 65 | test_args = ["check_nodejs.py", "16,14"] 66 | monkeypatch.setattr("sys.argv", test_args) 67 | 68 | # Mock open to simulate versions.json content 69 | mock_json = json.dumps( 70 | { 71 | "nodejs": { 72 | "16": {"version": "v16.19.0"}, 73 | "14": {"version": "v14.20.0"}, 74 | } 75 | } 76 | ) 77 | 78 | with patch("builtins.open", mock_open(read_data=mock_json)) as mock_file: 79 | with patch("check_nodejs.requests.get") as mock_get: 80 | mock_get.return_value.content = mock_previous_releases_html() 81 | 82 | with patch("builtins.print") as mock_print: 83 | main() 84 | 85 | # Check that the print statement output matches the updated versions 86 | mock_print.assert_called_once_with("16.20.0,14.21.3") 87 | 88 | # Ensure the file was read 89 | mock_file.assert_called_once_with("versions.json", encoding="utf-8") 90 | 91 | 92 | def test_main_no_updates(monkeypatch): 93 | """Test the main function when there are no updates to versions.""" 94 | test_args = ["check_nodejs.py", "16,14"] 95 | monkeypatch.setattr("sys.argv", test_args) 96 | 97 | # Mock open to simulate versions.json content 98 | mock_json = json.dumps( 99 | { 100 | "nodejs": { 101 | "16": {"version": "v16.20.0"}, 102 | "14": {"version": "v14.21.3"}, 103 | } 104 | } 105 | ) 106 | 107 | with patch("builtins.open", mock_open(read_data=mock_json)) as mock_file: 108 | with patch("check_nodejs.requests.get") as mock_get: 109 | mock_get.return_value.content = mock_previous_releases_html() 110 | 111 | with patch("builtins.print") as mock_print: 112 | main() 113 | 114 | # Ensure nothing was printed (no updates) 115 | mock_print.assert_not_called() 116 | 117 | # Ensure the file was read 118 | mock_file.assert_called_once_with("versions.json", encoding="utf-8") 119 | 120 | 121 | @pytest.mark.skip 122 | def test_main_missing_major_version(monkeypatch): 123 | """Test the main function with a missing major version in the JSON file.""" 124 | test_args = ["check_nodejs.py", "12"] 125 | monkeypatch.setattr("sys.argv", test_args) 126 | 127 | # Mock open to simulate versions.json content 128 | mock_json = json.dumps( 129 | { 130 | "nodejs": { 131 | "16": {"version": "v16.19.0"}, 132 | } 133 | } 134 | ) 135 | 136 | with patch("builtins.open", mock_open(read_data=mock_json)) as mock_file: 137 | with patch("check_nodejs.requests.get") as mock_get: 138 | mock_get.return_value.content = mock_previous_releases_html() 139 | 140 | with patch("builtins.print") as mock_print: # Patch print instead of stderr 141 | main() 142 | 143 | # Ensure error message for missing major version is printed 144 | mock_print.assert_any_call( 145 | "Error: Major version 12 not found in current versions." 146 | ) 147 | -------------------------------------------------------------------------------- /versions.json: -------------------------------------------------------------------------------- 1 | { 2 | "bun": { 3 | "latest": "v1.2.15", 4 | "canary": "v1.2.15-canary.20250606.1" 5 | }, 6 | "nodejs": { 7 | "23": { 8 | "name": "current", 9 | "version": "v23.11.0" 10 | }, 11 | "22": { 12 | "name": "jod", 13 | "version": "v22.15.0" 14 | }, 15 | "20": { 16 | "name": "iron", 17 | "version": "v20.19.1" 18 | }, 19 | "18": { 20 | "name": "hydrogen", 21 | "version": "v18.20.8" 22 | } 23 | } 24 | } 25 | --------------------------------------------------------------------------------