├── .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 |
--------------------------------------------------------------------------------
/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 |
29 |
30 |
31 |
32 |
40 |
41 |
42 |
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 |
29 |
30 |
31 |
32 |
40 |
41 |
42 |
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 | [](https://hub.docker.com/r/imbios/bun-node)
4 |
5 | [](https://github.com/ImBIOS/bun-node)
6 | [](https://github.com/ImBIOS/bun-node)
7 | 
8 | 
9 | 
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 | Node.js v16.20.0 |
16 |
17 |
18 | Node.js v14.21.3 |
19 |
20 |
21 | Node.js v12.22.12 |
22 |
23 |
24 | Node.js v10.24.1 |
25 |
26 |
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 |
--------------------------------------------------------------------------------