├── .github
├── ISSUE_TEMPLATE
│ └── bug_report.yml
├── dependabot.yml
└── workflows
│ ├── build.yml
│ └── release.yml
├── .gitignore
├── .release-please-manifest.json
├── CHANGELOG.md
├── LICENSE
├── README.md
├── __test__
├── DownloadURL.test.ts
├── DownloadURLFactory.test.ts
└── InstallerFactory.test.ts
├── action.yml
├── biome.json
├── package.json
├── pnpm-lock.yaml
├── release-please-config.json
├── src
├── DownloadURL.ts
├── DownloadURLFactory.ts
├── Installer.ts
├── InstallerFactory.ts
├── errors.ts
├── index.ts
├── platform.ts
└── versions.ts
└── tsconfig.json
/.github/ISSUE_TEMPLATE/bug_report.yml:
--------------------------------------------------------------------------------
1 | name: 🐞 Bug Report
2 | description: File a bug report
3 | title: "🐞
"
4 | labels: ["bug"]
5 | projects: []
6 | body:
7 | - type: markdown
8 | attributes:
9 | value: |
10 | Thanks for taking the time to fill out this bug report!
11 | - type: textarea
12 | attributes:
13 | label: What is happening?
14 | description: Please provide a clear and concise description of what the bug is.
15 | placeholder: A clear and concise description of what the bug is.
16 | validations:
17 | required: true
18 | - type: input
19 | attributes:
20 | label: Version where you found the bug
21 | description: What version of the action are you using?
22 | placeholder: vX.Y.Z (e.g. v1.0.0) or find it in the logs if you're using a latest version
23 | validations:
24 | required: true
25 | - type: input
26 | attributes:
27 | label: Runner specifics
28 | description: What runner are you using? Self-hosted, GitHub-hosted, or a specific cloud provider?
29 | placeholder: e.g. ubuntu-latest, macos-latest, windows-latest, Self-hosted, etc.
30 | validations:
31 | required: true
32 | - type: textarea
33 | attributes:
34 | label: Action workflow configuration
35 | description: Full workflow file content or a snippet that reproduces the issue.
36 | placeholder: |
37 | steps:
38 | - uses: browser-actions/setup-firefox@latest
39 | with:
40 | firefox-version: 'latest'
41 | render: yaml
42 | validations:
43 | required: true
44 | - type: input
45 | attributes:
46 | label: Link to the workflow run
47 | description: Please provide a link to the workflow run where you encountered the bug.
48 | placeholder: 'https://github.com/...'
49 | - type: textarea
50 | attributes:
51 | label: Relevant log output
52 | description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
53 | render: shell
54 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: 'npm'
4 | directory: '/'
5 | schedule:
6 | interval: 'daily'
7 | commit-message:
8 | prefix: "fix(deps)"
9 | prefix-development: 'chore(deps):'
10 | groups:
11 | actions:
12 | patterns:
13 | - "@actions/*"
14 | typescript:
15 | patterns:
16 | - "typescript"
17 | - "@typescript-*"
18 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: 'build-test'
2 | on:
3 | pull_request:
4 | push:
5 | branches-ignore:
6 | - master
7 | workflow_call:
8 |
9 | jobs:
10 | build:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/checkout@v4
14 | - uses: pnpm/action-setup@v3
15 | - uses: actions/setup-node@v4
16 | with:
17 | node-version-file: 'package.json'
18 | cache: 'pnpm'
19 | - run: pnpm install --frozen-lockfile
20 | - run: pnpm lint
21 | - run: pnpm test
22 | - run: pnpm build
23 | - run: pnpm package
24 | - uses: actions/upload-artifact@v4
25 | with:
26 | name: dist
27 | path: ./dist/
28 |
29 | test:
30 | needs: [build]
31 | strategy:
32 | matrix:
33 | os: [ubuntu, macos, windows]
34 | runs-on: ${{ matrix.os }}-latest
35 | steps:
36 | - uses: actions/download-artifact@v4
37 | with:
38 | name: dist
39 |
40 | - uses: ./
41 | - run: |
42 | firefox --version
43 | - uses: ./
44 | with:
45 | firefox-version: latest-esr
46 | - run: |
47 | firefox --version
48 | - uses: ./
49 | with:
50 | firefox-version: "132.0"
51 | - run: |
52 | firefox --version
53 | - uses: ./
54 | with:
55 | firefox-version: "devedition-132.0b1"
56 | - run: |
57 | firefox --version
58 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: 'release'
2 | on:
3 | push:
4 | branches:
5 | - master
6 |
7 | jobs:
8 | build:
9 | uses: ./.github/workflows/build.yml
10 |
11 | release:
12 | runs-on: ubuntu-latest
13 | needs: [build]
14 | steps:
15 | - uses: googleapis/release-please-action@v4
16 | id: release
17 |
18 | - uses: actions/checkout@v4
19 | with:
20 | fetch-depth: 0
21 | ref: 'latest'
22 | if: ${{ steps.release.outputs.release_created }}
23 | - uses: actions/download-artifact@v4
24 | with:
25 | name: dist
26 | if: ${{ steps.release.outputs.release_created }}
27 |
28 | - name: Publish to GitHub
29 | env:
30 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
31 | major_version: ${{ steps.release.outputs.major }}
32 | full_version: ${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }}.${{ steps.release.outputs.patch }}
33 | tag_name: ${{ steps.release.outputs.tag_name }}
34 | run: |
35 | gpg --allow-secret-key-import --import <<< "${{ secrets.PRIVATE_SIGNING_KEY }}"
36 | git remote set-url origin https://github-actions:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}
37 | git config commit.gpgsign true
38 | git config tag.gpgsign true
39 | git config --global user.name ueokande
40 | git config --global user.email ueokande@i-beam.org
41 | git config --global user.signingkey 7F94715D031FDE95
42 |
43 | git add .
44 | git commit --allow-empty --message "Release v${full_version} at ${GITHUB_SHA}"
45 |
46 | git tag -d v$major_version || true
47 | git tag -d v$full_version || true
48 | git tag -a v$major_version -m "Release v$full_version"
49 | git tag -a v$full_version -m "Release v$full_version"
50 |
51 | git push origin latest
52 | git push origin v$major_version --force
53 | git push origin v$full_version
54 |
55 | if: ${{ steps.release.outputs.release_created }}
56 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules/
2 |
3 | /dist/
4 |
--------------------------------------------------------------------------------
/.release-please-manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | ".": "1.5.4"
3 | }
4 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## [1.5.4](https://github.com/browser-actions/setup-firefox/compare/setup-firefox-v1.5.3...setup-firefox-v1.5.4) (2025-01-25)
4 |
5 |
6 | ### Bug Fixes
7 |
8 | * Fix an off-by-one error with bz2/xz download URLs ([#626](https://github.com/browser-actions/setup-firefox/issues/626)) ([f7574dd](https://github.com/browser-actions/setup-firefox/commit/f7574dd7c71ff2cf094cdaa89735bdcb096d72e5)), closes [#625](https://github.com/browser-actions/setup-firefox/issues/625)
9 |
10 | ## [1.5.3](https://github.com/browser-actions/setup-firefox/compare/setup-firefox-v1.5.2...setup-firefox-v1.5.3) (2025-01-19)
11 |
12 |
13 | ### Bug Fixes
14 |
15 | * Coping with compression change for linux download ([#623](https://github.com/browser-actions/setup-firefox/issues/623)) ([063eed6](https://github.com/browser-actions/setup-firefox/commit/063eed68fefb6e72be98fb0c0d2d106784c79634))
16 |
17 | ## [1.5.2](https://github.com/browser-actions/setup-firefox/compare/setup-firefox-v1.5.1...setup-firefox-v1.5.2) (2024-07-13)
18 |
19 |
20 | ### Bug Fixes
21 |
22 | * sign commits and tags ([#583](https://github.com/browser-actions/setup-firefox/issues/583)) ([6bcb267](https://github.com/browser-actions/setup-firefox/commit/6bcb26740ce1d8eabe7396b856c49439c24ed139))
23 |
24 | ## [1.5.1](https://github.com/browser-actions/setup-firefox/compare/setup-firefox-v1.5.0...setup-firefox-v1.5.1) (2024-05-04)
25 |
26 |
27 | ### Bug Fixes
28 |
29 | * Adding arm64 to osx for macos-14 ([#546](https://github.com/browser-actions/setup-firefox/issues/546)) ([d880b17](https://github.com/browser-actions/setup-firefox/commit/d880b175f181fe0d1fbad6629de56872bfaf0146))
30 |
31 | ## [1.5.0](https://github.com/browser-actions/setup-firefox/compare/setup-firefox-v1.4.1...setup-firefox-v1.5.0) (2024-02-29)
32 |
33 |
34 | ### Features
35 |
36 | * firefox devedition archive versions ([#517](https://github.com/browser-actions/setup-firefox/issues/517)) ([eb151a7](https://github.com/browser-actions/setup-firefox/commit/eb151a78a71e39af170d8510d66b4e7204853a94))
37 |
38 | ## [1.4.1](https://github.com/browser-actions/setup-firefox/compare/setup-firefox-v1.4.0...setup-firefox-v1.4.1) (2024-02-17)
39 |
40 |
41 | ### Bug Fixes
42 |
43 | * using node20 ([#520](https://github.com/browser-actions/setup-firefox/issues/520)) ([b7d1295](https://github.com/browser-actions/setup-firefox/commit/b7d1295db99649993e97d0a01870e7c1f0a5100b))
44 |
45 | ## [1.4.0](https://github.com/browser-actions/setup-firefox/compare/setup-firefox-v1.3.0...setup-firefox-v1.4.0) (2023-11-11)
46 |
47 |
48 | ### Features
49 |
50 | * output installed binary path ([#493](https://github.com/browser-actions/setup-firefox/issues/493)) ([e16c07e](https://github.com/browser-actions/setup-firefox/commit/e16c07ebedc21f9a09aabcb5b081200bb61fb309))
51 |
52 | ## [1.3.0](https://github.com/browser-actions/setup-firefox/compare/setup-firefox-v1.2.0...setup-firefox-v1.3.0) (2023-09-18)
53 |
54 |
55 | ### Features
56 |
57 | * firefox nightly ([#455](https://github.com/browser-actions/setup-firefox/issues/455)) ([b638071](https://github.com/browser-actions/setup-firefox/commit/b638071cda49366abcca9eb674072123f5c5b34e))
58 |
59 | ## [1.2.0](https://github.com/browser-actions/setup-firefox/compare/setup-firefox-v1.1.1...setup-firefox-v1.2.0) (2023-09-17)
60 |
61 |
62 | ### Features
63 |
64 | * restore Windows support ([#422](https://github.com/browser-actions/setup-firefox/issues/422)) ([6013839](https://github.com/browser-actions/setup-firefox/commit/6013839547aee35d36b4e705c9c044d7c789bb5b))
65 |
66 |
67 | ### Bug Fixes
68 |
69 | * **deps:** bump the actions group with 1 update ([#448](https://github.com/browser-actions/setup-firefox/issues/448)) ([b7727a2](https://github.com/browser-actions/setup-firefox/commit/b7727a275849f856e9b379f6cd3b1c3009f0fa72))
70 |
71 | ## [1.1.1](https://github.com/browser-actions/setup-firefox/compare/setup-firefox-v1.1.0...setup-firefox-v1.1.1) (2023-03-16)
72 |
73 |
74 | ### Bug Fixes
75 |
76 | * **deps:** bump @actions/io from 1.1.2 to 1.1.3 ([#412](https://github.com/browser-actions/setup-firefox/issues/412)) ([9f159e2](https://github.com/browser-actions/setup-firefox/commit/9f159e22432daecfcb5a1e8a2ee7d71bd3149437))
77 |
78 | ## [1.1.0](https://github.com/browser-actions/setup-firefox/compare/setup-firefox-v1.0.1...setup-firefox-v1.1.0) (2023-02-12)
79 |
80 |
81 | ### Features
82 |
83 | * Output version ([#394](https://github.com/browser-actions/setup-firefox/issues/394)) ([a2adddc](https://github.com/browser-actions/setup-firefox/commit/a2adddcf8cd190325f47bb3b0fd0144374745885))
84 |
85 |
86 | ### Bug Fixes
87 |
88 | * bump typescript from 4.3.2 to 4.9.5 ([#388](https://github.com/browser-actions/setup-firefox/issues/388)) ([a8f85c9](https://github.com/browser-actions/setup-firefox/commit/a8f85c9dfefee93d8db5ee3fc625bfbbd667e9e6))
89 | * **deps:** bump @actions/core from 1.5.0 to 1.10.0 ([#387](https://github.com/browser-actions/setup-firefox/issues/387)) ([76d61e2](https://github.com/browser-actions/setup-firefox/commit/76d61e2aa8beb9f67bb18a379162b92f05031085))
90 | * **deps:** bump @actions/io from 1.1.1 to 1.1.2 ([#384](https://github.com/browser-actions/setup-firefox/issues/384)) ([3eea4c1](https://github.com/browser-actions/setup-firefox/commit/3eea4c17e161f3542f7d87a6975880a74e3e7b6d))
91 |
92 | ## [1.0.1](https://github.com/browser-actions/setup-firefox/compare/setup-firefox-v1.0.0...setup-firefox-v1.0.1) (2023-01-29)
93 |
94 |
95 | ### Bug Fixes
96 |
97 | * use new set-output ([#378](https://github.com/browser-actions/setup-firefox/issues/378)) ([e85ec80](https://github.com/browser-actions/setup-firefox/commit/e85ec80fd078bd4ef19bcede476f6f69ecdf3152))
98 |
99 | ## 1.0.0 (2023-01-22)
100 |
101 |
102 | ### Miscellaneous Chores
103 |
104 | * use v1 ([baabf1a](https://github.com/browser-actions/setup-firefox/commit/baabf1a3410cf8af9ec825a31e7721680a165dd1))
105 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Shin'ya Ueoka
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # setup-firefox
4 |
5 | This action sets by Firefox for use in actions by:
6 |
7 | - downloading and caching a version of Firefox by version and add to PATH
8 |
9 | ## Usage
10 |
11 | See [action.yml](action.yml)
12 |
13 | Basic usage:
14 |
15 | ```yaml
16 | steps:
17 | - uses: browser-actions/setup-firefox@v1
18 | - run: firefox --version
19 | ```
20 |
21 | Use in the matrix:
22 | ```yaml
23 | jobs:
24 | build:
25 | runs-on: ubuntu-latest
26 | strategy:
27 | matrix:
28 | firefox: [ '84.0', 'devedition-84.0b1', 'latest-beta', 'latest-devedition', 'latest-nightly', 'latest-esr', 'latest' ]
29 | name: Firefox ${{ matrix.firefox }} sample
30 | steps:
31 | - name: Setup firefox
32 | id: setup-firefox
33 | uses: browser-actions/setup-firefox@v1
34 | with:
35 | firefox-version: ${{ matrix.firefox }}
36 | - run: |
37 | echo Installed firefox versions: ${{ steps.setup-firefox.outputs.firefox-version }}
38 | ${{ steps.setup-firefox.outputs.firefox-path }} --version
39 | ```
40 |
41 | ## License
42 |
43 | [MIT](LICENSE)
44 |
--------------------------------------------------------------------------------
/__test__/DownloadURL.test.ts:
--------------------------------------------------------------------------------
1 | import { describe, expect, test } from "vitest";
2 | import { ArchiveDownloadURL, LatestDownloadURL } from "../src/DownloadURL";
3 | import { UnsupportedPlatformError } from "../src/errors";
4 | import { Arch, OS } from "../src/platform";
5 | import { LatestVersion } from "../src/versions";
6 |
7 | describe("ArchiveDownloadURL", () => {
8 | describe.each([
9 | [
10 | { os: OS.LINUX, arch: Arch.I686 },
11 | "https://ftp.mozilla.org/pub/firefox/releases/134.0/linux-i686/en-US/firefox-134.0.tar.bz2",
12 | ],
13 | [
14 | { os: OS.LINUX, arch: Arch.AMD64 },
15 | "https://ftp.mozilla.org/pub/firefox/releases/134.0/linux-x86_64/en-US/firefox-134.0.tar.bz2",
16 | ],
17 | [
18 | { os: OS.MACOS, arch: Arch.AMD64 },
19 | "https://ftp.mozilla.org/pub/firefox/releases/134.0/mac/en-US/Firefox%20134.0.dmg",
20 | ],
21 | [
22 | { os: OS.WINDOWS, arch: Arch.I686 },
23 | "https://ftp.mozilla.org/pub/firefox/releases/134.0/win32/en-US/Firefox%20Setup%20134.0.exe",
24 | ],
25 | [
26 | { os: OS.WINDOWS, arch: Arch.AMD64 },
27 | "https://ftp.mozilla.org/pub/firefox/releases/134.0/win64/en-US/Firefox%20Setup%20134.0.exe",
28 | ],
29 | [
30 | { os: OS.WINDOWS, arch: Arch.ARM64 },
31 | "https://ftp.mozilla.org/pub/firefox/releases/134.0/win64-aarch64/en-US/Firefox%20Setup%20134.0.exe",
32 | ],
33 | ])("platform %s", ({ os, arch }, expected) => {
34 | test(`returns URL ${expected}`, () => {
35 | const sut = new ArchiveDownloadURL("134.0", { os, arch }, "en-US");
36 | expect(sut.getURL()).toEqual(expected);
37 | });
38 | });
39 |
40 | describe.each([
41 | [
42 | { version: "firefox-80.0", os: OS.LINUX, arch: Arch.I686 },
43 | "https://ftp.mozilla.org/pub/firefox/releases/80.0/linux-i686/en-US/firefox-80.0.tar.bz2",
44 | ],
45 | [
46 | { version: "devedition-135.0b1", os: OS.LINUX, arch: Arch.AMD64 },
47 | "https://ftp.mozilla.org/pub/devedition/releases/135.0b1/linux-x86_64/en-US/firefox-135.0b1.tar.xz",
48 | ],
49 | [
50 | { version: "beta-135.0b1", os: OS.LINUX, arch: Arch.AMD64 },
51 | "https://ftp.mozilla.org/pub/firefox/releases/135.0b1/linux-x86_64/en-US/firefox-135.0b1.tar.xz",
52 | ],
53 | ])("version %s", ({ version, os, arch }, expected) => {
54 | test(`returns URL ${expected}`, () => {
55 | const sut = new ArchiveDownloadURL(version, { os, arch }, "en-US");
56 | expect(sut.getURL()).toEqual(expected);
57 | });
58 | });
59 |
60 | describe.each([[OS.MACOS, Arch.I686]])("platform %s %s", (os, arch) => {
61 | test("throws an error", () => {
62 | const sut = new ArchiveDownloadURL("80.0", { os, arch }, "en-US");
63 | expect(() => sut.getURL()).toThrowError(UnsupportedPlatformError);
64 | });
65 | });
66 | });
67 |
68 | describe("LatestDownloadURL", () => {
69 | describe.each([
70 | [
71 | LatestVersion.LATEST,
72 | { os: OS.LINUX, arch: Arch.I686 },
73 | "https://download.mozilla.org/?product=firefox-latest&os=linux&lang=en-US",
74 | ],
75 | [
76 | LatestVersion.LATEST,
77 | { os: OS.LINUX, arch: Arch.AMD64 },
78 | "https://download.mozilla.org/?product=firefox-latest&os=linux64&lang=en-US",
79 | ],
80 | [
81 | LatestVersion.LATEST_DEVEDITION,
82 | { os: OS.LINUX, arch: Arch.AMD64 },
83 | "https://download.mozilla.org/?product=firefox-devedition-latest&os=linux64&lang=en-US",
84 | ],
85 | [
86 | LatestVersion.LATEST_NIGHTLY,
87 | { os: OS.LINUX, arch: Arch.AMD64 },
88 | "https://download.mozilla.org/?product=firefox-nightly-latest&os=linux64&lang=en-US",
89 | ],
90 | [
91 | LatestVersion.LATEST_ESR,
92 | { os: OS.MACOS, arch: Arch.AMD64 },
93 | "https://download.mozilla.org/?product=firefox-esr-latest&os=osx&lang=en-US",
94 | ],
95 | [
96 | LatestVersion.LATEST_ESR,
97 | { os: OS.MACOS, arch: Arch.ARM64 },
98 | "https://download.mozilla.org/?product=firefox-esr-latest&os=osx&lang=en-US",
99 | ],
100 | [
101 | LatestVersion.LATEST_ESR,
102 | { os: OS.WINDOWS, arch: Arch.I686 },
103 | "https://download.mozilla.org/?product=firefox-esr-latest&os=win&lang=en-US",
104 | ],
105 | [
106 | LatestVersion.LATEST_ESR,
107 | { os: OS.WINDOWS, arch: Arch.AMD64 },
108 | "https://download.mozilla.org/?product=firefox-esr-latest&os=win64&lang=en-US",
109 | ],
110 | ])("platform %s %s", (version, { os, arch }, expected) => {
111 | test(`returns URL ${expected}`, () => {
112 | const sut = new LatestDownloadURL(version, { os, arch }, "en-US");
113 | expect(sut.getURL()).toEqual(expected);
114 | });
115 | });
116 |
117 | describe.each([[OS.MACOS, Arch.I686]])("platform %s %s", (os, arch) => {
118 | test("throws an error", () => {
119 | const sut = new LatestDownloadURL(
120 | LatestVersion.LATEST,
121 | { os, arch },
122 | "en-US",
123 | );
124 | expect(() => sut.getURL()).toThrowError(UnsupportedPlatformError);
125 | });
126 | });
127 | });
128 |
--------------------------------------------------------------------------------
/__test__/DownloadURLFactory.test.ts:
--------------------------------------------------------------------------------
1 | import { describe, expect, test } from "vitest";
2 | import { ArchiveDownloadURL, LatestDownloadURL } from "../src/DownloadURL";
3 | import { DownloadURLFactory } from "../src/DownloadURLFactory";
4 | import { Arch, OS } from "../src/platform";
5 |
6 | describe("DownloadURLFactory", () => {
7 | describe.each([
8 | ["80.0", ArchiveDownloadURL],
9 | ["firefox-80.0", ArchiveDownloadURL],
10 | ["beta-80.0b1", ArchiveDownloadURL],
11 | ["devedition-80.0b1", ArchiveDownloadURL],
12 | ["latest", LatestDownloadURL],
13 | ["latest-beta", LatestDownloadURL],
14 | ["latest-devedition", LatestDownloadURL],
15 | ["latest-nightly", LatestDownloadURL],
16 | ["latest-esr", LatestDownloadURL],
17 | ])("for version %s", (version, expected) => {
18 | test(`returns ${String(expected.name)}`, () => {
19 | const sut = new DownloadURLFactory(
20 | version,
21 | { os: OS.LINUX, arch: Arch.AMD64 },
22 | "en-US",
23 | );
24 | expect(sut.create()).toBeInstanceOf(expected);
25 | });
26 | });
27 | });
28 |
--------------------------------------------------------------------------------
/__test__/InstallerFactory.test.ts:
--------------------------------------------------------------------------------
1 | import { describe, expect, test } from "vitest";
2 | import {
3 | LinuxInstaller,
4 | MacOSInstaller,
5 | WindowsInstaller,
6 | } from "../src/Installer";
7 | import InstallerFactory from "../src/InstallerFactory";
8 | import { Arch, OS } from "../src/platform";
9 |
10 | describe("InstallerFactory", () => {
11 | describe.each([
12 | [OS.LINUX, LinuxInstaller],
13 | [OS.MACOS, MacOSInstaller],
14 | [OS.WINDOWS, WindowsInstaller],
15 | ])("for platform %s", (os, expected) => {
16 | test(`returns ${String(expected.name)}`, () => {
17 | const sut = new InstallerFactory();
18 | expect(sut.create({ os, arch: Arch.AMD64 })).toBeInstanceOf(expected);
19 | });
20 | });
21 | });
22 |
--------------------------------------------------------------------------------
/action.yml:
--------------------------------------------------------------------------------
1 | name: 'Setup Firefox'
2 | description: 'Install and setup Firefox'
3 | author: "Shin'ya Ueoka"
4 | inputs:
5 | firefox-version:
6 | description: 'The Firefox version to install and use. Examples: 84.0, 84.0.1, latest-esr'
7 | outputs:
8 | firefox-version:
9 | description: 'The installed Firefox version. Useful when given a latest version.'
10 | firefox-path:
11 | description: 'The installed Firefox path.'
12 | runs:
13 | using: 'node20'
14 | main: 'index.js'
15 |
--------------------------------------------------------------------------------
/biome.json:
--------------------------------------------------------------------------------
1 | {
2 | "files": {
3 | "ignore": ["package.json"]
4 | },
5 | "linter": {
6 | "enabled": true,
7 | "rules": {
8 | "recommended": true,
9 | "complexity": {
10 | "useLiteralKeys": "off"
11 | },
12 | "style": {
13 | "noUselessElse": "off"
14 | }
15 | }
16 | },
17 | "formatter": {
18 | "enabled": true,
19 | "indentStyle": "space"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "setup-firefox",
3 | "version": "1.5.4",
4 | "description": "Set up your GitHub Actions workflow with a specific version of firefox",
5 | "main": "dist/index.js",
6 | "packageManager": "pnpm@8.7.5",
7 | "engines": {
8 | "node": "20.6.1"
9 | },
10 | "dependencies": {
11 | "@actions/core": "^1.10.1",
12 | "@actions/exec": "^1.1.1",
13 | "@actions/io": "^1.1.3",
14 | "@actions/tool-cache": "^2.0.1"
15 | },
16 | "devDependencies": {
17 | "@biomejs/biome": "^1.8.3",
18 | "@types/node": "^20.6.2",
19 | "@vercel/ncc": "^0.38.0",
20 | "typescript": "^5.2.2",
21 | "vitest": "^2.0.2"
22 | },
23 | "scripts": {
24 | "build": "ncc build src/index.ts",
25 | "test": "vitest",
26 | "package": "cp action.yml README.md dist/",
27 | "lint": "biome ci .",
28 | "lint:fix": "biome check --apply ."
29 | },
30 | "repository": {
31 | "type": "git",
32 | "url": "git+https://github.com/browser-actions/setup-firefox.git"
33 | },
34 | "keywords": [
35 | "actions",
36 | "node",
37 | "setup",
38 | "firefox"
39 | ],
40 | "author": "Shin'ya Ueoka",
41 | "license": "MIT",
42 | "bugs": {
43 | "url": "https://github.com/browser-actions/setup-firefox/issues"
44 | },
45 | "homepage": "https://github.com/browser-actions/setup-firefox#readme"
46 | }
47 |
--------------------------------------------------------------------------------
/pnpm-lock.yaml:
--------------------------------------------------------------------------------
1 | lockfileVersion: '6.0'
2 |
3 | settings:
4 | autoInstallPeers: true
5 | excludeLinksFromLockfile: false
6 |
7 | dependencies:
8 | '@actions/core':
9 | specifier: ^1.10.1
10 | version: 1.10.1
11 | '@actions/exec':
12 | specifier: ^1.1.1
13 | version: 1.1.1
14 | '@actions/io':
15 | specifier: ^1.1.3
16 | version: 1.1.3
17 | '@actions/tool-cache':
18 | specifier: ^2.0.1
19 | version: 2.0.1
20 |
21 | devDependencies:
22 | '@biomejs/biome':
23 | specifier: ^1.8.3
24 | version: 1.8.3
25 | '@types/node':
26 | specifier: ^20.6.2
27 | version: 20.6.2
28 | '@vercel/ncc':
29 | specifier: ^0.38.0
30 | version: 0.38.0
31 | typescript:
32 | specifier: ^5.2.2
33 | version: 5.2.2
34 | vitest:
35 | specifier: ^2.0.2
36 | version: 2.0.2(@types/node@20.6.2)
37 |
38 | packages:
39 |
40 | /@actions/core@1.10.1:
41 | resolution: {integrity: sha512-3lBR9EDAY+iYIpTnTIXmWcNbX3T2kCkAEQGIQx4NVQ0575nk2k3GRZDTPQG+vVtS2izSLmINlxXf0uLtnrTP+g==}
42 | dependencies:
43 | '@actions/http-client': 2.1.1
44 | uuid: 8.3.2
45 | dev: false
46 |
47 | /@actions/exec@1.1.1:
48 | resolution: {integrity: sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==}
49 | dependencies:
50 | '@actions/io': 1.1.3
51 | dev: false
52 |
53 | /@actions/http-client@2.0.1:
54 | resolution: {integrity: sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==}
55 | dependencies:
56 | tunnel: 0.0.6
57 | dev: false
58 |
59 | /@actions/http-client@2.1.1:
60 | resolution: {integrity: sha512-qhrkRMB40bbbLo7gF+0vu+X+UawOvQQqNAA/5Unx774RS8poaOhThDOG6BGmxvAnxhQnDp2BG/ZUm65xZILTpw==}
61 | dependencies:
62 | tunnel: 0.0.6
63 | dev: false
64 |
65 | /@actions/io@1.1.3:
66 | resolution: {integrity: sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==}
67 | dev: false
68 |
69 | /@actions/tool-cache@2.0.1:
70 | resolution: {integrity: sha512-iPU+mNwrbA8jodY8eyo/0S/QqCKDajiR8OxWTnSk/SnYg0sj8Hp4QcUEVC1YFpHWXtrfbQrE13Jz4k4HXJQKcA==}
71 | dependencies:
72 | '@actions/core': 1.10.1
73 | '@actions/exec': 1.1.1
74 | '@actions/http-client': 2.0.1
75 | '@actions/io': 1.1.3
76 | semver: 6.3.0
77 | uuid: 3.4.0
78 | dev: false
79 |
80 | /@ampproject/remapping@2.3.0:
81 | resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
82 | engines: {node: '>=6.0.0'}
83 | dependencies:
84 | '@jridgewell/gen-mapping': 0.3.5
85 | '@jridgewell/trace-mapping': 0.3.25
86 | dev: true
87 |
88 | /@biomejs/biome@1.8.3:
89 | resolution: {integrity: sha512-/uUV3MV+vyAczO+vKrPdOW0Iaet7UnJMU4bNMinggGJTAnBPjCoLEYcyYtYHNnUNYlv4xZMH6hVIQCAozq8d5w==}
90 | engines: {node: '>=14.21.3'}
91 | hasBin: true
92 | requiresBuild: true
93 | optionalDependencies:
94 | '@biomejs/cli-darwin-arm64': 1.8.3
95 | '@biomejs/cli-darwin-x64': 1.8.3
96 | '@biomejs/cli-linux-arm64': 1.8.3
97 | '@biomejs/cli-linux-arm64-musl': 1.8.3
98 | '@biomejs/cli-linux-x64': 1.8.3
99 | '@biomejs/cli-linux-x64-musl': 1.8.3
100 | '@biomejs/cli-win32-arm64': 1.8.3
101 | '@biomejs/cli-win32-x64': 1.8.3
102 | dev: true
103 |
104 | /@biomejs/cli-darwin-arm64@1.8.3:
105 | resolution: {integrity: sha512-9DYOjclFpKrH/m1Oz75SSExR8VKvNSSsLnVIqdnKexj6NwmiMlKk94Wa1kZEdv6MCOHGHgyyoV57Cw8WzL5n3A==}
106 | engines: {node: '>=14.21.3'}
107 | cpu: [arm64]
108 | os: [darwin]
109 | requiresBuild: true
110 | dev: true
111 | optional: true
112 |
113 | /@biomejs/cli-darwin-x64@1.8.3:
114 | resolution: {integrity: sha512-UeW44L/AtbmOF7KXLCoM+9PSgPo0IDcyEUfIoOXYeANaNXXf9mLUwV1GeF2OWjyic5zj6CnAJ9uzk2LT3v/wAw==}
115 | engines: {node: '>=14.21.3'}
116 | cpu: [x64]
117 | os: [darwin]
118 | requiresBuild: true
119 | dev: true
120 | optional: true
121 |
122 | /@biomejs/cli-linux-arm64-musl@1.8.3:
123 | resolution: {integrity: sha512-9yjUfOFN7wrYsXt/T/gEWfvVxKlnh3yBpnScw98IF+oOeCYb5/b/+K7YNqKROV2i1DlMjg9g/EcN9wvj+NkMuQ==}
124 | engines: {node: '>=14.21.3'}
125 | cpu: [arm64]
126 | os: [linux]
127 | requiresBuild: true
128 | dev: true
129 | optional: true
130 |
131 | /@biomejs/cli-linux-arm64@1.8.3:
132 | resolution: {integrity: sha512-fed2ji8s+I/m8upWpTJGanqiJ0rnlHOK3DdxsyVLZQ8ClY6qLuPc9uehCREBifRJLl/iJyQpHIRufLDeotsPtw==}
133 | engines: {node: '>=14.21.3'}
134 | cpu: [arm64]
135 | os: [linux]
136 | requiresBuild: true
137 | dev: true
138 | optional: true
139 |
140 | /@biomejs/cli-linux-x64-musl@1.8.3:
141 | resolution: {integrity: sha512-UHrGJX7PrKMKzPGoEsooKC9jXJMa28TUSMjcIlbDnIO4EAavCoVmNQaIuUSH0Ls2mpGMwUIf+aZJv657zfWWjA==}
142 | engines: {node: '>=14.21.3'}
143 | cpu: [x64]
144 | os: [linux]
145 | requiresBuild: true
146 | dev: true
147 | optional: true
148 |
149 | /@biomejs/cli-linux-x64@1.8.3:
150 | resolution: {integrity: sha512-I8G2QmuE1teISyT8ie1HXsjFRz9L1m5n83U1O6m30Kw+kPMPSKjag6QGUn+sXT8V+XWIZxFFBoTDEDZW2KPDDw==}
151 | engines: {node: '>=14.21.3'}
152 | cpu: [x64]
153 | os: [linux]
154 | requiresBuild: true
155 | dev: true
156 | optional: true
157 |
158 | /@biomejs/cli-win32-arm64@1.8.3:
159 | resolution: {integrity: sha512-J+Hu9WvrBevfy06eU1Na0lpc7uR9tibm9maHynLIoAjLZpQU3IW+OKHUtyL8p6/3pT2Ju5t5emReeIS2SAxhkQ==}
160 | engines: {node: '>=14.21.3'}
161 | cpu: [arm64]
162 | os: [win32]
163 | requiresBuild: true
164 | dev: true
165 | optional: true
166 |
167 | /@biomejs/cli-win32-x64@1.8.3:
168 | resolution: {integrity: sha512-/PJ59vA1pnQeKahemaQf4Nyj7IKUvGQSc3Ze1uIGi+Wvr1xF7rGobSrAAG01T/gUDG21vkDsZYM03NAmPiVkqg==}
169 | engines: {node: '>=14.21.3'}
170 | cpu: [x64]
171 | os: [win32]
172 | requiresBuild: true
173 | dev: true
174 | optional: true
175 |
176 | /@esbuild/aix-ppc64@0.20.2:
177 | resolution: {integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==}
178 | engines: {node: '>=12'}
179 | cpu: [ppc64]
180 | os: [aix]
181 | requiresBuild: true
182 | dev: true
183 | optional: true
184 |
185 | /@esbuild/android-arm64@0.20.2:
186 | resolution: {integrity: sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==}
187 | engines: {node: '>=12'}
188 | cpu: [arm64]
189 | os: [android]
190 | requiresBuild: true
191 | dev: true
192 | optional: true
193 |
194 | /@esbuild/android-arm@0.20.2:
195 | resolution: {integrity: sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==}
196 | engines: {node: '>=12'}
197 | cpu: [arm]
198 | os: [android]
199 | requiresBuild: true
200 | dev: true
201 | optional: true
202 |
203 | /@esbuild/android-x64@0.20.2:
204 | resolution: {integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==}
205 | engines: {node: '>=12'}
206 | cpu: [x64]
207 | os: [android]
208 | requiresBuild: true
209 | dev: true
210 | optional: true
211 |
212 | /@esbuild/darwin-arm64@0.20.2:
213 | resolution: {integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==}
214 | engines: {node: '>=12'}
215 | cpu: [arm64]
216 | os: [darwin]
217 | requiresBuild: true
218 | dev: true
219 | optional: true
220 |
221 | /@esbuild/darwin-x64@0.20.2:
222 | resolution: {integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==}
223 | engines: {node: '>=12'}
224 | cpu: [x64]
225 | os: [darwin]
226 | requiresBuild: true
227 | dev: true
228 | optional: true
229 |
230 | /@esbuild/freebsd-arm64@0.20.2:
231 | resolution: {integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==}
232 | engines: {node: '>=12'}
233 | cpu: [arm64]
234 | os: [freebsd]
235 | requiresBuild: true
236 | dev: true
237 | optional: true
238 |
239 | /@esbuild/freebsd-x64@0.20.2:
240 | resolution: {integrity: sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==}
241 | engines: {node: '>=12'}
242 | cpu: [x64]
243 | os: [freebsd]
244 | requiresBuild: true
245 | dev: true
246 | optional: true
247 |
248 | /@esbuild/linux-arm64@0.20.2:
249 | resolution: {integrity: sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==}
250 | engines: {node: '>=12'}
251 | cpu: [arm64]
252 | os: [linux]
253 | requiresBuild: true
254 | dev: true
255 | optional: true
256 |
257 | /@esbuild/linux-arm@0.20.2:
258 | resolution: {integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==}
259 | engines: {node: '>=12'}
260 | cpu: [arm]
261 | os: [linux]
262 | requiresBuild: true
263 | dev: true
264 | optional: true
265 |
266 | /@esbuild/linux-ia32@0.20.2:
267 | resolution: {integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==}
268 | engines: {node: '>=12'}
269 | cpu: [ia32]
270 | os: [linux]
271 | requiresBuild: true
272 | dev: true
273 | optional: true
274 |
275 | /@esbuild/linux-loong64@0.20.2:
276 | resolution: {integrity: sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==}
277 | engines: {node: '>=12'}
278 | cpu: [loong64]
279 | os: [linux]
280 | requiresBuild: true
281 | dev: true
282 | optional: true
283 |
284 | /@esbuild/linux-mips64el@0.20.2:
285 | resolution: {integrity: sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==}
286 | engines: {node: '>=12'}
287 | cpu: [mips64el]
288 | os: [linux]
289 | requiresBuild: true
290 | dev: true
291 | optional: true
292 |
293 | /@esbuild/linux-ppc64@0.20.2:
294 | resolution: {integrity: sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==}
295 | engines: {node: '>=12'}
296 | cpu: [ppc64]
297 | os: [linux]
298 | requiresBuild: true
299 | dev: true
300 | optional: true
301 |
302 | /@esbuild/linux-riscv64@0.20.2:
303 | resolution: {integrity: sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==}
304 | engines: {node: '>=12'}
305 | cpu: [riscv64]
306 | os: [linux]
307 | requiresBuild: true
308 | dev: true
309 | optional: true
310 |
311 | /@esbuild/linux-s390x@0.20.2:
312 | resolution: {integrity: sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==}
313 | engines: {node: '>=12'}
314 | cpu: [s390x]
315 | os: [linux]
316 | requiresBuild: true
317 | dev: true
318 | optional: true
319 |
320 | /@esbuild/linux-x64@0.20.2:
321 | resolution: {integrity: sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==}
322 | engines: {node: '>=12'}
323 | cpu: [x64]
324 | os: [linux]
325 | requiresBuild: true
326 | dev: true
327 | optional: true
328 |
329 | /@esbuild/netbsd-x64@0.20.2:
330 | resolution: {integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==}
331 | engines: {node: '>=12'}
332 | cpu: [x64]
333 | os: [netbsd]
334 | requiresBuild: true
335 | dev: true
336 | optional: true
337 |
338 | /@esbuild/openbsd-x64@0.20.2:
339 | resolution: {integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==}
340 | engines: {node: '>=12'}
341 | cpu: [x64]
342 | os: [openbsd]
343 | requiresBuild: true
344 | dev: true
345 | optional: true
346 |
347 | /@esbuild/sunos-x64@0.20.2:
348 | resolution: {integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==}
349 | engines: {node: '>=12'}
350 | cpu: [x64]
351 | os: [sunos]
352 | requiresBuild: true
353 | dev: true
354 | optional: true
355 |
356 | /@esbuild/win32-arm64@0.20.2:
357 | resolution: {integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==}
358 | engines: {node: '>=12'}
359 | cpu: [arm64]
360 | os: [win32]
361 | requiresBuild: true
362 | dev: true
363 | optional: true
364 |
365 | /@esbuild/win32-ia32@0.20.2:
366 | resolution: {integrity: sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==}
367 | engines: {node: '>=12'}
368 | cpu: [ia32]
369 | os: [win32]
370 | requiresBuild: true
371 | dev: true
372 | optional: true
373 |
374 | /@esbuild/win32-x64@0.20.2:
375 | resolution: {integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==}
376 | engines: {node: '>=12'}
377 | cpu: [x64]
378 | os: [win32]
379 | requiresBuild: true
380 | dev: true
381 | optional: true
382 |
383 | /@jridgewell/gen-mapping@0.3.5:
384 | resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==}
385 | engines: {node: '>=6.0.0'}
386 | dependencies:
387 | '@jridgewell/set-array': 1.2.1
388 | '@jridgewell/sourcemap-codec': 1.4.15
389 | '@jridgewell/trace-mapping': 0.3.25
390 | dev: true
391 |
392 | /@jridgewell/resolve-uri@3.1.2:
393 | resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
394 | engines: {node: '>=6.0.0'}
395 | dev: true
396 |
397 | /@jridgewell/set-array@1.2.1:
398 | resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==}
399 | engines: {node: '>=6.0.0'}
400 | dev: true
401 |
402 | /@jridgewell/sourcemap-codec@1.4.15:
403 | resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==}
404 | dev: true
405 |
406 | /@jridgewell/trace-mapping@0.3.25:
407 | resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
408 | dependencies:
409 | '@jridgewell/resolve-uri': 3.1.2
410 | '@jridgewell/sourcemap-codec': 1.4.15
411 | dev: true
412 |
413 | /@rollup/rollup-android-arm-eabi@4.17.2:
414 | resolution: {integrity: sha512-NM0jFxY8bB8QLkoKxIQeObCaDlJKewVlIEkuyYKm5An1tdVZ966w2+MPQ2l8LBZLjR+SgyV+nRkTIunzOYBMLQ==}
415 | cpu: [arm]
416 | os: [android]
417 | requiresBuild: true
418 | dev: true
419 | optional: true
420 |
421 | /@rollup/rollup-android-arm64@4.17.2:
422 | resolution: {integrity: sha512-yeX/Usk7daNIVwkq2uGoq2BYJKZY1JfyLTaHO/jaiSwi/lsf8fTFoQW/n6IdAsx5tx+iotu2zCJwz8MxI6D/Bw==}
423 | cpu: [arm64]
424 | os: [android]
425 | requiresBuild: true
426 | dev: true
427 | optional: true
428 |
429 | /@rollup/rollup-darwin-arm64@4.17.2:
430 | resolution: {integrity: sha512-kcMLpE6uCwls023+kknm71ug7MZOrtXo+y5p/tsg6jltpDtgQY1Eq5sGfHcQfb+lfuKwhBmEURDga9N0ol4YPw==}
431 | cpu: [arm64]
432 | os: [darwin]
433 | requiresBuild: true
434 | dev: true
435 | optional: true
436 |
437 | /@rollup/rollup-darwin-x64@4.17.2:
438 | resolution: {integrity: sha512-AtKwD0VEx0zWkL0ZjixEkp5tbNLzX+FCqGG1SvOu993HnSz4qDI6S4kGzubrEJAljpVkhRSlg5bzpV//E6ysTQ==}
439 | cpu: [x64]
440 | os: [darwin]
441 | requiresBuild: true
442 | dev: true
443 | optional: true
444 |
445 | /@rollup/rollup-linux-arm-gnueabihf@4.17.2:
446 | resolution: {integrity: sha512-3reX2fUHqN7sffBNqmEyMQVj/CKhIHZd4y631duy0hZqI8Qoqf6lTtmAKvJFYa6bhU95B1D0WgzHkmTg33In0A==}
447 | cpu: [arm]
448 | os: [linux]
449 | requiresBuild: true
450 | dev: true
451 | optional: true
452 |
453 | /@rollup/rollup-linux-arm-musleabihf@4.17.2:
454 | resolution: {integrity: sha512-uSqpsp91mheRgw96xtyAGP9FW5ChctTFEoXP0r5FAzj/3ZRv3Uxjtc7taRQSaQM/q85KEKjKsZuiZM3GyUivRg==}
455 | cpu: [arm]
456 | os: [linux]
457 | requiresBuild: true
458 | dev: true
459 | optional: true
460 |
461 | /@rollup/rollup-linux-arm64-gnu@4.17.2:
462 | resolution: {integrity: sha512-EMMPHkiCRtE8Wdk3Qhtciq6BndLtstqZIroHiiGzB3C5LDJmIZcSzVtLRbwuXuUft1Cnv+9fxuDtDxz3k3EW2A==}
463 | cpu: [arm64]
464 | os: [linux]
465 | requiresBuild: true
466 | dev: true
467 | optional: true
468 |
469 | /@rollup/rollup-linux-arm64-musl@4.17.2:
470 | resolution: {integrity: sha512-NMPylUUZ1i0z/xJUIx6VUhISZDRT+uTWpBcjdv0/zkp7b/bQDF+NfnfdzuTiB1G6HTodgoFa93hp0O1xl+/UbA==}
471 | cpu: [arm64]
472 | os: [linux]
473 | requiresBuild: true
474 | dev: true
475 | optional: true
476 |
477 | /@rollup/rollup-linux-powerpc64le-gnu@4.17.2:
478 | resolution: {integrity: sha512-T19My13y8uYXPw/L/k0JYaX1fJKFT/PWdXiHr8mTbXWxjVF1t+8Xl31DgBBvEKclw+1b00Chg0hxE2O7bTG7GQ==}
479 | cpu: [ppc64]
480 | os: [linux]
481 | requiresBuild: true
482 | dev: true
483 | optional: true
484 |
485 | /@rollup/rollup-linux-riscv64-gnu@4.17.2:
486 | resolution: {integrity: sha512-BOaNfthf3X3fOWAB+IJ9kxTgPmMqPPH5f5k2DcCsRrBIbWnaJCgX2ll77dV1TdSy9SaXTR5iDXRL8n7AnoP5cg==}
487 | cpu: [riscv64]
488 | os: [linux]
489 | requiresBuild: true
490 | dev: true
491 | optional: true
492 |
493 | /@rollup/rollup-linux-s390x-gnu@4.17.2:
494 | resolution: {integrity: sha512-W0UP/x7bnn3xN2eYMql2T/+wpASLE5SjObXILTMPUBDB/Fg/FxC+gX4nvCfPBCbNhz51C+HcqQp2qQ4u25ok6g==}
495 | cpu: [s390x]
496 | os: [linux]
497 | requiresBuild: true
498 | dev: true
499 | optional: true
500 |
501 | /@rollup/rollup-linux-x64-gnu@4.17.2:
502 | resolution: {integrity: sha512-Hy7pLwByUOuyaFC6mAr7m+oMC+V7qyifzs/nW2OJfC8H4hbCzOX07Ov0VFk/zP3kBsELWNFi7rJtgbKYsav9QQ==}
503 | cpu: [x64]
504 | os: [linux]
505 | requiresBuild: true
506 | dev: true
507 | optional: true
508 |
509 | /@rollup/rollup-linux-x64-musl@4.17.2:
510 | resolution: {integrity: sha512-h1+yTWeYbRdAyJ/jMiVw0l6fOOm/0D1vNLui9iPuqgRGnXA0u21gAqOyB5iHjlM9MMfNOm9RHCQ7zLIzT0x11Q==}
511 | cpu: [x64]
512 | os: [linux]
513 | requiresBuild: true
514 | dev: true
515 | optional: true
516 |
517 | /@rollup/rollup-win32-arm64-msvc@4.17.2:
518 | resolution: {integrity: sha512-tmdtXMfKAjy5+IQsVtDiCfqbynAQE/TQRpWdVataHmhMb9DCoJxp9vLcCBjEQWMiUYxO1QprH/HbY9ragCEFLA==}
519 | cpu: [arm64]
520 | os: [win32]
521 | requiresBuild: true
522 | dev: true
523 | optional: true
524 |
525 | /@rollup/rollup-win32-ia32-msvc@4.17.2:
526 | resolution: {integrity: sha512-7II/QCSTAHuE5vdZaQEwJq2ZACkBpQDOmQsE6D6XUbnBHW8IAhm4eTufL6msLJorzrHDFv3CF8oCA/hSIRuZeQ==}
527 | cpu: [ia32]
528 | os: [win32]
529 | requiresBuild: true
530 | dev: true
531 | optional: true
532 |
533 | /@rollup/rollup-win32-x64-msvc@4.17.2:
534 | resolution: {integrity: sha512-TGGO7v7qOq4CYmSBVEYpI1Y5xDuCEnbVC5Vth8mOsW0gDSzxNrVERPc790IGHsrT2dQSimgMr9Ub3Y1Jci5/8w==}
535 | cpu: [x64]
536 | os: [win32]
537 | requiresBuild: true
538 | dev: true
539 | optional: true
540 |
541 | /@types/estree@1.0.5:
542 | resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
543 | dev: true
544 |
545 | /@types/node@20.6.2:
546 | resolution: {integrity: sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw==}
547 | dev: true
548 |
549 | /@vercel/ncc@0.38.0:
550 | resolution: {integrity: sha512-B4YKZMm/EqMptKSFyAq4q2SlgJe+VCmEH6Y8gf/E1pTlWbsUJpuH1ymik2Ex3aYO5mCWwV1kaSYHSQOT8+4vHA==}
551 | hasBin: true
552 | dev: true
553 |
554 | /@vitest/expect@2.0.2:
555 | resolution: {integrity: sha512-nKAvxBYqcDugYZ4nJvnm5OR8eDJdgWjk4XM9owQKUjzW70q0icGV2HVnQOyYsp906xJaBDUXw0+9EHw2T8e0mQ==}
556 | dependencies:
557 | '@vitest/spy': 2.0.2
558 | '@vitest/utils': 2.0.2
559 | chai: 5.1.1
560 | tinyrainbow: 1.2.0
561 | dev: true
562 |
563 | /@vitest/pretty-format@2.0.2:
564 | resolution: {integrity: sha512-SBCyOXfGVvddRd9r2PwoVR0fonQjh9BMIcBMlSzbcNwFfGr6ZhOhvBzurjvi2F4ryut2HcqiFhNeDVGwru8tLg==}
565 | dependencies:
566 | tinyrainbow: 1.2.0
567 | dev: true
568 |
569 | /@vitest/runner@2.0.2:
570 | resolution: {integrity: sha512-OCh437Vi8Wdbif1e0OvQcbfM3sW4s2lpmOjAE7qfLrpzJX2M7J1IQlNvEcb/fu6kaIB9n9n35wS0G2Q3en5kHg==}
571 | dependencies:
572 | '@vitest/utils': 2.0.2
573 | pathe: 1.1.2
574 | dev: true
575 |
576 | /@vitest/snapshot@2.0.2:
577 | resolution: {integrity: sha512-Yc2ewhhZhx+0f9cSUdfzPRcsM6PhIb+S43wxE7OG0kTxqgqzo8tHkXFuFlndXeDMp09G3sY/X5OAo/RfYydf1g==}
578 | dependencies:
579 | '@vitest/pretty-format': 2.0.2
580 | magic-string: 0.30.10
581 | pathe: 1.1.2
582 | dev: true
583 |
584 | /@vitest/spy@2.0.2:
585 | resolution: {integrity: sha512-MgwJ4AZtCgqyp2d7WcQVE8aNG5vQ9zu9qMPYQHjsld/QVsrvg78beNrXdO4HYkP0lDahCO3P4F27aagIag+SGQ==}
586 | dependencies:
587 | tinyspy: 3.0.0
588 | dev: true
589 |
590 | /@vitest/utils@2.0.2:
591 | resolution: {integrity: sha512-pxCY1v7kmOCWYWjzc0zfjGTA3Wmn8PKnlPvSrsA643P1NHl1fOyXj2Q9SaNlrlFE+ivCsxM80Ov3AR82RmHCWQ==}
592 | dependencies:
593 | '@vitest/pretty-format': 2.0.2
594 | estree-walker: 3.0.3
595 | loupe: 3.1.1
596 | tinyrainbow: 1.2.0
597 | dev: true
598 |
599 | /assertion-error@2.0.1:
600 | resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
601 | engines: {node: '>=12'}
602 | dev: true
603 |
604 | /cac@6.7.14:
605 | resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
606 | engines: {node: '>=8'}
607 | dev: true
608 |
609 | /chai@5.1.1:
610 | resolution: {integrity: sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==}
611 | engines: {node: '>=12'}
612 | dependencies:
613 | assertion-error: 2.0.1
614 | check-error: 2.1.1
615 | deep-eql: 5.0.2
616 | loupe: 3.1.1
617 | pathval: 2.0.0
618 | dev: true
619 |
620 | /check-error@2.1.1:
621 | resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==}
622 | engines: {node: '>= 16'}
623 | dev: true
624 |
625 | /cross-spawn@7.0.3:
626 | resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
627 | engines: {node: '>= 8'}
628 | dependencies:
629 | path-key: 3.1.1
630 | shebang-command: 2.0.0
631 | which: 2.0.2
632 | dev: true
633 |
634 | /debug@4.3.5:
635 | resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==}
636 | engines: {node: '>=6.0'}
637 | peerDependencies:
638 | supports-color: '*'
639 | peerDependenciesMeta:
640 | supports-color:
641 | optional: true
642 | dependencies:
643 | ms: 2.1.2
644 | dev: true
645 |
646 | /deep-eql@5.0.2:
647 | resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
648 | engines: {node: '>=6'}
649 | dev: true
650 |
651 | /esbuild@0.20.2:
652 | resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==}
653 | engines: {node: '>=12'}
654 | hasBin: true
655 | requiresBuild: true
656 | optionalDependencies:
657 | '@esbuild/aix-ppc64': 0.20.2
658 | '@esbuild/android-arm': 0.20.2
659 | '@esbuild/android-arm64': 0.20.2
660 | '@esbuild/android-x64': 0.20.2
661 | '@esbuild/darwin-arm64': 0.20.2
662 | '@esbuild/darwin-x64': 0.20.2
663 | '@esbuild/freebsd-arm64': 0.20.2
664 | '@esbuild/freebsd-x64': 0.20.2
665 | '@esbuild/linux-arm': 0.20.2
666 | '@esbuild/linux-arm64': 0.20.2
667 | '@esbuild/linux-ia32': 0.20.2
668 | '@esbuild/linux-loong64': 0.20.2
669 | '@esbuild/linux-mips64el': 0.20.2
670 | '@esbuild/linux-ppc64': 0.20.2
671 | '@esbuild/linux-riscv64': 0.20.2
672 | '@esbuild/linux-s390x': 0.20.2
673 | '@esbuild/linux-x64': 0.20.2
674 | '@esbuild/netbsd-x64': 0.20.2
675 | '@esbuild/openbsd-x64': 0.20.2
676 | '@esbuild/sunos-x64': 0.20.2
677 | '@esbuild/win32-arm64': 0.20.2
678 | '@esbuild/win32-ia32': 0.20.2
679 | '@esbuild/win32-x64': 0.20.2
680 | dev: true
681 |
682 | /estree-walker@3.0.3:
683 | resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
684 | dependencies:
685 | '@types/estree': 1.0.5
686 | dev: true
687 |
688 | /execa@8.0.1:
689 | resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==}
690 | engines: {node: '>=16.17'}
691 | dependencies:
692 | cross-spawn: 7.0.3
693 | get-stream: 8.0.1
694 | human-signals: 5.0.0
695 | is-stream: 3.0.0
696 | merge-stream: 2.0.0
697 | npm-run-path: 5.3.0
698 | onetime: 6.0.0
699 | signal-exit: 4.1.0
700 | strip-final-newline: 3.0.0
701 | dev: true
702 |
703 | /fsevents@2.3.3:
704 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
705 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
706 | os: [darwin]
707 | requiresBuild: true
708 | dev: true
709 | optional: true
710 |
711 | /get-func-name@2.0.2:
712 | resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==}
713 | dev: true
714 |
715 | /get-stream@8.0.1:
716 | resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==}
717 | engines: {node: '>=16'}
718 | dev: true
719 |
720 | /human-signals@5.0.0:
721 | resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==}
722 | engines: {node: '>=16.17.0'}
723 | dev: true
724 |
725 | /is-stream@3.0.0:
726 | resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==}
727 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
728 | dev: true
729 |
730 | /isexe@2.0.0:
731 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
732 | dev: true
733 |
734 | /loupe@3.1.1:
735 | resolution: {integrity: sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw==}
736 | dependencies:
737 | get-func-name: 2.0.2
738 | dev: true
739 |
740 | /magic-string@0.30.10:
741 | resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==}
742 | dependencies:
743 | '@jridgewell/sourcemap-codec': 1.4.15
744 | dev: true
745 |
746 | /merge-stream@2.0.0:
747 | resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
748 | dev: true
749 |
750 | /mimic-fn@4.0.0:
751 | resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
752 | engines: {node: '>=12'}
753 | dev: true
754 |
755 | /ms@2.1.2:
756 | resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
757 | dev: true
758 |
759 | /nanoid@3.3.7:
760 | resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
761 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
762 | hasBin: true
763 | dev: true
764 |
765 | /npm-run-path@5.3.0:
766 | resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==}
767 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
768 | dependencies:
769 | path-key: 4.0.0
770 | dev: true
771 |
772 | /onetime@6.0.0:
773 | resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
774 | engines: {node: '>=12'}
775 | dependencies:
776 | mimic-fn: 4.0.0
777 | dev: true
778 |
779 | /path-key@3.1.1:
780 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
781 | engines: {node: '>=8'}
782 | dev: true
783 |
784 | /path-key@4.0.0:
785 | resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==}
786 | engines: {node: '>=12'}
787 | dev: true
788 |
789 | /pathe@1.1.2:
790 | resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==}
791 | dev: true
792 |
793 | /pathval@2.0.0:
794 | resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==}
795 | engines: {node: '>= 14.16'}
796 | dev: true
797 |
798 | /picocolors@1.0.0:
799 | resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
800 | dev: true
801 |
802 | /postcss@8.4.38:
803 | resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==}
804 | engines: {node: ^10 || ^12 || >=14}
805 | dependencies:
806 | nanoid: 3.3.7
807 | picocolors: 1.0.0
808 | source-map-js: 1.2.0
809 | dev: true
810 |
811 | /rollup@4.17.2:
812 | resolution: {integrity: sha512-/9ClTJPByC0U4zNLowV1tMBe8yMEAxewtR3cUNX5BoEpGH3dQEWpJLr6CLp0fPdYRF/fzVOgvDb1zXuakwF5kQ==}
813 | engines: {node: '>=18.0.0', npm: '>=8.0.0'}
814 | hasBin: true
815 | dependencies:
816 | '@types/estree': 1.0.5
817 | optionalDependencies:
818 | '@rollup/rollup-android-arm-eabi': 4.17.2
819 | '@rollup/rollup-android-arm64': 4.17.2
820 | '@rollup/rollup-darwin-arm64': 4.17.2
821 | '@rollup/rollup-darwin-x64': 4.17.2
822 | '@rollup/rollup-linux-arm-gnueabihf': 4.17.2
823 | '@rollup/rollup-linux-arm-musleabihf': 4.17.2
824 | '@rollup/rollup-linux-arm64-gnu': 4.17.2
825 | '@rollup/rollup-linux-arm64-musl': 4.17.2
826 | '@rollup/rollup-linux-powerpc64le-gnu': 4.17.2
827 | '@rollup/rollup-linux-riscv64-gnu': 4.17.2
828 | '@rollup/rollup-linux-s390x-gnu': 4.17.2
829 | '@rollup/rollup-linux-x64-gnu': 4.17.2
830 | '@rollup/rollup-linux-x64-musl': 4.17.2
831 | '@rollup/rollup-win32-arm64-msvc': 4.17.2
832 | '@rollup/rollup-win32-ia32-msvc': 4.17.2
833 | '@rollup/rollup-win32-x64-msvc': 4.17.2
834 | fsevents: 2.3.3
835 | dev: true
836 |
837 | /semver@6.3.0:
838 | resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==}
839 | hasBin: true
840 | dev: false
841 |
842 | /shebang-command@2.0.0:
843 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
844 | engines: {node: '>=8'}
845 | dependencies:
846 | shebang-regex: 3.0.0
847 | dev: true
848 |
849 | /shebang-regex@3.0.0:
850 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
851 | engines: {node: '>=8'}
852 | dev: true
853 |
854 | /siginfo@2.0.0:
855 | resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
856 | dev: true
857 |
858 | /signal-exit@4.1.0:
859 | resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
860 | engines: {node: '>=14'}
861 | dev: true
862 |
863 | /source-map-js@1.2.0:
864 | resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==}
865 | engines: {node: '>=0.10.0'}
866 | dev: true
867 |
868 | /stackback@0.0.2:
869 | resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
870 | dev: true
871 |
872 | /std-env@3.7.0:
873 | resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==}
874 | dev: true
875 |
876 | /strip-final-newline@3.0.0:
877 | resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==}
878 | engines: {node: '>=12'}
879 | dev: true
880 |
881 | /tinybench@2.8.0:
882 | resolution: {integrity: sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==}
883 | dev: true
884 |
885 | /tinypool@1.0.0:
886 | resolution: {integrity: sha512-KIKExllK7jp3uvrNtvRBYBWBOAXSX8ZvoaD8T+7KB/QHIuoJW3Pmr60zucywjAlMb5TeXUkcs/MWeWLu0qvuAQ==}
887 | engines: {node: ^18.0.0 || >=20.0.0}
888 | dev: true
889 |
890 | /tinyrainbow@1.2.0:
891 | resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==}
892 | engines: {node: '>=14.0.0'}
893 | dev: true
894 |
895 | /tinyspy@3.0.0:
896 | resolution: {integrity: sha512-q5nmENpTHgiPVd1cJDDc9cVoYN5x4vCvwT3FMilvKPKneCBZAxn2YWQjDF0UMcE9k0Cay1gBiDfTMU0g+mPMQA==}
897 | engines: {node: '>=14.0.0'}
898 | dev: true
899 |
900 | /tunnel@0.0.6:
901 | resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==}
902 | engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'}
903 | dev: false
904 |
905 | /typescript@5.2.2:
906 | resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==}
907 | engines: {node: '>=14.17'}
908 | hasBin: true
909 | dev: true
910 |
911 | /uuid@3.4.0:
912 | resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==}
913 | deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.
914 | hasBin: true
915 | dev: false
916 |
917 | /uuid@8.3.2:
918 | resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
919 | hasBin: true
920 | dev: false
921 |
922 | /vite-node@2.0.2(@types/node@20.6.2):
923 | resolution: {integrity: sha512-w4vkSz1Wo+NIQg8pjlEn0jQbcM/0D+xVaYjhw3cvarTanLLBh54oNiRbsT8PNK5GfuST0IlVXjsNRoNlqvY/fw==}
924 | engines: {node: ^18.0.0 || >=20.0.0}
925 | hasBin: true
926 | dependencies:
927 | cac: 6.7.14
928 | debug: 4.3.5
929 | pathe: 1.1.2
930 | tinyrainbow: 1.2.0
931 | vite: 5.2.11(@types/node@20.6.2)
932 | transitivePeerDependencies:
933 | - '@types/node'
934 | - less
935 | - lightningcss
936 | - sass
937 | - stylus
938 | - sugarss
939 | - supports-color
940 | - terser
941 | dev: true
942 |
943 | /vite@5.2.11(@types/node@20.6.2):
944 | resolution: {integrity: sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ==}
945 | engines: {node: ^18.0.0 || >=20.0.0}
946 | hasBin: true
947 | peerDependencies:
948 | '@types/node': ^18.0.0 || >=20.0.0
949 | less: '*'
950 | lightningcss: ^1.21.0
951 | sass: '*'
952 | stylus: '*'
953 | sugarss: '*'
954 | terser: ^5.4.0
955 | peerDependenciesMeta:
956 | '@types/node':
957 | optional: true
958 | less:
959 | optional: true
960 | lightningcss:
961 | optional: true
962 | sass:
963 | optional: true
964 | stylus:
965 | optional: true
966 | sugarss:
967 | optional: true
968 | terser:
969 | optional: true
970 | dependencies:
971 | '@types/node': 20.6.2
972 | esbuild: 0.20.2
973 | postcss: 8.4.38
974 | rollup: 4.17.2
975 | optionalDependencies:
976 | fsevents: 2.3.3
977 | dev: true
978 |
979 | /vitest@2.0.2(@types/node@20.6.2):
980 | resolution: {integrity: sha512-WlpZ9neRIjNBIOQwBYfBSr0+of5ZCbxT2TVGKW4Lv0c8+srCFIiRdsP7U009t8mMn821HQ4XKgkx5dVWpyoyLw==}
981 | engines: {node: ^18.0.0 || >=20.0.0}
982 | hasBin: true
983 | peerDependencies:
984 | '@edge-runtime/vm': '*'
985 | '@types/node': ^18.0.0 || >=20.0.0
986 | '@vitest/browser': 2.0.2
987 | '@vitest/ui': 2.0.2
988 | happy-dom: '*'
989 | jsdom: '*'
990 | peerDependenciesMeta:
991 | '@edge-runtime/vm':
992 | optional: true
993 | '@types/node':
994 | optional: true
995 | '@vitest/browser':
996 | optional: true
997 | '@vitest/ui':
998 | optional: true
999 | happy-dom:
1000 | optional: true
1001 | jsdom:
1002 | optional: true
1003 | dependencies:
1004 | '@ampproject/remapping': 2.3.0
1005 | '@types/node': 20.6.2
1006 | '@vitest/expect': 2.0.2
1007 | '@vitest/pretty-format': 2.0.2
1008 | '@vitest/runner': 2.0.2
1009 | '@vitest/snapshot': 2.0.2
1010 | '@vitest/spy': 2.0.2
1011 | '@vitest/utils': 2.0.2
1012 | chai: 5.1.1
1013 | debug: 4.3.5
1014 | execa: 8.0.1
1015 | magic-string: 0.30.10
1016 | pathe: 1.1.2
1017 | std-env: 3.7.0
1018 | tinybench: 2.8.0
1019 | tinypool: 1.0.0
1020 | tinyrainbow: 1.2.0
1021 | vite: 5.2.11(@types/node@20.6.2)
1022 | vite-node: 2.0.2(@types/node@20.6.2)
1023 | why-is-node-running: 2.2.2
1024 | transitivePeerDependencies:
1025 | - less
1026 | - lightningcss
1027 | - sass
1028 | - stylus
1029 | - sugarss
1030 | - supports-color
1031 | - terser
1032 | dev: true
1033 |
1034 | /which@2.0.2:
1035 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
1036 | engines: {node: '>= 8'}
1037 | hasBin: true
1038 | dependencies:
1039 | isexe: 2.0.0
1040 | dev: true
1041 |
1042 | /why-is-node-running@2.2.2:
1043 | resolution: {integrity: sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==}
1044 | engines: {node: '>=8'}
1045 | hasBin: true
1046 | dependencies:
1047 | siginfo: 2.0.0
1048 | stackback: 0.0.2
1049 | dev: true
1050 |
--------------------------------------------------------------------------------
/release-please-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "packages": {
3 | ".": {
4 | "changelog-path": "CHANGELOG.md",
5 | "release-type": "node",
6 | "bump-minor-pre-major": false,
7 | "bump-patch-for-minor-pre-major": false
8 | }
9 | },
10 | "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json"
11 | }
12 |
--------------------------------------------------------------------------------
/src/DownloadURL.ts:
--------------------------------------------------------------------------------
1 | import * as core from "@actions/core";
2 | import { UnsupportedPlatformError } from "./errors";
3 | import { Arch, OS, type Platform } from "./platform";
4 | import { LatestVersion } from "./versions";
5 |
6 | export default interface DownloadURL {
7 | getURL(): string;
8 | }
9 |
10 | export class ArchiveDownloadURL implements DownloadURL {
11 | constructor(
12 | private readonly version: string,
13 | private readonly platform: Platform,
14 | private readonly language: string,
15 | ) {}
16 |
17 | getURL(): string {
18 | return `https://ftp.mozilla.org/pub/${this.productPart()}/releases/${this.versionPart()}/${this.platformPart()}/${
19 | this.language
20 | }/${this.filename()}`;
21 | }
22 |
23 | private productPart(): string {
24 | const lastIndex = this.version.lastIndexOf("-");
25 | const productName = this.version.slice(0, lastIndex);
26 | switch (productName) {
27 | case "firefox":
28 | return "firefox";
29 | case "beta":
30 | return "firefox";
31 | case "devedition":
32 | return "devedition";
33 | default: // nightly, esr are unsupported
34 | return "firefox";
35 | }
36 | }
37 |
38 | private versionPart(): string {
39 | const lastIndex = this.version.lastIndexOf("-");
40 | const version = this.version.slice(lastIndex + 1);
41 | return version;
42 | }
43 |
44 | private platformPart(): string {
45 | const { os, arch } = this.platform;
46 |
47 | if (os === OS.MACOS && arch === Arch.AMD64) {
48 | return "mac";
49 | } else if (os === OS.MACOS && arch === Arch.ARM64) {
50 | return "mac";
51 | } else if (os === OS.LINUX && arch === Arch.I686) {
52 | return "linux-i686";
53 | } else if (os === OS.LINUX && arch === Arch.AMD64) {
54 | return "linux-x86_64";
55 | } else if (os === OS.WINDOWS && arch === Arch.I686) {
56 | return "win32";
57 | } else if (os === OS.WINDOWS && arch === Arch.AMD64) {
58 | return "win64";
59 | } else if (os === OS.WINDOWS && arch === Arch.ARM64) {
60 | return "win64-aarch64";
61 | }
62 | throw new UnsupportedPlatformError({ os, arch }, this.versionPart());
63 | }
64 |
65 | private filename(): string {
66 | const { os } = this.platform;
67 | core.info(
68 | `This is the version number:${Number.parseInt(this.versionPart(), 10)}`,
69 | );
70 | switch (os) {
71 | case OS.MACOS:
72 | return `Firefox%20${this.versionPart()}.dmg`;
73 | case OS.LINUX:
74 | if (Number.parseInt(this.versionPart(), 10) <= 134) {
75 | return `firefox-${this.versionPart()}.tar.bz2`;
76 | } else {
77 | return `firefox-${this.versionPart()}.tar.xz`;
78 | }
79 | case OS.WINDOWS:
80 | return `Firefox%20Setup%20${this.versionPart()}.exe`;
81 | }
82 | }
83 | }
84 |
85 | export class LatestDownloadURL implements DownloadURL {
86 | constructor(
87 | private readonly version: LatestVersion,
88 | private readonly platform: Platform,
89 | private readonly language: string,
90 | ) {}
91 |
92 | getURL(): string {
93 | return `https://download.mozilla.org/?product=${this.productPart()}&os=${this.platformPart()}&lang=${
94 | this.language
95 | }`;
96 | }
97 |
98 | private productPart(): string {
99 | switch (this.version) {
100 | case LatestVersion.LATEST:
101 | return "firefox-latest";
102 | case LatestVersion.LATEST_BETA:
103 | return "firefox-beta-latest";
104 | case LatestVersion.LATEST_DEVEDITION:
105 | return "firefox-devedition-latest";
106 | case LatestVersion.LATEST_NIGHTLY:
107 | return "firefox-nightly-latest";
108 | case LatestVersion.LATEST_ESR:
109 | return "firefox-esr-latest";
110 | }
111 | }
112 |
113 | private platformPart(): string {
114 | const { os, arch } = this.platform;
115 | if (os === OS.MACOS && arch === Arch.AMD64) {
116 | return "osx";
117 | } else if (os === OS.MACOS && arch === Arch.ARM64) {
118 | return "osx";
119 | } else if (os === OS.LINUX && arch === Arch.I686) {
120 | return "linux";
121 | } else if (os === OS.LINUX && arch === Arch.AMD64) {
122 | return "linux64";
123 | } else if (os === OS.WINDOWS && arch === Arch.I686) {
124 | return "win";
125 | } else if (os === OS.WINDOWS && arch === Arch.AMD64) {
126 | return "win64";
127 | }
128 | throw new UnsupportedPlatformError({ os, arch }, this.version);
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/src/DownloadURLFactory.ts:
--------------------------------------------------------------------------------
1 | import type DownloadURL from "./DownloadURL";
2 | import { ArchiveDownloadURL, LatestDownloadURL } from "./DownloadURL";
3 | import type { Platform } from "./platform";
4 | import { isLatestVersion } from "./versions";
5 |
6 | export class DownloadURLFactory {
7 | constructor(
8 | private readonly version: string,
9 | private readonly platform: Platform,
10 | private readonly language: string,
11 | ) {}
12 | create(): DownloadURL {
13 | if (isLatestVersion(this.version)) {
14 | return new LatestDownloadURL(this.version, this.platform, this.language);
15 | }
16 | return new ArchiveDownloadURL(this.version, this.platform, this.language);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/Installer.ts:
--------------------------------------------------------------------------------
1 | import fs from "node:fs";
2 | import path from "node:path";
3 | import * as core from "@actions/core";
4 | import * as exec from "@actions/exec";
5 | import * as io from "@actions/io";
6 | import * as tc from "@actions/tool-cache";
7 | import { DownloadURLFactory } from "./DownloadURLFactory";
8 | import type { Platform } from "./platform";
9 | import { LatestVersion } from "./versions";
10 |
11 | export type InstallSpec = {
12 | version: string;
13 | platform: Platform;
14 | language: string;
15 | };
16 |
17 | export default interface Installer {
18 | install(spec: InstallSpec): Promise;
19 |
20 | testVersion(bin: string): Promise;
21 | }
22 |
23 | const commonTestVersion = async (bin: string): Promise => {
24 | const output = await exec.getExecOutput(`"${bin}"`, ["--version"]);
25 | if (output.exitCode !== 0) {
26 | throw new Error(
27 | `firefox exits with status ${output.exitCode}: ${output.stderr}`,
28 | );
29 | }
30 | if (!output.stdout.startsWith("Mozilla Firefox ")) {
31 | throw new Error(`firefox outputs unexpected results: ${output.stdout}`);
32 | }
33 | return output.stdout.trimEnd().replace("Mozilla Firefox ", "");
34 | };
35 |
36 | export class LinuxInstaller implements Installer {
37 | async install(spec: InstallSpec): Promise {
38 | return this.download(spec);
39 | }
40 |
41 | private async download({
42 | version,
43 | platform,
44 | language,
45 | }: InstallSpec): Promise {
46 | const toolPath = tc.find("firefox", version);
47 | if (toolPath) {
48 | core.info(`Found in cache @ ${toolPath}`);
49 | return toolPath;
50 | }
51 | core.info(`Attempting to download firefox ${version}...`);
52 |
53 | const url = new DownloadURLFactory(version, platform, language)
54 | .create()
55 | .getURL();
56 | core.info(`Acquiring ${version} from ${url}`);
57 |
58 | const archivePath = await tc.downloadTool(url);
59 | core.info("Extracting Firefox...");
60 | const handle = await fs.promises.open(archivePath, "r");
61 | const firstBytes = new Int8Array(3);
62 | if (handle !== null) {
63 | await handle.read(firstBytes, 0, 3, null);
64 | core.debug(
65 | `Extracted ${firstBytes[0]}, ${firstBytes[1]} and ${firstBytes[2]}`,
66 | );
67 | }
68 | const options =
69 | firstBytes[0] === 66 && firstBytes[1] === 90 && firstBytes[2] === 104
70 | ? "xj"
71 | : "xJ";
72 | const extPath = await tc.extractTar(archivePath, "", [
73 | options,
74 | "--strip-components=1",
75 | ]);
76 | core.info(`Successfully extracted firefox ${version} to ${extPath}`);
77 |
78 | core.info("Adding to the cache ...");
79 | const cachedDir = await tc.cacheDir(extPath, "firefox", version);
80 | core.info(`Successfully cached firefox ${version} to ${cachedDir}`);
81 | return cachedDir;
82 | }
83 |
84 | testVersion = commonTestVersion;
85 | }
86 |
87 | export class MacOSInstaller implements Installer {
88 | async install(spec: InstallSpec): Promise {
89 | const installPath = await this.download(spec);
90 | return path.join(installPath, "Contents", "MacOS");
91 | }
92 |
93 | async download({
94 | version,
95 | platform,
96 | language,
97 | }: InstallSpec): Promise {
98 | const toolPath = tc.find("firefox", version);
99 | if (toolPath) {
100 | core.info(`Found in cache @ ${toolPath}`);
101 | return toolPath;
102 | }
103 | core.info(`Attempting to download firefox ${version}...`);
104 |
105 | const url = new DownloadURLFactory(version, platform, language)
106 | .create()
107 | .getURL();
108 | core.info(`Acquiring ${version} from ${url}`);
109 |
110 | const archivePath = await tc.downloadTool(url);
111 | core.info("Extracting Firefox...");
112 |
113 | const mountpoint = path.join("/Volumes", path.basename(archivePath));
114 | const appPath = (() => {
115 | if (version === LatestVersion.LATEST_NIGHTLY) {
116 | return path.join(mountpoint, "Firefox Nightly.app");
117 | } else if (version.includes("devedition")) {
118 | return path.join(mountpoint, "Firefox Developer Edition.app");
119 | } else {
120 | return path.join(mountpoint, "Firefox.app");
121 | }
122 | })();
123 |
124 | await exec.exec("hdiutil", [
125 | "attach",
126 | "-quiet",
127 | "-noautofsck",
128 | "-noautoopen",
129 | "-mountpoint",
130 | mountpoint,
131 | archivePath,
132 | ]);
133 | core.info(`Successfully extracted firefox ${version} to ${appPath}`);
134 |
135 | core.info("Adding to the cache ...");
136 | const cachedDir = await tc.cacheDir(appPath, "firefox", version);
137 | core.info(`Successfully cached firefox ${version} to ${cachedDir}`);
138 | return cachedDir;
139 | }
140 |
141 | testVersion = commonTestVersion;
142 | }
143 |
144 | export class WindowsInstaller implements Installer {
145 | install(spec: InstallSpec): Promise {
146 | return this.download(spec);
147 | }
148 |
149 | async download({
150 | version,
151 | platform,
152 | language,
153 | }: InstallSpec): Promise {
154 | const installPath = `C:\\Program Files\\Firefox_${version}`;
155 | if (await this.checkInstall(installPath)) {
156 | core.info(`Already installed @ ${installPath}`);
157 | return installPath;
158 | }
159 |
160 | core.info(`Attempting to download firefox ${version}...`);
161 |
162 | const url = new DownloadURLFactory(version, platform, language)
163 | .create()
164 | .getURL();
165 | core.info(`Acquiring ${version} from ${url}`);
166 |
167 | const installerPath = await tc.downloadTool(url);
168 | await io.mv(installerPath, `${installerPath}.exe`);
169 | core.info("Extracting Firefox...");
170 |
171 | await exec.exec(installerPath, [
172 | "/S",
173 | `/InstallDirectoryName=${path.basename(installPath)}`,
174 | ]);
175 | core.info(`Successfully installed firefox ${version} to ${installPath}`);
176 |
177 | return installPath;
178 | }
179 |
180 | private async checkInstall(dir: string): Promise {
181 | try {
182 | await fs.promises.access(dir, fs.constants.F_OK);
183 | } catch (err) {
184 | return false;
185 | }
186 | return true;
187 | }
188 |
189 | testVersion = commonTestVersion;
190 | }
191 |
--------------------------------------------------------------------------------
/src/InstallerFactory.ts:
--------------------------------------------------------------------------------
1 | import type Installer from "./Installer";
2 | import { LinuxInstaller, MacOSInstaller, WindowsInstaller } from "./Installer";
3 | import { OS, type Platform } from "./platform";
4 |
5 | export default class InstallerFactory {
6 | create(platform: Platform): Installer {
7 | switch (platform.os) {
8 | case OS.LINUX:
9 | return new LinuxInstaller();
10 | case OS.MACOS:
11 | return new MacOSInstaller();
12 | case OS.WINDOWS:
13 | return new WindowsInstaller();
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/errors.ts:
--------------------------------------------------------------------------------
1 | import type { Platform } from "./platform";
2 |
3 | export class UnsupportedPlatformError extends Error {
4 | constructor(
5 | private readonly platform: Platform,
6 | private readonly version?: string,
7 | ) {
8 | super(
9 | version
10 | ? `Unsupported platform ${platform.os} ${platform.arch} for version ${version}`
11 | : `Unsupported platform ${platform.os} ${platform.arch}`,
12 | );
13 |
14 | this.name = "UnsupportedPlatform";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import * as path from "node:path";
2 | import * as core from "@actions/core";
3 | import InstallerFactory from "./InstallerFactory";
4 | import { getPlatform } from "./platform";
5 | import { LatestVersion } from "./versions";
6 |
7 | const hasErrorMessage = (e: unknown): e is { message: string | Error } => {
8 | return typeof e === "object" && e !== null && "message" in e;
9 | };
10 |
11 | const run = async (): Promise => {
12 | try {
13 | const version = core.getInput("firefox-version") || LatestVersion.LATEST;
14 | const platform = getPlatform();
15 | const language = core.getInput("firefox-language") || "en-US";
16 |
17 | core.info(`Setup firefox ${version} (${language})`);
18 |
19 | const installer = new InstallerFactory().create(platform);
20 | const installDir = await installer.install({ version, platform, language });
21 |
22 | core.addPath(installDir);
23 |
24 | const installedBinPath = path.join(installDir, "firefox");
25 | const installedVersion = await installer.testVersion(installedBinPath);
26 | core.info(`Successfully setup firefox version ${installedVersion}`);
27 | core.setOutput("firefox-version", installedVersion);
28 | core.setOutput("firefox-path", installedBinPath);
29 | } catch (error) {
30 | if (hasErrorMessage(error)) {
31 | core.setFailed(error.message);
32 | } else {
33 | core.setFailed(String(error));
34 | }
35 | }
36 | };
37 |
38 | run();
39 |
--------------------------------------------------------------------------------
/src/platform.ts:
--------------------------------------------------------------------------------
1 | import os from "node:os";
2 |
3 | export type Platform = {
4 | os: OS;
5 | arch: Arch;
6 | };
7 |
8 | export const OS = {
9 | MACOS: "macos",
10 | LINUX: "linux",
11 | WINDOWS: "windows",
12 | } as const;
13 |
14 | export type OS = (typeof OS)[keyof typeof OS];
15 |
16 | export const Arch = {
17 | AMD64: "amd64",
18 | I686: "i686",
19 | ARM64: "arm64",
20 | } as const;
21 |
22 | export type Arch = (typeof Arch)[keyof typeof Arch];
23 |
24 | export const getOS = (): OS => {
25 | const platform = os.platform();
26 | switch (platform) {
27 | case "linux":
28 | return OS.LINUX;
29 | case "darwin":
30 | return OS.MACOS;
31 | case "win32":
32 | return OS.WINDOWS;
33 | }
34 | throw new Error(`Unsupported platform: ${platform}`);
35 | };
36 |
37 | export const getArch = (): Arch => {
38 | const arch = os.arch();
39 | switch (arch) {
40 | case "arm64":
41 | return Arch.ARM64;
42 | case "x32":
43 | return Arch.I686;
44 | case "x64":
45 | return Arch.AMD64;
46 | }
47 | throw new Error(`Unsupported arch: ${arch}`);
48 | };
49 |
50 | export const getPlatform = (): Platform => {
51 | return {
52 | os: getOS(),
53 | arch: getArch(),
54 | };
55 | };
56 |
--------------------------------------------------------------------------------
/src/versions.ts:
--------------------------------------------------------------------------------
1 | export const LatestVersion = {
2 | LATEST_DEVEDITION: "latest-devedition",
3 | LATEST_NIGHTLY: "latest-nightly",
4 | LATEST_BETA: "latest-beta",
5 | LATEST_ESR: "latest-esr",
6 | LATEST: "latest",
7 | } as const;
8 |
9 | export type LatestVersion = (typeof LatestVersion)[keyof typeof LatestVersion];
10 |
11 | export const isLatestVersion = (version: string): version is LatestVersion => {
12 | return (
13 | version === LatestVersion.LATEST ||
14 | version === LatestVersion.LATEST_BETA ||
15 | version === LatestVersion.LATEST_DEVEDITION ||
16 | version === LatestVersion.LATEST_NIGHTLY ||
17 | version === LatestVersion.LATEST_ESR
18 | );
19 | };
20 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es6",
4 | "module": "commonjs",
5 | "moduleResolution": "node",
6 | "outDir": "./dist",
7 | "rootDir": "./src",
8 | "strict": true,
9 | "noImplicitAny": true,
10 | "esModuleInterop": true
11 | },
12 | "exclude": ["node_modules", "**/*.test.ts"]
13 | }
14 |
--------------------------------------------------------------------------------