diff --git a/.air.toml b/.air.toml new file mode 100644 index 0000000..26569b4 --- /dev/null +++ b/.air.toml @@ -0,0 +1,63 @@ +root = "." +tmp_dir = "tmp" +testdata_dir = "testdata" + +[build] + pre_cmd = ["make generate-required"] + cmd = "go build -buildvcs=false -o ./tmp/main ./cmd/codexgo" + post_cmd = [] + bin = "./tmp/main" + full_bin = "" + args_bin = [] + include_ext = [ + "go", + "html", + "templ", + "tmpl", + "tpl" + ] + exclude_dir = [] + include_dir = [ + "pkg" + ] + include_file = [] + exclude_file = [] + exclude_regex = [ + "^.*_test\\.go$", + "^.*\\.mother\\.go$", + "^.*\\.mock\\.go$", + "^.*_templ\\.go$" + ] + exclude_unchanged = true + follow_symlink = true + log = "air.log" + poll = false + poll_interval = 1000 + delay = 1000 + stop_on_error = false + send_interrupt = true + kill_delay = 1000 + rerun = false + rerun_delay = 1000 + +[log] + time = true + main_only = false + +[color] + main = "magenta" + watcher = "cyan" + build = "yellow" + runner = "green" + +[misc] + clean_on_exit = true + +[screen] + clear_on_rebuild = true + keep_scroll = true + +[proxy] + enabled = true + proxy_port = 8090 + app_port = 8080 diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..78e4f65 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,51 @@ +{ + "name": "codexgo", + "image": "mcr.microsoft.com/devcontainers/base:bookworm", + "features": { + "ghcr.io/devcontainers/features/docker-in-docker:2": {}, + "ghcr.io/devcontainers/features/go:1": {}, + "ghcr.io/devcontainers/features/node:1": {} + }, + "postCreateCommand": "make init", + "customizations": { + "vscode": { + "extensions": [ + "a-h.templ", + "aaron-bond.better-comments", + "CucumberOpen.cucumber-official", + "esbenp.prettier-vscode", + "github.vscode-github-actions", + "golang.go", + "Gruntfuggly.todo-tree", + "ms-azuretools.vscode-docker", + "ms-vscode.makefile-tools", + "redhat.vscode-yaml", + "streetsidesoftware.code-spell-checker", + "tamasfe.even-better-toml", + "thejltres.fomantic-ui-snippets" + ], + "settings": { + "[cucumber]": { + "editor.defaultFormatter": "CucumberOpen.cucumber-official" + }, + "[go]": { + "editor.defaultFormatter": "golang.go" + }, + "[templ]": { + "editor.defaultFormatter": "a-h.templ" + }, + "cSpell.language": "en,lorem", + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnPaste": true, + "editor.formatOnSave": true, + "emmet.includeLanguages": { + "templ": "html" + }, + "go.toolsManagement.autoUpdate": true, + "gopls": { + "ui.semanticTokens": true + } + } + } + } +} diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..6313b56 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..9b77ea7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,40 @@ +--- +name: Bug report +about: Create a report to help us improve +title: "" +labels: "" +assignees: "" +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: + +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + +- OS: [e.g. iOS] +- Browser [e.g. chrome, safari] +- Version [e.g. 22] + +**Smartphone (please complete the following information):** + +- Device: [e.g. iPhone6] +- OS: [e.g. iOS8.1] +- Browser [e.g. stock browser, safari] +- Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..2bc5d5f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,19 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: "" +labels: "" +assignees: "" +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml new file mode 100644 index 0000000..8812e98 --- /dev/null +++ b/.github/actions/setup/action.yml @@ -0,0 +1,23 @@ +name: Setup + +description: Setup & Caching Dependencies + +runs: + using: "composite" + + steps: + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version-file: "go.mod" + cache-dependency-path: "go.sum" + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version-file: "package.json" + cache: "npm" + + - name: Install Dependencies + shell: ${{ runner.os == 'Windows' && 'pwsh' || 'bash' }} + run: make init diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..64f9d8f --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,56 @@ +name: CI + +on: + push: + branches: [main, ci/**] + pull_request: + branches: [main] + +jobs: + TruffleHog: + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Secret Scanning + uses: trufflesecurity/trufflehog@main + with: + extra_args: --only-verified + + Lint: + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup + uses: ./.github/actions/setup + + - name: Check + run: make lint-check + + Test: + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup + uses: ./.github/actions/setup + + - name: Unit + run: make test-unit + + - name: Upload Report + uses: actions/upload-artifact@v4 + if: success() || failure() + with: + name: Test Report + path: ./test/report + retention-days: 30 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..c5bddab --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,64 @@ +name: Release + +on: + workflow_dispatch: + inputs: + status: + type: choice + description: Status + options: + - alpha + - beta + - stable + default: stable + + bump: + type: choice + description: Bump + options: + - patch + - minor + - major + - auto + default: auto + + dry: + type: boolean + description: Dry Release + default: false + +jobs: + Generate: + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup + uses: ./.github/actions/setup + + - name: Import GPG Key + id: import-gpg + uses: crazy-max/ghaction-import-gpg@v6 + with: + gpg_private_key: ${{ secrets.BOT_GPG_PRIVATE_KEY }} + passphrase: ${{ secrets.BOT_GPG_PASSPHRASE }} + git_config_global: true + git_user_signingkey: true + git_commit_gpgsign: true + git_tag_gpgsign: true + + - name: Generate Release + run: OPTIONS="$STATUS_ARG $BUMP_ARG $DRY_ARG" make release-ci + env: + STATUS_ARG: ${{ fromJSON('{"alpha":"--preRelease=alpha", "beta":"--preRelease=beta", "stable":""}')[github.event.inputs.status] }} + BUMP_ARG: ${{ fromJSON('{"patch":"-i patch", "minor":"-i minor", "major":"-i major", "auto":""}')[github.event.inputs.bump] }} + DRY_ARG: ${{ github.event.inputs.dry == 'true' && '-d' || '' }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GIT_AUTHOR_NAME: ${{ steps.import-gpg.outputs.name }} + GIT_AUTHOR_EMAIL: ${{ steps.import-gpg.outputs.email }} + GIT_COMMITTER_NAME: ${{ steps.import-gpg.outputs.name }} + GIT_COMMITTER_EMAIL: ${{ steps.import-gpg.outputs.email }} diff --git a/.github/workflows/upgrade.yml b/.github/workflows/upgrade.yml new file mode 100644 index 0000000..97e2934 --- /dev/null +++ b/.github/workflows/upgrade.yml @@ -0,0 +1,38 @@ +name: Upgrade + +on: + workflow_dispatch: + +jobs: + Dependencies: + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup + uses: ./.github/actions/setup + + - name: Import GPG Key + id: import-gpg + uses: crazy-max/ghaction-import-gpg@v6 + with: + gpg_private_key: ${{ secrets.BOT_GPG_PRIVATE_KEY }} + passphrase: ${{ secrets.BOT_GPG_PASSPHRASE }} + git_config_global: true + git_user_signingkey: true + git_commit_gpgsign: true + git_tag_gpgsign: true + + - name: Upgrade Dependencies + run: | + make upgrade + git push origin main + env: + GIT_AUTHOR_NAME: ${{ steps.import-gpg.outputs.name }} + GIT_AUTHOR_EMAIL: ${{ steps.import-gpg.outputs.email }} + GIT_COMMITTER_NAME: ${{ steps.import-gpg.outputs.name }} + GIT_COMMITTER_EMAIL: ${{ steps.import-gpg.outputs.email }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e139505 --- /dev/null +++ b/.gitignore @@ -0,0 +1,55 @@ +#* Editor Directories & Files +.vscode/* +!.vscode/extensions.json +!.vscode/settings.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? +*.local + +#* Package Managers +vendor +node_modules +package +pnpm-lock.yaml +yarn.lock +go.work.sum + +#* Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +#* ENV +.env* +.env.* +!.env.demo* +!.env.example* +.npmrc + +#* Production +dist +dist-ssr +build + +#* Tooling +vite.config.js.timestamp-* +vite.config.ts.timestamp-* +*_templ.txt +*_templ.go + +#* Misc +ignore* +report* +temp* +tmp* + +#* Repository diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100755 index 0000000..0398b7a --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1 @@ +npx --no -- commitlint --edit ${1} diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000..1524ad6 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +npx --no -- lint-staged diff --git a/.husky/pre-push b/.husky/pre-push new file mode 100755 index 0000000..c5c13ca --- /dev/null +++ b/.husky/pre-push @@ -0,0 +1 @@ +make leak-check diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..e139505 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,55 @@ +#* Editor Directories & Files +.vscode/* +!.vscode/extensions.json +!.vscode/settings.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? +*.local + +#* Package Managers +vendor +node_modules +package +pnpm-lock.yaml +yarn.lock +go.work.sum + +#* Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +#* ENV +.env* +.env.* +!.env.demo* +!.env.example* +.npmrc + +#* Production +dist +dist-ssr +build + +#* Tooling +vite.config.js.timestamp-* +vite.config.ts.timestamp-* +*_templ.txt +*_templ.go + +#* Misc +ignore* +report* +temp* +tmp* + +#* Repository diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..082bc94 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["ms-vscode-remote.remote-containers"] +} diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..61defd0 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,344 @@ +# Changelog + +## [4.3.0](https://github.com/bastean/codexgo/compare/v4.2.1...v4.3.0) (2024-06-26) + +### Chores + +- **deps:** upgrade dependencies ([bce72d8](https://github.com/bastean/codexgo/commit/bce72d872897ad527dd3e435fe45fe5f93300d81)) +- **deps:** upgrade jwt to v5 ([18054b7](https://github.com/bastean/codexgo/commit/18054b747b8250e7a169359dc1f54287328d0edc)) + +### Documentation + +- add scanners ([a34ea61](https://github.com/bastean/codexgo/commit/a34ea616ff1425c3053115df604e64ef9609e283)) + +### New Features + +- add trivy and osv scanners ([6fe3c53](https://github.com/bastean/codexgo/commit/6fe3c53255d3fb68dbbda985a0c15e7b9b68ae5c)) + +### Refactors + +- **context:** change domain message components ([157ef5b](https://github.com/bastean/codexgo/commit/157ef5bcd3a54c9784ddcdd6339e9223da735a38)) +- **context:** rename variables in value objects ([c8f46a1](https://github.com/bastean/codexgo/commit/c8f46a1e857c25d38a72da5a9f30273c8dc64e3d)) +- **scripts:** change panic on error ([4577790](https://github.com/bastean/codexgo/commit/4577790af035df66e18aa96ee8289c30409a1687)) +- **server:** rename service logs ([65bd07c](https://github.com/bastean/codexgo/commit/65bd07c900686326c91d5fba163c501348a8589e)) +- **server:** reorganize services ([f559715](https://github.com/bastean/codexgo/commit/f5597153bd121cce16d77aecba2cf0e268bcf1ce)) + +### Tests + +- **context:** add assertion for duplication error in mongo ([201fd53](https://github.com/bastean/codexgo/commit/201fd53f5970546dddaf62c2b21d50a35841052c)) +- **context:** add assertion for omitted json errors ([a08ea38](https://github.com/bastean/codexgo/commit/a08ea38efd3fa0d191505f48de571a234c9b2217)) + +## [4.2.1](https://github.com/bastean/codexgo/compare/v4.2.0...v4.2.1) (2024-06-19) + +### Bug Fixes + +- add boolean format verb in strings ([e317911](https://github.com/bastean/codexgo/commit/e317911d22e1798a4bc0a1c917089b06d8228a35)) +- remove default format verb in strings ([57beb5e](https://github.com/bastean/codexgo/commit/57beb5e3339a6ac9685e47bd2c798fdcccf619b2)) + +## [4.2.0](https://github.com/bastean/codexgo/compare/v4.1.1...v4.2.0) (2024-06-17) + +### Chores + +- **deps:** upgrade dependencies ([7b19ee7](https://github.com/bastean/codexgo/commit/7b19ee7dee15d14a7fad328977d090c031ef2964)) + +### New Features + +- **context:** add handling of omitted errors ([f70c276](https://github.com/bastean/codexgo/commit/f70c2767a368859560c1c2986411384ee36ae92e)) + +### Refactors + +- add default format verb to strings ([c459caa](https://github.com/bastean/codexgo/commit/c459caaf4c6fb7c5aede730caad10ab0093e3a3e)) +- change panic on error ([1fc83fa](https://github.com/bastean/codexgo/commit/1fc83fa7b6433059e098bbe8a21762b7eb95000a)) +- **context:** remove notify module ([064815f](https://github.com/bastean/codexgo/commit/064815f9efb7b75638c4f2d88efe1a27cacecc80)) +- **context:** remove redundant details from type names ([27a666a](https://github.com/bastean/codexgo/commit/27a666a11bf7232df9d9ba34c20f1d15e03abade)) + +### Tests + +- **context:** add handling of unexpected errors in mothers to avoid flaky tests ([2fbea22](https://github.com/bastean/codexgo/commit/2fbea223fada03944b1deb6a1b83f2f7df879e93)) + +## [4.1.1](https://github.com/bastean/codexgo/compare/v4.1.0...v4.1.1) (2024-06-12) + +### Bug Fixes + +- **makefile:** add pipefail to return an error when a test fails ([5b4c26e](https://github.com/bastean/codexgo/commit/5b4c26e4621fec259eb1b6cfa0bd263534b50588)) + +## [4.1.0](https://github.com/bastean/codexgo/compare/v4.0.0...v4.1.0) (2024-06-10) + +### Chores + +- **deps:** upgrade dependencies ([93fc426](https://github.com/bastean/codexgo/commit/93fc4264ee2f2937e07e9a8f9c96156df4dfb4f1)) + +### Documentation + +- **readme:** add basic layers workflow ([b6f6d5d](https://github.com/bastean/codexgo/commit/b6f6d5d0f8b6bb75759a8a0744f86bd5abc44893)) + +### New Features + +- **makefile:** add tee in test rules ([1d21d7a](https://github.com/bastean/codexgo/commit/1d21d7a31fac96db750c9266e181f93765ca1089)) + +### Bug Fixes + +- **dockerfile:** update air module name ([71bc376](https://github.com/bastean/codexgo/commit/71bc376c7a6e834d16eaf10684806ca652bd3e51)) + +### Refactors + +- add type alias ([f55bb9d](https://github.com/bastean/codexgo/commit/f55bb9d1fbe3c933c1bb48e6885270c92e69beee)) +- **context:** add pointer to search criteria type ([8648a18](https://github.com/bastean/codexgo/commit/8648a184464c355d5b6216a4cb6a2f58c4bc1b95)) +- **context:** change empty type from struct to interface ([4e5dcf0](https://github.com/bastean/codexgo/commit/4e5dcf0152a5eec35818edf90030ae449037e0a2)) +- **context:** change errors in shared module ([47fe621](https://github.com/bastean/codexgo/commit/47fe62172d93792694beef6df3145502690e8d6a)) +- **context:** change parameters to use primitive type in user module ([db8fc5b](https://github.com/bastean/codexgo/commit/db8fc5b12b24968677f2a452e703a5af3192020f)) +- **context:** change updates in user module ([ba294af](https://github.com/bastean/codexgo/commit/ba294aff99ac5a6d35b2701531d97bf16f6191fd)) +- squash struct fields ([8ccc22c](https://github.com/bastean/codexgo/commit/8ccc22c0ed57d02e1717d723462673ee1ebc55d3)) + +### Tests + +- **context:** add more explicit test case names ([5027a31](https://github.com/bastean/codexgo/commit/5027a31a0fafcdbcac17ad09a04b557e145c5a55)) + +## [4.0.0](https://github.com/bastean/codexgo/compare/v3.0.1...v4.0.0) (2024-05-28) + +### ⚠ BREAKING CHANGES + +- **server:** decouple service initializations +- **context:** change notification system workflow +- **server:** change acceptance tests to work with the new ui +- **server:** add fomantic-ui +- **server:** change error handling from panic to wrapped errors +- **context:** change package names in shared module +- **context:** change integration tests to check for wrapped errors instead of panic +- **context:** change unit tests to check for wrapped errors instead of panic +- **context:** change error handling from panic to wrapped errors + +### Chores + +- change air config ([a3b2f94](https://github.com/bastean/codexgo/commit/a3b2f94cb9f1f5b69ab719ae09001bac8382e7b2)) +- change git ignore list ([122f7b2](https://github.com/bastean/codexgo/commit/122f7b2ba448cf79e741e5c7c3e3b7283a2dcaaf)) +- change go version in mod file ([95ac107](https://github.com/bastean/codexgo/commit/95ac107f7b6dee5618ec459c911ca07440521c04)) +- change makefile rules ([285b30b](https://github.com/bastean/codexgo/commit/285b30b7e1c88503681279e097d4a6e0abf8154c)) +- **deps:** upgrade dependencies ([f804fc8](https://github.com/bastean/codexgo/commit/f804fc8c0e22f660407e80c826811455d9d13303)) + +### Documentation + +- **readme:** add updated screenshots ([ffd6b17](https://github.com/bastean/codexgo/commit/ffd6b175b19292111ba5bff3611322c7ee8cdbb6)) +- **readme:** change description ([122b14c](https://github.com/bastean/codexgo/commit/122b14c69174c5de0f9cc0cac54e4b55ea3a25d2)) + +### New Features + +- **air:** enable live-reloading on the browser ([7714c38](https://github.com/bastean/codexgo/commit/7714c38cf0a74ef07dff07d232b98f462070a71a)) +- **context:** add json marshal error handler to error bubble ([68819fe](https://github.com/bastean/codexgo/commit/68819fe9521117adb43504105b90f91abecebce4)) +- **context:** add new terminal transport port adapter to notify module ([28fd1fe](https://github.com/bastean/codexgo/commit/28fd1fe865666b65f25d93e1f7b1895f2b40a998)) +- **scripts:** add copy-deps script ([79e2d73](https://github.com/bastean/codexgo/commit/79e2d73989674b9a2d62841db87da89ef4bd8564)) +- **server:** add accepts cookies nag ([682c370](https://github.com/bastean/codexgo/commit/682c370366139911fa145defa9127310503d86e9)) +- **server:** add cookies cleaning ([30d4b9a](https://github.com/bastean/codexgo/commit/30d4b9aca620098e1ed4b9c0c0501003570f8007)) +- **server:** add fomantic-ui ([738bf51](https://github.com/bastean/codexgo/commit/738bf5140c0dcb310c4effcbd3659720ba2c20a5)) +- **server:** add log files ([141001a](https://github.com/bastean/codexgo/commit/141001a2d0bf0269a25030597c45d3a2b7c2f891)) +- **server:** add missing error handlers ([99938f6](https://github.com/bastean/codexgo/commit/99938f6a5c00a47a5d4471d07354fe565a6c50f5)) +- **server:** add popup to inform about account status ([77eb4a9](https://github.com/bastean/codexgo/commit/77eb4a917e1487a3736da346064befa0ff3d35c8)) + +### Bug Fixes + +- add missing pointers ([b6b9343](https://github.com/bastean/codexgo/commit/b6b934305caecf51eea9c058e84d75cfaa2d353f)) +- **deps:** upgrade dependencies ([4574f31](https://github.com/bastean/codexgo/commit/4574f3147dff657eb1672a97d0acea236bf8d5c4)) +- **server:** add json unmarshal type error handler ([eb9eeb5](https://github.com/bastean/codexgo/commit/eb9eeb5e4442caf2abd07c294cd68a0c9db8f9b9)) + +### Refactors + +- add field names at struct initialization ([55c5de3](https://github.com/bastean/codexgo/commit/55c5de3902be83a9066b9867e9493ad4ebab6f87)) +- **context:** change error handling from panic to wrapped errors ([ec3245c](https://github.com/bastean/codexgo/commit/ec3245c9caf81562cfb8c2ae61aa16ee34b4d5e6)) +- **context:** change exchange to router in broker model ([be19870](https://github.com/bastean/codexgo/commit/be198705206d0f0370b73dc5ed8bb9cf1c3d3572)) +- **context:** change notification system workflow ([f7ec73c](https://github.com/bastean/codexgo/commit/f7ec73cd038337f63b792f1f2623285b7e0eb854)) +- **context:** change package names in shared module ([e26da1e](https://github.com/bastean/codexgo/commit/e26da1e123692559f9a84a2ad3f0e53c4a1b1743)) +- **context:** change time format in errors ([23362e4](https://github.com/bastean/codexgo/commit/23362e40d7ea9fafe2b83a120f3bbc6652644057)) +- **context:** change type name of shared errors ([61c9b93](https://github.com/bastean/codexgo/commit/61c9b93fcec544e6d95c4e3ecd76a0f49ba38e43)) +- **context:** rename folders using plural names instead of the prefix s in shared module ([fe5aabf](https://github.com/bastean/codexgo/commit/fe5aabf7b3815b60a48382076f7f453e065f15f2)) +- **context:** rename packages using plural names in shared module ([db66e1d](https://github.com/bastean/codexgo/commit/db66e1d7e9c62ed8600f048512c37ec30bcba4ef)) +- **makefile:** add MAKE variable to rules with a recursive recipe ([75e31a8](https://github.com/bastean/codexgo/commit/75e31a84e9b58b1723270bce738162240628e21d)) +- **makefile:** change target names of test rules ([f078581](https://github.com/bastean/codexgo/commit/f0785811deabe3ab8343185cb14ca97933c6341c)) +- rename files using flatcase ([28d3e5f](https://github.com/bastean/codexgo/commit/28d3e5fafad4cdbeed23a8c6bb51724e6e6f746e)) +- **scripts:** change commit message on upgrade script ([9b257a2](https://github.com/bastean/codexgo/commit/9b257a223f1c2cc22dfe9c7dc5b1764389f3f8f1)) +- **server:** add ui class in jquery component selectors ([3c1743e](https://github.com/bastean/codexgo/commit/3c1743ed59d0e35fe5b4d2e2e7d9a4e62066a4a5)) +- **server:** change broker service components to individual files ([93d3c29](https://github.com/bastean/codexgo/commit/93d3c29e4669be36e5ed2f196fdb4e1183314a72)) +- **server:** change error handling from panic to wrapped errors ([1e3d766](https://github.com/bastean/codexgo/commit/1e3d766be194b64960e302b83318a9929f104e5c)) +- **server:** change error messages in services ([0f6a21e](https://github.com/bastean/codexgo/commit/0f6a21e98a89347d721f32b611fdacd6b405430d)) +- **server:** decouple service initializations ([61961d2](https://github.com/bastean/codexgo/commit/61961d2327948df5b9611ff75034c28d9f34a859)) + +### Tests + +- **context:** add spaces between definitions in setup test ([4318ea2](https://github.com/bastean/codexgo/commit/4318ea27f6cac20154489c55917b9d639bd54fe0)) +- **context:** change integration tests to check for wrapped errors instead of panic ([6bb93ac](https://github.com/bastean/codexgo/commit/6bb93ac315e0049a2407952406e8349886274b2a)) +- **context:** change time on expected error messages ([56137d6](https://github.com/bastean/codexgo/commit/56137d695a6663e18272db70c1d98dcf97c03140)) +- **context:** change unit tests to check for wrapped errors instead of panic ([971b9de](https://github.com/bastean/codexgo/commit/971b9de188f998f9b6ecdec5435375be46789c9f)) +- **server:** change acceptance tests to work with the new ui ([8df4c59](https://github.com/bastean/codexgo/commit/8df4c59c9c280d7c7a55285fa662b682b2df9469)) + +## [3.0.1](https://github.com/bastean/codexgo/compare/v3.0.0...v3.0.1) (2024-04-08) + +### Bug Fixes + +- **deps:** upgrade dependencies ([bd92cf7](https://github.com/bastean/codexgo/commit/bd92cf74fced77cb9011171e60f15d687ddc94f7)) +- **makefile:** add phony target ([3c33a90](https://github.com/bastean/codexgo/commit/3c33a9005396067e0a2c130d78648a41bc677f73)) +- **makefile:** remove init-ci rule ([3311e14](https://github.com/bastean/codexgo/commit/3311e144798aaff6dfe34df1c2c8aa9751f3ca68)) + +### Refactors + +- **makefile:** change rules order ([95c6170](https://github.com/bastean/codexgo/commit/95c6170e4719d0702efe2ed75197c42cd3103494)) + +## [3.0.0](https://github.com/bastean/codexgo/compare/v2.0.1...v3.0.0) (2024-04-04) + +### Documentation + +- **readme:** add features ([6d36f5d](https://github.com/bastean/codexgo/commit/6d36f5d75dfc6e1e3cf9cb50ca01d6f7ab1a4b7a)) + +### New Features + +- add account confirmation via email ([66f7b6e](https://github.com/bastean/codexgo/commit/66f7b6eda53e2f3ea897603c032e85f51fe6cf83)) +- add event-driven architecture using rabbitmq ([1fd11cb](https://github.com/bastean/codexgo/commit/1fd11cb1b1b9096dc2aafccd2da8982d6d041279)) +- add example env demo file ([c288d3c](https://github.com/bastean/codexgo/commit/c288d3ccdd7e4d348b915f22c9fa0236df7de247)) +- add gracefully close infrastructure connections ([fb91c9a](https://github.com/bastean/codexgo/commit/fb91c9a569d7f2d6be67e983e19bb53ec5cb5191)) + +### Bug Fixes + +- **deps:** upgrade dependencies ([a27389f](https://github.com/bastean/codexgo/commit/a27389f51cfc9b37d6b11dcc1013c2e02be84ea4)) +- remove files generated by templ ([0adc9c6](https://github.com/bastean/codexgo/commit/0adc9c6cd570b672f8f9719ee0f3691b895804fd)) + +### Refactors + +- change env handling in context to app ([f395933](https://github.com/bastean/codexgo/commit/f395933288ba2ad6fbb95eb683faa7195ebad890)) +- change templ components ([e54c18a](https://github.com/bastean/codexgo/commit/e54c18a8421a1f5a62bb7ef0e2e58f90f2b50f4b)) + +### Tests + +- add individual execution of unit, integration and acceptance tests ([4dc646f](https://github.com/bastean/codexgo/commit/4dc646f52794c0ad80803ce95900c0bf402029fd)) +- remove shared value objects ([618ab5c](https://github.com/bastean/codexgo/commit/618ab5c990f2c54ec574380f54778fb64757ea2a)) + +## [2.0.1](https://github.com/bastean/codexgo/compare/v2.0.0...v2.0.1) (2024-03-13) + +### Bug Fixes + +- **deps:** upgrade dependencies ([4e3f621](https://github.com/bastean/codexgo/commit/4e3f621bf8b3833ef2cd4d7bbe877cf5d38a81ac)) + +### Refactors + +- change domain models ([f80911a](https://github.com/bastean/codexgo/commit/f80911acf48a9bfb115d3328a7834babfa123b02)) + +## [2.0.0](https://github.com/bastean/codexgo/compare/v1.5.0...v2.0.0) (2024-03-02) + +### ⚠ BREAKING CHANGES + +- add standard project layout + +### Bug Fixes + +- **deps:** upgrade dependencies ([f11b15f](https://github.com/bastean/codexgo/commit/f11b15f77899ab50ae0ac744dd84346cb71a7760)) + +### Refactors + +- add standard project layout ([307089c](https://github.com/bastean/codexgo/commit/307089c56975716fb6788e6fafd06ffa8b42f620)) + +## [1.5.0](https://github.com/bastean/codexgo/compare/v1.4.0...v1.5.0) (2024-02-18) + +### New Features + +- add script to sync .env\* files ([e7fcc0b](https://github.com/bastean/codexgo/commit/e7fcc0b6355e5abf00a97526e7becb111cdf2dda)) + +### Bug Fixes + +- **deps:** upgrade dependencies ([fecaafa](https://github.com/bastean/codexgo/commit/fecaafa9bf35e6a5fa71ae0468845bd32bef26ea)) + +## [1.4.0](https://github.com/bastean/codexgo/compare/v1.3.1...v1.4.0) (2024-02-15) + +### New Features + +- add commit message types to include in the changelog ([db06cf9](https://github.com/bastean/codexgo/commit/db06cf95d6d637f097a6745d04302b8f272a50a6)) + +### Bug Fixes + +- **deps:** upgrade dependencies ([80c2256](https://github.com/bastean/codexgo/commit/80c22563516b5da15ea07475fbc94c4fcbffd5c6)) + +## [1.3.1](https://github.com/bastean/codexgo/compare/v1.3.0...v1.3.1) (2024-02-14) + +### Bug Fixes + +- **actions:** upgrade go setup action ([da7bc21](https://github.com/bastean/codexgo/commit/da7bc213a052d088efaac6b20c5ec5ad92f4d037)) +- change live reload ([2f97bdb](https://github.com/bastean/codexgo/commit/2f97bdbe0675a747ac4eddcfe99632dcf0803b0f)) + +## [1.3.0](https://github.com/bastean/codexgo/compare/v1.2.0...v1.3.0) (2024-02-06) + +### Features + +- **actions:** add upgrade workflow ([e2d62d4](https://github.com/bastean/codexgo/commit/e2d62d4d76e56e0dfaabe0cbd474ef23ee1e5687)) +- add script to upgrade dependencies ([a7cd088](https://github.com/bastean/codexgo/commit/a7cd088099d336526e00c6187a835f9938e48a55)) +- **backend:** add secure middleware ([370db08](https://github.com/bastean/codexgo/commit/370db087b6df9ce1aaa3fa2e5589abc9756ec9b2)) + +### Bug Fixes + +- **actions:** add commit push to upgrade workflow ([9ea06db](https://github.com/bastean/codexgo/commit/9ea06dbfdb1f2af22f187734d757fe2ad8b0e88a)) +- **deps:** upgrade dependencies ([811345c](https://github.com/bastean/codexgo/commit/811345c603d2b07ed76f83620fc6386ea90d1861)) +- **deps:** upgrade dependencies ([c99be30](https://github.com/bastean/codexgo/commit/c99be30ae77f766ca09dece90a627f657f8458c3)) + +## [1.2.0](https://github.com/bastean/codexgo/compare/v1.1.0...v1.2.0) (2024-01-28) + +### Features + +- **backend:** add rate limiter middleware ([a6c1b2b](https://github.com/bastean/codexgo/commit/a6c1b2b2a484d0b4ac63364b76c1ba18f8c3e4b3)) + +### Bug Fixes + +- **deps:** upgrade modules dependencies ([d9851aa](https://github.com/bastean/codexgo/commit/d9851aaeb9ff510148935043ab446bea52e3dc26)) +- remove go vet from lint-staged ([3869cbf](https://github.com/bastean/codexgo/commit/3869cbf84fb83bc105b16be0fb6f1a03ab830e9f)) + +## [1.1.0](https://github.com/bastean/codexgo/compare/v1.0.0...v1.1.0) (2024-01-22) + +### Features + +- **actions:** add brew setup ([ef7a00d](https://github.com/bastean/codexgo/commit/ef7a00de57e7cf524223f6e4ced5f7bf2ad71e55)) +- add go vet on lint-staged ([8c52de4](https://github.com/bastean/codexgo/commit/8c52de4ace6d34c2174fe8f03c35e84b6a4040a5)) +- add upx to compress binaries ([9d4e926](https://github.com/bastean/codexgo/commit/9d4e926a3b764f6fe2e49009fb69adc127acb7ea)) +- **devcontainer:** add brew to simplify installation of tools ([8c77ed4](https://github.com/bastean/codexgo/commit/8c77ed45692b6303fcb6235b4ddb612d4e175505)) +- **makefile:** add go mod tidy on lint rule ([d203639](https://github.com/bastean/codexgo/commit/d203639765560e1e375b77b9759bed581c2176ab)) + +### Bug Fixes + +- **docker:** add optimization to compose ([0730183](https://github.com/bastean/codexgo/commit/0730183bfbc522f0c5278a733e63b346fbe41044)) + +## [1.0.0](https://github.com/bastean/codexgo/compare/v0.1.1...v1.0.0) (2024-01-17) + +### ⚠ BREAKING CHANGES + +- **readme:** Ready for v1 + +### Features + +- add codexgo logos ([7ff0641](https://github.com/bastean/codexgo/commit/7ff0641a5db2df5f180242e3d05d93c1ba0cfc92)) +- add trufflehog scan on lint-staged ([bdc473c](https://github.com/bastean/codexgo/commit/bdc473c56a446e0268c1ed02222af2a37185c244)) +- **ci:** add tests job to workflow ([c033f54](https://github.com/bastean/codexgo/commit/c033f5429ddbe07f55281a921b706e6820537ffa)) +- **devcontainer:** add cucumber extension ([fabb6d8](https://github.com/bastean/codexgo/commit/fabb6d8e990b87a71f0152cdeb43b6c28f3cd878)) +- **docker:** add production compose ([4963296](https://github.com/bastean/codexgo/commit/49632964e8a238fd676204cd4eb0bff03a959ac7)) + +### Bug Fixes + +- **backend:** add responsive to alerts ([fc1e4c8](https://github.com/bastean/codexgo/commit/fc1e4c80ba071edc7bfaf39a43bae4aaad8f5b1d)) + +### Documentation + +- **readme:** add contributing section ([54e95f6](https://github.com/bastean/codexgo/commit/54e95f65a5deddd73e1021ad520c848a75ca29cc)) + +## [0.1.1](https://github.com/bastean/codexgo/compare/v0.1.0...v0.1.1) (2024-01-07) + +## 0.1.0 (2024-01-07) + +### Features + +- **backend:** add basis to use htmx with tailwindcss ([5f260b5](https://github.com/bastean/codexgo/commit/5f260b5a594c0eaa50324d04f715f614145f7adc)) +- **backend:** add crud endpoints ([08957ba](https://github.com/bastean/codexgo/commit/08957ba38446d9c3d52e75d225f5b77c1541c7f3)) +- **backend:** add development dockerfile ([a8cef51](https://github.com/bastean/codexgo/commit/a8cef51c8f158fac22c71a567441b3efb49abfc8)) +- **backend:** add pwa ([a370906](https://github.com/bastean/codexgo/commit/a3709064ba027b9c2e60cd157de55c95e41802a3)) +- **context|backend:** add authentication to protected endpoints ([b582c11](https://github.com/bastean/codexgo/commit/b582c112f11e9a206fd037a2ecd7ea2bafa252ce)) +- **context|backend:** add password hashing ([8264127](https://github.com/bastean/codexgo/commit/82641276144048800e1a99ac0806f3a1402f98a7)) +- **context:** add basis to run use cases ([fa28f1f](https://github.com/bastean/codexgo/commit/fa28f1f87471e6c84dccdcebd35fc198bb46b96d)) +- **context:** add crud use cases ([d503539](https://github.com/bastean/codexgo/commit/d5035397c7485e2826e4ed4cf594db2f32ef7145)) +- **context:** add mongo repository adapter ([f25a793](https://github.com/bastean/codexgo/commit/f25a7931fab225edebc6e03a4f6f0a124a8ab05d)) +- **devcontainer:** add prettier extension ([d833c1b](https://github.com/bastean/codexgo/commit/d833c1b62defdc6407534662358c89396948e7dc)) + +### Bug Fixes + +- **ci:** upgrade actions ([3054b85](https://github.com/bastean/codexgo/commit/3054b85e405293668d0e2647b584e7cb0f815710)) +- **release:** change manifest path ([05918f0](https://github.com/bastean/codexgo/commit/05918f0961fed086665c3e8572efcee5cdf9a025)) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3c8a03b --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) Bastean + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d09e669 --- /dev/null +++ b/Makefile @@ -0,0 +1,265 @@ +.PHONY: * + +#*------------VARS------------ + +#*______URL______ + +github = https://github.com/bastean/codexgo + +#*______Go______ + +go-tidy = go mod tidy -e + +#*______Node______ + +npx = npx --no -- +npm-ci = npm ci --legacy-peer-deps + +release-it = ${npx} release-it -V +release-it-dry = ${npx} release-it -V -d --no-git.requireCleanWorkingDir + +#*______Bash______ + +bash = bash -o pipefail -c + +#*______Git______ + +git-reset-hard = git reset --hard HEAD + +#*______Docker______ + +compose = cd deployments/ && docker compose +compose-env = ${compose} --env-file + +#*------------RULES------------ + +#*______Upgrades______ + +upgrade-managers: + #? sudo apt update && sudo apt upgrade -y + npm upgrade -g + +upgrade-go: + go get -t -u ./... + +upgrade-node: + ${npx} ncu --root -ws -u + rm -f package-lock.json + npm i --legacy-peer-deps + +upgrade-reset: + ${git-reset-hard} + ${npm-ci} + +upgrade: + go run ./scripts/upgrade + +#*______Dependencies______ + +install-tools: + curl -sSfL https://raw.githubusercontent.com/trufflesecurity/trufflehog/main/scripts/install.sh | sudo sh -s -- -b /usr/local/bin v3.63.11 + curl -sSfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sudo sh -s -- -b /usr/local/bin v0.52.2 + go install github.com/google/osv-scanner/cmd/osv-scanner@latest + go install honnef.co/go/tools/cmd/staticcheck@latest + go install github.com/a-h/templ/cmd/templ@latest + +install-deps: + go mod download + ${npm-ci} + +copy-deps: + go run ./scripts/copydeps + +#*______Generators______ + +generate-required: + go generate ./... + templ generate + +#*______Initializations______ + +init: upgrade-managers install-tools install-deps copy-deps generate-required + +init-zero: + git init + $(MAKE) init + ${npx} husky install + +#*______Linters/Formatters______ + +lint: generate-required + go mod tidy + gofmt -l -s -w . + ${npx} prettier --ignore-unknown --write . + templ fmt . + +lint-check: + staticcheck ./... + ${npx} prettier --check . + +#*______Scanners______ + +leak-check: + sudo trufflehog git file://. --only-verified + trivy repo --scanners secret . + +leak-remote-check: + sudo trufflehog git ${github} --only-verified + trivy repo --scanners secret ${github} + +vuln-check: + osv-scanner --call-analysis=all -r . + trivy repo --scanners vuln . + +misconfig-check: + trivy repo --scanners misconfig . + +scan-leaks: leak-check leak-remote-check + +scan-vulns: vuln-check + +scan-misconfigs: misconfig-check + +scans: scan-leaks scan-vulns scan-misconfigs + +#*______Tests______ + +test-sut: + air + +test-clean: generate-required + go clean -testcache + cd test/ && mkdir -p report + +test-codegen: + ${npx} playwright codegen http://localhost:8080 + +test-sync: upgrade-go + ${npx} concurrently -s first -k --names 'SUT,TEST' '$(MAKE) test-sut' '${npx} wait-on -l http-get://localhost:8080 && $(TEST_SYNC)' + +test-unit: test-clean + ${bash} 'go test -v -cover ./pkg/context/... -run TestUnit.* |& tee test/report/unit.report.log' + +test-integration: test-clean + ${bash} 'go test -v -cover ./pkg/context/... -run TestIntegration.* |& tee test/report/integration.report.log' + +test-acceptance-sync: + ${bash} 'TEST_URL="http://localhost:8080" go test -v -cover ./pkg/cmd/... -run TestAcceptance.* |& tee test/report/acceptance.report.log' + +test-acceptance: test-clean + TEST_SYNC="$(MAKE) test-acceptance-sync" $(MAKE) test-sync + +tests-sync: + ${bash} 'TEST_URL="http://localhost:8080" go test -v -cover ./... |& tee test/report/report.log' + +tests: test-clean + TEST_SYNC="$(MAKE) tests-sync" $(MAKE) test-sync + +#*______Releases______ + +release: + ${release-it} + +release-alpha: + ${release-it} --preRelease=alpha + +release-beta: + ${release-it} --preRelease=beta + +release-ci: + ${release-it} --ci $(OPTIONS) + +release-dry: + ${release-it-dry} + +release-dry-version: + ${release-it-dry} --release-version + +release-dry-changelog: + ${release-it-dry} --changelog + +#*______Builds______ + +build: generate-required lint + rm -rf build/ + go build -ldflags="-s -w" -o build/codexgo ./cmd/codexgo + +#*______ENVs______ + +sync-env-reset: + ${git-reset-hard} + +sync-env: + cd deployments && go run ../scripts/syncenv + +#*______Git______ + +commit: + ${npx} cz + +WARNING-git-forget: + git rm -r --cached . + git add . + +WARNING-git-genesis: + git clean -e .env*-fdx + ${git-reset-hard} + $(MAKE) init + +#*______Docker______ + +docker-usage: + docker system df + +docker-it: + docker exec -it $(ID) bash + +compose-dev-down: + ${compose-env} .env.dev down + docker volume rm codexgo-database-dev -f + +compose-dev: compose-dev-down + ${compose-env} .env.dev up + +compose-test-down: + ${compose-env} .env.test down + docker volume rm codexgo-database-test -f + +compose-test-integration: compose-test-down + ${compose-env} .env.test --env-file .env.demo.test.integration up --exit-code-from server + +compose-test-acceptance: compose-test-down + ${compose-env} .env.test --env-file .env.demo.test.acceptance up --exit-code-from server + +compose-tests: compose-test-down + ${compose-env} .env.test up --exit-code-from server + +compose-prod-down: + ${compose-env} .env.prod down + +compose-prod: compose-prod-down + ${compose-env} .env.prod up + +demo-down: + ${compose-env} .env.demo down + +demo: demo-down + ${compose-env} .env.demo up + +compose-down: compose-dev-down compose-test-down compose-prod-down demo-down + +WARNING-docker-prune-soft: + docker system prune + $(MAKE) compose-down + $(MAKE) docker-usage + +WARNING-docker-prune-hard: + docker system prune --volumes -a + $(MAKE) compose-down + $(MAKE) docker-usage + +#*______Fixes______ + +fix-local-playwright: + go get -u github.com/playwright-community/playwright-go + go run github.com/playwright-community/playwright-go/cmd/playwright@latest install chromium --with-deps diff --git a/README.md b/README.md new file mode 100644 index 0000000..75f5577 --- /dev/null +++ b/README.md @@ -0,0 +1,404 @@ +

+ + + +[![logo readme](assets/readme/logo.png)](https://github.com/bastean/codexgo) + +

+ +
+ +> Example CRUD project applying Hexagonal Architecture, Domain-Driven Design (DDD), Event-Driven Architecture (EDA), Command Query Responsibility Segregation (CQRS), Behavior-Driven Development (BDD), Continuous Integration (CI), and more... in Go. + +
+ +
+ +
+ +[![license MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) +[![go report card](https://goreportcard.com/badge/github.com/bastean/codexgo)](https://goreportcard.com/report/github.com/bastean/codexgo) +[![commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](https://github.com/commitizen/cz-cli) +[![release it](https://img.shields.io/badge/%F0%9F%93%A6%F0%9F%9A%80-release--it-orange.svg)](https://github.com/release-it/release-it) + +
+ +
+ +[![upgrade workflow](https://github.com/bastean/codexgo/actions/workflows/upgrade.yml/badge.svg)](https://github.com/bastean/codexgo/actions/workflows/upgrade.yml) +[![ci workflow](https://github.com/bastean/codexgo/actions/workflows/ci.yml/badge.svg)](https://github.com/bastean/codexgo/actions/workflows/ci.yml) +[![release workflow](https://github.com/bastean/codexgo/actions/workflows/release.yml/badge.svg)](https://github.com/bastean/codexgo/actions/workflows/release.yml) + +
+ +
+ +[![go reference](https://pkg.go.dev/badge/github.com/bastean/codexgo.svg)](https://pkg.go.dev/github.com/bastean/codexgo) +[![github release](https://img.shields.io/github/v/release/bastean/codexgo.svg)](https://github.com/bastean/codexgo/releases) + +
+ +## Showcase + +
+ + + + + + + + + + + +
+ +## Usage (Demo) + +> [!NOTE] +> +> - [System Requirements](#locally) +> - In the Demo version, the link to confirm the account is sent through the Terminal. +> - _"Hi \, please confirm your account through this link: \"_ +> - You can define your own **SMTP** configuration in the [.env.demo](deployments/.env.demo) file by simply modifying the **SERVER_SMTP\_\*** variables, then you will receive the links by mail. + +```bash +make demo +``` + +## Features + +### Project Layout + +- Based on [Standard Go Project Layout](https://github.com/golang-standards/project-layout). + +### Git + +- Hooks managed by [husky](https://github.com/typicode/husky): + - Pre-Push: + - Scanning Repository for leaks using [TruffleHog CLI](https://github.com/trufflesecurity/trufflehog) and [Trivy](https://github.com/aquasecurity/trivy) + - Pre-Commit: [lint-staged](https://github.com/lint-staged/lint-staged) + - Scanning files for leaks using [TruffleHog CLI](https://github.com/trufflesecurity/trufflehog?tab=readme-ov-file#8-scan-individual-files-or-directories) + - Formatting + - Commit-Msg: [commitlint](https://github.com/conventional-changelog/commitlint) + - Check [Conventional Commits](https://www.conventionalcommits.org) rules +- Commit message helper using [Commitizen](https://github.com/commitizen/cz-cli). + - Interactive prompt that allows you to write commits following the [Conventional Commits](https://www.conventionalcommits.org) rules: + ```bash + make commit + ``` + +### Linting/Formatting Tools + +- Go: **staticcheck** and **gofmt**. +- templ: **templ fmt**. +- Gherkin: **Cucumber extension**. +- Others: **Prettier cli/extension**. + +### Scanners + +- [TruffleHog CLI](https://github.com/trufflesecurity/trufflehog): Secrets. +- [Trivy](https://github.com/aquasecurity/trivy): Secrets, Vulnerabilities and Misconfigurations. +- [OSV-Scanner](https://github.com/google/osv-scanner): Vulnerabilities. + +### Testing Packages + +- Random data generator: [Gofakeit](https://github.com/brianvoe/gofakeit). +- Unit/Integration: [Testify](https://github.com/stretchr/testify). +- Acceptance: [Testify](https://github.com/stretchr/testify), [Godog (Cucumber)](https://github.com/cucumber/godog) and [Playwright](https://github.com/playwright-community/playwright-go). + +### Releases + +- Automatically managed by [Release It!](https://github.com/release-it/release-it): + - Before/After Hooks for: + - Linting + - Testing + - Bump version based on [Conventional Commits](https://www.conventionalcommits.org) and [SemVer](https://semver.org/): + - CHANGELOG generator + - Commits and Tags generator + - GitHub Releases + +### GitHub + +- Actions for: + - Setup Languages and Dependencies +- Workflows running: + - Automatically (Triggered by **Push** or **Pull requests**): + - Secrets Scanning ([TruffleHog Action](https://github.com/trufflesecurity/trufflehog?tab=readme-ov-file#octocat-trufflehog-github-action)) + - Linting + - Testing + - Manually (Using the **Actions tab** on GitHub): + - Upgrade Dependencies + - Automate Release +- Issue Templates **(Defaults)**. + +### Devcontainer + +- Multiple Features already pre-configured: + - Go + - Node + - Docker in Docker +- Extensions and their respective settings to work with: + - Go + - templ + - Cucumber + - Gherkin + - Prettier + - Better Comments + - Todo Tree + - cSpell + +### Docker + +- Dockerfile + - **Multi-stage builds**: + - Development + - Testing + - Build + - Production +- Compose + - Switched by ENVs. + +### Message Broker + +- Routing Key based on [AsyncAPI Topic Definition](https://github.com/fmvilas/topic-definition). + +### Security + +- Form validation at the client using [Fomantic - Form Validation](https://fomantic-ui.com/behaviors/form.html). + - On the server, the validations are performed using the **Value Objects** defined in the **Context**. +- Data **authentication** via **JWT** managed by **Session Cookies**. +- Account confirmation via **Mail** or **Terminal**. +- Password hashing using [Bcrypt](https://pkg.go.dev/golang.org/x/crypto/bcrypt). +- Requests **Rate Limiting**. +- Server log files. + +### Scripts + +- [syncenv](scripts/syncenv/syncenv.go) + - Synchronize all **.env\*** files in the directory using an **.env** model. +- [copydeps](scripts/copydeps/copydeps.go) + - Copies the files required by the browser dependencies from the **node_modules** folder and places them inside the **static** folder on the server. +- [upgrade](scripts/upgrade/upgrade.go) + - Perform the following steps to upgrade the project: + 1. Upgrade Go and Node dependencies. + 2. Linting and Testing. + 3. Commit changes. +- [run](deployments/run.sh) + - Display the logs and redirect them to a file whose name depends on the time at which the service was run. + - Used in Production Image. + +## Basic Workflow (Domain > (Infrastructure | Application) > Presentation) + +### Context (Domain, Infrastructure & Application) > (Modules) + +- Domain + - Value Objects + - Mother Creators + - Unit Tests + - Messages (Event/Command) + - Mother Creators + - Aggregates + - Aggregate Root + - Mother Creators + - Models (Ports) + - Repository + - Broker +- Infrastructure + - Persistence + - Repository Mocks + - Adapters + - Integration Tests + - Communication + - Broker Mocks + - Adapters + - Integration Tests +- Application + - Commands + - Mother Creators + - Querys/Responses + - Mother Creators + - Handlers/Consumers + - Inputs & Outputs + - Uses Cases + - Unit Tests + +### App (Presentation) > (Server) + +- Presentation + - Services (Modules) + - Templates + - Handlers + - Routes + - Features (Gherkin) + - Acceptance Tests + +## First Steps + +### Clone + +#### HTTPS + +```bash +git clone https://github.com/bastean/codexgo.git && cd codexgo +``` + +#### SSH + +```bash +git clone git@github.com:bastean/codexgo.git && cd codexgo +``` + +### Initialize + +#### Dev Container (recommended) + +1. System Requirements + + - [Docker](https://docs.docker.com/get-docker) + + - [Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) + +2. Start VS Code + + ```bash + code . + ``` + +3. Open Command Palette + + - Ctrl+Shift+P + +4. Run + + ```txt + Dev Containers: Reopen in Container + ``` + +#### Locally + +1. System Requirements + + - [Go](https://go.dev/doc/install) + - [Node](https://nodejs.org/en/download) + - [Make](https://www.gnu.org/software/make) + - [Docker](https://docs.docker.com/get-docker) + +2. Run + + ```bash + make init + ``` + +#### ZIP + +1. [System Requirements](#locally) + +2. Run + + ```bash + make init-zero + ``` + +### GitHub Repository + +#### Settings + +##### Actions + +- General + + - Workflow permissions + + - [x] Read and write permissions + +##### Secrets and variables + +- Actions + + - New repository secret + + - BOT_GPG_PRIVATE_KEY + + ```bash + gpg --armor --export-secret-key [Pub_Key_ID (*-BOT)] + ``` + + - BOT_GPG_PASSPHRASE + +### Run + +#### ENVs + +> [!IMPORTANT] +> Before running it, you must set the following environment variables and rename the file to **.env.(dev|test|prod)**. +> +> - [.env.example](deployments/.env.example) + +> [!TIP] +> You can check the demo file to see which values you can use. +> +> - [.env.example.demo](deployments/.env.example.demo) + +#### Development + +```bash +make compose-dev +``` + +#### Tests + +##### Unit + +```bash +make test-unit +``` + +##### Integration + +```bash +make compose-test-integration +``` + +##### Acceptance + +```bash +make compose-test-acceptance +``` + +##### Unit/Integration/Acceptance + +```bash +make compose-tests +``` + +#### Production + +```bash +make compose-prod +``` + +## Tech Stack + +#### Base + +- [Go](https://go.dev) +- [templ](https://templ.guide) + - [Fomantic-UI](https://fomantic-ui.com) +- [RabbitMQ](https://www.rabbitmq.com/tutorials/tutorial-one-go) +- [MongoDB](https://www.mongodb.com/docs/drivers/go) + +#### Please see + +- [go.mod](go.mod) +- [package.json](package.json) + +## Contributing + +- Contributions and Feedback are always welcome! + - [Open a new issue](https://github.com/bastean/codexgo/issues/new/choose) + +## License + +- [MIT](LICENSE) diff --git a/assets/readme/desktop-dashboard.png b/assets/readme/desktop-dashboard.png new file mode 100644 index 0000000..d95966c Binary files /dev/null and b/assets/readme/desktop-dashboard.png differ diff --git a/assets/readme/desktop-home.png b/assets/readme/desktop-home.png new file mode 100644 index 0000000..4862636 Binary files /dev/null and b/assets/readme/desktop-home.png differ diff --git a/assets/readme/logo.png b/assets/readme/logo.png new file mode 100644 index 0000000..52ba8b9 Binary files /dev/null and b/assets/readme/logo.png differ diff --git a/assets/readme/mail-confirm-account.png b/assets/readme/mail-confirm-account.png new file mode 100644 index 0000000..f50ab4a Binary files /dev/null and b/assets/readme/mail-confirm-account.png differ diff --git a/assets/readme/mobile-dashboard.png b/assets/readme/mobile-dashboard.png new file mode 100644 index 0000000..7cf862c Binary files /dev/null and b/assets/readme/mobile-dashboard.png differ diff --git a/assets/readme/mobile-home.png b/assets/readme/mobile-home.png new file mode 100644 index 0000000..0992c3b Binary files /dev/null and b/assets/readme/mobile-home.png differ diff --git a/assets/social-preview/social-preview.png b/assets/social-preview/social-preview.png new file mode 100644 index 0000000..0d5f38d Binary files /dev/null and b/assets/social-preview/social-preview.png differ diff --git a/cmd/codexgo/codex.go b/cmd/codexgo/codex.go new file mode 100644 index 0000000..c1a3586 --- /dev/null +++ b/cmd/codexgo/codex.go @@ -0,0 +1,29 @@ +package main + +import ( + "flag" + "fmt" + "os" + + "github.com/bastean/codexgo/pkg/cmd/server" +) + +const cli = "codexgo" + +var port string + +func usage() { + fmt.Printf("Usage: %s [OPTIONS]\n", cli) + fmt.Printf("\nE.g.: %s -p 8080\n\n", cli) + flag.PrintDefaults() +} + +func main() { + flag.StringVar(&port, "p", os.Getenv("PORT"), "Port") + + flag.Usage = usage + + flag.Parse() + + server.Run(port) +} diff --git a/deployments/.env.demo b/deployments/.env.demo new file mode 100644 index 0000000..81142fa --- /dev/null +++ b/deployments/.env.demo @@ -0,0 +1,33 @@ +RABBITMQ_CONTAINER_NAME=codexgo-rabbitmq-demo +RABBITMQ_DEFAULT_USER=codexgo-demo +RABBITMQ_DEFAULT_PASS=codexgo-demo +RABBITMQ_AMQP_PORT=5672 +RABBITMQ_ADMIN_PORT=15672 +RABBITMQ_RESTART=on-failure + +MONGO_CONTAINER_NAME=codexgo-database-demo +MONGO_INITDB_ROOT_USERNAME=codexgo-demo +MONGO_INITDB_ROOT_PASSWORD=codexgo-demo +MONGO_INITDB_PORT=27017 +MONGO_RESTART=on-failure + +SERVER_CONTAINER_NAME=codexgo-server-demo +SERVER_IMAGE_TAG=codexgo-server-demo +SERVER_BUILD_TARGET=prod +SERVER_SMTP_HOST= +SERVER_SMTP_PORT= +SERVER_SMTP_USERNAME= +SERVER_SMTP_PASSWORD= +SERVER_JWT_SECRET_KEY=codexgo-demo +SERVER_COOKIE_SECRET_KEY=codexgo-demo +SERVER_COOKIE_SESSION_NAME=codexgo +SERVER_ALLOWED_HOSTS=localhost:8080 +SERVER_URL=http://localhost:8080 +SERVER_MODE=release +SERVER_PORT=8080 +SERVER_PROXY_PORT=8080 +SERVER_COMMAND=./run +SERVER_VOLUMES_APP=codexgo-server:/app/logs +SERVER_RESTART=on-failure + +DATABASE_VOLUME=codexgo-database-demo diff --git a/deployments/.env.demo.test.acceptance b/deployments/.env.demo.test.acceptance new file mode 100644 index 0000000..86dc92b --- /dev/null +++ b/deployments/.env.demo.test.acceptance @@ -0,0 +1 @@ +SERVER_COMMAND="make test-acceptance" diff --git a/deployments/.env.demo.test.integration b/deployments/.env.demo.test.integration new file mode 100644 index 0000000..ea2c348 --- /dev/null +++ b/deployments/.env.demo.test.integration @@ -0,0 +1 @@ +SERVER_COMMAND="make test-integration" diff --git a/deployments/.env.example b/deployments/.env.example new file mode 100644 index 0000000..98a5573 --- /dev/null +++ b/deployments/.env.example @@ -0,0 +1,33 @@ +RABBITMQ_CONTAINER_NAME= +RABBITMQ_DEFAULT_USER= +RABBITMQ_DEFAULT_PASS= +RABBITMQ_AMQP_PORT= +RABBITMQ_ADMIN_PORT= +RABBITMQ_RESTART= + +MONGO_CONTAINER_NAME= +MONGO_INITDB_ROOT_USERNAME= +MONGO_INITDB_ROOT_PASSWORD= +MONGO_INITDB_PORT= +MONGO_RESTART= + +SERVER_CONTAINER_NAME= +SERVER_IMAGE_TAG= +SERVER_BUILD_TARGET= +SERVER_SMTP_HOST= +SERVER_SMTP_PORT= +SERVER_SMTP_USERNAME= +SERVER_SMTP_PASSWORD= +SERVER_JWT_SECRET_KEY= +SERVER_COOKIE_SECRET_KEY= +SERVER_COOKIE_SESSION_NAME= +SERVER_ALLOWED_HOSTS= +SERVER_URL= +SERVER_MODE= +SERVER_PORT= +SERVER_PROXY_PORT= +SERVER_COMMAND= +SERVER_VOLUMES_APP= +SERVER_RESTART= + +DATABASE_VOLUME= diff --git a/deployments/.env.example.demo b/deployments/.env.example.demo new file mode 100644 index 0000000..21d75cf --- /dev/null +++ b/deployments/.env.example.demo @@ -0,0 +1,33 @@ +RABBITMQ_CONTAINER_NAME=codexgo-rabbitmq|-dev|-test|-prod +RABBITMQ_DEFAULT_USER=example|-dev|-test|-prod +RABBITMQ_DEFAULT_PASS=example|-dev|-test|-prod +RABBITMQ_AMQP_PORT=5672 +RABBITMQ_ADMIN_PORT=15672 +RABBITMQ_RESTART=on-failure|always + +MONGO_CONTAINER_NAME=codexgo-database|-dev|-test|-prod +MONGO_INITDB_ROOT_USERNAME=example|-dev|-test|-prod +MONGO_INITDB_ROOT_PASSWORD=example|-dev|-test|-prod +MONGO_INITDB_PORT=27017 +MONGO_RESTART=on-failure|always + +SERVER_CONTAINER_NAME=codexgo-server|-dev|-test|-prod +SERVER_IMAGE_TAG=codexgo-server|-dev|-test|-prod +SERVER_BUILD_TARGET=dev|test|prod +SERVER_SMTP_HOST=smtp.example.com +SERVER_SMTP_PORT=25|465|587|2525 +SERVER_SMTP_USERNAME=example|-dev|-test|-prod +SERVER_SMTP_PASSWORD=example|-dev|-test|-prod +SERVER_JWT_SECRET_KEY=example|-dev|-test|-prod +SERVER_COOKIE_SECRET_KEY=example|-dev|-test|-prod +SERVER_COOKIE_SESSION_NAME=example|-dev|-test|-prod +SERVER_ALLOWED_HOSTS=localhost:8080 +SERVER_URL=http://localhost:8080 +SERVER_MODE=debug|test|release +SERVER_PORT=8080 +SERVER_PROXY_PORT=8090|8080 +SERVER_COMMAND=air|'make tests'|./codexgo|./run +SERVER_VOLUMES_APP=..:/app|codexgo-server:/app/logs +SERVER_RESTART=on-failure|always + +DATABASE_VOLUME=codexgo-database|-dev|-test|-prod diff --git a/deployments/Dockerfile b/deployments/Dockerfile new file mode 100644 index 0000000..9a24fa3 --- /dev/null +++ b/deployments/Dockerfile @@ -0,0 +1,39 @@ +FROM golang:bookworm AS dev + +WORKDIR /app + +RUN apt update && apt upgrade -y + +RUN go install github.com/air-verse/air@latest + +RUN go install github.com/a-h/templ/cmd/templ@latest + +RUN apt install -y nodejs npm + +FROM dev AS test + +WORKDIR /app + +RUN go run github.com/playwright-community/playwright-go/cmd/playwright@latest install chromium --with-deps + +RUN npm i -g concurrently wait-on + +FROM dev AS build + +WORKDIR /app + +COPY . . + +RUN npm i -g prettier + +RUN make build + +FROM golang:bookworm AS prod + +WORKDIR /app + +COPY --from=build app/deployments/run.sh run + +RUN chmod +x run + +COPY --from=build app/build/codexgo . diff --git a/deployments/docker-compose.yml b/deployments/docker-compose.yml new file mode 100644 index 0000000..8e2226d --- /dev/null +++ b/deployments/docker-compose.yml @@ -0,0 +1,77 @@ +services: + broker: + container_name: ${RABBITMQ_CONTAINER_NAME} + image: rabbitmq:3-management + environment: + RABBITMQ_DEFAULT_USER: ${RABBITMQ_DEFAULT_USER} + RABBITMQ_DEFAULT_PASS: ${RABBITMQ_DEFAULT_PASS} + ports: + - ${RABBITMQ_AMQP_PORT}:${RABBITMQ_AMQP_PORT} + - ${RABBITMQ_ADMIN_PORT}:${RABBITMQ_ADMIN_PORT} + restart: ${RABBITMQ_RESTART} + healthcheck: + test: rabbitmq-diagnostics -q status + interval: 12s + timeout: 12s + retries: 12 + + database: + container_name: ${MONGO_CONTAINER_NAME} + image: mongo:4.4 + environment: + MONGO_INITDB_ROOT_USERNAME: ${MONGO_INITDB_ROOT_USERNAME} + MONGO_INITDB_ROOT_PASSWORD: ${MONGO_INITDB_ROOT_PASSWORD} + command: mongod --quiet --logpath /dev/null + ports: + - ${MONGO_INITDB_PORT}:${MONGO_INITDB_PORT} + volumes: + - codexgo-database:/data/db + restart: ${MONGO_RESTART} + healthcheck: + test: echo 'db.runCommand({serverStatus:1}).ok' | mongo admin -u ${MONGO_INITDB_ROOT_USERNAME} -p ${MONGO_INITDB_ROOT_PASSWORD} --quiet | grep 1 + interval: 12s + timeout: 12s + retries: 12 + + server: + container_name: ${SERVER_CONTAINER_NAME} + image: ${SERVER_IMAGE_TAG} + build: + context: .. + dockerfile: deployments/Dockerfile + target: ${SERVER_BUILD_TARGET} + environment: + BROKER_URI: "amqp://${RABBITMQ_DEFAULT_USER}:${RABBITMQ_DEFAULT_PASS}@broker:${RABBITMQ_AMQP_PORT}" + DATABASE_URI: "mongodb://${MONGO_INITDB_ROOT_USERNAME}:${MONGO_INITDB_ROOT_PASSWORD}@database:${MONGO_INITDB_PORT}" + SMTP_HOST: ${SERVER_SMTP_HOST} + SMTP_PORT: ${SERVER_SMTP_PORT} + SMTP_USERNAME: ${SERVER_SMTP_USERNAME} + SMTP_PASSWORD: ${SERVER_SMTP_PASSWORD} + JWT_SECRET_KEY: ${SERVER_JWT_SECRET_KEY} + COOKIE_SECRET_KEY: ${SERVER_COOKIE_SECRET_KEY} + COOKIE_SESSION_NAME: ${SERVER_COOKIE_SESSION_NAME} + ALLOWED_HOSTS: ${SERVER_ALLOWED_HOSTS} + URL: ${SERVER_URL} + GIN_MODE: ${SERVER_MODE} + PORT: ${SERVER_PORT} + command: ${SERVER_COMMAND} + ports: + - ${SERVER_PORT}:${SERVER_PORT} + - ${SERVER_PROXY_PORT}:${SERVER_PROXY_PORT} + volumes: + - ${SERVER_VOLUMES_APP} + - codexgo-modules:/go/pkg/mod + restart: ${SERVER_RESTART} + depends_on: + broker: + condition: service_healthy + database: + condition: service_healthy + +volumes: + codexgo-database: + name: ${DATABASE_VOLUME} + codexgo-server: + name: codexgo-server + codexgo-modules: + name: codexgo-modules diff --git a/deployments/run.sh b/deployments/run.sh new file mode 100644 index 0000000..a12cfe0 --- /dev/null +++ b/deployments/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +logs=logs + +today=$(date -u +%d-%m-%Y) + +now=$(date -u +%H_%M_%S) + +log=$logs/$today/$now.log + +./codexgo |& tee $log diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..8af0451 --- /dev/null +++ b/go.mod @@ -0,0 +1,78 @@ +module github.com/bastean/codexgo + +go 1.22 + +require ( + github.com/JGLTechnologies/gin-rate-limit v1.5.4 + github.com/a-h/templ v0.2.707 + github.com/brianvoe/gofakeit/v7 v7.0.4 + github.com/cucumber/godog v0.14.1 + github.com/gin-contrib/secure v1.1.0 + github.com/gin-contrib/sessions v1.0.1 + github.com/gin-gonic/gin v1.10.0 + github.com/go-playground/validator/v10 v10.22.0 + github.com/golang-jwt/jwt/v5 v5.2.1 + github.com/google/uuid v1.6.0 + github.com/playwright-community/playwright-go v0.4401.1 + github.com/rabbitmq/amqp091-go v1.10.0 + github.com/stretchr/testify v1.9.0 + go.mongodb.org/mongo-driver v1.15.1 + golang.org/x/crypto v0.24.0 + golang.org/x/text v0.16.0 +) + +require ( + github.com/bytedance/sonic v1.11.9 // indirect + github.com/bytedance/sonic/loader v0.1.1 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/cloudwego/base64x v0.1.4 // indirect + github.com/cloudwego/iasm v0.2.0 // indirect + github.com/cucumber/gherkin/go/v26 v26.2.0 // indirect + github.com/cucumber/messages/go/v21 v21.0.1 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/deckarep/golang-set/v2 v2.6.0 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/gabriel-vasile/mimetype v1.4.4 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-jose/go-jose/v3 v3.0.3 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-stack/stack v1.8.1 // indirect + github.com/goccy/go-json v0.10.3 // indirect + github.com/gofrs/uuid v4.4.0+incompatible // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/gorilla/context v1.1.2 // indirect + github.com/gorilla/securecookie v1.1.2 // indirect + github.com/gorilla/sessions v1.3.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-memdb v1.3.4 // indirect + github.com/hashicorp/golang-lru v1.0.2 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.17.9 // indirect + github.com/klauspost/cpuid/v2 v2.2.8 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/montanaflynn/stats v0.7.1 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/redis/go-redis/v9 v9.5.3 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/stretchr/objx v0.5.2 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect + github.com/xdg-go/pbkdf2 v1.0.0 // indirect + github.com/xdg-go/scram v1.1.2 // indirect + github.com/xdg-go/stringprep v1.0.4 // indirect + github.com/youmark/pkcs8 v0.0.0-20240424034433-3c2c7870ae76 // indirect + go.uber.org/multierr v1.11.0 // indirect + golang.org/x/arch v0.8.0 // indirect + golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect + golang.org/x/net v0.26.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.21.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..2eb7db7 --- /dev/null +++ b/go.sum @@ -0,0 +1,236 @@ +github.com/JGLTechnologies/gin-rate-limit v1.5.4 h1:1hIaXIdGM9MZFZlXgjWJLpxaK0WHEa5MeloK49nmQsc= +github.com/JGLTechnologies/gin-rate-limit v1.5.4/go.mod h1:mGEhNzlHEg/Tk+KH/mKylZLTfDjACnx7MVYaAlj07eU= +github.com/a-h/templ v0.2.707 h1:T1Gkd2ugbRglZ9rYw/VBchWOSZVKmetDbBkm4YubM7U= +github.com/a-h/templ v0.2.707/go.mod h1:5cqsugkq9IerRNucNsI4DEamdHPsoGMQy99DzydLhM8= +github.com/brianvoe/gofakeit/v7 v7.0.4 h1:Mkxwz9jYg8Ad8NvT9HA27pCMZGFQo08MK6jD0QTKEww= +github.com/brianvoe/gofakeit/v7 v7.0.4/go.mod h1:QXuPeBw164PJCzCUZVmgpgHJ3Llj49jSLVkKPMtxtxA= +github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= +github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= +github.com/bytedance/sonic v1.11.9 h1:LFHENlIY/SLzDWverzdOvgMztTxcfcF+cqNsz9pK5zg= +github.com/bytedance/sonic v1.11.9/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= +github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= +github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cucumber/gherkin/go/v26 v26.2.0 h1:EgIjePLWiPeslwIWmNQ3XHcypPsWAHoMCz/YEBKP4GI= +github.com/cucumber/gherkin/go/v26 v26.2.0/go.mod h1:t2GAPnB8maCT4lkHL99BDCVNzCh1d7dBhCLt150Nr/0= +github.com/cucumber/godog v0.14.1 h1:HGZhcOyyfaKclHjJ+r/q93iaTJZLKYW6Tv3HkmUE6+M= +github.com/cucumber/godog v0.14.1/go.mod h1:FX3rzIDybWABU4kuIXLZ/qtqEe1Ac5RdXmqvACJOces= +github.com/cucumber/messages/go/v21 v21.0.1 h1:wzA0LxwjlWQYZd32VTlAVDTkW6inOFmSM+RuOwHZiMI= +github.com/cucumber/messages/go/v21 v21.0.1/go.mod h1:zheH/2HS9JLVFukdrsPWoPdmUtmYQAQPLk7w5vWsk5s= +github.com/cucumber/messages/go/v22 v22.0.0/go.mod h1:aZipXTKc0JnjCsXrJnuZpWhtay93k7Rn3Dee7iyPJjs= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= +github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/gabriel-vasile/mimetype v1.4.4 h1:QjV6pZ7/XZ7ryI2KuyeEDE8wnh7fHP9YnQy+R0LnH8I= +github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSeEuJfJE+TtfvdB/s= +github.com/gin-contrib/secure v1.1.0 h1:wy/psCWbgUBDCLH13KgB/m06NHXb1jczSTRp+H2hK7E= +github.com/gin-contrib/secure v1.1.0/go.mod h1:LtEfyy326NRwgkUq8ac6npf845L0L9B8yfEaLcxMHIc= +github.com/gin-contrib/sessions v1.0.1 h1:3hsJyNs7v7N8OtelFmYXFrulAf6zSR7nW/putcPEHxI= +github.com/gin-contrib/sessions v1.0.1/go.mod h1:ouxSFM24/OgIud5MJYQJLpy6AwxQ5EYO9yLhbtObGkM= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= +github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= +github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= +github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao= +github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= +github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= +github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= +github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= +github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= +github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/context v1.1.2 h1:WRkNAv2uoa03QNIc1A6u4O7DAGMUVoopZhkiXWA2V1o= +github.com/gorilla/context v1.1.2/go.mod h1:KDPwT9i/MeWHiLl90fuTgrt4/wPcv75vFAZLaOOcbxM= +github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= +github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= +github.com/gorilla/sessions v1.3.0 h1:XYlkq7KcpOB2ZhHBPv5WpjMIxrQosiZanfoy1HLZFzg= +github.com/gorilla/sessions v1.3.0/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ= +github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-memdb v1.3.4 h1:XSL3NR682X/cVk2IeV0d70N4DZ9ljI885xAEU8IoK3c= +github.com/hashicorp/go-memdb v1.3.4/go.mod h1:uBTr1oQbtuMgd1SSGoR8YV27eT3sBHbYiNm53bMpgSg= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= +github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= +github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc= +github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= +github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/playwright-community/playwright-go v0.4401.1 h1:3EMTn9HUGETP3vjZLrVVNW+2xh+AtastOe7NHdT3fMs= +github.com/playwright-community/playwright-go v0.4401.1/go.mod h1:bpArn5TqNzmP0jroCgw4poSOG9gSeQg490iLqWAaa7w= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rabbitmq/amqp091-go v1.10.0 h1:STpn5XsHlHGcecLmMFCtg7mqq0RnD+zFr4uzukfVhBw= +github.com/rabbitmq/amqp091-go v1.10.0/go.mod h1:Hy4jKW5kQART1u+JkDTF9YYOQUHXqMuhrgxOEeS7G4o= +github.com/redis/go-redis/v9 v9.5.3 h1:fOAp1/uJG+ZtcITgZOfYFmTKPE7n4Vclj1wZFgRciUU= +github.com/redis/go-redis/v9 v9.5.3/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= +github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= +github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= +github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= +github.com/youmark/pkcs8 v0.0.0-20240424034433-3c2c7870ae76 h1:tBiBTKHnIjovYoLX/TPkcf+OjqqKGQrPtGT3Foz+Pgo= +github.com/youmark/pkcs8 v0.0.0-20240424034433-3c2c7870ae76/go.mod h1:SQliXeA7Dhkt//vS29v3zpbEwoa+zb2Cn5xj5uO4K5U= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.mongodb.org/mongo-driver v1.15.1 h1:l+RvoUOoMXFmADTLfYDm7On9dRm7p4T80/lEQM+r7HU= +go.mongodb.org/mongo-driver v1.15.1/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= +golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY= +golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..693e5c2 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,16813 @@ +{ + "name": "codexgo", + "version": "4.3.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "codexgo", + "version": "4.3.0", + "license": "MIT", + "workspaces": [ + "pkg/cmd/*" + ], + "devDependencies": { + "@commitlint/cli": "19.3.0", + "@commitlint/config-conventional": "19.2.2", + "@release-it/bumper": "6.0.1", + "@release-it/conventional-changelog": "8.0.1", + "commitizen": "4.3.0", + "cz-conventional-changelog": "3.3.0", + "husky": "9.0.11", + "lint-staged": "15.2.7", + "npm-check-updates": "16.14.20", + "prettier": "3.3.2", + "release-it": "17.4.0" + }, + "engines": { + "node": ">=20", + "npm": ">=10" + } + }, + "node_modules/@actions/core": { + "version": "1.10.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@actions/http-client": "^2.0.1", + "uuid": "^8.3.2" + } + }, + "node_modules/@actions/http-client": { + "version": "2.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "tunnel": "^0.0.6", + "undici": "^5.25.4" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.23.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.23.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@commitlint/cli": { + "version": "19.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/format": "^19.3.0", + "@commitlint/lint": "^19.2.2", + "@commitlint/load": "^19.2.0", + "@commitlint/read": "^19.2.1", + "@commitlint/types": "^19.0.3", + "execa": "^8.0.1", + "yargs": "^17.0.0" + }, + "bin": { + "commitlint": "cli.js" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/cli/node_modules/execa": { + "version": "8.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/@commitlint/cli/node_modules/get-stream": { + "version": "8.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/cli/node_modules/human-signals": { + "version": "5.0.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/@commitlint/cli/node_modules/is-stream": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/cli/node_modules/mimic-fn": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/cli/node_modules/npm-run-path": { + "version": "5.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/cli/node_modules/onetime": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/cli/node_modules/path-key": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/cli/node_modules/signal-exit": { + "version": "4.1.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@commitlint/cli/node_modules/strip-final-newline": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/config-conventional": { + "version": "19.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^19.0.3", + "conventional-changelog-conventionalcommits": "^7.0.2" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/config-validator": { + "version": "19.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^19.0.3", + "ajv": "^8.11.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/ensure": { + "version": "19.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^19.0.3", + "lodash.camelcase": "^4.3.0", + "lodash.kebabcase": "^4.1.1", + "lodash.snakecase": "^4.1.1", + "lodash.startcase": "^4.4.0", + "lodash.upperfirst": "^4.3.1" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/execute-rule": { + "version": "19.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/format": { + "version": "19.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^19.0.3", + "chalk": "^5.3.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/format/node_modules/chalk": { + "version": "5.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@commitlint/is-ignored": { + "version": "19.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^19.0.3", + "semver": "^7.6.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/lint": { + "version": "19.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/is-ignored": "^19.2.2", + "@commitlint/parse": "^19.0.3", + "@commitlint/rules": "^19.0.3", + "@commitlint/types": "^19.0.3" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/load": { + "version": "19.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/config-validator": "^19.0.3", + "@commitlint/execute-rule": "^19.0.0", + "@commitlint/resolve-extends": "^19.1.0", + "@commitlint/types": "^19.0.3", + "chalk": "^5.3.0", + "cosmiconfig": "^9.0.0", + "cosmiconfig-typescript-loader": "^5.0.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "lodash.uniq": "^4.5.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/load/node_modules/chalk": { + "version": "5.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@commitlint/message": { + "version": "19.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/parse": { + "version": "19.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^19.0.3", + "conventional-changelog-angular": "^7.0.0", + "conventional-commits-parser": "^5.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/read": { + "version": "19.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/top-level": "^19.0.0", + "@commitlint/types": "^19.0.3", + "execa": "^8.0.1", + "git-raw-commits": "^4.0.0", + "minimist": "^1.2.8" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/read/node_modules/execa": { + "version": "8.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/@commitlint/read/node_modules/get-stream": { + "version": "8.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/read/node_modules/human-signals": { + "version": "5.0.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/@commitlint/read/node_modules/is-stream": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/read/node_modules/mimic-fn": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/read/node_modules/minimist": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@commitlint/read/node_modules/npm-run-path": { + "version": "5.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/read/node_modules/onetime": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/read/node_modules/path-key": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/read/node_modules/signal-exit": { + "version": "4.1.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@commitlint/read/node_modules/strip-final-newline": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/resolve-extends": { + "version": "19.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/config-validator": "^19.0.3", + "@commitlint/types": "^19.0.3", + "global-directory": "^4.0.1", + "import-meta-resolve": "^4.0.0", + "lodash.mergewith": "^4.6.2", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/rules": { + "version": "19.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/ensure": "^19.0.3", + "@commitlint/message": "^19.0.0", + "@commitlint/to-lines": "^19.0.0", + "@commitlint/types": "^19.0.3", + "execa": "^8.0.1" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/rules/node_modules/execa": { + "version": "8.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/@commitlint/rules/node_modules/get-stream": { + "version": "8.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/rules/node_modules/human-signals": { + "version": "5.0.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/@commitlint/rules/node_modules/is-stream": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/rules/node_modules/mimic-fn": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/rules/node_modules/npm-run-path": { + "version": "5.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/rules/node_modules/onetime": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/rules/node_modules/path-key": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/rules/node_modules/signal-exit": { + "version": "4.1.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@commitlint/rules/node_modules/strip-final-newline": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/to-lines": { + "version": "19.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/top-level": { + "version": "19.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^7.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/top-level/node_modules/find-up": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^7.2.0", + "path-exists": "^5.0.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/top-level/node_modules/locate-path": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/top-level/node_modules/p-limit": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/top-level/node_modules/p-locate": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/top-level/node_modules/path-exists": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/@commitlint/top-level/node_modules/yocto-queue": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/types": { + "version": "19.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/conventional-commits-parser": "^5.0.0", + "chalk": "^5.3.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/types/node_modules/chalk": { + "version": "5.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@fastify/busboy": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/@gar/promisify": { + "version": "1.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@hutson/parse-repository-url": { + "version": "5.0.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@iarna/toml": { + "version": "2.2.5", + "dev": true, + "license": "ISC" + }, + "node_modules/@inquirer/figures": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.3.tgz", + "integrity": "sha512-ErXXzENMH5pJt5/ssXV0DfWUZqly8nGzf0UcBV9xTnP+KyffE2mqyxIMBrZ8ijQck2nU0TQm40EQB53YreyWHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@ljharb/through": { + "version": "2.3.13", + "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.13.tgz", + "integrity": "sha512-/gKJun8NNiWGZJkGzI/Ragc53cOdcLNdzjLaIa+GEjguQs0ulsurx8WN0jijdK9yPqDvziX995sMRLyLt1uZMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/fs": { + "version": "3.1.0", + "dev": true, + "license": "ISC", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git": { + "version": "4.1.0", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/promise-spawn": "^6.0.0", + "lru-cache": "^7.4.4", + "npm-pick-manifest": "^8.0.0", + "proc-log": "^3.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git/node_modules/lru-cache": { + "version": "7.18.3", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/@npmcli/git/node_modules/which": { + "version": "3.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/installed-package-contents": { + "version": "2.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "bin": { + "installed-package-contents": "lib/index.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/move-file": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/move-file/node_modules/rimraf": { + "version": "3.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/node-gyp": { + "version": "3.0.0", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/promise-spawn": { + "version": "6.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/promise-spawn/node_modules/which": { + "version": "3.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/run-script": { + "version": "6.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/promise-spawn": "^6.0.0", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^3.0.0", + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/run-script/node_modules/which": { + "version": "3.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@octokit/auth-token": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/core": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/auth-token": "^4.0.0", + "@octokit/graphql": "^7.1.0", + "@octokit/request": "^8.3.1", + "@octokit/request-error": "^5.1.0", + "@octokit/types": "^13.0.0", + "before-after-hook": "^2.2.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/endpoint": { + "version": "9.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^13.1.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/graphql": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/request": "^8.3.0", + "@octokit/types": "^13.0.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "22.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@octokit/plugin-paginate-rest": { + "version": "11.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^13.5.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": "5" + } + }, + "node_modules/@octokit/plugin-request-log": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": "5" + } + }, + "node_modules/@octokit/plugin-rest-endpoint-methods": { + "version": "13.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^13.5.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": "^5" + } + }, + "node_modules/@octokit/request": { + "version": "8.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/endpoint": "^9.0.1", + "@octokit/request-error": "^5.1.0", + "@octokit/types": "^13.1.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/request-error": { + "version": "5.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^13.1.0", + "deprecation": "^2.0.0", + "once": "^1.4.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/rest": { + "version": "20.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/core": "^5.0.2", + "@octokit/plugin-paginate-rest": "11.3.1", + "@octokit/plugin-request-log": "^4.0.0", + "@octokit/plugin-rest-endpoint-methods": "13.2.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/types": { + "version": "13.5.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^22.2.0" + } + }, + "node_modules/@one-ini/wasm": { + "version": "0.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pnpm/config.env-replace": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "4.2.10" + }, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { + "version": "4.2.10", + "dev": true, + "license": "ISC" + }, + "node_modules/@pnpm/npm-conf": { + "version": "2.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@release-it/bumper": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@iarna/toml": "^2.2.5", + "detect-indent": "7.0.1", + "fast-glob": "^3.3.2", + "ini": "^4.1.1", + "js-yaml": "^4.1.0", + "lodash-es": "^4.17.21", + "semver": "^7.3.7" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "release-it": "^17.0.0" + } + }, + "node_modules/@release-it/bumper/node_modules/detect-indent": { + "version": "7.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + } + }, + "node_modules/@release-it/bumper/node_modules/ini": { + "version": "4.1.1", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@release-it/conventional-changelog": { + "version": "8.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "concat-stream": "^2.0.0", + "conventional-changelog": "^5.1.0", + "conventional-recommended-bump": "^9.0.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "release-it": "^17.0.0" + } + }, + "node_modules/@sigstore/bundle": { + "version": "1.1.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.2.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/protobuf-specs": { + "version": "0.2.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/sign": { + "version": "1.0.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^1.1.0", + "@sigstore/protobuf-specs": "^0.2.0", + "make-fetch-happen": "^11.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/tuf": { + "version": "1.0.3", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.2.0", + "tuf-js": "^1.1.7" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@sindresorhus/is": { + "version": "5.6.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "2.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "defer-to-connect": "^2.0.1" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@tufjs/canonical-json": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@tufjs/canonical-json": "1.0.0", + "minimatch": "^9.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models/node_modules/brace-expansion": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@tufjs/models/node_modules/minimatch": { + "version": "9.0.3", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@types/conventional-commits-parser": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/expect": { + "version": "1.20.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.11.24", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/semver-utils": { + "version": "1.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/vinyl": { + "version": "2.0.12", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/expect": "^1.20.4", + "@types/node": "*" + } + }, + "node_modules/abbrev": { + "version": "1.1.1", + "dev": true, + "license": "ISC" + }, + "node_modules/add-stream": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/agent-base": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/agentkeepalive": { + "version": "4.5.0", + "dev": true, + "license": "MIT", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.12.0", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-colors": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-wrap": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-cyan": { + "version": "0.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-gray": { + "version": "0.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-red": { + "version": "0.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ansi-wrap": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/any-shell-escape": { + "version": "0.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "2.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "node_modules/anymatch/node_modules/braces": { + "version": "2.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/anymatch/node_modules/braces/node_modules/extend-shallow": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/anymatch/node_modules/fill-range": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/anymatch/node_modules/fill-range/node_modules/extend-shallow": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/anymatch/node_modules/is-extendable": { + "version": "0.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/anymatch/node_modules/is-number": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/anymatch/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/anymatch/node_modules/kind-of": { + "version": "6.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/anymatch/node_modules/micromatch": { + "version": "3.1.10", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/anymatch/node_modules/normalize-path": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/anymatch/node_modules/to-regex-range": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/append-buffer": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-equal": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/aproba": { + "version": "2.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/archy": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/are-we-there-yet": { + "version": "3.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/arr-diff": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-filter": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-flatten": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-map": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-union": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-differ": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-each": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-ify": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/array-initial": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "array-slice": "^1.0.0", + "is-number": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-initial/node_modules/is-number": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-last": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-last/node_modules/is-number": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-slice": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-sort": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "default-compare": "^1.0.0", + "get-value": "^2.0.6", + "kind-of": "^5.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/array-uniq": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-unique": { + "version": "0.3.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array.prototype.map": { + "version": "1.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/assign-symbols": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ast-types": { + "version": "0.13.4", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/async": { + "version": "1.5.2", + "dev": true, + "license": "MIT" + }, + "node_modules/async-done": { + "version": "1.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.2", + "process-nextick-args": "^2.0.0", + "stream-exhaust": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/async-each": { + "version": "1.0.6", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT" + }, + "node_modules/async-retry": { + "version": "1.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "retry": "0.13.1" + } + }, + "node_modules/async-settle": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "async-done": "^1.2.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/atob": { + "version": "2.1.2", + "dev": true, + "license": "(MIT OR Apache-2.0)", + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.19", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-lite": "^1.0.30001599", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/bach": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-filter": "^1.1.1", + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "array-each": "^1.0.0", + "array-initial": "^1.0.0", + "array-last": "^1.1.1", + "async-done": "^1.2.2", + "async-settle": "^1.0.0", + "now-and-later": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/base": { + "version": "0.11.2", + "dev": true, + "license": "MIT", + "dependencies": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/define-property": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/basic-ftp": { + "version": "5.0.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/beeper": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/before-after-hook": { + "version": "2.2.3", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/better-console": { + "version": "1.0.1", + "dev": true, + "license": "BSD", + "dependencies": { + "chalk": "^1.1.3", + "cli-table": "~0.3.1" + } + }, + "node_modules/better-console/node_modules/ansi-regex": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/better-console/node_modules/ansi-styles": { + "version": "2.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/better-console/node_modules/chalk": { + "version": "1.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/better-console/node_modules/strip-ansi": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/better-console/node_modules/supports-color": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/binary-extensions": { + "version": "1.13.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/binaryextensions": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/boxen": { + "version": "7.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-align": "^3.0.1", + "camelcase": "^7.0.1", + "chalk": "^5.2.0", + "cli-boxes": "^3.0.0", + "string-width": "^5.1.2", + "type-fest": "^2.13.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/ansi-regex": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/boxen/node_modules/ansi-styles": { + "version": "6.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/boxen/node_modules/camelcase": { + "version": "7.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/chalk": { + "version": "5.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/boxen/node_modules/emoji-regex": { + "version": "9.2.2", + "dev": true, + "license": "MIT" + }, + "node_modules/boxen/node_modules/string-width": { + "version": "5.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/strip-ansi": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/boxen/node_modules/type-fest": { + "version": "2.19.0", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/wrap-ansi": { + "version": "8.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.23.0", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-equal": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/builtins": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.0.0" + } + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cacache": { + "version": "17.1.4", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^7.7.1", + "minipass": "^7.0.3", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/cacache/node_modules/brace-expansion": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/cacache/node_modules/glob": { + "version": "10.3.10", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/lru-cache": { + "version": "7.18.3", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/cacache/node_modules/minimatch": { + "version": "9.0.3", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/minipass": { + "version": "7.0.4", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/cache-base": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cacheable-lookup": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + } + }, + "node_modules/cacheable-request": { + "version": "10.2.14", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-cache-semantics": "^4.0.2", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.3", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/cachedir": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001617", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "2.4.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "dev": true, + "license": "MIT" + }, + "node_modules/chokidar": { + "version": "2.1.8", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + }, + "optionalDependencies": { + "fsevents": "^1.2.7" + } + }, + "node_modules/chokidar/node_modules/braces": { + "version": "2.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/chokidar/node_modules/extend-shallow": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/chokidar/node_modules/fill-range": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "3.1.0", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + } + }, + "node_modules/chokidar/node_modules/glob-parent/node_modules/is-glob": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/chokidar/node_modules/is-extendable": { + "version": "0.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/chokidar/node_modules/is-number": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/chokidar/node_modules/kind-of": { + "version": "3.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/chokidar/node_modules/to-regex-range": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/class-utils": { + "version": "0.3.6", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/define-property": { + "version": "0.2.5", + "dev": true, + "license": "MIT", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-descriptor": { + "version": "0.1.7", + "dev": true, + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/clean-css": { + "version": "4.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-boxes": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-table": { + "version": "0.3.11", + "dev": true, + "dependencies": { + "colors": "1.0.3" + }, + "engines": { + "node": ">= 0.2.0" + } + }, + "node_modules/cli-table3": { + "version": "0.6.3", + "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cli-truncate": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/ansi-regex": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/cli-truncate/node_modules/emoji-regex": { + "version": "10.3.0", + "dev": true, + "license": "MIT" + }, + "node_modules/cli-truncate/node_modules/string-width": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/strip-ansi": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 10" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-buffer": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/clone-stats": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/cloneable-readable": { + "version": "1.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "process-nextick-args": "^2.0.0", + "readable-stream": "^2.3.5" + } + }, + "node_modules/cloneable-readable/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/cloneable-readable/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/cloneable-readable/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/cloneable-readable/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/code-point-at": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/collection-map": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-map": "^2.0.2", + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/collection-visit": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/color-support": { + "version": "1.1.3", + "dev": true, + "license": "ISC", + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/colorette": { + "version": "2.0.20", + "dev": true, + "license": "MIT" + }, + "node_modules/colors": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/commander": { + "version": "12.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/commitizen": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "cachedir": "2.3.0", + "cz-conventional-changelog": "3.3.0", + "dedent": "0.7.0", + "detect-indent": "6.1.0", + "find-node-modules": "^2.1.2", + "find-root": "1.1.0", + "fs-extra": "9.1.0", + "glob": "7.2.3", + "inquirer": "8.2.5", + "is-utf8": "^0.2.1", + "lodash": "4.17.21", + "minimist": "1.2.7", + "strip-bom": "4.0.0", + "strip-json-comments": "3.1.1" + }, + "bin": { + "commitizen": "bin/commitizen", + "cz": "bin/git-cz", + "git-cz": "bin/git-cz" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/compare-func": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + }, + "node_modules/component-emitter": { + "version": "1.3.1", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-stream": { + "version": "2.0.0", + "dev": true, + "engines": [ + "node >= 6.0" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/concat-with-sourcemaps": { + "version": "1.1.0", + "dev": true, + "license": "ISC", + "dependencies": { + "source-map": "^0.6.1" + } + }, + "node_modules/config-chain": { + "version": "1.1.13", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/configstore": { + "version": "6.0.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dot-prop": "^6.0.1", + "graceful-fs": "^4.2.6", + "unique-string": "^3.0.0", + "write-file-atomic": "^3.0.3", + "xdg-basedir": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/yeoman/configstore?sponsor=1" + } + }, + "node_modules/configstore/node_modules/dot-prop": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "dev": true, + "license": "ISC" + }, + "node_modules/conventional-changelog": { + "version": "5.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "conventional-changelog-angular": "^7.0.0", + "conventional-changelog-atom": "^4.0.0", + "conventional-changelog-codemirror": "^4.0.0", + "conventional-changelog-conventionalcommits": "^7.0.2", + "conventional-changelog-core": "^7.0.0", + "conventional-changelog-ember": "^4.0.0", + "conventional-changelog-eslint": "^5.0.0", + "conventional-changelog-express": "^4.0.0", + "conventional-changelog-jquery": "^5.0.0", + "conventional-changelog-jshint": "^4.0.0", + "conventional-changelog-preset-loader": "^4.1.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/conventional-changelog-angular": { + "version": "7.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/conventional-changelog-atom": { + "version": "4.0.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16" + } + }, + "node_modules/conventional-changelog-codemirror": { + "version": "4.0.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16" + } + }, + "node_modules/conventional-changelog-conventionalcommits": { + "version": "7.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/conventional-changelog-core": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@hutson/parse-repository-url": "^5.0.0", + "add-stream": "^1.0.0", + "conventional-changelog-writer": "^7.0.0", + "conventional-commits-parser": "^5.0.0", + "git-raw-commits": "^4.0.0", + "git-semver-tags": "^7.0.0", + "hosted-git-info": "^7.0.0", + "normalize-package-data": "^6.0.0", + "read-pkg": "^8.0.0", + "read-pkg-up": "^10.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/conventional-changelog-core/node_modules/find-up": { + "version": "6.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/conventional-changelog-core/node_modules/hosted-git-info": { + "version": "7.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/conventional-changelog-core/node_modules/json-parse-even-better-errors": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/conventional-changelog-core/node_modules/lines-and-columns": { + "version": "2.0.4", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/conventional-changelog-core/node_modules/locate-path": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/conventional-changelog-core/node_modules/lru-cache": { + "version": "10.1.0", + "dev": true, + "license": "ISC", + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/conventional-changelog-core/node_modules/normalize-package-data": { + "version": "6.0.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^7.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/conventional-changelog-core/node_modules/p-limit": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/conventional-changelog-core/node_modules/p-locate": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/conventional-changelog-core/node_modules/parse-json": { + "version": "7.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.21.4", + "error-ex": "^1.3.2", + "json-parse-even-better-errors": "^3.0.0", + "lines-and-columns": "^2.0.3", + "type-fest": "^3.8.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/conventional-changelog-core/node_modules/parse-json/node_modules/type-fest": { + "version": "3.13.1", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/conventional-changelog-core/node_modules/path-exists": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/conventional-changelog-core/node_modules/read-pkg": { + "version": "8.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/normalize-package-data": "^2.4.1", + "normalize-package-data": "^6.0.0", + "parse-json": "^7.0.0", + "type-fest": "^4.2.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/conventional-changelog-core/node_modules/read-pkg-up": { + "version": "10.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^6.3.0", + "read-pkg": "^8.1.0", + "type-fest": "^4.2.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/conventional-changelog-core/node_modules/type-fest": { + "version": "4.9.0", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/conventional-changelog-core/node_modules/yocto-queue": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/conventional-changelog-ember": { + "version": "4.0.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16" + } + }, + "node_modules/conventional-changelog-eslint": { + "version": "5.0.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16" + } + }, + "node_modules/conventional-changelog-express": { + "version": "4.0.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16" + } + }, + "node_modules/conventional-changelog-jquery": { + "version": "5.0.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16" + } + }, + "node_modules/conventional-changelog-jshint": { + "version": "4.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/conventional-changelog-preset-loader": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/conventional-changelog-writer": { + "version": "7.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "conventional-commits-filter": "^4.0.0", + "handlebars": "^4.7.7", + "json-stringify-safe": "^5.0.1", + "meow": "^12.0.1", + "semver": "^7.5.2", + "split2": "^4.0.0" + }, + "bin": { + "conventional-changelog-writer": "cli.mjs" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/conventional-commit-types": { + "version": "3.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/conventional-commits-filter": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/conventional-commits-parser": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-text-path": "^2.0.0", + "JSONStream": "^1.3.5", + "meow": "^12.0.1", + "split2": "^4.0.0" + }, + "bin": { + "conventional-commits-parser": "cli.mjs" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/conventional-recommended-bump": { + "version": "9.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "conventional-changelog-preset-loader": "^4.1.0", + "conventional-commits-filter": "^4.0.0", + "conventional-commits-parser": "^5.0.0", + "git-raw-commits": "^4.0.0", + "git-semver-tags": "^7.0.0", + "meow": "^12.0.1" + }, + "bin": { + "conventional-recommended-bump": "cli.mjs" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/convert-source-map": { + "version": "0.3.5", + "dev": true, + "license": "MIT" + }, + "node_modules/copy-anything": { + "version": "2.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "is-what": "^3.14.1" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/copy-descriptor": { + "version": "0.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/copy-props": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "each-props": "^1.3.2", + "is-plain-object": "^5.0.0" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/cosmiconfig": { + "version": "9.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cosmiconfig-typescript-loader": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "jiti": "^1.19.1" + }, + "engines": { + "node": ">=v16" + }, + "peerDependencies": { + "@types/node": "*", + "cosmiconfig": ">=8.2", + "typescript": ">=4" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-random-string": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^1.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/crypto-random-string/node_modules/type-fest": { + "version": "1.4.0", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/css": { + "version": "2.2.4", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "source-map": "^0.6.1", + "source-map-resolve": "^0.5.2", + "urix": "^0.1.0" + } + }, + "node_modules/cz-conventional-changelog": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^2.4.1", + "commitizen": "^4.0.3", + "conventional-commit-types": "^3.0.0", + "lodash.map": "^4.5.1", + "longest": "^2.0.1", + "word-wrap": "^1.0.3" + }, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@commitlint/load": ">6.1.1" + } + }, + "node_modules/d": { + "version": "1.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "es5-ext": "^0.10.64", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/dargs": { + "version": "8.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/dateformat": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decode-uri-component": { + "version": "0.2.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/dedent": { + "version": "0.7.0", + "dev": true, + "license": "MIT" + }, + "node_modules/deep-assign": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/deep-assign/node_modules/is-obj": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-browser": { + "version": "5.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-compare": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^5.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-resolution": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-property": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/degenerator": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/del": { + "version": "6.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "globby": "^11.0.1", + "graceful-fs": "^4.2.4", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.2", + "p-map": "^4.0.0", + "rimraf": "^3.0.2", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/del/node_modules/globby": { + "version": "11.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/del/node_modules/rimraf": { + "version": "3.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/del/node_modules/slash": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/deprecation": { + "version": "2.3.1", + "dev": true, + "license": "ISC" + }, + "node_modules/detect-file": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-indent": { + "version": "6.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "1.0.8", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/duplexer2": { + "version": "0.0.2", + "dev": true, + "license": "BSD", + "dependencies": { + "readable-stream": "~1.1.9" + } + }, + "node_modules/duplexer2/node_modules/isarray": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/duplexer2/node_modules/readable-stream": { + "version": "1.1.14", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/duplexer2/node_modules/string_decoder": { + "version": "0.10.31", + "dev": true, + "license": "MIT" + }, + "node_modules/duplexify": { + "version": "3.7.1", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/duplexify/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/duplexify/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/duplexify/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/duplexify/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/each-props": { + "version": "1.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.1", + "object.defaults": "^1.1.0" + } + }, + "node_modules/each-props/node_modules/is-plain-object": { + "version": "2.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/editorconfig": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@one-ini/wasm": "0.1.1", + "commander": "^10.0.0", + "minimatch": "9.0.1", + "semver": "^7.5.3" + }, + "bin": { + "editorconfig": "bin/editorconfig" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/editorconfig/node_modules/brace-expansion": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/editorconfig/node_modules/commander": { + "version": "10.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/editorconfig/node_modules/minimatch": { + "version": "9.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.763", + "dev": true, + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/encoding": { + "version": "0.1.13", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/errno": { + "version": "0.1.8", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.22.3", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.2", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.5", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.2", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.12", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "safe-array-concat": "^1.0.1", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.8", + "string.prototype.trimend": "^1.0.7", + "string.prototype.trimstart": "^1.0.7", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-array-method-boxes-properly": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-get-iterator": { + "version": "1.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.2", + "has-tostringtag": "^1.0.0", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es5-ext": { + "version": "0.10.64", + "dev": true, + "hasInstallScript": true, + "license": "ISC", + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.4", + "dev": true, + "license": "ISC", + "dependencies": { + "d": "^1.0.2", + "ext": "^1.7.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/es6-weak-map": { + "version": "2.0.3", + "dev": true, + "license": "ISC", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/escalade": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-goat": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/esniff": { + "version": "2.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/event-emitter": { + "version": "0.3.5", + "dev": true, + "license": "MIT", + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/execa": { + "version": "5.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/expand-brackets": { + "version": "2.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/debug": { + "version": "2.6.9", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/expand-brackets/node_modules/define-property": { + "version": "0.2.5", + "dev": true, + "license": "MIT", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/extend-shallow": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-descriptor": { + "version": "0.1.7", + "dev": true, + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/expand-brackets/node_modules/is-extendable": { + "version": "0.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/ms": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/expand-tilde": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.1", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/ext": { + "version": "1.7.0", + "dev": true, + "license": "ISC", + "dependencies": { + "type": "^2.7.2" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/extend-shallow": { + "version": "3.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/external-editor": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/extglob": { + "version": "2.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/define-property": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/extend-shallow": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-extendable": { + "version": "0.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fancy-log": { + "version": "1.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-gray": "^0.1.1", + "color-support": "^1.1.3", + "parse-node-version": "^1.0.0", + "time-stamp": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-levenshtein": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-memoize": { + "version": "2.5.2", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.16.0", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-node-modules": { + "version": "2.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "findup-sync": "^4.0.0", + "merge": "^2.1.1" + } + }, + "node_modules/find-root": { + "version": "1.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/find-up": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/findup-sync": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^4.0.2", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fined": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^2.0.3", + "object.defaults": "^1.1.0", + "object.pick": "^1.2.0", + "parse-filepath": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/fined/node_modules/is-plain-object": { + "version": "2.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/first-chunk-stream": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/first-chunk-stream/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/first-chunk-stream/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/first-chunk-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/first-chunk-stream/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/flagged-respawn": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/flush-write-stream": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "node_modules/flush-write-stream/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/flush-write-stream/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/flush-write-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/flush-write-stream/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/fomantic-ui": { + "version": "2.9.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@actions/core": "^1.6.0", + "@octokit/core": "^3.6.0", + "@octokit/rest": "^18.12.0", + "better-console": "^1.0.1", + "browserslist": "^4.21.4", + "del": "^6.1.1", + "extend": "^3.0.2", + "gulp": "^4.0.0", + "gulp-autoprefixer": "^8.0.0", + "gulp-chmod": "^2.0.0", + "gulp-clean-css": "^4.3.0", + "gulp-clone": "^2.0.1", + "gulp-concat": "^2.6.1", + "gulp-concat-css": "^3.1.0", + "gulp-concat-filenames": "^1.2.0", + "gulp-copy": "^4.0.0", + "gulp-dedupe": "^0.0.2", + "gulp-flatten": "^0.4.0", + "gulp-git": "^2.9.0", + "gulp-header": "^2.0.5", + "gulp-if": "^2.0.2", + "gulp-json-editor": "^2.4.3", + "gulp-less": "^5.0.0", + "gulp-plumber": "^1.1.0", + "gulp-print": "^5.0.0", + "gulp-rename": "^1.4.0", + "gulp-replace": "^1.0.0", + "gulp-rtlcss": "^2.0.0", + "gulp-tap": "^1.0.1", + "gulp-uglify": "^3.0.1", + "inquirer": "^8.2.0", + "jquery": "^3.4.0", + "less": "^3.12.0 || ^4.0.0", + "map-stream": "^0.1.0", + "merge-stream": "^2.0.0", + "mkdirp": "^1.0.4", + "normalize-path": "^3.0.0", + "replace-ext": "^1.0.0", + "require-dot-file": "^0.4.0", + "wrench-sui": "^0.0.3", + "yamljs": "^0.3.0" + }, + "engines": { + "node": ">=12", + "npm": ">=6.14.8" + } + }, + "node_modules/fomantic-ui/node_modules/@octokit/auth-token": { + "version": "2.5.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^6.0.3" + } + }, + "node_modules/fomantic-ui/node_modules/@octokit/core": { + "version": "3.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/auth-token": "^2.4.4", + "@octokit/graphql": "^4.5.8", + "@octokit/request": "^5.6.3", + "@octokit/request-error": "^2.0.5", + "@octokit/types": "^6.0.3", + "before-after-hook": "^2.2.0", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/fomantic-ui/node_modules/@octokit/endpoint": { + "version": "6.0.12", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^6.0.3", + "is-plain-object": "^5.0.0", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/fomantic-ui/node_modules/@octokit/graphql": { + "version": "4.8.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/request": "^5.6.0", + "@octokit/types": "^6.0.3", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/fomantic-ui/node_modules/@octokit/openapi-types": { + "version": "12.11.0", + "dev": true, + "license": "MIT" + }, + "node_modules/fomantic-ui/node_modules/@octokit/plugin-paginate-rest": { + "version": "2.21.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^6.40.0" + }, + "peerDependencies": { + "@octokit/core": ">=2" + } + }, + "node_modules/fomantic-ui/node_modules/@octokit/plugin-request-log": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@octokit/core": ">=3" + } + }, + "node_modules/fomantic-ui/node_modules/@octokit/plugin-rest-endpoint-methods": { + "version": "5.16.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^6.39.0", + "deprecation": "^2.3.1" + }, + "peerDependencies": { + "@octokit/core": ">=3" + } + }, + "node_modules/fomantic-ui/node_modules/@octokit/request": { + "version": "5.6.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/endpoint": "^6.0.1", + "@octokit/request-error": "^2.1.0", + "@octokit/types": "^6.16.1", + "is-plain-object": "^5.0.0", + "node-fetch": "^2.6.7", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/fomantic-ui/node_modules/@octokit/request-error": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^6.0.3", + "deprecation": "^2.0.0", + "once": "^1.4.0" + } + }, + "node_modules/fomantic-ui/node_modules/@octokit/rest": { + "version": "18.12.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/core": "^3.5.1", + "@octokit/plugin-paginate-rest": "^2.16.8", + "@octokit/plugin-request-log": "^1.0.4", + "@octokit/plugin-rest-endpoint-methods": "^5.12.0" + } + }, + "node_modules/fomantic-ui/node_modules/@octokit/types": { + "version": "6.41.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^12.11.0" + } + }, + "node_modules/fomantic-ui/node_modules/node-fetch": { + "version": "2.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/for-own": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "for-in": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/foreground-child": { + "version": "3.1.1", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fork-stream": { + "version": "0.0.4", + "dev": true, + "license": "BSD" + }, + "node_modules/form-data-encoder": { + "version": "2.1.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.17" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "dev": true, + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/fp-and-or": { + "version": "0.1.4", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fragment-cache": { + "version": "0.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "map-cache": "^0.2.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fs-extra": { + "version": "9.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fs-minipass": { + "version": "3.0.3", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "7.0.4", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/fs-mkdirp-stream": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.11", + "through2": "^2.0.3" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/fs-mkdirp-stream/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/fs-mkdirp-stream/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/fs-mkdirp-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/fs-mkdirp-stream/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/fs-mkdirp-stream/node_modules/through2": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/function-bind": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gauge": { + "version": "4.0.4", + "dev": true, + "license": "ISC", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-imports": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "array-uniq": "^1.0.1", + "import-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stdin": { + "version": "8.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-uri": { + "version": "6.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4", + "fs-extra": "^11.2.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/get-uri/node_modules/data-uri-to-buffer": { + "version": "6.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/get-uri/node_modules/fs-extra": { + "version": "11.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/get-value": { + "version": "2.0.6", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/git-raw-commits": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "dargs": "^8.0.0", + "meow": "^12.0.1", + "split2": "^4.0.0" + }, + "bin": { + "git-raw-commits": "cli.mjs" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/git-semver-tags": { + "version": "7.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "meow": "^12.0.1", + "semver": "^7.5.2" + }, + "bin": { + "git-semver-tags": "cli.mjs" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/git-up": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-ssh": "^1.4.0", + "parse-url": "^8.1.0" + } + }, + "node_modules/git-url-parse": { + "version": "14.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "git-up": "^7.0.0" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-stream": { + "version": "6.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "extend": "^3.0.0", + "glob": "^7.1.1", + "glob-parent": "^3.1.0", + "is-negated-glob": "^1.0.0", + "ordered-read-streams": "^1.0.0", + "pumpify": "^1.3.5", + "readable-stream": "^2.1.5", + "remove-trailing-separator": "^1.0.1", + "to-absolute-glob": "^2.0.0", + "unique-stream": "^2.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/glob-stream/node_modules/glob-parent": { + "version": "3.1.0", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + } + }, + "node_modules/glob-stream/node_modules/is-glob": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-stream/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/glob-stream/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/glob-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/glob-stream/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/glob-watcher": { + "version": "5.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "^2.0.0", + "async-done": "^1.2.0", + "chokidar": "^2.0.0", + "is-negated-glob": "^1.0.0", + "just-debounce": "^1.0.0", + "normalize-path": "^3.0.0", + "object.defaults": "^1.1.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/global-directory": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "4.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-directory/node_modules/ini": { + "version": "4.1.1", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/global-modules": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "14.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.2", + "ignore": "^5.2.4", + "path-type": "^5.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby/node_modules/path-type": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glogg": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "sparkles": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "13.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "dev": true, + "license": "ISC" + }, + "node_modules/gulp": { + "version": "4.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "glob-watcher": "^5.0.3", + "gulp-cli": "^2.2.0", + "undertaker": "^1.2.1", + "vinyl-fs": "^3.0.0" + }, + "bin": { + "gulp": "bin/gulp.js" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-autoprefixer": { + "version": "8.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "autoprefixer": "^10.2.6", + "fancy-log": "^1.3.3", + "plugin-error": "^1.0.1", + "postcss": "^8.3.0", + "through2": "^4.0.2", + "vinyl-sourcemaps-apply": "^0.2.1" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "gulp": ">=4" + }, + "peerDependenciesMeta": { + "gulp": { + "optional": true + } + } + }, + "node_modules/gulp-chmod": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-assign": "^1.0.0", + "stat-mode": "^0.2.0", + "through2": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/gulp-chmod/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-chmod/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/gulp-chmod/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-chmod/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/gulp-chmod/node_modules/through2": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/gulp-clean-css": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "clean-css": "4.2.3", + "plugin-error": "1.0.1", + "through2": "3.0.1", + "vinyl-sourcemaps-apply": "0.2.1" + } + }, + "node_modules/gulp-clean-css/node_modules/through2": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "2 || 3" + } + }, + "node_modules/gulp-cli": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^1.0.1", + "archy": "^1.0.0", + "array-sort": "^1.0.0", + "color-support": "^1.1.3", + "concat-stream": "^1.6.0", + "copy-props": "^2.0.1", + "fancy-log": "^1.3.2", + "gulplog": "^1.0.0", + "interpret": "^1.4.0", + "isobject": "^3.0.1", + "liftoff": "^3.1.0", + "matchdep": "^2.0.0", + "mute-stdout": "^1.0.0", + "pretty-hrtime": "^1.0.0", + "replace-homedir": "^1.0.0", + "semver-greatest-satisfied-range": "^1.1.0", + "v8flags": "^3.2.0", + "yargs": "^7.1.0" + }, + "bin": { + "gulp": "bin/gulp.js" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-cli/node_modules/ansi-regex": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-cli/node_modules/cliui": { + "version": "3.2.0", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "node_modules/gulp-cli/node_modules/concat-stream": { + "version": "1.6.2", + "dev": true, + "engines": [ + "node >= 0.8" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/gulp-cli/node_modules/get-caller-file": { + "version": "1.0.3", + "dev": true, + "license": "ISC" + }, + "node_modules/gulp-cli/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-cli/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-cli/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/gulp-cli/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-cli/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/gulp-cli/node_modules/string-width": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-cli/node_modules/strip-ansi": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-cli/node_modules/wrap-ansi": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-cli/node_modules/y18n": { + "version": "3.2.2", + "dev": true, + "license": "ISC" + }, + "node_modules/gulp-cli/node_modules/yargs": { + "version": "7.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase": "^3.0.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.2", + "which-module": "^1.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^5.0.1" + } + }, + "node_modules/gulp-cli/node_modules/yargs-parser": { + "version": "5.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^3.0.0", + "object.assign": "^4.1.0" + } + }, + "node_modules/gulp-clone": { + "version": "2.0.1", + "dev": true, + "dependencies": { + "plugin-error": "^0.1.2", + "through2": "^2.0.3" + } + }, + "node_modules/gulp-clone/node_modules/arr-diff": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-flatten": "^1.0.1", + "array-slice": "^0.2.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-clone/node_modules/arr-union": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-clone/node_modules/array-slice": { + "version": "0.2.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-clone/node_modules/extend-shallow": { + "version": "1.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-clone/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-clone/node_modules/kind-of": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-clone/node_modules/plugin-error": { + "version": "0.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-cyan": "^0.1.1", + "ansi-red": "^0.1.1", + "arr-diff": "^1.0.1", + "arr-union": "^2.0.1", + "extend-shallow": "^1.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-clone/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/gulp-clone/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-clone/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/gulp-clone/node_modules/through2": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/gulp-concat": { + "version": "2.6.1", + "dev": true, + "license": "MIT", + "dependencies": { + "concat-with-sourcemaps": "^1.0.0", + "through2": "^2.0.0", + "vinyl": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-concat-css": { + "version": "3.1.0", + "dev": true, + "dependencies": { + "lodash.defaults": "^3.0.0", + "parse-import": "^2.0.0", + "plugin-error": "^0.1.2", + "rework": "~1.0.0", + "rework-import": "^2.0.0", + "rework-plugin-url": "^1.0.1", + "through2": "~1.1.1", + "vinyl": "^2.1.0" + } + }, + "node_modules/gulp-concat-css/node_modules/arr-diff": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-flatten": "^1.0.1", + "array-slice": "^0.2.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-concat-css/node_modules/arr-union": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-concat-css/node_modules/array-slice": { + "version": "0.2.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-concat-css/node_modules/extend-shallow": { + "version": "1.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-concat-css/node_modules/isarray": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-concat-css/node_modules/kind-of": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-concat-css/node_modules/plugin-error": { + "version": "0.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-cyan": "^0.1.1", + "ansi-red": "^0.1.1", + "arr-diff": "^1.0.1", + "arr-union": "^2.0.1", + "extend-shallow": "^1.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-concat-css/node_modules/readable-stream": { + "version": "1.1.14", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/gulp-concat-css/node_modules/string_decoder": { + "version": "0.10.31", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-concat-css/node_modules/through2": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": ">=1.1.13-1 <1.2.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + } + }, + "node_modules/gulp-concat-filenames": { + "version": "1.2.0", + "dev": true, + "dependencies": { + "gulp-util": "3.x.x", + "through": "2.x.x" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-concat/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-concat/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/gulp-concat/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-concat/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/gulp-concat/node_modules/through2": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/gulp-copy": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "gulp": "^4.0.0", + "plugin-error": "^0.1.2", + "through2": "^2.0.3" + } + }, + "node_modules/gulp-copy/node_modules/arr-diff": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-flatten": "^1.0.1", + "array-slice": "^0.2.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-copy/node_modules/arr-union": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-copy/node_modules/array-slice": { + "version": "0.2.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-copy/node_modules/extend-shallow": { + "version": "1.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-copy/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-copy/node_modules/kind-of": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-copy/node_modules/plugin-error": { + "version": "0.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-cyan": "^0.1.1", + "ansi-red": "^0.1.1", + "arr-diff": "^1.0.1", + "arr-union": "^2.0.1", + "extend-shallow": "^1.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-copy/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/gulp-copy/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-copy/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/gulp-copy/node_modules/through2": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/gulp-dedupe": { + "version": "0.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "colors": "~1.0.2", + "diff": "~1.0.8", + "gulp-util": "~3.0.1", + "lodash.defaults": "~2.4.1", + "through": "~2.3.6" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/gulp-dedupe/node_modules/lodash.defaults": { + "version": "2.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash._objecttypes": "~2.4.1", + "lodash.keys": "~2.4.1" + } + }, + "node_modules/gulp-dedupe/node_modules/lodash.keys": { + "version": "2.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash._isnative": "~2.4.1", + "lodash._shimkeys": "~2.4.1", + "lodash.isobject": "~2.4.1" + } + }, + "node_modules/gulp-flatten": { + "version": "0.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "plugin-error": "^0.1.2", + "through2": "^2.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/gulp-flatten/node_modules/arr-diff": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-flatten": "^1.0.1", + "array-slice": "^0.2.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-flatten/node_modules/arr-union": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-flatten/node_modules/array-slice": { + "version": "0.2.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-flatten/node_modules/extend-shallow": { + "version": "1.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-flatten/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-flatten/node_modules/kind-of": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-flatten/node_modules/plugin-error": { + "version": "0.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-cyan": "^0.1.1", + "ansi-red": "^0.1.1", + "arr-diff": "^1.0.1", + "arr-union": "^2.0.1", + "extend-shallow": "^1.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-flatten/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/gulp-flatten/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-flatten/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/gulp-flatten/node_modules/through2": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/gulp-git": { + "version": "2.10.1", + "dev": true, + "license": "MIT", + "dependencies": { + "any-shell-escape": "^0.1.1", + "fancy-log": "^1.3.2", + "lodash.template": "^4.4.0", + "plugin-error": "^1.0.1", + "require-dir": "^1.0.0", + "strip-bom-stream": "^3.0.0", + "through2": "^2.0.3", + "vinyl": "^2.0.1" + }, + "engines": { + "node": ">= 0.9.0" + } + }, + "node_modules/gulp-git/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-git/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/gulp-git/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-git/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/gulp-git/node_modules/through2": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/gulp-header": { + "version": "2.0.9", + "dev": true, + "license": "MIT", + "dependencies": { + "concat-with-sourcemaps": "^1.1.0", + "lodash.template": "^4.5.0", + "map-stream": "0.0.7", + "through2": "^2.0.0" + } + }, + "node_modules/gulp-header/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-header/node_modules/map-stream": { + "version": "0.0.7", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-header/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/gulp-header/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-header/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/gulp-header/node_modules/through2": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/gulp-if": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "gulp-match": "^1.0.3", + "ternary-stream": "^2.0.1", + "through2": "^2.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/gulp-if/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-if/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/gulp-if/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-if/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/gulp-if/node_modules/through2": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/gulp-json-editor": { + "version": "2.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "deepmerge": "^4.3.1", + "detect-indent": "^6.1.0", + "js-beautify": "^1.14.11", + "plugin-error": "^2.0.1", + "through2": "^4.0.2" + } + }, + "node_modules/gulp-json-editor/node_modules/plugin-error": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^1.0.1" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/gulp-less": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "less": "^3.7.1 || ^4.0.0", + "object-assign": "^4.0.1", + "plugin-error": "^1.0.0", + "replace-ext": "^2.0.0", + "through2": "^4.0.0", + "vinyl-sourcemaps-apply": "^0.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/gulp-less/node_modules/replace-ext": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/gulp-match": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "minimatch": "^3.0.3" + } + }, + "node_modules/gulp-plumber": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^1.1.3", + "fancy-log": "^1.3.2", + "plugin-error": "^0.1.2", + "through2": "^2.0.3" + }, + "engines": { + "node": ">=0.10", + "npm": ">=1.2.10" + } + }, + "node_modules/gulp-plumber/node_modules/ansi-regex": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-plumber/node_modules/ansi-styles": { + "version": "2.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-plumber/node_modules/arr-diff": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-flatten": "^1.0.1", + "array-slice": "^0.2.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-plumber/node_modules/arr-union": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-plumber/node_modules/array-slice": { + "version": "0.2.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-plumber/node_modules/chalk": { + "version": "1.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-plumber/node_modules/extend-shallow": { + "version": "1.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-plumber/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-plumber/node_modules/kind-of": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-plumber/node_modules/plugin-error": { + "version": "0.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-cyan": "^0.1.1", + "ansi-red": "^0.1.1", + "arr-diff": "^1.0.1", + "arr-union": "^2.0.1", + "extend-shallow": "^1.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-plumber/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/gulp-plumber/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-plumber/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/gulp-plumber/node_modules/strip-ansi": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-plumber/node_modules/supports-color": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/gulp-plumber/node_modules/through2": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/gulp-print": { + "version": "5.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^3.2.4", + "fancy-log": "^1.3.3", + "map-stream": "0.0.7", + "vinyl": "^2.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/gulp-print/node_modules/ansi-colors": { + "version": "3.2.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/gulp-print/node_modules/map-stream": { + "version": "0.0.7", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-rename": { + "version": "1.4.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/gulp-replace": { + "version": "1.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/vinyl": "^2.0.4", + "istextorbinary": "^3.0.0", + "replacestream": "^4.0.3", + "yargs-parser": ">=5.0.0-security.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gulp-rtlcss": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "plugin-error": "^1.0.1", + "rtlcss": "^3.5.0", + "through2": "^2.0.5", + "vinyl-sourcemaps-apply": "^0.2.1" + } + }, + "node_modules/gulp-rtlcss/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-rtlcss/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/gulp-rtlcss/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-rtlcss/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/gulp-rtlcss/node_modules/through2": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/gulp-tap": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "through2": "^2.0.3" + } + }, + "node_modules/gulp-tap/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-tap/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/gulp-tap/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-tap/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/gulp-tap/node_modules/through2": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/gulp-uglify": { + "version": "3.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "array-each": "^1.0.1", + "extend-shallow": "^3.0.2", + "gulplog": "^1.0.0", + "has-gulplog": "^0.1.0", + "isobject": "^3.0.1", + "make-error-cause": "^1.1.1", + "safe-buffer": "^5.1.2", + "through2": "^2.0.0", + "uglify-js": "^3.0.5", + "vinyl-sourcemaps-apply": "^0.2.0" + } + }, + "node_modules/gulp-uglify/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-uglify/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/gulp-uglify/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-uglify/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/gulp-uglify/node_modules/through2": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/gulp-util": { + "version": "3.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "array-differ": "^1.0.0", + "array-uniq": "^1.0.2", + "beeper": "^1.0.0", + "chalk": "^1.0.0", + "dateformat": "^2.0.0", + "fancy-log": "^1.1.0", + "gulplog": "^1.0.0", + "has-gulplog": "^0.1.0", + "lodash._reescape": "^3.0.0", + "lodash._reevaluate": "^3.0.0", + "lodash._reinterpolate": "^3.0.0", + "lodash.template": "^3.0.0", + "minimist": "^1.1.0", + "multipipe": "^0.1.2", + "object-assign": "^3.0.0", + "replace-ext": "0.0.1", + "through2": "^2.0.0", + "vinyl": "^0.5.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/gulp-util/node_modules/ansi-regex": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-util/node_modules/ansi-styles": { + "version": "2.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-util/node_modules/chalk": { + "version": "1.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-util/node_modules/clone-stats": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-util/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-util/node_modules/lodash.template": { + "version": "3.6.2", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash._basecopy": "^3.0.0", + "lodash._basetostring": "^3.0.0", + "lodash._basevalues": "^3.0.0", + "lodash._isiterateecall": "^3.0.0", + "lodash._reinterpolate": "^3.0.0", + "lodash.escape": "^3.0.0", + "lodash.keys": "^3.0.0", + "lodash.restparam": "^3.0.0", + "lodash.templatesettings": "^3.0.0" + } + }, + "node_modules/gulp-util/node_modules/lodash.templatesettings": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash._reinterpolate": "^3.0.0", + "lodash.escape": "^3.0.0" + } + }, + "node_modules/gulp-util/node_modules/object-assign": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-util/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/gulp-util/node_modules/replace-ext": { + "version": "0.0.1", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gulp-util/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-util/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/gulp-util/node_modules/strip-ansi": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-util/node_modules/supports-color": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/gulp-util/node_modules/through2": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/gulp-util/node_modules/vinyl": { + "version": "0.5.3", + "dev": true, + "license": "MIT", + "dependencies": { + "clone": "^1.0.0", + "clone-stats": "^0.0.1", + "replace-ext": "0.0.1" + }, + "engines": { + "node": ">= 0.9" + } + }, + "node_modules/gulplog": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "glogg": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/handlebars": { + "version": "4.7.8", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/has-ansi": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-gulplog": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "sparkles": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "dev": true, + "license": "ISC" + }, + "node_modules/has-value": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/is-number": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/kind-of": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-yarn": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/homedir-polyfill": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-passwd": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "dev": true, + "license": "ISC" + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http2-wrapper": { + "version": "2.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/http2-wrapper/node_modules/quick-lru": { + "version": "5.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/husky": { + "version": "9.0.11", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.mjs" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-walk": { + "version": "6.0.4", + "dev": true, + "license": "ISC", + "dependencies": { + "minimatch": "^9.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/ignore-walk/node_modules/brace-expansion": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/ignore-walk/node_modules/minimatch": { + "version": "9.0.3", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/image-size": { + "version": "0.5.5", + "dev": true, + "license": "MIT", + "optional": true, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/import-lazy": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/import-meta-resolve": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/import-regex": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/infer-owner": { + "version": "1.0.4", + "dev": true, + "license": "ISC" + }, + "node_modules/inflight": { + "version": "1.0.6", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "dev": true, + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "dev": true, + "license": "ISC" + }, + "node_modules/inquirer": { + "version": "8.2.5", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/inquirer/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/inquirer/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/inquirer/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/inquirer/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/inquirer/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/internal-slot": { + "version": "1.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.2", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/interpret": { + "version": "1.4.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/invert-kv": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ip-regex": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-absolute": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-accessor-descriptor": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "dev": true, + "license": "MIT" + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "dev": true, + "license": "MIT" + }, + "node_modules/is-callable": { + "version": "1.2.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-ci": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ci-info": "^3.2.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-descriptor": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-descriptor": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extendable": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extendable/node_modules/is-plain-object": { + "version": "2.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-in-ci": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "bin": { + "is-in-ci": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-installed-globally": { + "version": "0.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-installed-globally/node_modules/global-dirs": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-installed-globally/node_modules/ini": { + "version": "2.0.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/is-map": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negated-glob": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-npm": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-path-cwd": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-relative": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-unc-path": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-set": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-ssh": { + "version": "1.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "protocols": "^2.0.1" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-text-path": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "text-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.12", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/is-unc-path": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "unc-path-regex": "^0.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-utf8": { + "version": "0.2.1", + "dev": true, + "license": "MIT" + }, + "node_modules/is-valid-glob": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-what": { + "version": "3.14.1", + "dev": true, + "license": "MIT" + }, + "node_modules/is-windows": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-wsl": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-yarn-global": { + "version": "0.4.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/isobject": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/issue-parser": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-7.0.1.tgz", + "integrity": "sha512-3YZcUUR2Wt1WsapF+S/WiA2WmlW0cWAoPccMqne7AxEBhCdFeTPjfv/Axb8V2gyCgY3nRw+ksZ3xSUX+R47iAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash.capitalize": "^4.2.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.uniqby": "^4.7.0" + }, + "engines": { + "node": "^18.17 || >=20.6.1" + } + }, + "node_modules/istextorbinary": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "binaryextensions": "^2.2.0", + "textextensions": "^3.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/iterate-iterator": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/iterate-value": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "es-get-iterator": "^1.0.2", + "iterate-iterator": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/jackspeak": { + "version": "2.3.6", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jiti": { + "version": "1.21.0", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/jju": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/jquery": { + "version": "3.7.1", + "dev": true, + "license": "MIT" + }, + "node_modules/js-beautify": { + "version": "1.15.1", + "dev": true, + "license": "MIT", + "dependencies": { + "config-chain": "^1.1.13", + "editorconfig": "^1.0.4", + "glob": "^10.3.3", + "js-cookie": "^3.0.5", + "nopt": "^7.2.0" + }, + "bin": { + "css-beautify": "js/bin/css-beautify.js", + "html-beautify": "js/bin/html-beautify.js", + "js-beautify": "js/bin/js-beautify.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/js-beautify/node_modules/abbrev": { + "version": "2.0.0", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/js-beautify/node_modules/brace-expansion": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/js-beautify/node_modules/glob": { + "version": "10.3.15", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.6", + "minimatch": "^9.0.1", + "minipass": "^7.0.4", + "path-scurry": "^1.11.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/js-beautify/node_modules/minimatch": { + "version": "9.0.4", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/js-beautify/node_modules/minipass": { + "version": "7.1.1", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/js-beautify/node_modules/nopt": { + "version": "7.2.1", + "dev": true, + "license": "ISC", + "dependencies": { + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/js-cookie": { + "version": "3.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-helpfulerror": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "jju": "^1.1.0" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "dev": true, + "license": "ISC" + }, + "node_modules/json5": { + "version": "2.2.3", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonlines": { + "version": "0.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "dev": true, + "engines": [ + "node >= 0.2.0" + ], + "license": "MIT" + }, + "node_modules/JSONStream": { + "version": "1.3.5", + "dev": true, + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/just-debounce": { + "version": "1.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "5.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "4.1.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/last-run": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "default-resolution": "^2.0.0", + "es6-weak-map": "^2.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/latest-version": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "package-json": "^8.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lazystream": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/lazystream/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/lazystream/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/lazystream/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/lazystream/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/lcid": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "invert-kv": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lead": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "flush-write-stream": "^1.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/less": { + "version": "4.2.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "copy-anything": "^2.0.1", + "parse-node-version": "^1.0.1", + "tslib": "^2.3.0" + }, + "bin": { + "lessc": "bin/lessc" + }, + "engines": { + "node": ">=6" + }, + "optionalDependencies": { + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^3.1.0", + "source-map": "~0.6.0" + } + }, + "node_modules/liftoff": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "extend": "^3.0.0", + "findup-sync": "^3.0.0", + "fined": "^1.0.1", + "flagged-respawn": "^1.0.0", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.0", + "rechoir": "^0.6.2", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/liftoff/node_modules/braces": { + "version": "2.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/liftoff/node_modules/braces/node_modules/extend-shallow": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/liftoff/node_modules/fill-range": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/liftoff/node_modules/fill-range/node_modules/extend-shallow": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/liftoff/node_modules/findup-sync": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/liftoff/node_modules/is-extendable": { + "version": "0.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/liftoff/node_modules/is-number": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/liftoff/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/liftoff/node_modules/is-plain-object": { + "version": "2.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/liftoff/node_modules/kind-of": { + "version": "6.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/liftoff/node_modules/micromatch": { + "version": "3.1.10", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/liftoff/node_modules/to-regex-range": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lilconfig": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "dev": true, + "license": "MIT" + }, + "node_modules/lint-staged": { + "version": "15.2.7", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "~5.3.0", + "commander": "~12.1.0", + "debug": "~4.3.4", + "execa": "~8.0.1", + "lilconfig": "~3.1.1", + "listr2": "~8.2.1", + "micromatch": "~4.0.7", + "pidtree": "~0.6.0", + "string-argv": "~0.3.2", + "yaml": "~2.4.2" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/lint-staged/node_modules/chalk": { + "version": "5.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/execa": { + "version": "8.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/get-stream": { + "version": "8.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/human-signals": { + "version": "5.0.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/lint-staged/node_modules/is-stream": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/mimic-fn": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/npm-run-path": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/onetime": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/path-key": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/signal-exit": { + "version": "4.1.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/lint-staged/node_modules/strip-final-newline": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2": { + "version": "8.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.0.0", + "rfdc": "^1.3.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/listr2/node_modules/ansi-regex": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/listr2/node_modules/ansi-styles": { + "version": "6.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/listr2/node_modules/emoji-regex": { + "version": "10.3.0", + "dev": true, + "license": "MIT" + }, + "node_modules/listr2/node_modules/string-width": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2/node_modules/strip-ansi": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/listr2/node_modules/wrap-ansi": { + "version": "9.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/load-json-file": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/load-json-file/node_modules/parse-json": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "error-ex": "^1.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/load-json-file/node_modules/pify": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/load-json-file/node_modules/strip-bom": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-utf8": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash._baseassign": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash._basecopy": "^3.0.0", + "lodash.keys": "^3.0.0" + } + }, + "node_modules/lodash._basecopy": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash._basetostring": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash._basevalues": { + "version": "3.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash._bindcallback": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash._createassigner": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash._bindcallback": "^3.0.0", + "lodash._isiterateecall": "^3.0.0", + "lodash.restparam": "^3.0.0" + } + }, + "node_modules/lodash._getnative": { + "version": "3.9.1", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash._isiterateecall": { + "version": "3.0.9", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash._isnative": { + "version": "2.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash._objecttypes": { + "version": "2.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash._reescape": { + "version": "3.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash._reevaluate": { + "version": "3.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash._reinterpolate": { + "version": "3.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash._root": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash._shimkeys": { + "version": "2.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash._objecttypes": "~2.4.1" + } + }, + "node_modules/lodash.assign": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash._baseassign": "^3.0.0", + "lodash._createassigner": "^3.0.0", + "lodash.keys": "^3.0.0" + } + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.capitalize": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz", + "integrity": "sha512-kZzYOKspf8XVX5AvmQF94gQW0lejFVgb80G85bU4ZWzoJ6C03PQg3coYAUpSTpQWelrZELd3XWgHzw4Ck5kaIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.defaults": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash.assign": "^3.0.0", + "lodash.restparam": "^3.0.0" + } + }, + "node_modules/lodash.escape": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash._root": "^3.0.0" + } + }, + "node_modules/lodash.escaperegexp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", + "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isarguments": { + "version": "3.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isarray": { + "version": "3.0.4", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isobject": { + "version": "2.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash._objecttypes": "~2.4.1" + } + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.kebabcase": { + "version": "4.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.keys": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + } + }, + "node_modules/lodash.map": { + "version": "4.6.0", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.mergewith": { + "version": "4.6.2", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.restparam": { + "version": "3.6.1", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.snakecase": { + "version": "4.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.startcase": { + "version": "4.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.template": { + "version": "4.5.0", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash._reinterpolate": "^3.0.0", + "lodash.templatesettings": "^4.0.0" + } + }, + "node_modules/lodash.templatesettings": { + "version": "4.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash._reinterpolate": "^3.0.0" + } + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.uniqby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", + "integrity": "sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.upperfirst": { + "version": "4.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-update": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^6.2.0", + "cli-cursor": "^4.0.0", + "slice-ansi": "^7.0.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-escapes": { + "version": "6.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-regex": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "6.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-update/node_modules/cli-cursor": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/emoji-regex": { + "version": "10.3.0", + "dev": true, + "license": "MIT" + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/restore-cursor": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/string-width": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/strip-ansi": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "9.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/longest": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lowercase-keys": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/macos-release": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "5.7.2", + "dev": true, + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "dev": true, + "license": "ISC" + }, + "node_modules/make-error-cause": { + "version": "1.2.2", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "make-error": "^1.2.0" + } + }, + "node_modules/make-fetch-happen": { + "version": "11.1.1", + "dev": true, + "license": "ISC", + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^5.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/agent-base": { + "version": "6.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/http-proxy-agent": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/make-fetch-happen/node_modules/https-proxy-agent": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/make-fetch-happen/node_modules/lru-cache": { + "version": "7.18.3", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/make-fetch-happen/node_modules/socks-proxy-agent": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/make-iterator": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/make-iterator/node_modules/kind-of": { + "version": "6.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-cache": { + "version": "0.2.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-stream": { + "version": "0.1.0", + "dev": true + }, + "node_modules/map-visit": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "findup-sync": "^2.0.0", + "micromatch": "^3.0.4", + "resolve": "^1.4.0", + "stack-trace": "0.0.10" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/matchdep/node_modules/braces": { + "version": "2.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/node_modules/braces/node_modules/extend-shallow": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/node_modules/fill-range": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/node_modules/fill-range/node_modules/extend-shallow": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/node_modules/findup-sync": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^3.1.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/matchdep/node_modules/is-extendable": { + "version": "0.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/node_modules/is-glob": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/node_modules/is-number": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/node_modules/kind-of": { + "version": "6.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/node_modules/micromatch": { + "version": "3.1.10", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/node_modules/to-regex-range": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/meow": { + "version": "12.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge": { + "version": "2.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "dev": true, + "license": "MIT", + "optional": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-response": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.7", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "5.0.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-collect/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-fetch": { + "version": "3.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/minipass-fetch/node_modules/minipass": { + "version": "7.0.4", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-json-stream": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "node_modules/minipass-json-stream/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mixin-deep": { + "version": "1.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/multipipe": { + "version": "0.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "duplexer2": "0.0.2" + } + }, + "node_modules/mute-stdout": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "dev": true, + "license": "ISC" + }, + "node_modules/nanoid": { + "version": "3.3.7", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/nanomatch": { + "version": "1.2.13", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/kind-of": { + "version": "6.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/needle": { + "version": "3.3.1", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, + "node_modules/needle/node_modules/iconv-lite": { + "version": "0.6.3", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "dev": true, + "license": "MIT" + }, + "node_modules/netmask": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/new-github-release-url": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^2.5.1" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/new-github-release-url/node_modules/type-fest": { + "version": "2.19.0", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/next-tick": { + "version": "1.1.0", + "dev": true, + "license": "ISC" + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/node-gyp": { + "version": "9.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^10.0.3", + "nopt": "^6.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^12.13 || ^14.13 || >=16" + } + }, + "node_modules/node-gyp/node_modules/@npmcli/fs": { + "version": "2.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/node-gyp/node_modules/agent-base": { + "version": "6.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/node-gyp/node_modules/brace-expansion": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/node-gyp/node_modules/cacache": { + "version": "16.1.3", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", + "infer-owner": "^1.0.4", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/node-gyp/node_modules/cacache/node_modules/glob": { + "version": "8.1.0", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-gyp/node_modules/fs-minipass": { + "version": "2.1.0", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/node-gyp/node_modules/http-proxy-agent": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/node-gyp/node_modules/https-proxy-agent": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/node-gyp/node_modules/lru-cache": { + "version": "7.18.3", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/node-gyp/node_modules/make-fetch-happen": { + "version": "10.2.1", + "dev": true, + "license": "ISC", + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^16.1.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^2.0.3", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^9.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/node-gyp/node_modules/minimatch": { + "version": "5.1.6", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-gyp/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/node-gyp/node_modules/minipass-fetch": { + "version": "2.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/node-gyp/node_modules/rimraf": { + "version": "3.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-gyp/node_modules/socks-proxy-agent": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/node-gyp/node_modules/ssri": { + "version": "9.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/node-gyp/node_modules/unique-filename": { + "version": "2.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "unique-slug": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/node-gyp/node_modules/unique-slug": { + "version": "3.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/node-gyp/node_modules/which": { + "version": "2.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/node-releases": { + "version": "2.0.14", + "dev": true, + "license": "MIT" + }, + "node_modules/nopt": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "abbrev": "^1.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.2", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "8.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/now-and-later": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.3.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/npm-bundled": { + "version": "3.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-check-updates": { + "version": "16.14.20", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/semver-utils": "^1.1.1", + "chalk": "^5.3.0", + "cli-table3": "^0.6.3", + "commander": "^10.0.1", + "fast-memoize": "^2.5.2", + "find-up": "5.0.0", + "fp-and-or": "^0.1.4", + "get-stdin": "^8.0.0", + "globby": "^11.0.4", + "hosted-git-info": "^5.1.0", + "ini": "^4.1.1", + "js-yaml": "^4.1.0", + "json-parse-helpfulerror": "^1.0.3", + "jsonlines": "^0.1.1", + "lodash": "^4.17.21", + "make-fetch-happen": "^11.1.1", + "minimatch": "^9.0.3", + "p-map": "^4.0.0", + "pacote": "15.2.0", + "parse-github-url": "^1.0.2", + "progress": "^2.0.3", + "prompts-ncu": "^3.0.0", + "rc-config-loader": "^4.1.3", + "remote-git-tags": "^3.0.0", + "rimraf": "^5.0.5", + "semver": "^7.5.4", + "semver-utils": "^1.1.4", + "source-map-support": "^0.5.21", + "spawn-please": "^2.0.2", + "strip-ansi": "^7.1.0", + "strip-json-comments": "^5.0.1", + "untildify": "^4.0.0", + "update-notifier": "^6.0.2" + }, + "bin": { + "ncu": "build/src/bin/cli.js", + "npm-check-updates": "build/src/bin/cli.js" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/npm-check-updates/node_modules/ansi-regex": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/npm-check-updates/node_modules/brace-expansion": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/npm-check-updates/node_modules/chalk": { + "version": "5.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/npm-check-updates/node_modules/commander": { + "version": "10.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/npm-check-updates/node_modules/globby": { + "version": "11.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-check-updates/node_modules/hosted-git-info": { + "version": "5.2.1", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^7.5.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-check-updates/node_modules/ini": { + "version": "4.1.1", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-check-updates/node_modules/lru-cache": { + "version": "7.18.3", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/npm-check-updates/node_modules/minimatch": { + "version": "9.0.3", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm-check-updates/node_modules/slash": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm-check-updates/node_modules/strip-ansi": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/npm-check-updates/node_modules/strip-json-comments": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-check-updates/node_modules/update-notifier": { + "version": "6.0.2", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boxen": "^7.0.0", + "chalk": "^5.0.1", + "configstore": "^6.0.0", + "has-yarn": "^3.0.0", + "import-lazy": "^4.0.0", + "is-ci": "^3.0.1", + "is-installed-globally": "^0.4.0", + "is-npm": "^6.0.0", + "is-yarn-global": "^0.4.0", + "latest-version": "^7.0.0", + "pupa": "^3.1.0", + "semver": "^7.3.7", + "semver-diff": "^4.0.0", + "xdg-basedir": "^5.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/yeoman/update-notifier?sponsor=1" + } + }, + "node_modules/npm-install-checks": { + "version": "6.3.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "3.0.1", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-package-arg": { + "version": "10.1.0", + "dev": true, + "license": "ISC", + "dependencies": { + "hosted-git-info": "^6.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-package-arg/node_modules/hosted-git-info": { + "version": "6.1.1", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^7.5.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-package-arg/node_modules/lru-cache": { + "version": "7.18.3", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/npm-packlist": { + "version": "7.0.4", + "dev": true, + "license": "ISC", + "dependencies": { + "ignore-walk": "^6.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-pick-manifest": { + "version": "8.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^10.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-registry-fetch": { + "version": "14.0.5", + "dev": true, + "license": "ISC", + "dependencies": { + "make-fetch-happen": "^11.0.0", + "minipass": "^5.0.0", + "minipass-fetch": "^3.0.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^10.0.0", + "proc-log": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npmlog": { + "version": "6.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/define-property": { + "version": "0.2.5", + "dev": true, + "license": "MIT", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-descriptor": { + "version": "0.1.7", + "dev": true, + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object-copy/node_modules/kind-of": { + "version": "3.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object-visit": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.defaults": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.map": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.pick": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.reduce": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "10.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ora/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/ora/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/ora/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ora/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ordered-read-streams": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "^2.0.1" + } + }, + "node_modules/ordered-read-streams/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/ordered-read-streams/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/ordered-read-streams/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/ordered-read-streams/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/os-locale": { + "version": "1.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "lcid": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/os-name": { + "version": "5.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "macos-release": "^3.1.0", + "windows-release": "^5.0.1" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-cancelable": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pac-proxy-agent": { + "version": "7.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.2", + "pac-resolver": "^7.0.0", + "socks-proxy-agent": "^8.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-resolver": { + "version": "7.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "degenerator": "^5.0.0", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/package-json": { + "version": "8.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "got": "^12.1.0", + "registry-auth-token": "^5.0.1", + "registry-url": "^6.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json/node_modules/got": { + "version": "12.6.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/pacote": { + "version": "15.2.0", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^4.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/promise-spawn": "^6.0.1", + "@npmcli/run-script": "^6.0.0", + "cacache": "^17.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^5.0.0", + "npm-package-arg": "^10.0.0", + "npm-packlist": "^7.0.0", + "npm-pick-manifest": "^8.0.0", + "npm-registry-fetch": "^14.0.0", + "proc-log": "^3.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^6.0.0", + "read-package-json-fast": "^3.0.0", + "sigstore": "^1.3.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "lib/bin.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-filepath": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-absolute": "^1.0.0", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/parse-github-url": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "bin": { + "parse-github-url": "cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/parse-import": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "get-imports": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-node-version": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/parse-passwd": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/parse-path": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "protocols": "^2.0.0" + } + }, + "node_modules/parse-url": { + "version": "8.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-path": "^7.0.0" + } + }, + "node_modules/pascalcase": { + "version": "0.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-dirname": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "dev": true, + "license": "MIT" + }, + "node_modules/path-root": { + "version": "0.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "path-root-regex": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-root-regex": { + "version": "0.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.2.0", + "dev": true, + "license": "ISC", + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "0.6.0", + "dev": true, + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/plugin-error": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^1.0.1", + "arr-diff": "^4.0.0", + "arr-union": "^3.1.0", + "extend-shallow": "^3.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/posix-character-classes": { + "version": "0.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss": { + "version": "8.4.38", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/prettier": { + "version": "3.3.2", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/pretty-hrtime": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/proc-log": { + "version": "3.0.0", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/progress": { + "version": "2.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "dev": true, + "license": "ISC" + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/promise-retry/node_modules/retry": { + "version": "0.12.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/promise.allsettled": { + "version": "1.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "array.prototype.map": "^1.0.5", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "iterate-value": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/prompts-ncu": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^4.0.1", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proto-list": { + "version": "1.2.4", + "dev": true, + "license": "ISC" + }, + "node_modules/protocols": { + "version": "2.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/proxy-agent": { + "version": "6.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.3", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.0.1", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/lru-cache": { + "version": "7.18.3", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/prr": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/pump": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/pumpify": { + "version": "1.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pupa": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-goat": "^4.0.0" + }, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/rc": { + "version": "1.2.8", + "dev": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc-config-loader": { + "version": "4.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "js-yaml": "^4.1.0", + "json5": "^2.2.2", + "require-from-string": "^2.0.2" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-package-json": { + "version": "6.0.4", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^10.2.2", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^5.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-package-json-fast": { + "version": "3.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-package-json-fast/node_modules/json-parse-even-better-errors": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-package-json/node_modules/brace-expansion": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/read-package-json/node_modules/glob": { + "version": "10.3.10", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/read-package-json/node_modules/hosted-git-info": { + "version": "6.1.1", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^7.5.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-package-json/node_modules/json-parse-even-better-errors": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-package-json/node_modules/lru-cache": { + "version": "7.18.3", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/read-package-json/node_modules/minimatch": { + "version": "9.0.3", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/read-package-json/node_modules/normalize-package-data": { + "version": "5.0.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^6.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-pkg": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg-up": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg-up/node_modules/path-exists": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg/node_modules/path-type": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg/node_modules/pify": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "2.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/readdirp/node_modules/braces": { + "version": "2.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readdirp/node_modules/braces/node_modules/extend-shallow": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readdirp/node_modules/fill-range": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readdirp/node_modules/fill-range/node_modules/extend-shallow": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readdirp/node_modules/is-extendable": { + "version": "0.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readdirp/node_modules/is-number": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readdirp/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readdirp/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/readdirp/node_modules/kind-of": { + "version": "6.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readdirp/node_modules/micromatch": { + "version": "3.1.10", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readdirp/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readdirp/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/readdirp/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/readdirp/node_modules/to-regex-range": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rechoir": { + "version": "0.6.2", + "dev": true, + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/regex-not": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "set-function-name": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/registry-auth-token": { + "version": "5.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@pnpm/npm-conf": "^2.1.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/registry-url": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "rc": "1.2.8" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/release-it": { + "version": "17.4.0", + "resolved": "https://registry.npmjs.org/release-it/-/release-it-17.4.0.tgz", + "integrity": "sha512-tYnk1tS530TLQtV8UQ+6OCiV3opVtkgwmLOpjXeV63ZtlZpSAGLZCXrA/I6ywiYKcEQWxW8WV7YJQvdxxGNZSg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/webpro" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/webpro" + } + ], + "license": "MIT", + "dependencies": { + "@iarna/toml": "2.2.5", + "@octokit/rest": "20.1.1", + "async-retry": "1.3.3", + "chalk": "5.3.0", + "cosmiconfig": "9.0.0", + "execa": "8.0.1", + "git-url-parse": "14.0.0", + "globby": "14.0.1", + "got": "13.0.0", + "inquirer": "9.2.23", + "is-ci": "3.0.1", + "issue-parser": "7.0.1", + "lodash": "4.17.21", + "mime-types": "2.1.35", + "new-github-release-url": "2.0.0", + "node-fetch": "3.3.2", + "open": "10.1.0", + "ora": "8.0.1", + "os-name": "5.1.0", + "promise.allsettled": "1.0.7", + "proxy-agent": "6.4.0", + "semver": "7.6.2", + "shelljs": "0.8.5", + "update-notifier": "7.0.0", + "url-join": "5.0.0", + "wildcard-match": "5.1.3", + "yargs-parser": "21.1.1" + }, + "bin": { + "release-it": "bin/release-it.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || ^22.0.0" + } + }, + "node_modules/release-it/node_modules/ansi-regex": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/release-it/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/release-it/node_modules/chalk": { + "version": "5.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/release-it/node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 12" + } + }, + "node_modules/release-it/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/release-it/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/release-it/node_modules/emoji-regex": { + "version": "10.3.0", + "dev": true, + "license": "MIT" + }, + "node_modules/release-it/node_modules/execa": { + "version": "8.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/release-it/node_modules/get-stream": { + "version": "8.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/release-it/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/release-it/node_modules/human-signals": { + "version": "5.0.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/release-it/node_modules/inquirer": { + "version": "9.2.23", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.23.tgz", + "integrity": "sha512-kod5s+FBPIDM2xiy9fu+6wdU/SkK5le5GS9lh4FEBjBHqiMgD9lLFbCbuqFNAjNL2ZOy9Wd9F694IOzN9pZHBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/figures": "^1.0.3", + "@ljharb/through": "^2.3.13", + "ansi-escapes": "^4.3.2", + "chalk": "^5.3.0", + "cli-cursor": "^3.1.0", + "cli-width": "^4.1.0", + "external-editor": "^3.1.0", + "lodash": "^4.17.21", + "mute-stream": "1.0.0", + "ora": "^5.4.1", + "run-async": "^3.0.0", + "rxjs": "^7.8.1", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/release-it/node_modules/inquirer/node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/release-it/node_modules/inquirer/node_modules/ora/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/release-it/node_modules/is-stream": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/release-it/node_modules/mimic-fn": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/release-it/node_modules/mute-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", + "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/release-it/node_modules/npm-run-path": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/release-it/node_modules/onetime": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/release-it/node_modules/ora": { + "version": "8.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "cli-cursor": "^4.0.0", + "cli-spinners": "^2.9.2", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^2.0.0", + "log-symbols": "^6.0.0", + "stdin-discarder": "^0.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/release-it/node_modules/ora/node_modules/cli-cursor": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/release-it/node_modules/ora/node_modules/is-interactive": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/release-it/node_modules/ora/node_modules/is-unicode-supported": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/release-it/node_modules/ora/node_modules/log-symbols": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "is-unicode-supported": "^1.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/release-it/node_modules/ora/node_modules/log-symbols/node_modules/is-unicode-supported": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/release-it/node_modules/ora/node_modules/string-width": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/release-it/node_modules/ora/node_modules/strip-ansi": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/release-it/node_modules/path-key": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/release-it/node_modules/restore-cursor": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/release-it/node_modules/restore-cursor/node_modules/mimic-fn": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/release-it/node_modules/restore-cursor/node_modules/onetime": { + "version": "5.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/release-it/node_modules/restore-cursor/node_modules/signal-exit": { + "version": "3.0.7", + "dev": true, + "license": "ISC" + }, + "node_modules/release-it/node_modules/run-async": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", + "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/release-it/node_modules/signal-exit": { + "version": "4.1.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/release-it/node_modules/strip-final-newline": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/release-it/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/release-it/node_modules/url-join": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/release-it/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/remote-git-tags": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/remove-bom-buffer": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5", + "is-utf8": "^0.2.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/remove-bom-stream": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "remove-bom-buffer": "^3.0.0", + "safe-buffer": "^5.1.0", + "through2": "^2.0.3" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/remove-bom-stream/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/remove-bom-stream/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/remove-bom-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/remove-bom-stream/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/remove-bom-stream/node_modules/through2": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/remove-trailing-separator": { + "version": "1.1.0", + "dev": true, + "license": "ISC" + }, + "node_modules/repeat-element": { + "version": "1.1.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/replace-ext": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/replace-homedir": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "homedir-polyfill": "^1.0.1", + "is-absolute": "^1.0.0", + "remove-trailing-separator": "^1.1.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/replacestream": { + "version": "4.0.3", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "escape-string-regexp": "^1.0.3", + "object-assign": "^4.0.1", + "readable-stream": "^2.0.2" + } + }, + "node_modules/replacestream/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/replacestream/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/replacestream/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/replacestream/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/require-dir": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-dot-file": { + "version": "0.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "1.0.1", + "dev": true, + "license": "ISC" + }, + "node_modules/resolve": { + "version": "1.22.8", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "dev": true, + "license": "MIT" + }, + "node_modules/resolve-dir": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-options": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "value-or-function": "^3.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/resolve-url": { + "version": "0.2.1", + "dev": true, + "license": "MIT" + }, + "node_modules/responselike": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "lowercase-keys": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ret": { + "version": "0.1.15", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rework": { + "version": "1.0.1", + "dev": true, + "dependencies": { + "convert-source-map": "^0.3.3", + "css": "^2.0.0" + } + }, + "node_modules/rework-import": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "css": "^2.0.0", + "globby": "^2.0.0", + "parse-import": "^2.0.0", + "url-regex": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rework-import/node_modules/array-union": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "array-uniq": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rework-import/node_modules/glob": { + "version": "5.0.15", + "dev": true, + "license": "ISC", + "dependencies": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/rework-import/node_modules/globby": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^1.0.1", + "async": "^1.2.1", + "glob": "^5.0.3", + "object-assign": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rework-import/node_modules/object-assign": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rework-plugin-function": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "rework-visit": "^1.0.0" + } + }, + "node_modules/rework-plugin-url": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "rework-plugin-function": "^1.0.0" + } + }, + "node_modules/rework-visit": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/rfdc": { + "version": "1.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/rimraf": { + "version": "5.0.5", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "10.3.10", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "9.0.3", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rtlcss": { + "version": "3.5.0", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^5.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.3.11", + "strip-json-comments": "^3.1.1" + }, + "bin": { + "rtlcss": "bin/rtlcss.js" + } + }, + "node_modules/run-applescript": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-async": { + "version": "2.4.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.1", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-array-concat": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-regex": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ret": "~0.1.10" + } + }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/sax": { + "version": "1.3.0", + "dev": true, + "license": "ISC", + "optional": true + }, + "node_modules/semver": { + "version": "7.6.2", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-diff": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semver-greatest-satisfied-range": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "sver-compat": "^1.5.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/semver-utils": { + "version": "1.1.4", + "dev": true, + "license": "APACHEv2" + }, + "node_modules/server": { + "resolved": "pkg/cmd/server", + "link": true + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-value": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/set-value/node_modules/extend-shallow": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/set-value/node_modules/is-extendable": { + "version": "0.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/set-value/node_modules/is-plain-object": { + "version": "2.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shelljs": { + "version": "0.8.5", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "dev": true, + "license": "ISC" + }, + "node_modules/sigstore": { + "version": "1.9.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^1.1.0", + "@sigstore/protobuf-specs": "^0.2.0", + "@sigstore/sign": "^1.0.0", + "@sigstore/tuf": "^1.0.3", + "make-fetch-happen": "^11.0.1" + }, + "bin": { + "sigstore": "bin/sigstore.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/slash": { + "version": "5.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/snapdragon": { + "version": "0.8.2", + "dev": true, + "license": "MIT", + "dependencies": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/define-property": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^3.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util/node_modules/kind-of": { + "version": "3.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/debug": { + "version": "2.6.9", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/snapdragon/node_modules/define-property": { + "version": "0.2.5", + "dev": true, + "license": "MIT", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/extend-shallow": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-descriptor": { + "version": "0.1.7", + "dev": true, + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/snapdragon/node_modules/is-extendable": { + "version": "0.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/ms": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/snapdragon/node_modules/source-map": { + "version": "0.5.7", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/socks": { + "version": "2.7.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "socks": "^2.7.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/socks/node_modules/ip": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.0", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-resolve": { + "version": "0.5.3", + "dev": true, + "license": "MIT", + "dependencies": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-url": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/sparkles": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/spawn-please": { + "version": "2.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "dev": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.16", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/split-string": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "extend-shallow": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/ssri": { + "version": "10.0.5", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/ssri/node_modules/minipass": { + "version": "7.0.4", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/stat-mode": { + "version": "0.2.2", + "dev": true, + "license": "MIT" + }, + "node_modules/static-extend": { + "version": "0.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/define-property": { + "version": "0.2.5", + "dev": true, + "license": "MIT", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-descriptor": { + "version": "0.1.7", + "dev": true, + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/stdin-discarder": { + "version": "0.2.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stop-iteration-iterator": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "internal-slot": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/stream-exhaust": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/stream-shift": { + "version": "1.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-argv": { + "version": "0.3.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom-buf": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-utf8": "^0.2.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-bom-stream": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "first-chunk-stream": "^2.0.0", + "strip-bom-buf": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sver-compat": { + "version": "1.5.0", + "dev": true, + "license": "MIT", + "dependencies": { + "es6-iterator": "^2.0.1", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/tar": { + "version": "6.2.0", + "dev": true, + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ternary-stream": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "duplexify": "^3.5.0", + "fork-stream": "^0.0.4", + "merge-stream": "^1.0.0", + "through2": "^2.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/ternary-stream/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/ternary-stream/node_modules/merge-stream": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "^2.0.1" + } + }, + "node_modules/ternary-stream/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/ternary-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/ternary-stream/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/ternary-stream/node_modules/through2": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/text-extensions": { + "version": "2.4.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/textextensions": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/through": { + "version": "2.3.8", + "dev": true, + "license": "MIT" + }, + "node_modules/through2": { + "version": "4.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "3" + } + }, + "node_modules/through2-filter": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "through2": "~2.0.0", + "xtend": "~4.0.0" + } + }, + "node_modules/through2-filter/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/through2-filter/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/through2-filter/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/through2-filter/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/through2-filter/node_modules/through2": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/time-stamp": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tmp": { + "version": "0.0.33", + "dev": true, + "license": "MIT", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-absolute-glob": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-absolute": "^1.0.0", + "is-negated-glob": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-object-path": { + "version": "0.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-object-path/node_modules/kind-of": { + "version": "3.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex": { + "version": "3.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/to-through": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "through2": "^2.0.3" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/to-through/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/to-through/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/to-through/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/to-through/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/to-through/node_modules/through2": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/tslib": { + "version": "2.6.2", + "dev": true, + "license": "0BSD" + }, + "node_modules/tuf-js": { + "version": "1.1.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@tufjs/models": "1.0.4", + "debug": "^4.3.4", + "make-fetch-happen": "^11.1.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/tunnel": { + "version": "0.0.6", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } + }, + "node_modules/type": { + "version": "2.7.2", + "dev": true, + "license": "ISC" + }, + "node_modules/type-fest": { + "version": "0.21.3", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/uglify-js": { + "version": "3.17.4", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/unc-path-regex": { + "version": "0.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/undertaker": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "bach": "^1.0.0", + "collection-map": "^1.0.0", + "es6-weak-map": "^2.0.1", + "fast-levenshtein": "^1.0.0", + "last-run": "^1.1.0", + "object.defaults": "^1.0.0", + "object.reduce": "^1.0.0", + "undertaker-registry": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/undertaker-registry": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/undici": { + "version": "5.28.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "dev": true, + "license": "MIT" + }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/union-value": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/union-value/node_modules/is-extendable": { + "version": "0.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unique-filename": { + "version": "3.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/unique-slug": { + "version": "4.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/unique-stream": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "json-stable-stringify-without-jsonify": "^1.0.1", + "through2-filter": "^3.0.0" + } + }, + "node_modules/unique-string": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "crypto-random-string": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/universal-user-agent": { + "version": "6.0.1", + "dev": true, + "license": "ISC" + }, + "node_modules/universalify": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unset-value": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value": { + "version": "0.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "isarray": "1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-values": { + "version": "0.1.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/untildify": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/upath": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.15", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/update-notifier": { + "version": "7.0.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boxen": "^7.1.1", + "chalk": "^5.3.0", + "configstore": "^6.0.0", + "import-lazy": "^4.0.0", + "is-in-ci": "^0.1.0", + "is-installed-globally": "^0.4.0", + "is-npm": "^6.0.0", + "latest-version": "^7.0.0", + "pupa": "^3.1.0", + "semver": "^7.5.4", + "semver-diff": "^4.0.0", + "xdg-basedir": "^5.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/yeoman/update-notifier?sponsor=1" + } + }, + "node_modules/update-notifier/node_modules/chalk": { + "version": "5.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/urix": { + "version": "0.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/url-regex": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ip-regex": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/use": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/uuid": { + "version": "8.3.2", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8flags": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "5.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "builtins": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/value-or-function": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vinyl": { + "version": "2.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "clone": "^2.1.1", + "clone-buffer": "^1.0.0", + "clone-stats": "^1.0.0", + "cloneable-readable": "^1.0.0", + "remove-trailing-separator": "^1.0.1", + "replace-ext": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vinyl-fs": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "fs-mkdirp-stream": "^1.0.0", + "glob-stream": "^6.1.0", + "graceful-fs": "^4.0.0", + "is-valid-glob": "^1.0.0", + "lazystream": "^1.0.0", + "lead": "^1.0.0", + "object.assign": "^4.0.4", + "pumpify": "^1.3.5", + "readable-stream": "^2.3.3", + "remove-bom-buffer": "^3.0.0", + "remove-bom-stream": "^1.2.0", + "resolve-options": "^1.1.0", + "through2": "^2.0.0", + "to-through": "^2.0.0", + "value-or-function": "^3.0.0", + "vinyl": "^2.0.0", + "vinyl-sourcemap": "^1.1.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vinyl-fs/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/vinyl-fs/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/vinyl-fs/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/vinyl-fs/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/vinyl-fs/node_modules/through2": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/vinyl-sourcemap": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "append-buffer": "^1.0.2", + "convert-source-map": "^1.5.0", + "graceful-fs": "^4.1.6", + "normalize-path": "^2.1.1", + "now-and-later": "^2.0.0", + "remove-bom-buffer": "^3.0.0", + "vinyl": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vinyl-sourcemap/node_modules/convert-source-map": { + "version": "1.9.0", + "dev": true, + "license": "MIT" + }, + "node_modules/vinyl-sourcemap/node_modules/normalize-path": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/vinyl-sourcemaps-apply": { + "version": "0.2.1", + "dev": true, + "license": "ISC", + "dependencies": { + "source-map": "^0.5.1" + } + }, + "node_modules/vinyl-sourcemaps-apply/node_modules/source-map": { + "version": "0.5.7", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/vinyl/node_modules/clone": { + "version": "2.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "1.3.1", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-module": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/which-typed-array": { + "version": "1.1.13", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.4", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/widest-line": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/widest-line/node_modules/ansi-regex": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/widest-line/node_modules/emoji-regex": { + "version": "9.2.2", + "dev": true, + "license": "MIT" + }, + "node_modules/widest-line/node_modules/string-width": { + "version": "5.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/widest-line/node_modules/strip-ansi": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/wildcard-match": { + "version": "5.1.3", + "dev": true, + "license": "ISC" + }, + "node_modules/windows-release": { + "version": "5.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.1.1" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "dev": true, + "license": "ISC" + }, + "node_modules/wrench-sui": { + "version": "0.0.3", + "dev": true, + "engines": { + "node": ">=0.1.97" + } + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/xdg-basedir": { + "version": "5.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/yaml": { + "version": "2.4.2", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yamljs": { + "version": "0.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "glob": "^7.0.5" + }, + "bin": { + "json2yaml": "bin/json2yaml", + "yaml2json": "bin/yaml2json" + } + }, + "node_modules/yamljs/node_modules/argparse": { + "version": "1.0.10", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "pkg/cmd/server": { + "devDependencies": { + "fomantic-ui": "2.9.3", + "jquery": "3.7.1", + "lodash": "4.17.21" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..b48bfdc --- /dev/null +++ b/package.json @@ -0,0 +1,138 @@ +{ + "private": true, + "name": "codexgo", + "version": "4.3.0", + "description": "codexGO", + "author": "Bastean ", + "license": "MIT", + "homepage": "https://github.com/bastean/codexgo#readme", + "repository": { + "type": "git", + "url": "https://github.com/bastean/codexgo.git" + }, + "bugs": { + "url": "https://github.com/bastean/codexgo/issues" + }, + "engines": { + "node": ">=20", + "npm": ">=10" + }, + "workspaces": [ + "pkg/cmd/*" + ], + "devDependencies": { + "@commitlint/cli": "19.3.0", + "@commitlint/config-conventional": "19.2.2", + "@release-it/bumper": "6.0.1", + "@release-it/conventional-changelog": "8.0.1", + "commitizen": "4.3.0", + "cz-conventional-changelog": "3.3.0", + "husky": "9.0.11", + "lint-staged": "15.2.7", + "npm-check-updates": "16.14.20", + "prettier": "3.3.2", + "release-it": "17.4.0" + }, + "lint-staged": { + "**/*": [ + "trufflehog filesystem --no-update", + "prettier --ignore-unknown --write" + ], + "**/*.go": [ + "gofmt -l -s -w" + ] + }, + "config": { + "commitizen": { + "path": "cz-conventional-changelog" + } + }, + "commitlint": { + "extends": [ + "@commitlint/config-conventional" + ] + }, + "release-it": { + "git": { + "requireBranch": "main", + "commitMessage": "chore(release): v${version}", + "tagAnnotation": "codexgo ${version}", + "tagName": "v${version}" + }, + "github": { + "release": true, + "releaseName": "v${version}" + }, + "plugins": { + "@release-it/conventional-changelog": { + "preset": { + "name": "conventionalcommits", + "types": [ + { + "type": "build", + "section": "Builds" + }, + { + "type": "chore", + "section": "Chores" + }, + { + "type": "ci", + "section": "Continuous Integration" + }, + { + "type": "docs", + "section": "Documentation" + }, + { + "type": "feat", + "section": "New Features" + }, + { + "type": "fix", + "section": "Bug Fixes" + }, + { + "type": "perf", + "section": "Performance Improvements" + }, + { + "type": "refactor", + "section": "Refactors" + }, + { + "type": "revert", + "section": "Reverts" + }, + { + "type": "style", + "section": "Styles" + }, + { + "type": "test", + "section": "Tests" + } + ] + }, + "infile": "CHANGELOG.md", + "header": "# Changelog" + }, + "@release-it/bumper": { + "out": [ + "pkg/**/manifest.json" + ] + } + }, + "hooks": { + "before:init": [ + "make lint-check", + "make test-unit" + ], + "before:release": [ + "make lint", + "git add . --update" + ], + "after:release": "echo Successfully released ${name} v${version} to ${repo.repository}" + } + } +} diff --git a/pkg/cmd/server/component/layout/index.templ b/pkg/cmd/server/component/layout/index.templ new file mode 100644 index 0000000..efc4405 --- /dev/null +++ b/pkg/cmd/server/component/layout/index.templ @@ -0,0 +1,71 @@ +package layout + +import ( + "github.com/bastean/codexgo/pkg/cmd/server/component/script/fomantic" + "github.com/bastean/codexgo/pkg/cmd/server/component/script/storage" + "github.com/bastean/codexgo/pkg/cmd/server/component/script/jquery" + "github.com/bastean/codexgo/pkg/cmd/server/component/script" +) + +templ Index(headScripts script.Head, bodyScripts script.Body) { + + + + + + + + + + + + + + + codexGO + + + + + + + + + + + + + + @storage.Init() + + @jquery.Init() + + @fomantic.Init() + + for _, headScript := range headScripts { + @headScript + } + + +
+ { children... } +
+ for _, bodyScript := range bodyScripts { + @bodyScript + } + + +} diff --git a/pkg/cmd/server/component/page/dashboard/form.delete.templ b/pkg/cmd/server/component/page/dashboard/form.delete.templ new file mode 100644 index 0000000..a14ce25 --- /dev/null +++ b/pkg/cmd/server/component/page/dashboard/form.delete.templ @@ -0,0 +1,88 @@ +package dashboard + +var DeleteFormTagId = "delete" + +script DeleteFormInit(formTagId string) { + $(`#${formTagId}`) + .form({ + on: "blur", + inline : true, + preventLeaving: true, + keyboardShortcuts: false, + fields: { + Password: { + rules: [ + { + type: "size[8..64]" + }, + { + type: "regExp[/^.*[^0-9].*$/]", + prompt: "{name} cannot be only numbers" + } + ] + }, + ConfirmPassword: { + rules: [ + { + type: "match[Password]" + } + ] + } + } + }) + .api({ + action: "delete user", + method: "DELETE", + onSuccess: function(response, element, xhr) { + $.toast({ + class: "success", + message: response.message, + showProgress: "top", + }); + + _.delay(function() { + Storage.Clear(); + window.location.replace("/"); + }, 1000); + }, + onFailure: function(response, element, xhr) { + $.toast({ + class: "error", + message: response.message, + showProgress: "top" + }); + } + }) + ; +} + +script DeleteFormShow() { + $(".ui.mini.modal").modal("show"); +} + +templ DeleteForm() { + + @DeleteFormInit(DeleteFormTagId) +} diff --git a/pkg/cmd/server/component/page/dashboard/form.update.templ b/pkg/cmd/server/component/page/dashboard/form.update.templ new file mode 100644 index 0000000..a50679d --- /dev/null +++ b/pkg/cmd/server/component/page/dashboard/form.update.templ @@ -0,0 +1,154 @@ +package dashboard + +var UpdateFormTagId = "update" + +script UpdateFormInit(formTagId string) { + $(`#${formTagId}`) + .form({ + on: "blur", + inline : true, + preventLeaving: true, + keyboardShortcuts: false, + fields: { + Email: { + optional : true, + rules: [ + { + type: "email" + } + ] + }, + Username: { + optional : true, + rules: [ + { + type: "size[2..20]" + }, + { + type: "regExp[/^[A-Za-z0-9]+$/]", + prompt: "{name} must be alphanumeric only" + }, + { + type: "regExp[/^.*[^0-9].*$/]", + prompt: "{name} cannot be only numbers" + } + ] + }, + UpdatedPassword: { + optional : true, + rules: [ + { + type: "size[8..64]" + }, + { + type: "regExp[/^.*[^0-9].*$/]", + prompt: "{name} cannot be only numbers" + } + ] + }, + ConfirmPassword: { + depends : "UpdatedPassword", + rules: [ + { + type: "match[UpdatedPassword]" + } + ] + }, + Password: { + rules: [ + { + type: "size[8..64]" + }, + { + type: "regExp[/^.*[^0-9].*$/]", + prompt: "{name} cannot be only numbers" + } + ] + } + } + }) + .api({ + action: "update user", + method: "PATCH", + onSuccess: function(response, element, xhr) { + $.toast({ + class: "success", + message: response.message, + showProgress: "top", + }); + + _.delay(function() { + window.location.replace("/dashboard"); + }, 1000); + }, + onFailure: function(response, element, xhr) { + $.toast({ + class: "error", + message: response.message, + showProgress: "top" + }); + } + }) + ; +} + +templ UpdateForm(email, username string) { +
+

+ Account settings +

+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+
+ +
+ + +
+
+
+
+
+
+ +
+
+ +
+
+
+
+ @UpdateFormInit(UpdateFormTagId) +} diff --git a/pkg/cmd/server/component/page/dashboard/page.dashboard.templ b/pkg/cmd/server/component/page/dashboard/page.dashboard.templ new file mode 100644 index 0000000..f2b6e16 --- /dev/null +++ b/pkg/cmd/server/component/page/dashboard/page.dashboard.templ @@ -0,0 +1,112 @@ +package dashboard + +import ( + "github.com/bastean/codexgo/pkg/cmd/server/component/layout" + "github.com/bastean/codexgo/pkg/cmd/server/component/script" + "github.com/bastean/codexgo/pkg/cmd/server/service/user" +) + +script PageInit() { + $(".ui.container") + .transition("fade in", "3s") + ; + + $(".ui.menu .right .dropdown") + .dropdown() + ; + + $(".ui.menu .right .header .icon") + .popup() + ; + + $(".ui.blue.nag") + .nag({ + key: "account-confirmation", + value: true + }) + ; + + $(".ui.green.nag") + .nag({ + key: "account-confirmed", + value: true + }) + ; +} + +script Logout() { + Storage.ClearSession(); + window.location.replace("/"); +} + +templ Page(user *user.ReadResponse) { + @layout.Index(script.Head{}, script.Body{}) { +
+
+ +
+
+ @UpdateForm(user.Email, user.Username) + @DeleteForm() +
+ if !user.Verified { +
+
+ + Account Confirmation +
+
Link sent. Please check your inbox
+ +
+ } else { +
+
+ + Account Confirmed +
+ +
+ } +
+ @PageInit() + } +} diff --git a/pkg/cmd/server/component/page/home/form.login.templ b/pkg/cmd/server/component/page/home/form.login.templ new file mode 100644 index 0000000..bf00407 --- /dev/null +++ b/pkg/cmd/server/component/page/home/form.login.templ @@ -0,0 +1,82 @@ +package home + +var LoginFormTagId = "login" + +script LoginFormInit(formTagId string) { + $(`#${formTagId}`) + .form({ + on: "blur", + inline : true, + preventLeaving: true, + keyboardShortcuts: false, + fields: { + Email: { + rules: [ + { + type: "email" + } + ] + }, + Password: { + rules: [ + { + type: "size[8..64]" + }, + { + type: "regExp[/^.*[^0-9].*$/]", + prompt: "{name} cannot be only numbers" + } + ] + } + } + }) + .api({ + action: "login user", + method: "POST", + onSuccess: function(response, element, xhr) { + $.toast({ + class: "success", + message: response.message, + showProgress: "top", + }); + + _.delay(function() { + window.location.replace("/dashboard"); + }, 1000); + }, + onFailure: function(response, element, xhr) { + $.toast({ + class: "error", + message: response.message, + showProgress: "top" + }); + } + }) + ; +} + +templ LoginForm() { +
+

+ Sign in to your account +
Don't have an account? Sign up
+

+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ @LoginFormInit(LoginFormTagId) +} diff --git a/pkg/cmd/server/component/page/home/form.register.templ b/pkg/cmd/server/component/page/home/form.register.templ new file mode 100644 index 0000000..e188bcf --- /dev/null +++ b/pkg/cmd/server/component/page/home/form.register.templ @@ -0,0 +1,148 @@ +package home + +var RegisterFormTagId = "register" + +script RegisterFormInit(formTagId, loginTabTagId string) { + $(`#${formTagId}`) + .form({ + on: "blur", + inline : true, + preventLeaving: true, + keyboardShortcuts: false, + fields: { + Email: { + rules: [ + { + type: "email" + } + ] + }, + Username: { + rules: [ + { + type: "size[2..20]" + }, + { + type: "regExp[/^[A-Za-z0-9]+$/]", + prompt: "{name} must be alphanumeric only" + }, + { + type: "regExp[/^.*[^0-9].*$/]", + prompt: "{name} cannot be only numbers" + } + ] + }, + Password: { + rules: [ + { + type: "size[8..64]" + }, + { + type: "regExp[/^.*[^0-9].*$/]", + prompt: "{name} cannot be only numbers" + } + ] + }, + ConfirmPassword: { + rules: [ + { + type: "match[Password]" + } + ] + }, + Terms: { + rules: [ + { + type: "checked", + prompt: "Terms & Conditions must be checked" + } + ] + } + } + }) + .api({ + action: "create user", + method: "PUT", + beforeSend: function(settings) { + settings.data.Id = crypto.randomUUID(); + + settings.data = JSON.stringify(settings.data); + + return settings; + }, + onSuccess: function(response, element, xhr) { + $.toast({ + class: "success", + message: response.message, + showProgress: "top", + }); + + _.delay(function() { + $.tab("change tab", loginTabTagId); + $(`#${formTagId}`).form("reset"); + }, 1000); + }, + onFailure: function(response, element, xhr) { + $.toast({ + class: "error", + message: response.message, + showProgress: "top" + }); + } + }) + ; +} + +script ShowTerms(modalTagId string) { + $(`#${modalTagId}`).modal("show") +} + +templ RegisterForm() { +
+

+ Create an account +
Already have an account? Sign in
+

+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+
+
+
+
+ + +
+
+ +
+
+
+ @RegisterFormInit(RegisterFormTagId, LoginTabTagId) +} diff --git a/pkg/cmd/server/component/page/home/modal.terms.templ b/pkg/cmd/server/component/page/home/modal.terms.templ new file mode 100644 index 0000000..c2a9a6a --- /dev/null +++ b/pkg/cmd/server/component/page/home/modal.terms.templ @@ -0,0 +1,28 @@ +package home + +var TermsModalTagId = "terms" + +templ TermsModal() { + +} diff --git a/pkg/cmd/server/component/page/home/page.home.templ b/pkg/cmd/server/component/page/home/page.home.templ new file mode 100644 index 0000000..b2615ca --- /dev/null +++ b/pkg/cmd/server/component/page/home/page.home.templ @@ -0,0 +1,71 @@ +package home + +import ( + "github.com/bastean/codexgo/pkg/cmd/server/component/layout" + "github.com/bastean/codexgo/pkg/cmd/server/component/script" +) + +var RegisterTabTagId = "tab-register" +var LoginTabTagId = "tab-login" + +script PageInit() { + $(".ui.container") + .transition("fade in", "3s") + ; + + $(".ui.container .column .menu .right .item") + .tab({ + context: ".container" + }) + ; + + $(".ui.cookie.nag") + .nag({ + key: "accepts-cookies", + value: true + }) + ; +} + +script ShowTab(tabTagId string) { + $(`.ui.menu .right .item[data-tab=${tabTagId}]`).trigger("click"); +} + +templ Page() { + @layout.Index(script.Head{}, script.Body{}) { +
+
+ +
+
+
+ @RegisterForm() + @TermsModal() +
+
+ @LoginForm() +
+
+ +
+ @PageInit() + } +} diff --git a/pkg/cmd/server/component/script/body.templ b/pkg/cmd/server/component/script/body.templ new file mode 100644 index 0000000..ef771a8 --- /dev/null +++ b/pkg/cmd/server/component/script/body.templ @@ -0,0 +1,3 @@ +package script + +type Body []templ.ComponentScript diff --git a/pkg/cmd/server/component/script/fomantic/init.templ b/pkg/cmd/server/component/script/fomantic/init.templ new file mode 100644 index 0000000..0670486 --- /dev/null +++ b/pkg/cmd/server/component/script/fomantic/init.templ @@ -0,0 +1,27 @@ +package fomantic + +script Init() { + $.api.settings.api = { + "create user" : "/", + "login user" : "/", + "update user" : "/dashboard", + "delete user" : "/dashboard", + }; + + $.api.settings.serializeForm = true; + + $.api.settings.contentType = "application/json; charset=UTF-8"; + + $.api.settings.beforeSend = function(settings) { + settings.data = JSON.stringify(settings.data); + return settings; + }; + + $.api.settings.successTest = function(response) { + if(response && response.success) { + return response.success; + } + + return false; + }; +} diff --git a/pkg/cmd/server/component/script/head.templ b/pkg/cmd/server/component/script/head.templ new file mode 100644 index 0000000..2887a0a --- /dev/null +++ b/pkg/cmd/server/component/script/head.templ @@ -0,0 +1,3 @@ +package script + +type Head []templ.ComponentScript diff --git a/pkg/cmd/server/component/script/jquery/init.templ b/pkg/cmd/server/component/script/jquery/init.templ new file mode 100644 index 0000000..9ba5b0e --- /dev/null +++ b/pkg/cmd/server/component/script/jquery/init.templ @@ -0,0 +1,6 @@ +package jquery + +script Init() { + //? $(document).ready(handler) + $(() => {}); +} diff --git a/pkg/cmd/server/component/script/storage/storage.templ b/pkg/cmd/server/component/script/storage/storage.templ new file mode 100644 index 0000000..2be6fc0 --- /dev/null +++ b/pkg/cmd/server/component/script/storage/storage.templ @@ -0,0 +1,57 @@ +package storage + +script Init() { + const Storage = { + MasterKey: "codexgo", + Key: {}, + Init() { + let storage = localStorage.getItem(this.MasterKey); + + if (storage == null) { + localStorage.setItem(this.MasterKey, JSON.stringify({})); + } + }, + Put(key, value) { + let storage = localStorage.getItem(this.MasterKey); + + storage = JSON.parse(storage) + + storage[key] = value; + + localStorage.setItem(this.MasterKey, JSON.stringify(storage)); + }, + Get(key) { + let storage = localStorage.getItem(this.MasterKey); + + storage = JSON.parse(storage) + + return _.get(storage, key, null); + }, + Delete(key) { + let storage = localStorage.getItem(this.MasterKey); + + storage = JSON.parse(storage) + + delete storage[key]; + + localStorage.setItem(this.MasterKey, JSON.stringify(storage)); + }, + async ClearSession() { + localStorage.removeItem(this.MasterKey); + cookieStore.delete(this.MasterKey); + }, + async Clear() { + localStorage.clear(); + + let cookies = await cookieStore.getAll(); + + _.each(cookies, function(cookie) { + cookieStore.delete(cookie); + }); + } + } + + Storage.Init(); + + window.Storage = Storage +} diff --git a/pkg/cmd/server/features/page/default.feature b/pkg/cmd/server/features/page/default.feature new file mode 100644 index 0000000..64b2799 --- /dev/null +++ b/pkg/cmd/server/features/page/default.feature @@ -0,0 +1,6 @@ +Feature: Default Redirect + + Scenario: Check the correct redirect for not found page + Given I am on /non-existing page + Then redirect me to / page + And the page title should be codexGO diff --git a/pkg/cmd/server/features/user/create.feature b/pkg/cmd/server/features/user/create.feature new file mode 100644 index 0000000..0fa6a26 --- /dev/null +++ b/pkg/cmd/server/features/user/create.feature @@ -0,0 +1,21 @@ +Feature: Create a new User account + + Scenario: Create a valid non existing account + Given I am on / page + Then I fill the Email with create@example.com + * I fill the Username with create + * I fill the Password with create@example + * I fill the Confirm Password with create@example + * I check the I agree to the terms and conditions + * I click the Sign up button + And I see account created notification + + Scenario: Create already existing account + Given I am on / page + Then I fill the Email with create@example.com + * I fill the Username with create + * I fill the Password with create@example + * I fill the Confirm Password with create@example + * I check the I agree to the terms and conditions + * I click the Sign up button + But I see already registered notification diff --git a/pkg/cmd/server/features/user/delete.feature b/pkg/cmd/server/features/user/delete.feature new file mode 100644 index 0000000..2ea4d76 --- /dev/null +++ b/pkg/cmd/server/features/user/delete.feature @@ -0,0 +1,30 @@ +Feature: Delete a User account + + Scenario: Create a valid non existing account + Given I am on / page + Then I fill the Email with delete@example.com + * I fill the Username with delete + * I fill the Password with delete@example + * I fill the Confirm Password with delete@example + * I check the I agree to the terms and conditions + * I click the Sign up button + And I see account created notification + + Scenario: Login a valid existing account + Given I am on / page + Then I click on the Sign in button + * I fill the Email with delete@example.com + * I fill the Password with delete@example + * I click the Sign in button + * I see logged in notification + And redirect me to /dashboard page + + Scenario: Delete a valid existing account + Given I am on /dashboard page + Then I open the account menu + * I click on the Delete button + * I fill the Password with delete@example + * I fill the Confirm Password with delete@example + * I click the Approve button + * I see account deleted notification + And redirect me to / page diff --git a/pkg/cmd/server/features/user/login.feature b/pkg/cmd/server/features/user/login.feature new file mode 100644 index 0000000..ef286dc --- /dev/null +++ b/pkg/cmd/server/features/user/login.feature @@ -0,0 +1,28 @@ +Feature: Login a User account + + Scenario: Create a valid non existing account + Given I am on / page + Then I fill the Email with login@example.com + * I fill the Username with login + * I fill the Password with login@example + * I fill the Confirm Password with login@example + * I check the I agree to the terms and conditions + * I click the Sign up button + And I see account created notification + + Scenario: Login a valid existing account + Given I am on / page + Then I click on the Sign in button + * I fill the Email with login@example.com + * I fill the Password with login@example + * I click the Sign in button + * I see logged in notification + And redirect me to /dashboard page + + Scenario: Login a valid non existing account + Given I am on / page + Then I click on the Sign in button + * I fill the Email with non-existing@example.com + * I fill the Password with non-existing@example + * I click the Sign in button + But I see not found notification diff --git a/pkg/cmd/server/features/user/update.feature b/pkg/cmd/server/features/user/update.feature new file mode 100644 index 0000000..7b21881 --- /dev/null +++ b/pkg/cmd/server/features/user/update.feature @@ -0,0 +1,30 @@ +Feature: Update a User account + + Scenario: Create a valid non existing account + Given I am on / page + Then I fill the Email with update@example.com + * I fill the Username with update + * I fill the Password with update@example + * I fill the Confirm Password with update@example + * I check the I agree to the terms and conditions + * I click the Sign up button + And I see account created notification + + Scenario: Login a valid existing account + Given I am on / page + Then I click on the Sign in button + * I fill the Email with update@example.com + * I fill the Password with update@example + * I click the Sign in button + * I see logged in notification + And redirect me to /dashboard page + + Scenario: Update a valid existing account + Given I am on /dashboard page + Then I fill the Email with updated@example.com + * I fill the Username with updated + * I fill the New Password with updated@example + * I fill the Confirm Password with updated@example + * I fill the Current Password with update@example + * I click the Update button + And I see account updated notification diff --git a/pkg/cmd/server/handler/page/dashboard.go b/pkg/cmd/server/handler/page/dashboard.go new file mode 100644 index 0000000..845811b --- /dev/null +++ b/pkg/cmd/server/handler/page/dashboard.go @@ -0,0 +1,39 @@ +package page + +import ( + "net/http" + + "github.com/bastean/codexgo/pkg/cmd/server/component/page/dashboard" + "github.com/bastean/codexgo/pkg/cmd/server/service/user" + "github.com/bastean/codexgo/pkg/cmd/server/util/errs" + "github.com/bastean/codexgo/pkg/cmd/server/util/key" + "github.com/gin-gonic/gin" +) + +func Dashboard() gin.HandlerFunc { + return func(c *gin.Context) { + id, exists := c.Get(key.UserId) + + if !exists { + c.Error(errs.MissingKey(key.UserId, "Dashboard")) + c.Redirect(http.StatusFound, "/") + c.Abort() + return + } + + query := new(user.ReadQuery) + + query.Id = id.(string) + + user, err := user.Read.Handle(query) + + if err != nil { + c.Error(err) + c.Redirect(http.StatusFound, "/") + c.Abort() + return + } + + dashboard.Page(user).Render(c.Request.Context(), c.Writer) + } +} diff --git a/pkg/cmd/server/handler/page/default.go b/pkg/cmd/server/handler/page/default.go new file mode 100644 index 0000000..208b242 --- /dev/null +++ b/pkg/cmd/server/handler/page/default.go @@ -0,0 +1,13 @@ +package page + +import ( + "net/http" + + "github.com/gin-gonic/gin" +) + +func Default() gin.HandlerFunc { + return func(c *gin.Context) { + c.Redirect(http.StatusFound, "/") + } +} diff --git a/pkg/cmd/server/handler/page/home.go b/pkg/cmd/server/handler/page/home.go new file mode 100644 index 0000000..0df1df0 --- /dev/null +++ b/pkg/cmd/server/handler/page/home.go @@ -0,0 +1,12 @@ +package page + +import ( + "github.com/bastean/codexgo/pkg/cmd/server/component/page/home" + "github.com/gin-gonic/gin" +) + +func Home() gin.HandlerFunc { + return func(c *gin.Context) { + home.Page().Render(c.Request.Context(), c.Writer) + } +} diff --git a/pkg/cmd/server/handler/user/create.go b/pkg/cmd/server/handler/user/create.go new file mode 100644 index 0000000..31bc600 --- /dev/null +++ b/pkg/cmd/server/handler/user/create.go @@ -0,0 +1,34 @@ +package user + +import ( + "net/http" + + "github.com/bastean/codexgo/pkg/cmd/server/service/user" + "github.com/bastean/codexgo/pkg/cmd/server/util/errs" + "github.com/bastean/codexgo/pkg/cmd/server/util/reply" + "github.com/gin-gonic/gin" +) + +func Create() gin.HandlerFunc { + return func(c *gin.Context) { + command := new(user.CreateCommand) + + err := c.BindJSON(command) + + if err != nil { + c.Error(errs.BindingJSON(err, "Create")) + c.Abort() + return + } + + err = user.Create.Handle(command) + + if err != nil { + c.Error(err) + c.Abort() + return + } + + c.JSON(http.StatusCreated, reply.JSON(true, "account created", reply.Payload{})) + } +} diff --git a/pkg/cmd/server/handler/user/delete.go b/pkg/cmd/server/handler/user/delete.go new file mode 100644 index 0000000..6f7ca3d --- /dev/null +++ b/pkg/cmd/server/handler/user/delete.go @@ -0,0 +1,45 @@ +package user + +import ( + "net/http" + + "github.com/bastean/codexgo/pkg/cmd/server/service/user" + "github.com/bastean/codexgo/pkg/cmd/server/util/errs" + "github.com/bastean/codexgo/pkg/cmd/server/util/key" + "github.com/bastean/codexgo/pkg/cmd/server/util/reply" + "github.com/gin-gonic/gin" +) + +func Delete() gin.HandlerFunc { + return func(c *gin.Context) { + id, exists := c.Get(key.UserId) + + if !exists { + c.Error(errs.MissingKey(key.UserId, "Delete")) + c.Abort() + return + } + + command := new(user.DeleteCommand) + + err := c.BindJSON(command) + + if err != nil { + c.Error(errs.BindingJSON(err, "Delete")) + c.Abort() + return + } + + command.Id = id.(string) + + err = user.Delete.Handle(command) + + if err != nil { + c.Error(err) + c.Abort() + return + } + + c.JSON(http.StatusOK, reply.JSON(true, "account deleted", reply.Payload{})) + } +} diff --git a/pkg/cmd/server/handler/user/login.go b/pkg/cmd/server/handler/user/login.go new file mode 100644 index 0000000..8a5f5d2 --- /dev/null +++ b/pkg/cmd/server/handler/user/login.go @@ -0,0 +1,55 @@ +package user + +import ( + "net/http" + "time" + + "github.com/bastean/codexgo/pkg/cmd/server/service/authentication/jwt" + "github.com/bastean/codexgo/pkg/cmd/server/service/user" + "github.com/bastean/codexgo/pkg/cmd/server/util/errs" + "github.com/bastean/codexgo/pkg/cmd/server/util/key" + "github.com/bastean/codexgo/pkg/cmd/server/util/reply" + "github.com/gin-contrib/sessions" + "github.com/gin-gonic/gin" +) + +func Login() gin.HandlerFunc { + return func(c *gin.Context) { + query := new(user.LoginQuery) + + err := c.BindJSON(query) + + if err != nil { + c.Error(errs.BindingJSON(err, "Login")) + c.Abort() + return + } + + user, err := user.Login.Handle(query) + + if err != nil { + c.Error(err) + c.Abort() + return + } + + token, err := jwt.Generate(jwt.Payload{ + key.Exp: time.Now().Add((24 * time.Hour) * 7).Unix(), + key.UserId: user.Id, + }) + + if err != nil { + c.Error(err) + c.Abort() + return + } + + session := sessions.Default(c) + + session.Set(key.Authorization, "Bearer "+token) + + session.Save() + + c.JSON(http.StatusOK, reply.JSON(true, "logged in", reply.Payload{})) + } +} diff --git a/pkg/cmd/server/handler/user/update.go b/pkg/cmd/server/handler/user/update.go new file mode 100644 index 0000000..ef1efe0 --- /dev/null +++ b/pkg/cmd/server/handler/user/update.go @@ -0,0 +1,45 @@ +package user + +import ( + "net/http" + + "github.com/bastean/codexgo/pkg/cmd/server/service/user" + "github.com/bastean/codexgo/pkg/cmd/server/util/errs" + "github.com/bastean/codexgo/pkg/cmd/server/util/key" + "github.com/bastean/codexgo/pkg/cmd/server/util/reply" + "github.com/gin-gonic/gin" +) + +func Update() gin.HandlerFunc { + return func(c *gin.Context) { + id, exists := c.Get(key.UserId) + + if !exists { + c.Error(errs.MissingKey(key.UserId, "Update")) + c.Abort() + return + } + + command := new(user.UpdateCommand) + + err := c.BindJSON(command) + + if err != nil { + c.Error(errs.BindingJSON(err, "Update")) + c.Abort() + return + } + + command.Id = id.(string) + + err = user.Update.Handle(command) + + if err != nil { + c.Error(err) + c.Abort() + return + } + + c.JSON(http.StatusOK, reply.JSON(true, "account updated", reply.Payload{})) + } +} diff --git a/pkg/cmd/server/handler/user/verify.go b/pkg/cmd/server/handler/user/verify.go new file mode 100644 index 0000000..e3a4f36 --- /dev/null +++ b/pkg/cmd/server/handler/user/verify.go @@ -0,0 +1,37 @@ +package user + +import ( + "net/http" + + "github.com/bastean/codexgo/pkg/cmd/server/service/user" + "github.com/bastean/codexgo/pkg/cmd/server/util/errs" + "github.com/bastean/codexgo/pkg/cmd/server/util/key" + "github.com/gin-gonic/gin" +) + +func Verify() gin.HandlerFunc { + return func(c *gin.Context) { + id := c.Param(key.Id) + + if id == "" { + c.Error(errs.MissingKey(key.Id, "Verify")) + c.Redirect(http.StatusFound, "/") + c.Abort() + return + } + + command := new(user.VerifyCommand) + + command.Id = id + + err := user.Verify.Handle(command) + + if err != nil { + c.Error(err) + c.Abort() + return + } + + c.Redirect(http.StatusFound, "/dashboard") + } +} diff --git a/pkg/cmd/server/middleware/authentication.go b/pkg/cmd/server/middleware/authentication.go new file mode 100644 index 0000000..a7ca2e0 --- /dev/null +++ b/pkg/cmd/server/middleware/authentication.go @@ -0,0 +1,46 @@ +package middleware + +import ( + "net/http" + "strings" + + "github.com/bastean/codexgo/pkg/cmd/server/service/authentication/jwt" + "github.com/bastean/codexgo/pkg/cmd/server/util/key" + "github.com/gin-contrib/sessions" + "github.com/gin-gonic/gin" +) + +func abort(c *gin.Context) { + c.Redirect(http.StatusFound, "/") + c.Abort() +} + +func VerifyAuthentication() gin.HandlerFunc { + return func(c *gin.Context) { + session := sessions.Default(c) + + token := session.Get(key.Authorization) + + if token == nil { + abort(c) + return + } + + signature := strings.Split(token.(string), " ")[1] + + claims, err := jwt.Validate(signature) + + if err != nil { + c.Error(err) + abort(c) + return + } + + if value, exists := claims[key.UserId]; exists { + c.Set(key.UserId, value) + c.Next() + } else { + abort(c) + } + } +} diff --git a/pkg/cmd/server/middleware/cookie.go b/pkg/cmd/server/middleware/cookie.go new file mode 100644 index 0000000..8196928 --- /dev/null +++ b/pkg/cmd/server/middleware/cookie.go @@ -0,0 +1,17 @@ +package middleware + +import ( + "github.com/bastean/codexgo/pkg/cmd/server/service/env" + "github.com/gin-contrib/sessions" + "github.com/gin-contrib/sessions/cookie" + "github.com/gin-gonic/gin" +) + +var secretKey = env.Cookie.SecretKey + +var sessionName = env.Cookie.SessionName + +func CookieSession() gin.HandlerFunc { + store := cookie.NewStore([]byte(secretKey)) + return sessions.Sessions(sessionName, store) +} diff --git a/pkg/cmd/server/middleware/error.go b/pkg/cmd/server/middleware/error.go new file mode 100644 index 0000000..402d430 --- /dev/null +++ b/pkg/cmd/server/middleware/error.go @@ -0,0 +1,40 @@ +package middleware + +import ( + "net/http" + + "github.com/bastean/codexgo/pkg/cmd/server/service/errors" + "github.com/bastean/codexgo/pkg/cmd/server/service/logger" + "github.com/bastean/codexgo/pkg/cmd/server/util/reply" + "github.com/gin-gonic/gin" +) + +func ErrorHandler() gin.HandlerFunc { + return func(c *gin.Context) { + c.Next() + + var invalidValue *errors.InvalidValue + var alreadyExist *errors.AlreadyExist + var notExist *errors.NotExist + var failure *errors.Failure + var internal *errors.Internal + + for _, err := range c.Errors { + switch { + case errors.As(err, &invalidValue): + c.JSON(http.StatusUnprocessableEntity, reply.JSON(false, invalidValue.What, invalidValue.Why)) + case errors.As(err, &alreadyExist): + c.JSON(http.StatusConflict, reply.JSON(false, alreadyExist.What, alreadyExist.Why)) + case errors.As(err, ¬Exist): + c.JSON(http.StatusNotFound, reply.JSON(false, notExist.What, notExist.Why)) + case errors.As(err, &failure): + c.JSON(http.StatusBadRequest, reply.JSON(false, failure.What, failure.Why)) + case errors.As(err, &internal): + c.JSON(http.StatusInternalServerError, reply.JSON(false, "internal server error", reply.Payload{})) + fallthrough + default: + logger.Error(err.Error()) + } + } + } +} diff --git a/pkg/cmd/server/middleware/limiter.go b/pkg/cmd/server/middleware/limiter.go new file mode 100644 index 0000000..cd7f1c6 --- /dev/null +++ b/pkg/cmd/server/middleware/limiter.go @@ -0,0 +1,31 @@ +package middleware + +import ( + "net/http" + "time" + + ratelimit "github.com/JGLTechnologies/gin-rate-limit" + "github.com/gin-gonic/gin" +) + +func keyFunc(c *gin.Context) string { + return c.ClientIP() +} + +func errorHandler(c *gin.Context, info ratelimit.Info) { + c.Status(http.StatusTooManyRequests) +} + +func RateLimiter() gin.HandlerFunc { + store := ratelimit.InMemoryStore(&ratelimit.InMemoryOptions{ + Rate: time.Second, + Limit: 20, + }) + + limiter := ratelimit.RateLimiter(store, &ratelimit.Options{ + ErrorHandler: errorHandler, + KeyFunc: keyFunc, + }) + + return limiter +} diff --git a/pkg/cmd/server/middleware/panic.go b/pkg/cmd/server/middleware/panic.go new file mode 100644 index 0000000..4ad397f --- /dev/null +++ b/pkg/cmd/server/middleware/panic.go @@ -0,0 +1,14 @@ +package middleware + +import ( + "net/http" + + "github.com/bastean/codexgo/pkg/cmd/server/service/logger" + "github.com/bastean/codexgo/pkg/cmd/server/util/reply" + "github.com/gin-gonic/gin" +) + +func PanicHandler(c *gin.Context, err any) { + logger.Error(err.(error).Error()) + c.AbortWithStatusJSON(http.StatusInternalServerError, reply.JSON(false, "internal server error", reply.Payload{})) +} diff --git a/pkg/cmd/server/middleware/security.go b/pkg/cmd/server/middleware/security.go new file mode 100644 index 0000000..7d246de --- /dev/null +++ b/pkg/cmd/server/middleware/security.go @@ -0,0 +1,28 @@ +package middleware + +import ( + "strings" + + "github.com/bastean/codexgo/pkg/cmd/server/service/env" + "github.com/gin-contrib/secure" + "github.com/gin-gonic/gin" +) + +var allowedHosts = env.Security.AllowedHosts + +func getAllowedHosts() []string { + return strings.Split(allowedHosts, ", ") +} + +func SecurityConfig() gin.HandlerFunc { + return secure.New(secure.Config{ + AllowedHosts: getAllowedHosts(), + STSSeconds: 315360000, + STSIncludeSubdomains: true, + FrameDeny: true, + ContentTypeNosniff: true, + BrowserXssFilter: true, + IENoOpen: true, + ReferrerPolicy: "strict-origin-when-cross-origin", + }) +} diff --git a/pkg/cmd/server/package.json b/pkg/cmd/server/package.json new file mode 100644 index 0000000..6d46429 --- /dev/null +++ b/pkg/cmd/server/package.json @@ -0,0 +1,7 @@ +{ + "devDependencies": { + "fomantic-ui": "2.9.3", + "jquery": "3.7.1", + "lodash": "4.17.21" + } +} diff --git a/pkg/cmd/server/router/router.go b/pkg/cmd/server/router/router.go new file mode 100644 index 0000000..8adb049 --- /dev/null +++ b/pkg/cmd/server/router/router.go @@ -0,0 +1,33 @@ +package router + +import ( + "embed" + "net/http" + + "github.com/bastean/codexgo/pkg/cmd/server/middleware" + "github.com/gin-gonic/gin" +) + +var router = gin.Default() + +func New(files *embed.FS) *gin.Engine { + router.Use(gin.CustomRecovery(middleware.PanicHandler)) + + router.Use(middleware.ErrorHandler()) + + router.Use(middleware.SecurityConfig()) + + router.Use(middleware.RateLimiter()) + + router.Use(middleware.CookieSession()) + + fs := http.FS(files) + + router.StaticFS("/public", fs) + + router.StaticFileFS("/robots.txt", "static/robots.txt", fs) + + InitRoutes() + + return router +} diff --git a/pkg/cmd/server/router/routes.go b/pkg/cmd/server/router/routes.go new file mode 100644 index 0000000..f8a1831 --- /dev/null +++ b/pkg/cmd/server/router/routes.go @@ -0,0 +1,25 @@ +package router + +import ( + "github.com/bastean/codexgo/pkg/cmd/server/handler/page" + "github.com/bastean/codexgo/pkg/cmd/server/handler/user" + "github.com/bastean/codexgo/pkg/cmd/server/middleware" +) + +func InitRoutes() { + router.NoRoute(page.Default()) + + public := router.Group("/") + + public.GET("/", page.Home()) + public.PUT("/", user.Create()) + public.POST("/", user.Login()) + + public.GET("/verify/:id", user.Verify()) + + auth := public.Group("/dashboard", middleware.VerifyAuthentication()) + + auth.GET("/", page.Dashboard()) + auth.PATCH("/", user.Update()) + auth.DELETE("/", user.Delete()) +} diff --git a/pkg/cmd/server/server.go b/pkg/cmd/server/server.go new file mode 100644 index 0000000..5f08f67 --- /dev/null +++ b/pkg/cmd/server/server.go @@ -0,0 +1,72 @@ +package server + +import ( + "context" + "embed" + "errors" + "net/http" + "os" + "os/signal" + "syscall" + "time" + + "github.com/bastean/codexgo/pkg/cmd/server/router" + "github.com/bastean/codexgo/pkg/cmd/server/service" + "github.com/bastean/codexgo/pkg/cmd/server/service/logger" +) + +//go:embed static +var Files embed.FS + +func Run(port string) { + logger.Info("starting services") + + err := service.Start() + + if err != nil { + logger.Fatal(err.Error()) + } + + logger.Info("starting server") + + server := &http.Server{ + Addr: ":" + port, + Handler: router.New(&Files), + } + + go func() { + if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { + logger.Fatal(err.Error()) + } + }() + + logger.Info("listening and serving HTTP on :" + port) + + shutdown := make(chan os.Signal, 1) + + signal.Notify(shutdown, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) + + <-shutdown + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + + defer cancel() + + logger.Info("stopping services") + + errService := service.Stop(ctx) + + logger.Info("stopping server") + + errServer := server.Shutdown(ctx) + + err = errors.Join(errService, errServer) + + if err != nil { + logger.Error(err.Error()) + } + + <-ctx.Done() + + logger.Info("exiting server") +} diff --git a/pkg/cmd/server/server_test.go b/pkg/cmd/server/server_test.go new file mode 100644 index 0000000..8d9e4ac --- /dev/null +++ b/pkg/cmd/server/server_test.go @@ -0,0 +1,156 @@ +package server_test + +import ( + "context" + "log" + "os" + "strings" + "testing" + "time" + + "github.com/cucumber/godog" + "github.com/playwright-community/playwright-go" + testify "github.com/stretchr/testify/assert" +) + +var testURL = os.Getenv("TEST_URL") + +var pw *playwright.Playwright +var browser playwright.Browser +var browserCtx playwright.BrowserContext +var page playwright.Page + +var headless = true +var exact = true +var sleep = 4 * time.Second +var err error + +var assert *testify.Assertions + +func InitializeAssert(t *testing.T) { + assert = testify.New(t) +} + +func InitializePlaywright() { + pw, err = playwright.Run() + + if err != nil { + log.Fatalf("could not start playwright: %s", err) + } + + browser, err = pw.Chromium.Launch(playwright.BrowserTypeLaunchOptions{Headless: &headless}) + + if err != nil { + log.Fatalf("could not launch browser: %s", err) + } + + browserCtx, err = browser.NewContext(playwright.BrowserNewContextOptions{BaseURL: &testURL}) + + if err != nil { + log.Fatalf("could not create context: %s", err) + } + + page, err = browserCtx.NewPage() + + if err != nil { + log.Fatalf("could not create page: %s", err) + } +} + +func InitializeScenario(sc *godog.ScenarioContext) { + sc.Before(func(ctx context.Context, sc *godog.Scenario) (context.Context, error) { + //? browserCtx.ClearCookies() + return ctx, nil + }) + + sc.Given(`^I am on (.+) page$`, func(route string) { + _, err = page.Goto(route) + assert.NoError(err) + }) + + sc.Then(`^redirect me to (.+) page$`, func(actual string) { + time.Sleep(sleep) + + if actual == "/" { + actual = "" + } + + expected := page.URL() + + assert.True(strings.Contains(expected, actual)) + }) + + sc.Then(`^the page title should be (.+)$`, func(expected string) { + actual, _ := page.Title() + assert.Equal(expected, actual) + }) + + sc.Then(`^I click on the (.+) button$`, func(name string) { + element := page.GetByText(name, playwright.PageGetByTextOptions{Exact: &exact}).First() + + err = element.Click() + + assert.NoError(err) + }) + + sc.Then(`^I open the (.+) menu$`, func(name string) { + element := page.GetByRole("heading").First() + + err = element.Click() + + assert.NoError(err) + }) + + sc.Then(`^I fill the (.+) with (.+)$`, func(placeholder, value string) { + element := page.GetByRole("textbox", playwright.PageGetByRoleOptions{Name: placeholder, Exact: &exact}).Last() + + err = element.Fill(value) + + assert.NoError(err) + }) + + sc.Then(`^I click the (.+) button$`, func(name string) { + element := page.GetByRole("button", playwright.PageGetByRoleOptions{Name: name}) + + err = element.Click() + + assert.NoError(err) + }) + + sc.Then(`^I check the (.+)$`, func(name string) { + element := page.GetByRole("checkbox") + + err = element.Check() + + assert.NoError(err) + }) + + sc.Then(`^I see (.+) notification$`, func(expected string) { + element := page.GetByRole("alert") + + actual, err := element.InnerText() + + assert.NoError(err) + + assert.Equal(expected, actual) + }) +} + +func TestAcceptanceServerFeatures(t *testing.T) { + InitializeAssert(t) + + InitializePlaywright() + + suite := godog.TestSuite{ + ScenarioInitializer: InitializeScenario, + Options: &godog.Options{ + Format: "pretty", + Paths: []string{"features"}, + TestingT: t, + }, + } + + if suite.Run() != 0 { + t.Fatal("non-zero status returned, failed to run feature tests") + } +} diff --git a/pkg/cmd/server/service/authentication/jwt/jwt.go b/pkg/cmd/server/service/authentication/jwt/jwt.go new file mode 100644 index 0000000..a70c559 --- /dev/null +++ b/pkg/cmd/server/service/authentication/jwt/jwt.go @@ -0,0 +1,14 @@ +package jwt + +import ( + "github.com/bastean/codexgo/pkg/cmd/server/service/env" + "github.com/bastean/codexgo/pkg/context/shared/infrastructure/authentications" +) + +type Payload = authentications.Payload + +var ( + jwt = authentications.NewJWT(env.JWT.SecretKey) + Generate = jwt.Generate + Validate = jwt.Validate +) diff --git a/pkg/cmd/server/service/communication/communication.go b/pkg/cmd/server/service/communication/communication.go new file mode 100644 index 0000000..eeb6a7e --- /dev/null +++ b/pkg/cmd/server/service/communication/communication.go @@ -0,0 +1,7 @@ +package communication + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/messages" +) + +type Broker = messages.Broker diff --git a/pkg/cmd/server/service/communication/rabbitmq/binding.go b/pkg/cmd/server/service/communication/rabbitmq/binding.go new file mode 100644 index 0000000..ec14e17 --- /dev/null +++ b/pkg/cmd/server/service/communication/rabbitmq/binding.go @@ -0,0 +1,15 @@ +package rabbitmq + +type Event struct { + CreatedSucceeded string +} + +type Key struct { + *Event +} + +var Binding = &Key{ + Event: &Event{ + CreatedSucceeded: "#.event.#.created.succeeded", + }, +} diff --git a/pkg/cmd/server/service/communication/rabbitmq/consumers.go b/pkg/cmd/server/service/communication/rabbitmq/consumers.go new file mode 100644 index 0000000..a9d511b --- /dev/null +++ b/pkg/cmd/server/service/communication/rabbitmq/consumers.go @@ -0,0 +1,7 @@ +package rabbitmq + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/messages" +) + +type Consumers = []messages.Consumer diff --git a/pkg/cmd/server/service/communication/rabbitmq/exchange.go b/pkg/cmd/server/service/communication/rabbitmq/exchange.go new file mode 100644 index 0000000..588fee0 --- /dev/null +++ b/pkg/cmd/server/service/communication/rabbitmq/exchange.go @@ -0,0 +1,11 @@ +package rabbitmq + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/messages" +) + +func Exchange(name string) *messages.Router { + return &messages.Router{ + Name: name, + } +} diff --git a/pkg/cmd/server/service/communication/rabbitmq/queues.go b/pkg/cmd/server/service/communication/rabbitmq/queues.go new file mode 100644 index 0000000..ea8b9cf --- /dev/null +++ b/pkg/cmd/server/service/communication/rabbitmq/queues.go @@ -0,0 +1,7 @@ +package rabbitmq + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/messages" +) + +type Queues = []*messages.Queue diff --git a/pkg/cmd/server/service/communication/rabbitmq/rabbitmq.go b/pkg/cmd/server/service/communication/rabbitmq/rabbitmq.go new file mode 100644 index 0000000..31dc109 --- /dev/null +++ b/pkg/cmd/server/service/communication/rabbitmq/rabbitmq.go @@ -0,0 +1,57 @@ +package rabbitmq + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/messages" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/infrastructure/communications" +) + +func New(uri string, logger models.Logger, exchange *messages.Router, queues []*messages.Queue, consumers []messages.Consumer) (messages.Broker, error) { + rabbitMQ, err := communications.NewRabbitMQ(uri, logger) + + if err != nil { + return nil, errors.BubbleUp(err, "New") + } + + err = rabbitMQ.AddRouter(exchange) + + if err != nil { + return nil, errors.BubbleUp(err, "New") + } + + for _, queue := range queues { + + err = rabbitMQ.AddQueue(queue) + + if err != nil { + return nil, errors.BubbleUp(err, "New") + } + + err = rabbitMQ.AddQueueMessageBind(queue, queue.Bindings) + + if err != nil { + return nil, errors.BubbleUp(err, "New") + } + } + + for _, consumer := range consumers { + err = rabbitMQ.AddQueueConsumer(consumer) + + if err != nil { + return nil, errors.BubbleUp(err, "New") + } + } + + return rabbitMQ, nil +} + +func Close(rabbitMQ messages.Broker) error { + err := communications.CloseRabbitMQ(rabbitMQ.(*communications.RabbitMQ)) + + if err != nil { + return errors.BubbleUp(err, "Close") + } + + return nil +} diff --git a/pkg/cmd/server/service/env/default.go b/pkg/cmd/server/service/env/default.go new file mode 100644 index 0000000..cfd61e3 --- /dev/null +++ b/pkg/cmd/server/service/env/default.go @@ -0,0 +1,48 @@ +package env + +import ( + "os" +) + +var ServerURL = os.Getenv("URL") + +var Broker = &struct { + URI string +}{ + URI: os.Getenv("BROKER_URI"), +} + +var Database = &struct { + URI string +}{ + URI: os.Getenv("DATABASE_URI"), +} + +var SMTP = &struct { + Host, Port, Username, Password, ServerURL string +}{ + Host: os.Getenv("SMTP_HOST"), + Port: os.Getenv("SMTP_PORT"), + Username: os.Getenv("SMTP_USERNAME"), + Password: os.Getenv("SMTP_PASSWORD"), + ServerURL: ServerURL, +} + +var Security = &struct { + AllowedHosts string +}{ + AllowedHosts: os.Getenv("ALLOWED_HOSTS"), +} + +var JWT = &struct { + SecretKey string +}{ + SecretKey: os.Getenv("JWT_SECRET_KEY"), +} + +var Cookie = &struct { + SecretKey, SessionName string +}{ + SecretKey: os.Getenv("COOKIE_SECRET_KEY"), + SessionName: os.Getenv("COOKIE_SESSION_NAME"), +} diff --git a/pkg/cmd/server/service/errors/errors.go b/pkg/cmd/server/service/errors/errors.go new file mode 100644 index 0000000..1236158 --- /dev/null +++ b/pkg/cmd/server/service/errors/errors.go @@ -0,0 +1,35 @@ +package errors + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" +) + +type ( + InvalidValue = errors.InvalidValue + AlreadyExist = errors.AlreadyExist + NotExist = errors.NotExist + Failure = errors.Failure + Internal = errors.Internal +) + +var ( + BubbleUp = errors.BubbleUp + As = errors.As + Is = errors.Is +) + +func NewInternal(where, what string, who error) error { + return errors.NewInternal(&errors.Bubble{ + Where: where, + What: what, + Who: who, + }) +} + +func NewFailure(where, what string, who error) error { + return errors.NewFailure(&errors.Bubble{ + Where: where, + What: what, + Who: who, + }) +} diff --git a/pkg/cmd/server/service/logger/logger.go b/pkg/cmd/server/service/logger/logger.go new file mode 100644 index 0000000..340448d --- /dev/null +++ b/pkg/cmd/server/service/logger/logger.go @@ -0,0 +1,13 @@ +package logger + +import ( + "github.com/bastean/codexgo/pkg/context/shared/infrastructure/loggers" +) + +var ( + Logger = new(loggers.Logger) + Debug = Logger.Debug + Error = Logger.Error + Fatal = Logger.Fatal + Info = Logger.Info +) diff --git a/pkg/cmd/server/service/persistence/mongodb/mongodb.go b/pkg/cmd/server/service/persistence/mongodb/mongodb.go new file mode 100644 index 0000000..b6edbcd --- /dev/null +++ b/pkg/cmd/server/service/persistence/mongodb/mongodb.go @@ -0,0 +1,30 @@ +package mongodb + +import ( + "context" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/infrastructure/persistences" +) + +type MongoDB = *persistences.MongoDB + +func New(uri, name string) (*persistences.MongoDB, error) { + mongoDB, err := persistences.NewMongoDatabase(uri, name) + + if err != nil { + return nil, errors.BubbleUp(err, "New") + } + + return mongoDB, nil +} + +func Close(mongoDB *persistences.MongoDB, ctx context.Context) error { + err := persistences.CloseMongoDatabase(ctx, mongoDB) + + if err != nil { + return errors.BubbleUp(err, "Close") + } + + return nil +} diff --git a/pkg/cmd/server/service/service.go b/pkg/cmd/server/service/service.go new file mode 100644 index 0000000..aa6b274 --- /dev/null +++ b/pkg/cmd/server/service/service.go @@ -0,0 +1,163 @@ +package service + +import ( + "context" + + "github.com/bastean/codexgo/pkg/cmd/server/service/communication" + "github.com/bastean/codexgo/pkg/cmd/server/service/communication/rabbitmq" + "github.com/bastean/codexgo/pkg/cmd/server/service/env" + "github.com/bastean/codexgo/pkg/cmd/server/service/errors" + "github.com/bastean/codexgo/pkg/cmd/server/service/logger" + "github.com/bastean/codexgo/pkg/cmd/server/service/persistence/mongodb" + "github.com/bastean/codexgo/pkg/cmd/server/service/transport/smtp" + "github.com/bastean/codexgo/pkg/cmd/server/service/user" +) + +var ( + err error + RabbitMQ communication.Broker + MongoDB mongodb.MongoDB + SMTP smtp.SMTP +) + +func startSMTP() { + if env.SMTP.Host == "" { + user.InitCreated(user.TerminalConfirmation(logger.Logger, env.ServerURL), user.QueueSendConfirmation) + return + } + + SMTP = smtp.New( + env.SMTP.Host, + env.SMTP.Port, + env.SMTP.Username, + env.SMTP.Password, + env.SMTP.ServerURL, + ) + + user.InitCreated(user.MailConfirmation(SMTP), user.QueueSendConfirmation) +} + +func startRabbitMQ() error { + RabbitMQ, err = rabbitmq.New( + env.Broker.URI, + logger.Logger, + rabbitmq.Exchange("codexgo"), + rabbitmq.Queues{ + user.QueueSendConfirmation, + }, + rabbitmq.Consumers{ + user.Created, + }, + ) + + if err != nil { + return errors.BubbleUp(err, "startRabbitMQ") + } + + return nil +} + +func startMongoDB() error { + MongoDB, err = mongodb.New( + env.Database.URI, + "codexgo", + ) + + if err != nil { + return errors.BubbleUp(err, "startMongoDB") + } + + return nil +} + +func startUser() error { + collection, err := user.MongoCollection( + MongoDB, + "users", + user.Bcrypt, + ) + + if err != nil { + return errors.BubbleUp(err, "startUser") + } + + user.Init( + collection, + RabbitMQ, + user.Bcrypt, + ) + + return nil +} + +func Start() error { + logger.Info("starting smtp") + + startSMTP() + + logger.Info("starting rabbitmq") + + err = startRabbitMQ() + + if err != nil { + return errors.BubbleUp(err, "Start") + } + + logger.Info("starting mongodb") + + err = startMongoDB() + + if err != nil { + return errors.BubbleUp(err, "Start") + } + + logger.Info("starting user") + + err = startUser() + + if err != nil { + return errors.BubbleUp(err, "Start") + } + + return nil +} + +func stopRabbitMQ() error { + err = rabbitmq.Close(RabbitMQ) + + if err != nil { + return errors.BubbleUp(err, "stopRabbitMQ") + } + + return nil +} + +func stopMongoDB(ctx context.Context) error { + err = mongodb.Close(MongoDB, ctx) + + if err != nil { + return errors.BubbleUp(err, "stopMongoDB") + } + + return nil +} + +func Stop(ctx context.Context) error { + logger.Info("stopping rabbitmq") + + err = stopRabbitMQ() + + if err != nil { + return errors.BubbleUp(err, "Stop") + } + + logger.Info("stopping mongodb") + + err = stopMongoDB(ctx) + + if err != nil { + return errors.BubbleUp(err, "Stop") + } + + return nil +} diff --git a/pkg/cmd/server/service/transport/smtp/smtp.go b/pkg/cmd/server/service/transport/smtp/smtp.go new file mode 100644 index 0000000..09bc3d6 --- /dev/null +++ b/pkg/cmd/server/service/transport/smtp/smtp.go @@ -0,0 +1,11 @@ +package smtp + +import ( + "github.com/bastean/codexgo/pkg/context/shared/infrastructure/transports" +) + +type SMTP = *transports.SMTP + +func New(host, port, username, password, serverURL string) *transports.SMTP { + return transports.NewSMTP(host, port, username, password, serverURL) +} diff --git a/pkg/cmd/server/service/user/consumer.go b/pkg/cmd/server/service/user/consumer.go new file mode 100644 index 0000000..8f4e34f --- /dev/null +++ b/pkg/cmd/server/service/user/consumer.go @@ -0,0 +1,22 @@ +package user + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/messages" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/user/application/created" +) + +var ( + Created *created.Consumer +) + +func InitCreated(transport models.Transport, queue *messages.Queue) { + usecase := &created.Created{ + Transport: transport, + } + + Created = &created.Consumer{ + UseCase: usecase, + Queues: []*messages.Queue{queue}, + } +} diff --git a/pkg/cmd/server/service/user/handler.go b/pkg/cmd/server/service/user/handler.go new file mode 100644 index 0000000..a326d18 --- /dev/null +++ b/pkg/cmd/server/service/user/handler.go @@ -0,0 +1,92 @@ +package user + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/messages" + "github.com/bastean/codexgo/pkg/context/user/application/create" + "github.com/bastean/codexgo/pkg/context/user/application/delete" + "github.com/bastean/codexgo/pkg/context/user/application/login" + "github.com/bastean/codexgo/pkg/context/user/application/read" + "github.com/bastean/codexgo/pkg/context/user/application/update" + "github.com/bastean/codexgo/pkg/context/user/application/verify" + "github.com/bastean/codexgo/pkg/context/user/domain/model" +) + +type ( + CreateCommand = create.Command + UpdateCommand = update.Command + DeleteCommand = delete.Command + VerifyCommand = verify.Command +) + +type ( + ReadQuery = read.Query + LoginQuery = login.Query +) + +type ( + ReadResponse = read.Response +) + +func NewCreate(repository model.Repository, broker messages.Broker) *create.Handler { + usecase := &create.Create{ + Repository: repository, + } + + return &create.Handler{ + UseCase: usecase, + Broker: broker, + } +} + +func NewRead(repository model.Repository) *read.Handler { + usecase := &read.Read{ + Repository: repository, + } + + return &read.Handler{ + UseCase: usecase, + } +} + +func NewUpdate(repository model.Repository, hashing model.Hashing) *update.Handler { + usecase := &update.Update{ + Repository: repository, + Hashing: hashing, + } + + return &update.Handler{ + UseCase: usecase, + } +} + +func NewDelete(repository model.Repository, hashing model.Hashing) *delete.Handler { + usecase := &delete.Delete{ + Repository: repository, + Hashing: hashing, + } + + return &delete.Handler{ + UseCase: usecase, + } +} + +func NewVerify(repository model.Repository) *verify.Handler { + usecase := &verify.Verify{ + Repository: repository, + } + + return &verify.Handler{ + UseCase: usecase, + } +} + +func NewLogin(repository model.Repository, hashing model.Hashing) *login.Handler { + usecase := &login.Login{ + Repository: repository, + Hashing: hashing, + } + + return &login.Handler{ + UseCase: usecase, + } +} diff --git a/pkg/cmd/server/service/user/hashing.go b/pkg/cmd/server/service/user/hashing.go new file mode 100644 index 0000000..bcad1aa --- /dev/null +++ b/pkg/cmd/server/service/user/hashing.go @@ -0,0 +1,7 @@ +package user + +import ( + "github.com/bastean/codexgo/pkg/context/user/infrastructure/cryptographic" +) + +var Bcrypt = new(cryptographic.Bcrypt) diff --git a/pkg/cmd/server/service/user/message.go b/pkg/cmd/server/service/user/message.go new file mode 100644 index 0000000..754b446 --- /dev/null +++ b/pkg/cmd/server/service/user/message.go @@ -0,0 +1,17 @@ +package user + +import ( + "github.com/bastean/codexgo/pkg/cmd/server/service/communication/rabbitmq" + "github.com/bastean/codexgo/pkg/context/shared/domain/messages" +) + +var QueueSendConfirmation = &messages.Queue{ + Name: messages.NewRecipientName(&messages.RecipientNameComponents{ + Service: "user", + Entity: "user", + Action: "send confirmation", + Event: "created", + Status: "succeeded", + }), + Bindings: []string{rabbitmq.Binding.Event.CreatedSucceeded}, +} diff --git a/pkg/cmd/server/service/user/repository.go b/pkg/cmd/server/service/user/repository.go new file mode 100644 index 0000000..7f3295b --- /dev/null +++ b/pkg/cmd/server/service/user/repository.go @@ -0,0 +1,18 @@ +package user + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/infrastructure/persistences" + "github.com/bastean/codexgo/pkg/context/user/domain/model" + "github.com/bastean/codexgo/pkg/context/user/infrastructure/persistence" +) + +func MongoCollection(database *persistences.MongoDB, name string, hashing model.Hashing) (model.Repository, error) { + collection, err := persistence.NewMongoCollection(database, name, hashing) + + if err != nil { + return nil, errors.BubbleUp(err, "MongoCollection") + } + + return collection, nil +} diff --git a/pkg/cmd/server/service/user/transport.go b/pkg/cmd/server/service/user/transport.go new file mode 100644 index 0000000..a5f0b8c --- /dev/null +++ b/pkg/cmd/server/service/user/transport.go @@ -0,0 +1,21 @@ +package user + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/infrastructure/transports" + "github.com/bastean/codexgo/pkg/context/user/infrastructure/communication/mail" + "github.com/bastean/codexgo/pkg/context/user/infrastructure/communication/terminal" +) + +func MailConfirmation(smtp *transports.SMTP) models.Transport { + return &mail.Confirmation{ + SMTP: smtp, + } +} + +func TerminalConfirmation(logger models.Logger, serverURL string) models.Transport { + return &terminal.Confirmation{ + Logger: logger, + ServerURL: serverURL, + } +} diff --git a/pkg/cmd/server/service/user/user.go b/pkg/cmd/server/service/user/user.go new file mode 100644 index 0000000..e44866b --- /dev/null +++ b/pkg/cmd/server/service/user/user.go @@ -0,0 +1,35 @@ +package user + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/messages" + "github.com/bastean/codexgo/pkg/context/user/application/create" + "github.com/bastean/codexgo/pkg/context/user/application/delete" + "github.com/bastean/codexgo/pkg/context/user/application/login" + "github.com/bastean/codexgo/pkg/context/user/application/read" + "github.com/bastean/codexgo/pkg/context/user/application/update" + "github.com/bastean/codexgo/pkg/context/user/application/verify" + "github.com/bastean/codexgo/pkg/context/user/domain/model" +) + +var ( + Create *create.Handler + Read *read.Handler + Update *update.Handler + Delete *delete.Handler + Verify *verify.Handler + Login *login.Handler +) + +func Init(repository model.Repository, broker messages.Broker, hashing model.Hashing) { + Create = NewCreate(repository, broker) + + Read = NewRead(repository) + + Update = NewUpdate(repository, hashing) + + Delete = NewDelete(repository, hashing) + + Verify = NewVerify(repository) + + Login = NewLogin(repository, hashing) +} diff --git a/pkg/cmd/server/static/assets/apple-touch-icon.png b/pkg/cmd/server/static/assets/apple-touch-icon.png new file mode 100644 index 0000000..26001ca Binary files /dev/null and b/pkg/cmd/server/static/assets/apple-touch-icon.png differ diff --git a/pkg/cmd/server/static/assets/favicon.png b/pkg/cmd/server/static/assets/favicon.png new file mode 100644 index 0000000..26001ca Binary files /dev/null and b/pkg/cmd/server/static/assets/favicon.png differ diff --git a/pkg/cmd/server/static/assets/logo.png b/pkg/cmd/server/static/assets/logo.png new file mode 100644 index 0000000..52ba8b9 Binary files /dev/null and b/pkg/cmd/server/static/assets/logo.png differ diff --git a/pkg/cmd/server/static/assets/pwa-any.png b/pkg/cmd/server/static/assets/pwa-any.png new file mode 100644 index 0000000..2fd4f0c Binary files /dev/null and b/pkg/cmd/server/static/assets/pwa-any.png differ diff --git a/pkg/cmd/server/static/assets/pwa-maskable.png b/pkg/cmd/server/static/assets/pwa-maskable.png new file mode 100644 index 0000000..2fd4f0c Binary files /dev/null and b/pkg/cmd/server/static/assets/pwa-maskable.png differ diff --git a/pkg/cmd/server/static/manifest.json b/pkg/cmd/server/static/manifest.json new file mode 100644 index 0000000..be3027e --- /dev/null +++ b/pkg/cmd/server/static/manifest.json @@ -0,0 +1,27 @@ +{ + "name": "codexGO", + "short_name": "codexGO", + "version": "4.3.0", + "description": "codexGO", + "author": "Bastean ", + "homepage_url": "https://github.com/bastean/codexgo#readme", + "start_url": ".", + "display": "standalone", + "orientation": "portrait-primary", + "background_color": "#202224", + "theme_color": "#202224", + "icons": [ + { + "src": "assets/pwa-any.png", + "type": "image/png", + "sizes": "512x512", + "purpose": "any" + }, + { + "src": "assets/pwa-maskable.png", + "type": "image/png", + "sizes": "512x512", + "purpose": "maskable" + } + ] +} diff --git a/pkg/cmd/server/static/robots.txt b/pkg/cmd/server/static/robots.txt new file mode 100644 index 0000000..1f53798 --- /dev/null +++ b/pkg/cmd/server/static/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: / diff --git a/pkg/cmd/server/util/errs/binding.go b/pkg/cmd/server/util/errs/binding.go new file mode 100644 index 0000000..aed9725 --- /dev/null +++ b/pkg/cmd/server/util/errs/binding.go @@ -0,0 +1,26 @@ +package errs + +import ( + "encoding/json" + "fmt" + + "github.com/bastean/codexgo/pkg/cmd/server/service/errors" +) + +func BindingJSON(who error, where string) error { + var err *json.UnmarshalTypeError + + if errors.As(who, &err) { + return errors.NewFailure( + where, + fmt.Sprintf("invalid type field [%s] required type is [%s] and [%s] was obtained", err.Field, err.Type, err.Value), + who, + ) + } + + return errors.NewInternal( + where, + "cannot bind a json to a struct", + who, + ) +} diff --git a/pkg/cmd/server/util/errs/missing.go b/pkg/cmd/server/util/errs/missing.go new file mode 100644 index 0000000..a325abd --- /dev/null +++ b/pkg/cmd/server/util/errs/missing.go @@ -0,0 +1,15 @@ +package errs + +import ( + "fmt" + + "github.com/bastean/codexgo/pkg/cmd/server/service/errors" +) + +func MissingKey(what, where string) error { + return errors.NewInternal( + where, + fmt.Sprintf("failure to obtain the value of the key [%s]", what), + nil, + ) +} diff --git a/pkg/cmd/server/util/key/key.go b/pkg/cmd/server/util/key/key.go new file mode 100644 index 0000000..4bbb6c4 --- /dev/null +++ b/pkg/cmd/server/util/key/key.go @@ -0,0 +1,9 @@ +package key + +var Authorization = "Authorization" + +var Exp = "exp" + +var Id = "id" + +var UserId = "userId" diff --git a/pkg/cmd/server/util/reply/reply.go b/pkg/cmd/server/util/reply/reply.go new file mode 100644 index 0000000..e95f1e4 --- /dev/null +++ b/pkg/cmd/server/util/reply/reply.go @@ -0,0 +1,11 @@ +package reply + +type Payload = map[string]any + +func JSON(success bool, message string, data map[string]any) map[string]any { + return map[string]any{ + "success": success, + "message": message, + "data": data, + } +} diff --git a/pkg/context/shared/domain/aggregates/root.go b/pkg/context/shared/domain/aggregates/root.go new file mode 100644 index 0000000..af22da8 --- /dev/null +++ b/pkg/context/shared/domain/aggregates/root.go @@ -0,0 +1,27 @@ +package aggregates + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/messages" +) + +type AggregateRoot struct { + Messages []*messages.Message +} + +func (root *AggregateRoot) RecordMessage(message *messages.Message) { + root.Messages = append(root.Messages, message) +} + +func (root *AggregateRoot) PullMessages() []*messages.Message { + recordedMessages := root.Messages + + root.Messages = []*messages.Message{} + + return recordedMessages +} + +func NewAggregateRoot() *AggregateRoot { + return &AggregateRoot{ + Messages: []*messages.Message{}, + } +} diff --git a/pkg/context/shared/domain/errors/bubble.go b/pkg/context/shared/domain/errors/bubble.go new file mode 100644 index 0000000..d93008d --- /dev/null +++ b/pkg/context/shared/domain/errors/bubble.go @@ -0,0 +1,52 @@ +package errors + +import ( + "encoding/json" + "fmt" + "time" +) + +type Bubble struct { + When time.Time + Where, What string + Why map[string]any + Who error +} + +func (err *Bubble) Error() string { + message := fmt.Sprintf("%s (%s): %s", err.When.Format(time.RFC3339Nano), err.Where, err.What) + + if err.Why != nil { + why, err := json.Marshal(err.Why) + + if err != nil { + Panic(fmt.Sprintf("cannot json encoding \"why\" from error bubble: %s: [%s]", message, err.Error()), "Error") + } + + message = fmt.Sprintf("%s: %s", message, why) + } + + if err.Who != nil { + message = fmt.Sprintf("%s: [%s]", message, err.Who) + } + + return message +} + +func NewBubble(where, what string, why Meta, who error) *Bubble { + if where == "" { + Panic("cannot create a error bubble if \"where\" is not defined", "NewBubble") + } + + if what == "" { + Panic("cannot create a error bubble if \"what\" is not defined", "NewBubble") + } + + return &Bubble{ + When: time.Now().UTC(), + Where: where, + What: what, + Why: why, + Who: who, + } +} diff --git a/pkg/context/shared/domain/errors/bubbleup.go b/pkg/context/shared/domain/errors/bubbleup.go new file mode 100644 index 0000000..15e5415 --- /dev/null +++ b/pkg/context/shared/domain/errors/bubbleup.go @@ -0,0 +1,9 @@ +package errors + +import ( + "fmt" +) + +func BubbleUp(who error, where string) error { + return fmt.Errorf("(%s): [%w]", where, who) +} diff --git a/pkg/context/shared/domain/errors/default.go b/pkg/context/shared/domain/errors/default.go new file mode 100644 index 0000000..c6a2d0f --- /dev/null +++ b/pkg/context/shared/domain/errors/default.go @@ -0,0 +1,5 @@ +package errors + +func Default() error { + return new(Bubble) +} diff --git a/pkg/context/shared/domain/errors/exist.go b/pkg/context/shared/domain/errors/exist.go new file mode 100644 index 0000000..0d5eecc --- /dev/null +++ b/pkg/context/shared/domain/errors/exist.go @@ -0,0 +1,31 @@ +package errors + +type AlreadyExist struct { + *Bubble +} + +type NotExist struct { + *Bubble +} + +func NewAlreadyExist(bubble *Bubble) error { + return &AlreadyExist{ + Bubble: NewBubble( + bubble.Where, + bubble.What, + bubble.Why, + bubble.Who, + ), + } +} + +func NewNotExist(bubble *Bubble) error { + return &NotExist{ + Bubble: NewBubble( + bubble.Where, + bubble.What, + bubble.Why, + bubble.Who, + ), + } +} diff --git a/pkg/context/shared/domain/errors/failure.go b/pkg/context/shared/domain/errors/failure.go new file mode 100644 index 0000000..c330d5f --- /dev/null +++ b/pkg/context/shared/domain/errors/failure.go @@ -0,0 +1,16 @@ +package errors + +type Failure struct { + *Bubble +} + +func NewFailure(bubble *Bubble) error { + return &Failure{ + Bubble: NewBubble( + bubble.Where, + bubble.What, + bubble.Why, + bubble.Who, + ), + } +} diff --git a/pkg/context/shared/domain/errors/internal.go b/pkg/context/shared/domain/errors/internal.go new file mode 100644 index 0000000..3b06ebf --- /dev/null +++ b/pkg/context/shared/domain/errors/internal.go @@ -0,0 +1,16 @@ +package errors + +type Internal struct { + *Bubble +} + +func NewInternal(bubble *Bubble) error { + return &Internal{ + Bubble: NewBubble( + bubble.Where, + bubble.What, + bubble.Why, + bubble.Who, + ), + } +} diff --git a/pkg/context/shared/domain/errors/invalid.go b/pkg/context/shared/domain/errors/invalid.go new file mode 100644 index 0000000..8078f1e --- /dev/null +++ b/pkg/context/shared/domain/errors/invalid.go @@ -0,0 +1,16 @@ +package errors + +type InvalidValue struct { + *Bubble +} + +func NewInvalidValue(bubble *Bubble) error { + return &InvalidValue{ + Bubble: NewBubble( + bubble.Where, + bubble.What, + bubble.Why, + bubble.Who, + ), + } +} diff --git a/pkg/context/shared/domain/errors/meta.go b/pkg/context/shared/domain/errors/meta.go new file mode 100644 index 0000000..7033e59 --- /dev/null +++ b/pkg/context/shared/domain/errors/meta.go @@ -0,0 +1,3 @@ +package errors + +type Meta = map[string]any diff --git a/pkg/context/shared/domain/errors/panic.go b/pkg/context/shared/domain/errors/panic.go new file mode 100644 index 0000000..965b572 --- /dev/null +++ b/pkg/context/shared/domain/errors/panic.go @@ -0,0 +1,9 @@ +package errors + +import ( + "log" +) + +func Panic(what, where string) { + log.Panicf("(%s): %s", where, what) +} diff --git a/pkg/context/shared/domain/errors/wrap.go b/pkg/context/shared/domain/errors/wrap.go new file mode 100644 index 0000000..708aae4 --- /dev/null +++ b/pkg/context/shared/domain/errors/wrap.go @@ -0,0 +1,17 @@ +package errors + +import ( + "errors" +) + +func Join(errs ...error) error { + return errors.Join(errs...) +} + +func As(err error, target any) bool { + return errors.As(err, target) +} + +func Is(err, target error) bool { + return errors.Is(err, target) +} diff --git a/pkg/context/shared/domain/messages/broker.go b/pkg/context/shared/domain/messages/broker.go new file mode 100644 index 0000000..6182809 --- /dev/null +++ b/pkg/context/shared/domain/messages/broker.go @@ -0,0 +1,9 @@ +package messages + +type Broker interface { + AddRouter(router *Router) error + AddQueue(queue *Queue) error + AddQueueMessageBind(queue *Queue, bindingKeys []string) error + AddQueueConsumer(consumer Consumer) error + PublishMessages(messages []*Message) error +} diff --git a/pkg/context/shared/domain/messages/consumer.go b/pkg/context/shared/domain/messages/consumer.go new file mode 100644 index 0000000..c1c8809 --- /dev/null +++ b/pkg/context/shared/domain/messages/consumer.go @@ -0,0 +1,6 @@ +package messages + +type Consumer interface { + SubscribedTo() []*Queue + On(message *Message) error +} diff --git a/pkg/context/shared/domain/messages/key.go b/pkg/context/shared/domain/messages/key.go new file mode 100644 index 0000000..5c3a722 --- /dev/null +++ b/pkg/context/shared/domain/messages/key.go @@ -0,0 +1,74 @@ +package messages + +import ( + "fmt" + "strings" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/domain/valueobjs" +) + +var Type = struct { + Event, Command string +}{ + Event: "event", + Command: "command", +} + +var Status = struct { + Queued, Succeeded, Failed, Done string +}{ + Queued: "queued", + Succeeded: "succeeded", + Failed: "failed", + Done: "done", +} + +// Terminology: +// - Organization = Context +// - Service = Module +// - Entity = Aggregate/Root +// +// Nomenclature of a Routing Key (Topic): +// - organization.service.version.type.entity.event/command.status +// - codexgo.user.1.event.user.created.succeeded +type RoutingKeyComponents struct { + Organization, Service, Version, Type, Entity, Event, Command, Status string +} + +func NewRoutingKey(components *RoutingKeyComponents) string { + if components.Organization == "" { + components.Organization = "codexgo" + } + + organization, errOrganization := valueobjs.NewOrganization(components.Organization) + service, errService := valueobjs.NewService(components.Service) + version, errVersion := valueobjs.NewVersion(components.Version) + types, errType := valueobjs.NewType(components.Type) + entity, errEntity := valueobjs.NewEntity(components.Entity) + + var action models.ValueObject[string] + var errAction error + + switch components.Type { + case Type.Event: + action, errAction = valueobjs.NewEvent(components.Event) + case Type.Command: + action, errAction = valueobjs.NewCommand(components.Command) + } + + status, errStatus := valueobjs.NewStatus(components.Status) + + err := errors.Join(errOrganization, errService, errVersion, errType, errEntity, errAction, errStatus) + + if err != nil { + errors.Panic(err.Error(), "NewRoutingKey") + } + + key := fmt.Sprintf("%s.%s.%s.%s.%s.%s.%s", organization.Value(), service.Value(), version.Value(), types.Value(), entity.Value(), action.Value(), status.Value()) + + key = strings.ToLower(key) + + return key +} diff --git a/pkg/context/shared/domain/messages/key_test.go b/pkg/context/shared/domain/messages/key_test.go new file mode 100644 index 0000000..3ba62e8 --- /dev/null +++ b/pkg/context/shared/domain/messages/key_test.go @@ -0,0 +1,41 @@ +package messages_test + +import ( + "testing" + + "github.com/bastean/codexgo/pkg/context/shared/domain/messages" + "github.com/stretchr/testify/suite" +) + +type RoutingKeyTestSuite struct { + suite.Suite +} + +func (suite *RoutingKeyTestSuite) SetupTest() {} + +func (suite *RoutingKeyTestSuite) TestWithValidValue() { + components := &messages.RoutingKeyComponents{ + Organization: "codexgo", + Service: "user", + Version: "1", + Type: messages.Type.Event, + Entity: "user", + Event: "created", + Status: messages.Status.Succeeded, + } + + expected := "codexgo.user.1.event.user.created.succeeded" + + actual := messages.NewRoutingKey(components) + + suite.Equal(expected, actual) +} + +func (suite *RoutingKeyTestSuite) TestWithInvalidValue() { + components := &messages.RoutingKeyComponents{} + suite.Panics(func() { messages.NewRoutingKey(components) }) +} + +func TestUnitRoutingKeySuite(t *testing.T) { + suite.Run(t, new(RoutingKeyTestSuite)) +} diff --git a/pkg/context/shared/domain/messages/message.go b/pkg/context/shared/domain/messages/message.go new file mode 100644 index 0000000..2e8d937 --- /dev/null +++ b/pkg/context/shared/domain/messages/message.go @@ -0,0 +1,18 @@ +package messages + +type Attributes = []byte + +type Meta = []byte + +type Message struct { + Id, Type, OccurredOn string + Attributes, Meta []byte +} + +func NewMessage(routingKey string, attributes, meta []byte) *Message { + return &Message{ + Type: routingKey, + Attributes: attributes, + Meta: meta, + } +} diff --git a/pkg/context/shared/domain/messages/queue.go b/pkg/context/shared/domain/messages/queue.go new file mode 100644 index 0000000..0894227 --- /dev/null +++ b/pkg/context/shared/domain/messages/queue.go @@ -0,0 +1,19 @@ +package messages + +type Queue struct { + Name string + Bindings []string +} + +func HasNoQueue(queues []Queue, queue *Queue) bool { + isNotPresent := true + + for _, present := range queues { + if present.Name == queue.Name { + isNotPresent = false + break + } + } + + return isNotPresent +} diff --git a/pkg/context/shared/domain/messages/recipient.go b/pkg/context/shared/domain/messages/recipient.go new file mode 100644 index 0000000..1e1d750 --- /dev/null +++ b/pkg/context/shared/domain/messages/recipient.go @@ -0,0 +1,51 @@ +package messages + +import ( + "fmt" + "strings" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/domain/valueobjs" +) + +// Terminology: +// - Service = Module +// - Entity = Aggregate/Root +// +// Nomenclature of a Recipient Name: +// - service.entity.action_on_event/command_status +// - user.user.send_confirmation_on_created_succeeded +type RecipientNameComponents struct { + Service, Entity, Action, Event, Command, Status string +} + +func NewRecipientName(components *RecipientNameComponents) string { + service, errService := valueobjs.NewService(components.Service) + entity, errEntity := valueobjs.NewEntity(components.Entity) + action, errAction := valueobjs.NewAction(components.Action) + + var trigger models.ValueObject[string] + var errTrigger error + + switch { + case components.Event != "": + trigger, errTrigger = valueobjs.NewEvent(components.Event) + case components.Command != "": + trigger, errTrigger = valueobjs.NewCommand(components.Command) + } + + status, errStatus := valueobjs.NewStatus(components.Status) + + err := errors.Join(errService, errEntity, errAction, errTrigger, errStatus) + + if err != nil { + errors.Panic(err.Error(), "NewRecipientName") + } + + name := fmt.Sprintf("%s.%s.%s_on_%s_%s", service.Value(), entity.Value(), strings.ReplaceAll(action.Value(), " ", "_"), trigger.Value(), status.Value()) + + name = strings.ToLower(name) + + return name +} diff --git a/pkg/context/shared/domain/messages/recipient_test.go b/pkg/context/shared/domain/messages/recipient_test.go new file mode 100644 index 0000000..fe3d1ee --- /dev/null +++ b/pkg/context/shared/domain/messages/recipient_test.go @@ -0,0 +1,39 @@ +package messages_test + +import ( + "testing" + + "github.com/bastean/codexgo/pkg/context/shared/domain/messages" + "github.com/stretchr/testify/suite" +) + +type RecipientNameTestSuite struct { + suite.Suite +} + +func (suite *RecipientNameTestSuite) SetupTest() {} + +func (suite *RecipientNameTestSuite) TestWithValidValue() { + components := &messages.RecipientNameComponents{ + Service: "user", + Entity: "user", + Action: "send confirmation", + Event: "created", + Status: messages.Status.Succeeded, + } + + expected := "user.user.send_confirmation_on_created_succeeded" + + actual := messages.NewRecipientName(components) + + suite.Equal(expected, actual) +} + +func (suite *RecipientNameTestSuite) TestWithInvalidValue() { + components := &messages.RecipientNameComponents{} + suite.Panics(func() { messages.NewRecipientName(components) }) +} + +func TestUnitRecipientNameSuite(t *testing.T) { + suite.Run(t, new(RecipientNameTestSuite)) +} diff --git a/pkg/context/shared/domain/messages/router.go b/pkg/context/shared/domain/messages/router.go new file mode 100644 index 0000000..95c52d2 --- /dev/null +++ b/pkg/context/shared/domain/messages/router.go @@ -0,0 +1,5 @@ +package messages + +type Router struct { + Name string +} diff --git a/pkg/context/shared/domain/models/handler.go b/pkg/context/shared/domain/models/handler.go new file mode 100644 index 0000000..676e000 --- /dev/null +++ b/pkg/context/shared/domain/models/handler.go @@ -0,0 +1,9 @@ +package models + +type CommandHandler[Command any] interface { + Handle(Command) error +} + +type QueryHandler[Query, Response any] interface { + Handle(Query) (Response, error) +} diff --git a/pkg/context/shared/domain/models/logger.go b/pkg/context/shared/domain/models/logger.go new file mode 100644 index 0000000..302f0f4 --- /dev/null +++ b/pkg/context/shared/domain/models/logger.go @@ -0,0 +1,8 @@ +package models + +type Logger interface { + Debug(message string) + Error(message string) + Fatal(message string) + Info(message string) +} diff --git a/pkg/context/shared/domain/models/transport.go b/pkg/context/shared/domain/models/transport.go new file mode 100644 index 0000000..be94fb8 --- /dev/null +++ b/pkg/context/shared/domain/models/transport.go @@ -0,0 +1,5 @@ +package models + +type Transport interface { + Submit(any) error +} diff --git a/pkg/context/shared/domain/models/usecase.go b/pkg/context/shared/domain/models/usecase.go new file mode 100644 index 0000000..8c5f56d --- /dev/null +++ b/pkg/context/shared/domain/models/usecase.go @@ -0,0 +1,5 @@ +package models + +type UseCase[Input, Output any] interface { + Run(Input) (Output, error) +} diff --git a/pkg/context/shared/domain/models/valueobj.go b/pkg/context/shared/domain/models/valueobj.go new file mode 100644 index 0000000..5fbeffa --- /dev/null +++ b/pkg/context/shared/domain/models/valueobj.go @@ -0,0 +1,6 @@ +package models + +type ValueObject[Value any] interface { + Value() Value + IsValid() error +} diff --git a/pkg/context/shared/domain/services/context.go b/pkg/context/shared/domain/services/context.go new file mode 100644 index 0000000..61e921c --- /dev/null +++ b/pkg/context/shared/domain/services/context.go @@ -0,0 +1,17 @@ +package services + +import ( + "context" +) + +type CtxKey string + +const CtxDefaultKey CtxKey = "default" + +func SetDefaultContextValue(value any) context.Context { + return context.WithValue(context.Background(), CtxDefaultKey, value) +} + +func GetDefaultContextValue[T any](ctx context.Context) T { + return ctx.Value(CtxDefaultKey).(T) +} diff --git a/pkg/context/shared/domain/services/create.go b/pkg/context/shared/domain/services/create.go new file mode 100644 index 0000000..a426aee --- /dev/null +++ b/pkg/context/shared/domain/services/create.go @@ -0,0 +1,23 @@ +package services + +import ( + "fmt" + "strings" + + "github.com/brianvoe/gofakeit/v7" +) + +type mother struct { + *gofakeit.Faker +} + +func (create *mother) Email() string { + username := strings.Split(create.Faker.Email(), "@")[0] + domain := "example.com" + + return fmt.Sprintf("%s@%s", username, domain) +} + +var Create = &mother{ + Faker: gofakeit.New(0), +} diff --git a/pkg/context/shared/domain/types/empty.go b/pkg/context/shared/domain/types/empty.go new file mode 100644 index 0000000..c3a66d8 --- /dev/null +++ b/pkg/context/shared/domain/types/empty.go @@ -0,0 +1,3 @@ +package types + +type Empty = interface{} diff --git a/pkg/context/shared/domain/valueobjs/action.go b/pkg/context/shared/domain/valueobjs/action.go new file mode 100644 index 0000000..f41f20e --- /dev/null +++ b/pkg/context/shared/domain/valueobjs/action.go @@ -0,0 +1,45 @@ +package valueobjs + +import ( + "strings" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/go-playground/validator/v10" +) + +const ActionMinCharactersLength = "1" +const ActionMaxCharactersLength = "20" + +type Action struct { + Action string `validate:"gte=1,lte=20"` +} + +func (value *Action) Value() string { + return value.Action +} + +func (value *Action) IsValid() error { + validate := validator.New(validator.WithRequiredStructEnabled()) + return validate.Struct(value) +} + +func NewAction(value string) (models.ValueObject[string], error) { + value = strings.TrimSpace(value) + + valueObj := &Action{ + Action: value, + } + + if valueObj.IsValid() != nil { + return nil, errors.NewInvalidValue(&errors.Bubble{ + Where: "NewAction", + What: "action must be between " + ActionMinCharactersLength + " to " + ActionMaxCharactersLength + " characters", + Why: errors.Meta{ + "Action": value, + }, + }) + } + + return valueObj, nil +} diff --git a/pkg/context/shared/domain/valueobjs/action.mother.go b/pkg/context/shared/domain/valueobjs/action.mother.go new file mode 100644 index 0000000..0860dff --- /dev/null +++ b/pkg/context/shared/domain/valueobjs/action.mother.go @@ -0,0 +1,25 @@ +package valueobjs + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/domain/services" +) + +func ActionWithValidValue() models.ValueObject[string] { + value, err := NewAction(services.Create.Regex(`^[A-Za-z\s]{1,20}$`)) + + if err != nil { + errors.Panic(err.Error(), "ActionWithValidValue") + } + + return value +} + +func ActionWithInvalidLength() (string, error) { + value := "" + + _, err := NewAction(value) + + return value, err +} diff --git a/pkg/context/shared/domain/valueobjs/action_test.go b/pkg/context/shared/domain/valueobjs/action_test.go new file mode 100644 index 0000000..7906323 --- /dev/null +++ b/pkg/context/shared/domain/valueobjs/action_test.go @@ -0,0 +1,38 @@ +package valueobjs_test + +import ( + "testing" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/valueobjs" + "github.com/stretchr/testify/suite" +) + +type ActionValueObjectTestSuite struct { + suite.Suite +} + +func (suite *ActionValueObjectTestSuite) SetupTest() {} + +func (suite *ActionValueObjectTestSuite) TestWithInvalidLength() { + value, err := valueobjs.ActionWithInvalidLength() + + var actual *errors.InvalidValue + + suite.ErrorAs(err, &actual) + + expected := &errors.InvalidValue{Bubble: &errors.Bubble{ + When: actual.When, + Where: "NewAction", + What: "action must be between " + "1" + " to " + "20" + " characters", + Why: errors.Meta{ + "Action": value, + }, + }} + + suite.EqualError(expected, actual.Error()) +} + +func TestUnitActionValueObjectSuite(t *testing.T) { + suite.Run(t, new(ActionValueObjectTestSuite)) +} diff --git a/pkg/context/shared/domain/valueobjs/command.go b/pkg/context/shared/domain/valueobjs/command.go new file mode 100644 index 0000000..fa35111 --- /dev/null +++ b/pkg/context/shared/domain/valueobjs/command.go @@ -0,0 +1,45 @@ +package valueobjs + +import ( + "strings" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/go-playground/validator/v10" +) + +const CommandMinCharactersLength = "1" +const CommandMaxCharactersLength = "20" + +type Command struct { + Command string `validate:"gte=1,lte=20,alpha"` +} + +func (value *Command) Value() string { + return value.Command +} + +func (value *Command) IsValid() error { + validate := validator.New(validator.WithRequiredStructEnabled()) + return validate.Struct(value) +} + +func NewCommand(value string) (models.ValueObject[string], error) { + value = strings.TrimSpace(value) + + valueObj := &Command{ + Command: value, + } + + if valueObj.IsValid() != nil { + return nil, errors.NewInvalidValue(&errors.Bubble{ + Where: "NewCommand", + What: "command must be between " + CommandMinCharactersLength + " to " + CommandMaxCharactersLength + " characters and be alpha only", + Why: errors.Meta{ + "Command": value, + }, + }) + } + + return valueObj, nil +} diff --git a/pkg/context/shared/domain/valueobjs/command.mother.go b/pkg/context/shared/domain/valueobjs/command.mother.go new file mode 100644 index 0000000..3b0b869 --- /dev/null +++ b/pkg/context/shared/domain/valueobjs/command.mother.go @@ -0,0 +1,33 @@ +package valueobjs + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/domain/services" +) + +func CommandWithValidValue() models.ValueObject[string] { + value, err := NewCommand(services.Create.Regex(`^[A-Za-z]{1,20}$`)) + + if err != nil { + errors.Panic(err.Error(), "CommandWithValidValue") + } + + return value +} + +func CommandWithInvalidLength() (string, error) { + value := "" + + _, err := NewCommand(value) + + return value, err +} + +func CommandWithInvalidAlpha() (string, error) { + value := "<>" + + _, err := NewCommand(value) + + return value, err +} diff --git a/pkg/context/shared/domain/valueobjs/command_test.go b/pkg/context/shared/domain/valueobjs/command_test.go new file mode 100644 index 0000000..1f529fd --- /dev/null +++ b/pkg/context/shared/domain/valueobjs/command_test.go @@ -0,0 +1,57 @@ +package valueobjs_test + +import ( + "testing" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/valueobjs" + "github.com/stretchr/testify/suite" +) + +type CommandValueObjectTestSuite struct { + suite.Suite +} + +func (suite *CommandValueObjectTestSuite) SetupTest() {} + +func (suite *CommandValueObjectTestSuite) TestWithInvalidLength() { + value, err := valueobjs.CommandWithInvalidLength() + + var actual *errors.InvalidValue + + suite.ErrorAs(err, &actual) + + expected := &errors.InvalidValue{Bubble: &errors.Bubble{ + When: actual.When, + Where: "NewCommand", + What: "command must be between " + "1" + " to " + "20" + " characters and be alpha only", + Why: errors.Meta{ + "Command": value, + }, + }} + + suite.EqualError(expected, actual.Error()) +} + +func (suite *CommandValueObjectTestSuite) TestWithInvalidAlpha() { + value, err := valueobjs.CommandWithInvalidAlpha() + + var actual *errors.InvalidValue + + suite.ErrorAs(err, &actual) + + expected := &errors.InvalidValue{Bubble: &errors.Bubble{ + When: actual.When, + Where: "NewCommand", + What: "command must be between " + "1" + " to " + "20" + " characters and be alpha only", + Why: errors.Meta{ + "Command": value, + }, + }} + + suite.EqualError(expected, actual.Error()) +} + +func TestUnitCommandValueObjectSuite(t *testing.T) { + suite.Run(t, new(CommandValueObjectTestSuite)) +} diff --git a/pkg/context/shared/domain/valueobjs/email.go b/pkg/context/shared/domain/valueobjs/email.go new file mode 100644 index 0000000..3a072d0 --- /dev/null +++ b/pkg/context/shared/domain/valueobjs/email.go @@ -0,0 +1,42 @@ +package valueobjs + +import ( + "strings" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/go-playground/validator/v10" +) + +type Email struct { + Email string `validate:"email"` +} + +func (value *Email) Value() string { + return value.Email +} + +func (value *Email) IsValid() error { + validate := validator.New(validator.WithRequiredStructEnabled()) + return validate.Struct(value) +} + +func NewEmail(value string) (models.ValueObject[string], error) { + value = strings.TrimSpace(value) + + valueObj := &Email{ + Email: value, + } + + if valueObj.IsValid() != nil { + return nil, errors.NewInvalidValue(&errors.Bubble{ + Where: "NewEmail", + What: "invalid email format", + Why: errors.Meta{ + "Email": value, + }, + }) + } + + return valueObj, nil +} diff --git a/pkg/context/shared/domain/valueobjs/entity.go b/pkg/context/shared/domain/valueobjs/entity.go new file mode 100644 index 0000000..ae78747 --- /dev/null +++ b/pkg/context/shared/domain/valueobjs/entity.go @@ -0,0 +1,45 @@ +package valueobjs + +import ( + "strings" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/go-playground/validator/v10" +) + +const EntityMinCharactersLength = "1" +const EntityMaxCharactersLength = "20" + +type Entity struct { + Entity string `validate:"gte=1,lte=20,alpha"` +} + +func (value *Entity) Value() string { + return value.Entity +} + +func (value *Entity) IsValid() error { + validate := validator.New(validator.WithRequiredStructEnabled()) + return validate.Struct(value) +} + +func NewEntity(value string) (models.ValueObject[string], error) { + value = strings.TrimSpace(value) + + valueObj := &Entity{ + Entity: value, + } + + if valueObj.IsValid() != nil { + return nil, errors.NewInvalidValue(&errors.Bubble{ + Where: "NewEntity", + What: "entity must be between " + EntityMinCharactersLength + " to " + EntityMaxCharactersLength + " characters and be alpha only", + Why: errors.Meta{ + "Entity": value, + }, + }) + } + + return valueObj, nil +} diff --git a/pkg/context/shared/domain/valueobjs/entity.mother.go b/pkg/context/shared/domain/valueobjs/entity.mother.go new file mode 100644 index 0000000..84488f9 --- /dev/null +++ b/pkg/context/shared/domain/valueobjs/entity.mother.go @@ -0,0 +1,33 @@ +package valueobjs + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/domain/services" +) + +func EntityWithValidValue() models.ValueObject[string] { + value, err := NewEntity(services.Create.Regex(`^[A-Za-z]{1,20}$`)) + + if err != nil { + errors.Panic(err.Error(), "EntityWithValidValue") + } + + return value +} + +func EntityWithInvalidLength() (string, error) { + value := "" + + _, err := NewEntity(value) + + return value, err +} + +func EntityWithInvalidAlpha() (string, error) { + value := "<>" + + _, err := NewEntity(value) + + return value, err +} diff --git a/pkg/context/shared/domain/valueobjs/entity_test.go b/pkg/context/shared/domain/valueobjs/entity_test.go new file mode 100644 index 0000000..f9427d0 --- /dev/null +++ b/pkg/context/shared/domain/valueobjs/entity_test.go @@ -0,0 +1,57 @@ +package valueobjs_test + +import ( + "testing" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/valueobjs" + "github.com/stretchr/testify/suite" +) + +type EntityValueObjectTestSuite struct { + suite.Suite +} + +func (suite *EntityValueObjectTestSuite) SetupTest() {} + +func (suite *EntityValueObjectTestSuite) TestWithInvalidLength() { + value, err := valueobjs.EntityWithInvalidLength() + + var actual *errors.InvalidValue + + suite.ErrorAs(err, &actual) + + expected := &errors.InvalidValue{Bubble: &errors.Bubble{ + When: actual.When, + Where: "NewEntity", + What: "entity must be between " + "1" + " to " + "20" + " characters and be alpha only", + Why: errors.Meta{ + "Entity": value, + }, + }} + + suite.EqualError(expected, actual.Error()) +} + +func (suite *EntityValueObjectTestSuite) TestWithInvalidAlpha() { + value, err := valueobjs.EntityWithInvalidAlpha() + + var actual *errors.InvalidValue + + suite.ErrorAs(err, &actual) + + expected := &errors.InvalidValue{Bubble: &errors.Bubble{ + When: actual.When, + Where: "NewEntity", + What: "entity must be between " + "1" + " to " + "20" + " characters and be alpha only", + Why: errors.Meta{ + "Entity": value, + }, + }} + + suite.EqualError(expected, actual.Error()) +} + +func TestUnitEntityValueObjectSuite(t *testing.T) { + suite.Run(t, new(EntityValueObjectTestSuite)) +} diff --git a/pkg/context/shared/domain/valueobjs/event.go b/pkg/context/shared/domain/valueobjs/event.go new file mode 100644 index 0000000..6899a77 --- /dev/null +++ b/pkg/context/shared/domain/valueobjs/event.go @@ -0,0 +1,45 @@ +package valueobjs + +import ( + "strings" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/go-playground/validator/v10" +) + +const EventMinCharactersLength = "1" +const EventMaxCharactersLength = "20" + +type Event struct { + Event string `validate:"gte=1,lte=20,alpha"` +} + +func (value *Event) Value() string { + return value.Event +} + +func (value *Event) IsValid() error { + validate := validator.New(validator.WithRequiredStructEnabled()) + return validate.Struct(value) +} + +func NewEvent(value string) (models.ValueObject[string], error) { + value = strings.TrimSpace(value) + + valueObj := &Entity{ + Entity: value, + } + + if valueObj.IsValid() != nil { + return nil, errors.NewInvalidValue(&errors.Bubble{ + Where: "NewEvent", + What: "event must be between " + EventMinCharactersLength + " to " + EventMaxCharactersLength + " characters and be alpha only", + Why: errors.Meta{ + "Event": value, + }, + }) + } + + return valueObj, nil +} diff --git a/pkg/context/shared/domain/valueobjs/event.mother.go b/pkg/context/shared/domain/valueobjs/event.mother.go new file mode 100644 index 0000000..b6f2f04 --- /dev/null +++ b/pkg/context/shared/domain/valueobjs/event.mother.go @@ -0,0 +1,33 @@ +package valueobjs + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/domain/services" +) + +func EventWithValidValue() models.ValueObject[string] { + value, err := NewEvent(services.Create.Regex(`^[A-Za-z]{1,20}$`)) + + if err != nil { + errors.Panic(err.Error(), "EventWithValidValue") + } + + return value +} + +func EventWithInvalidLength() (string, error) { + value := "" + + _, err := NewEvent(value) + + return value, err +} + +func EventWithInvalidAlpha() (string, error) { + value := "<>" + + _, err := NewEvent(value) + + return value, err +} diff --git a/pkg/context/shared/domain/valueobjs/event_test.go b/pkg/context/shared/domain/valueobjs/event_test.go new file mode 100644 index 0000000..143ffce --- /dev/null +++ b/pkg/context/shared/domain/valueobjs/event_test.go @@ -0,0 +1,57 @@ +package valueobjs_test + +import ( + "testing" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/valueobjs" + "github.com/stretchr/testify/suite" +) + +type EventValueObjectTestSuite struct { + suite.Suite +} + +func (suite *EventValueObjectTestSuite) SetupTest() {} + +func (suite *EventValueObjectTestSuite) TestWithInvalidLength() { + value, err := valueobjs.EventWithInvalidLength() + + var actual *errors.InvalidValue + + suite.ErrorAs(err, &actual) + + expected := &errors.InvalidValue{Bubble: &errors.Bubble{ + When: actual.When, + Where: "NewEvent", + What: "event must be between " + "1" + " to " + "20" + " characters and be alpha only", + Why: errors.Meta{ + "Event": value, + }, + }} + + suite.EqualError(expected, actual.Error()) +} + +func (suite *EventValueObjectTestSuite) TestWithInvalidAlpha() { + value, err := valueobjs.EventWithInvalidAlpha() + + var actual *errors.InvalidValue + + suite.ErrorAs(err, &actual) + + expected := &errors.InvalidValue{Bubble: &errors.Bubble{ + When: actual.When, + Where: "NewEvent", + What: "event must be between " + "1" + " to " + "20" + " characters and be alpha only", + Why: errors.Meta{ + "Event": value, + }, + }} + + suite.EqualError(expected, actual.Error()) +} + +func TestUnitEventValueObjectSuite(t *testing.T) { + suite.Run(t, new(EventValueObjectTestSuite)) +} diff --git a/pkg/context/shared/domain/valueobjs/id.go b/pkg/context/shared/domain/valueobjs/id.go new file mode 100644 index 0000000..fdf9d47 --- /dev/null +++ b/pkg/context/shared/domain/valueobjs/id.go @@ -0,0 +1,42 @@ +package valueobjs + +import ( + "strings" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/go-playground/validator/v10" +) + +type Id struct { + Id string `validate:"uuid4"` +} + +func (value *Id) Value() string { + return value.Id +} + +func (value *Id) IsValid() error { + validate := validator.New(validator.WithRequiredStructEnabled()) + return validate.Struct(value) +} + +func NewId(value string) (models.ValueObject[string], error) { + value = strings.TrimSpace(value) + + valueObj := &Id{ + Id: value, + } + + if valueObj.IsValid() != nil { + return nil, errors.NewInvalidValue(&errors.Bubble{ + Where: "NewId", + What: "invalid uuid4 format", + Why: errors.Meta{ + "Id": value, + }, + }) + } + + return valueObj, nil +} diff --git a/pkg/context/shared/domain/valueobjs/organization.go b/pkg/context/shared/domain/valueobjs/organization.go new file mode 100644 index 0000000..97297c7 --- /dev/null +++ b/pkg/context/shared/domain/valueobjs/organization.go @@ -0,0 +1,45 @@ +package valueobjs + +import ( + "strings" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/go-playground/validator/v10" +) + +const OrganizationMinCharactersLength = "1" +const OrganizationMaxCharactersLength = "20" + +type Organization struct { + Organization string `validate:"gte=1,lte=20,alphanum"` +} + +func (value *Organization) Value() string { + return value.Organization +} + +func (value *Organization) IsValid() error { + validate := validator.New(validator.WithRequiredStructEnabled()) + return validate.Struct(value) +} + +func NewOrganization(value string) (models.ValueObject[string], error) { + value = strings.TrimSpace(value) + + valueObj := &Organization{ + Organization: value, + } + + if valueObj.IsValid() != nil { + return nil, errors.NewInvalidValue(&errors.Bubble{ + Where: "NewOrganization", + What: "organization must be between " + OrganizationMinCharactersLength + " to " + OrganizationMaxCharactersLength + " characters and be alphanumeric only", + Why: errors.Meta{ + "Organization": value, + }, + }) + } + + return valueObj, nil +} diff --git a/pkg/context/shared/domain/valueobjs/organization.mother.go b/pkg/context/shared/domain/valueobjs/organization.mother.go new file mode 100644 index 0000000..85f403e --- /dev/null +++ b/pkg/context/shared/domain/valueobjs/organization.mother.go @@ -0,0 +1,33 @@ +package valueobjs + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/domain/services" +) + +func OrganizationWithValidValue() models.ValueObject[string] { + value, err := NewOrganization(services.Create.Regex(`^[A-Za-z0-9]{1,20}$`)) + + if err != nil { + errors.Panic(err.Error(), "OrganizationWithValidValue") + } + + return value +} + +func OrganizationWithInvalidLength() (string, error) { + value := "" + + _, err := NewOrganization(value) + + return value, err +} + +func OrganizationWithInvalidAlphanumeric() (string, error) { + value := "<>" + + _, err := NewOrganization(value) + + return value, err +} diff --git a/pkg/context/shared/domain/valueobjs/organization_test.go b/pkg/context/shared/domain/valueobjs/organization_test.go new file mode 100644 index 0000000..c15b9f9 --- /dev/null +++ b/pkg/context/shared/domain/valueobjs/organization_test.go @@ -0,0 +1,57 @@ +package valueobjs_test + +import ( + "testing" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/valueobjs" + "github.com/stretchr/testify/suite" +) + +type OrganizationValueObjectTestSuite struct { + suite.Suite +} + +func (suite *OrganizationValueObjectTestSuite) SetupTest() {} + +func (suite *OrganizationValueObjectTestSuite) TestWithInvalidLength() { + value, err := valueobjs.OrganizationWithInvalidLength() + + var actual *errors.InvalidValue + + suite.ErrorAs(err, &actual) + + expected := &errors.InvalidValue{Bubble: &errors.Bubble{ + When: actual.When, + Where: "NewOrganization", + What: "organization must be between " + "1" + " to " + "20" + " characters and be alphanumeric only", + Why: errors.Meta{ + "Organization": value, + }, + }} + + suite.EqualError(expected, actual.Error()) +} + +func (suite *OrganizationValueObjectTestSuite) TestWithInvalidAlphanumeric() { + value, err := valueobjs.OrganizationWithInvalidAlphanumeric() + + var actual *errors.InvalidValue + + suite.ErrorAs(err, &actual) + + expected := &errors.InvalidValue{Bubble: &errors.Bubble{ + When: actual.When, + Where: "NewOrganization", + What: "organization must be between " + "1" + " to " + "20" + " characters and be alphanumeric only", + Why: errors.Meta{ + "Organization": value, + }, + }} + + suite.EqualError(expected, actual.Error()) +} + +func TestUnitOrganizationValueObjectSuite(t *testing.T) { + suite.Run(t, new(OrganizationValueObjectTestSuite)) +} diff --git a/pkg/context/shared/domain/valueobjs/service.go b/pkg/context/shared/domain/valueobjs/service.go new file mode 100644 index 0000000..9a23381 --- /dev/null +++ b/pkg/context/shared/domain/valueobjs/service.go @@ -0,0 +1,45 @@ +package valueobjs + +import ( + "strings" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/go-playground/validator/v10" +) + +const ServiceMinCharactersLength = "1" +const ServiceMaxCharactersLength = "20" + +type Service struct { + Service string `validate:"gte=1,lte=20,alphanum"` +} + +func (value *Service) Value() string { + return value.Service +} + +func (value *Service) IsValid() error { + validate := validator.New(validator.WithRequiredStructEnabled()) + return validate.Struct(value) +} + +func NewService(value string) (models.ValueObject[string], error) { + value = strings.TrimSpace(value) + + valueObj := &Service{ + Service: value, + } + + if valueObj.IsValid() != nil { + return nil, errors.NewInvalidValue(&errors.Bubble{ + Where: "NewService", + What: "service must be between " + ServiceMinCharactersLength + " to " + ServiceMaxCharactersLength + " characters and be alphanumeric only", + Why: errors.Meta{ + "Service": value, + }, + }) + } + + return valueObj, nil +} diff --git a/pkg/context/shared/domain/valueobjs/service.mother.go b/pkg/context/shared/domain/valueobjs/service.mother.go new file mode 100644 index 0000000..09e60c5 --- /dev/null +++ b/pkg/context/shared/domain/valueobjs/service.mother.go @@ -0,0 +1,33 @@ +package valueobjs + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/domain/services" +) + +func ServiceWithValidValue() models.ValueObject[string] { + value, err := NewService(services.Create.Regex(`^[A-Za-z0-9]{1,20}$`)) + + if err != nil { + errors.Panic(err.Error(), "ServiceWithValidValue") + } + + return value +} + +func ServiceWithInvalidLength() (string, error) { + value := "" + + _, err := NewService(value) + + return value, err +} + +func ServiceWithInvalidAlphanumeric() (string, error) { + value := "<>" + + _, err := NewService(value) + + return value, err +} diff --git a/pkg/context/shared/domain/valueobjs/service_test.go b/pkg/context/shared/domain/valueobjs/service_test.go new file mode 100644 index 0000000..4a5217b --- /dev/null +++ b/pkg/context/shared/domain/valueobjs/service_test.go @@ -0,0 +1,57 @@ +package valueobjs_test + +import ( + "testing" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/valueobjs" + "github.com/stretchr/testify/suite" +) + +type ServiceValueObjectTestSuite struct { + suite.Suite +} + +func (suite *ServiceValueObjectTestSuite) SetupTest() {} + +func (suite *ServiceValueObjectTestSuite) TestWithInvalidLength() { + value, err := valueobjs.ServiceWithInvalidLength() + + var actual *errors.InvalidValue + + suite.ErrorAs(err, &actual) + + expected := &errors.InvalidValue{Bubble: &errors.Bubble{ + When: actual.When, + Where: "NewService", + What: "service must be between " + "1" + " to " + "20" + " characters and be alphanumeric only", + Why: errors.Meta{ + "Service": value, + }, + }} + + suite.EqualError(expected, actual.Error()) +} + +func (suite *ServiceValueObjectTestSuite) TestWithInvalidAlphanumeric() { + value, err := valueobjs.ServiceWithInvalidAlphanumeric() + + var actual *errors.InvalidValue + + suite.ErrorAs(err, &actual) + + expected := &errors.InvalidValue{Bubble: &errors.Bubble{ + When: actual.When, + Where: "NewService", + What: "service must be between " + "1" + " to " + "20" + " characters and be alphanumeric only", + Why: errors.Meta{ + "Service": value, + }, + }} + + suite.EqualError(expected, actual.Error()) +} + +func TestUnitServiceValueObjectSuite(t *testing.T) { + suite.Run(t, new(ServiceValueObjectTestSuite)) +} diff --git a/pkg/context/shared/domain/valueobjs/status.go b/pkg/context/shared/domain/valueobjs/status.go new file mode 100644 index 0000000..768b8f1 --- /dev/null +++ b/pkg/context/shared/domain/valueobjs/status.go @@ -0,0 +1,44 @@ +package valueobjs + +import ( + "strings" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/go-playground/validator/v10" +) + +var StatusOneOf = []string{"queued", "succeeded", "failed", "done"} + +type Status struct { + Status string `validate:"oneof=queued succeeded failed done"` +} + +func (value *Status) Value() string { + return value.Status +} + +func (value *Status) IsValid() error { + validate := validator.New(validator.WithRequiredStructEnabled()) + return validate.Struct(value) +} + +func NewStatus(value string) (models.ValueObject[string], error) { + value = strings.TrimSpace(value) + + valueObj := &Status{ + Status: value, + } + + if valueObj.IsValid() != nil { + return nil, errors.NewInvalidValue(&errors.Bubble{ + Where: "NewStatus", + What: "status must be only one of these values: " + strings.Join(StatusOneOf, ", "), + Why: errors.Meta{ + "Status": value, + }, + }) + } + + return valueObj, nil +} diff --git a/pkg/context/shared/domain/valueobjs/status.mother.go b/pkg/context/shared/domain/valueobjs/status.mother.go new file mode 100644 index 0000000..73e1134 --- /dev/null +++ b/pkg/context/shared/domain/valueobjs/status.mother.go @@ -0,0 +1,25 @@ +package valueobjs + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/domain/services" +) + +func StatusWithValidValue() models.ValueObject[string] { + value, err := NewStatus(services.Create.RandomString([]string{"queued", "succeeded", "failed", "done"})) + + if err != nil { + errors.Panic(err.Error(), "StatusWithValidValue") + } + + return value +} + +func StatusWithInvalidValue() (string, error) { + value := "x" + + _, err := NewStatus(value) + + return value, err +} diff --git a/pkg/context/shared/domain/valueobjs/status_test.go b/pkg/context/shared/domain/valueobjs/status_test.go new file mode 100644 index 0000000..6a25366 --- /dev/null +++ b/pkg/context/shared/domain/valueobjs/status_test.go @@ -0,0 +1,38 @@ +package valueobjs_test + +import ( + "testing" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/valueobjs" + "github.com/stretchr/testify/suite" +) + +type StatusValueObjectTestSuite struct { + suite.Suite +} + +func (suite *StatusValueObjectTestSuite) SetupTest() {} + +func (suite *StatusValueObjectTestSuite) TestWithInvalidValue() { + value, err := valueobjs.StatusWithInvalidValue() + + var actual *errors.InvalidValue + + suite.ErrorAs(err, &actual) + + expected := &errors.InvalidValue{Bubble: &errors.Bubble{ + When: actual.When, + Where: "NewStatus", + What: "status must be only one of these values: queued, succeeded, failed, done", + Why: errors.Meta{ + "Status": value, + }, + }} + + suite.EqualError(expected, actual.Error()) +} + +func TestUnitStatusValueObjectSuite(t *testing.T) { + suite.Run(t, new(StatusValueObjectTestSuite)) +} diff --git a/pkg/context/shared/domain/valueobjs/type.go b/pkg/context/shared/domain/valueobjs/type.go new file mode 100644 index 0000000..b1f3e90 --- /dev/null +++ b/pkg/context/shared/domain/valueobjs/type.go @@ -0,0 +1,44 @@ +package valueobjs + +import ( + "strings" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/go-playground/validator/v10" +) + +var TypeOneOf = []string{"event", "command"} + +type Type struct { + Type string `validate:"oneof=event command"` +} + +func (value *Type) Value() string { + return value.Type +} + +func (value *Type) IsValid() error { + validate := validator.New(validator.WithRequiredStructEnabled()) + return validate.Struct(value) +} + +func NewType(value string) (models.ValueObject[string], error) { + value = strings.TrimSpace(value) + + valueObj := &Type{ + Type: value, + } + + if valueObj.IsValid() != nil { + return nil, errors.NewInvalidValue(&errors.Bubble{ + Where: "NewType", + What: "type must be only one of these values: " + strings.Join(TypeOneOf, ", "), + Why: errors.Meta{ + "Type": value, + }, + }) + } + + return valueObj, nil +} diff --git a/pkg/context/shared/domain/valueobjs/type.mother.go b/pkg/context/shared/domain/valueobjs/type.mother.go new file mode 100644 index 0000000..5b4aa1a --- /dev/null +++ b/pkg/context/shared/domain/valueobjs/type.mother.go @@ -0,0 +1,25 @@ +package valueobjs + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/domain/services" +) + +func TypeWithValidValue() models.ValueObject[string] { + value, err := NewType(services.Create.RandomString([]string{"event", "command"})) + + if err != nil { + errors.Panic(err.Error(), "TypeWithValidValue") + } + + return value +} + +func TypeWithInvalidValue() (string, error) { + value := "x" + + _, err := NewType(value) + + return value, err +} diff --git a/pkg/context/shared/domain/valueobjs/type_test.go b/pkg/context/shared/domain/valueobjs/type_test.go new file mode 100644 index 0000000..f3eeff2 --- /dev/null +++ b/pkg/context/shared/domain/valueobjs/type_test.go @@ -0,0 +1,38 @@ +package valueobjs_test + +import ( + "testing" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/valueobjs" + "github.com/stretchr/testify/suite" +) + +type TypeValueObjectTestSuite struct { + suite.Suite +} + +func (suite *TypeValueObjectTestSuite) SetupTest() {} + +func (suite *TypeValueObjectTestSuite) TestWithInvalidValue() { + value, err := valueobjs.TypeWithInvalidValue() + + var actual *errors.InvalidValue + + suite.ErrorAs(err, &actual) + + expected := &errors.InvalidValue{Bubble: &errors.Bubble{ + When: actual.When, + Where: "NewType", + What: "type must be only one of these values: event, command", + Why: errors.Meta{ + "Type": value, + }, + }} + + suite.EqualError(expected, actual.Error()) +} + +func TestUnitTypeValueObjectSuite(t *testing.T) { + suite.Run(t, new(TypeValueObjectTestSuite)) +} diff --git a/pkg/context/shared/domain/valueobjs/version.go b/pkg/context/shared/domain/valueobjs/version.go new file mode 100644 index 0000000..1105152 --- /dev/null +++ b/pkg/context/shared/domain/valueobjs/version.go @@ -0,0 +1,42 @@ +package valueobjs + +import ( + "strings" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/go-playground/validator/v10" +) + +type Version struct { + Version string `validate:"number"` +} + +func (value *Version) Value() string { + return value.Version +} + +func (value *Version) IsValid() error { + validate := validator.New(validator.WithRequiredStructEnabled()) + return validate.Struct(value) +} + +func NewVersion(value string) (models.ValueObject[string], error) { + value = strings.TrimSpace(value) + + valueObj := &Version{ + Version: value, + } + + if valueObj.IsValid() != nil { + return nil, errors.NewInvalidValue(&errors.Bubble{ + Where: "NewVersion", + What: "version must be numeric only", + Why: errors.Meta{ + "Version": value, + }, + }) + } + + return valueObj, nil +} diff --git a/pkg/context/shared/domain/valueobjs/version.mother.go b/pkg/context/shared/domain/valueobjs/version.mother.go new file mode 100644 index 0000000..3281277 --- /dev/null +++ b/pkg/context/shared/domain/valueobjs/version.mother.go @@ -0,0 +1,25 @@ +package valueobjs + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/domain/services" +) + +func VersionWithValidValue() models.ValueObject[string] { + value, err := NewVersion(services.Create.Regex(`^[0-9]{1,2}$`)) + + if err != nil { + errors.Panic(err.Error(), "VersionWithValidValue") + } + + return value +} + +func VersionWithInvalidValue() (string, error) { + value := "x" + + _, err := NewVersion(value) + + return value, err +} diff --git a/pkg/context/shared/domain/valueobjs/version_test.go b/pkg/context/shared/domain/valueobjs/version_test.go new file mode 100644 index 0000000..faca879 --- /dev/null +++ b/pkg/context/shared/domain/valueobjs/version_test.go @@ -0,0 +1,38 @@ +package valueobjs_test + +import ( + "testing" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/valueobjs" + "github.com/stretchr/testify/suite" +) + +type VersionValueObjectTestSuite struct { + suite.Suite +} + +func (suite *VersionValueObjectTestSuite) SetupTest() {} + +func (suite *VersionValueObjectTestSuite) TestWithInvalidValue() { + value, err := valueobjs.VersionWithInvalidValue() + + var actual *errors.InvalidValue + + suite.ErrorAs(err, &actual) + + expected := &errors.InvalidValue{Bubble: &errors.Bubble{ + When: actual.When, + Where: "NewVersion", + What: "version must be numeric only", + Why: errors.Meta{ + "Version": value, + }, + }} + + suite.EqualError(expected, actual.Error()) +} + +func TestUnitVersionValueObjectSuite(t *testing.T) { + suite.Run(t, new(VersionValueObjectTestSuite)) +} diff --git a/pkg/context/shared/infrastructure/authentications/jwt.go b/pkg/context/shared/infrastructure/authentications/jwt.go new file mode 100644 index 0000000..66a7d19 --- /dev/null +++ b/pkg/context/shared/infrastructure/authentications/jwt.go @@ -0,0 +1,52 @@ +package authentications + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/golang-jwt/jwt/v5" +) + +type Payload = map[string]any + +type JWT struct { + secretKey []byte +} + +func (auth *JWT) Generate(payload map[string]any) (string, error) { + token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims(payload)) + + signature, err := token.SignedString(auth.secretKey) + + if err != nil { + return "", errors.NewInternal(&errors.Bubble{ + Where: "Generate", + What: "failure to sign a jwt", + Who: err, + }) + } + + return signature, nil +} + +func (auth *JWT) Validate(signature string) (jwt.MapClaims, error) { + token, _ := jwt.Parse(signature, func(token *jwt.Token) (any, error) { + return auth.secretKey, nil + }) + + if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid { + return claims, nil + } + + return nil, errors.NewFailure(&errors.Bubble{ + Where: "Validate", + What: "invalid jwt signature", + Why: errors.Meta{ + "JWT": signature, + }, + }) +} + +func NewJWT(secretKey string) *JWT { + return &JWT{ + secretKey: []byte(secretKey), + } +} diff --git a/pkg/context/shared/infrastructure/communications/broker.mock.go b/pkg/context/shared/infrastructure/communications/broker.mock.go new file mode 100644 index 0000000..b0fb66f --- /dev/null +++ b/pkg/context/shared/infrastructure/communications/broker.mock.go @@ -0,0 +1,35 @@ +package communications + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/messages" + "github.com/stretchr/testify/mock" +) + +type BrokerMock struct { + mock.Mock +} + +func (broker *BrokerMock) PublishMessages(messages []*messages.Message) error { + broker.Called(messages) + return nil +} + +func (broker *BrokerMock) AddRouter(router *messages.Router) error { + broker.Called(router) + return nil +} + +func (broker *BrokerMock) AddQueue(queue *messages.Queue) error { + broker.Called(queue) + return nil +} + +func (broker *BrokerMock) AddQueueMessageBind(queue *messages.Queue, bindingKeys []string) error { + broker.Called(queue, bindingKeys) + return nil +} + +func (broker *BrokerMock) AddQueueConsumer(consumer messages.Consumer) error { + broker.Called(consumer) + return nil +} diff --git a/pkg/context/shared/infrastructure/communications/consumer.mock.go b/pkg/context/shared/infrastructure/communications/consumer.mock.go new file mode 100644 index 0000000..883cc47 --- /dev/null +++ b/pkg/context/shared/infrastructure/communications/consumer.mock.go @@ -0,0 +1,20 @@ +package communications + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/messages" + "github.com/stretchr/testify/mock" +) + +type ConsumerMock struct { + mock.Mock +} + +func (consumer *ConsumerMock) SubscribedTo() []*messages.Queue { + args := consumer.Called() + return args.Get(0).([]*messages.Queue) +} + +func (consumer *ConsumerMock) On(message *messages.Message) error { + // TODO?(goroutine): consumer.Called(message) + return nil +} diff --git a/pkg/context/shared/infrastructure/communications/rabbitmq.broker_test.go b/pkg/context/shared/infrastructure/communications/rabbitmq.broker_test.go new file mode 100644 index 0000000..c05eb46 --- /dev/null +++ b/pkg/context/shared/infrastructure/communications/rabbitmq.broker_test.go @@ -0,0 +1,95 @@ +package communications_test + +import ( + "fmt" + "os" + "testing" + + "github.com/bastean/codexgo/pkg/context/shared/domain/messages" + "github.com/bastean/codexgo/pkg/context/shared/infrastructure/communications" + "github.com/bastean/codexgo/pkg/context/shared/infrastructure/loggers" + "github.com/stretchr/testify/suite" +) + +type RabbitMQBrokerTestSuite struct { + suite.Suite + sut messages.Broker + logger *loggers.LoggerMock + router *messages.Router + queue *messages.Queue + consumer *communications.ConsumerMock + messages []*messages.Message +} + +func (suite *RabbitMQBrokerTestSuite) SetupTest() { + suite.logger = new(loggers.LoggerMock) + + uri := os.Getenv("BROKER_URI") + + suite.sut, _ = communications.NewRabbitMQ(uri, suite.logger) + + suite.router = &messages.Router{Name: "test"} + + queueName := messages.NewRecipientName(&messages.RecipientNameComponents{ + Service: "queue", + Entity: "queue", + Action: "assert", + Event: "test", + Status: "succeeded", + }) + + suite.queue = &messages.Queue{Name: queueName} + + suite.consumer = new(communications.ConsumerMock) + + messageRoutingKey := messages.NewRoutingKey(&messages.RoutingKeyComponents{ + Service: "publisher", + Version: "1", + Type: messages.Type.Event, + Entity: "publisher", + Event: "test", + Status: messages.Status.Succeeded, + }) + + messageAttributes := messages.Attributes{} + + messageMeta := messages.Meta{} + + message := messages.NewMessage(messageRoutingKey, messageAttributes, messageMeta) + + message.Id = "0" + + message.OccurredOn = "0" + + suite.messages = append(suite.messages, message) +} + +func (suite *RabbitMQBrokerTestSuite) TestBroker() { + suite.NoError(suite.sut.AddRouter(suite.router)) + + suite.NoError(suite.sut.AddQueue(suite.queue)) + + bindingKeys := []string{"#.event.#.test.succeeded"} + + bindingSucceeded := fmt.Sprintf("binding queue [%s] to exchange [%s] with binding key [%s]", suite.queue.Name, suite.router.Name, bindingKeys[0]) + + suite.logger.Mock.On("Info", bindingSucceeded) + + suite.NoError(suite.sut.AddQueueMessageBind(suite.queue, bindingKeys)) + + suite.consumer.Mock.On("SubscribedTo").Return([]*messages.Queue{suite.queue}) + + suite.NoError(suite.sut.AddQueueConsumer(suite.consumer)) + + // TODO?(goroutine): suite.consumer.Mock.On("On", suite.messages[0]) + + suite.NoError(suite.sut.PublishMessages(suite.messages)) + + suite.logger.AssertExpectations(suite.T()) + + suite.consumer.AssertExpectations(suite.T()) +} + +func TestIntegrationRabbitMQBrokerSuite(t *testing.T) { + suite.Run(t, new(RabbitMQBrokerTestSuite)) +} diff --git a/pkg/context/shared/infrastructure/communications/rabbitmq.go b/pkg/context/shared/infrastructure/communications/rabbitmq.go new file mode 100644 index 0000000..1ce12ef --- /dev/null +++ b/pkg/context/shared/infrastructure/communications/rabbitmq.go @@ -0,0 +1,288 @@ +package communications + +import ( + "context" + "encoding/json" + "fmt" + "time" + + "github.com/google/uuid" + amqp "github.com/rabbitmq/amqp091-go" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/messages" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" +) + +type RabbitMQ struct { + *amqp.Connection + *amqp.Channel + models.Logger + exchange string +} + +func (rmq *RabbitMQ) AddRouter(router *messages.Router) error { + err := rmq.Channel.ExchangeDeclare( + router.Name, + "topic", + true, + false, + false, + false, + nil, + ) + + rmq.exchange = router.Name + + if err != nil { + return errors.NewInternal(&errors.Bubble{ + Where: "AddRouter", + What: "failure to declare a router", + Why: errors.Meta{ + "Router": router.Name, + }, + Who: err, + }) + } + + return nil +} + +func (rmq *RabbitMQ) AddQueue(queue *messages.Queue) error { + _, err := rmq.Channel.QueueDeclare( + queue.Name, + true, + false, + false, + false, + nil, + ) + + if err != nil { + return errors.NewInternal(&errors.Bubble{ + Where: "AddQueue", + What: "failure to declare a queue", + Why: errors.Meta{ + "Queue": queue.Name, + }, + Who: err, + }) + } + + return nil +} + +func (rmq *RabbitMQ) AddQueueMessageBind(queue *messages.Queue, bindingKeys []string) error { + var errWrap error + + for _, bindingKey := range bindingKeys { + rmq.Logger.Info(fmt.Sprintf("binding queue [%s] to exchange [%s] with binding key [%s]", queue.Name, rmq.exchange, bindingKey)) + + err := rmq.Channel.QueueBind( + queue.Name, + bindingKey, + rmq.exchange, + false, + nil) + + if err != nil { + errToWrap := errors.NewInternal(&errors.Bubble{ + Where: "AddQueueMessageBind", + What: "failure to bind a queue", + Why: errors.Meta{ + "Queue": queue.Name, + "Binding Key": bindingKey, + "Exchange": rmq.exchange, + }, + Who: err, + }) + + errWrap = errors.Join(errWrap, errToWrap) + } + } + + if errWrap != nil { + return errors.BubbleUp(errWrap, "AddQueueMessageBind") + } + + return nil +} + +func (rmq *RabbitMQ) AddQueueConsumer(consumer messages.Consumer) error { + var errWrap error + + for _, queue := range consumer.SubscribedTo() { + deliveries, err := rmq.Channel.Consume( + queue.Name, + "", + false, + false, + false, + false, + nil, + ) + + if err != nil { + errToWrap := errors.NewInternal(&errors.Bubble{ + Where: "AddQueueConsumer", + What: "failure to register a consumer", + Why: errors.Meta{ + "Queue": queue.Name, + "Exchange": rmq.exchange, + }, + Who: err, + }) + + errWrap = errors.Join(errWrap, errToWrap) + + continue + } + + go func() { + for delivery := range deliveries { + message := new(messages.Message) + + err := json.Unmarshal(delivery.Body, message) + + if err != nil { + rmq.Logger.Error(fmt.Sprintf("failed to deliver a message with id [%s] from queue [%s]", message.Id, queue.Name)) + continue + } + + err = consumer.On(message) + + if err != nil { + rmq.Logger.Error(fmt.Sprintf("failed to consume a message with id [%s] from queue [%s]", message.Id, queue.Name)) + continue + } + + delivery.Ack(false) + } + }() + } + + if errWrap != nil { + return errors.BubbleUp(errWrap, "AddQueueConsumer") + } + + return nil +} + +func (rmq *RabbitMQ) PublishMessages(messages []*messages.Message) error { + var errWrap error + + for _, message := range messages { + if message.Id == "" { + message.Id = uuid.NewString() + } + + if message.OccurredOn == "" { + message.OccurredOn = time.Now().UTC().Format(time.RFC3339Nano) + } + + body, err := json.Marshal(message) + + if err != nil { + errToWrap := errors.NewInternal(&errors.Bubble{ + Where: "PublishMessages", + What: "cannot encode message to json", + Why: errors.Meta{ + "Exchange": rmq.exchange, + "Message": message.Id, + }, + Who: err, + }) + + errWrap = errors.Join(errWrap, errToWrap) + + continue + } + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + + defer cancel() + + err = rmq.Channel.PublishWithContext(ctx, + rmq.exchange, + message.Type, + false, + false, + amqp.Publishing{ + DeliveryMode: amqp.Persistent, + ContentType: "application/json", + Body: body, + }) + + if err != nil { + errToWrap := errors.NewInternal(&errors.Bubble{ + Where: "PublishMessages", + What: "failure to publish a message", + Why: errors.Meta{ + "Exchange": rmq.exchange, + "Message": message.Id, + }, + Who: err, + }) + + errWrap = errors.Join(errWrap, errToWrap) + } + } + + if errWrap != nil { + return errors.BubbleUp(errWrap, "PublishMessages") + } + + return nil +} + +func CloseRabbitMQ(rmq *RabbitMQ) error { + err := rmq.Channel.Close() + + if err != nil { + return errors.NewInternal(&errors.Bubble{ + Where: "CloseRabbitMQ", + What: "failure to close channel", + Who: err, + }) + } + + err = rmq.Connection.Close() + + if err != nil { + return errors.NewInternal(&errors.Bubble{ + Where: "CloseRabbitMQ", + What: "failure to close rabbitmq connection", + Who: err, + }) + } + + return nil +} + +func NewRabbitMQ(uri string, logger models.Logger) (messages.Broker, error) { + conn, err := amqp.Dial(uri) + + if err != nil { + return nil, errors.NewInternal(&errors.Bubble{ + Where: "NewRabbitMQ", + What: "failure connecting to rabbitmq", + Who: err, + }) + } + + ch, err := conn.Channel() + + if err != nil { + return nil, errors.NewInternal(&errors.Bubble{ + Where: "NewRabbitMQ", + What: "failure to open a channel", + Who: err, + }) + } + + return &RabbitMQ{ + Connection: conn, + Channel: ch, + Logger: logger, + }, nil +} diff --git a/pkg/context/shared/infrastructure/loggers/logger.go b/pkg/context/shared/infrastructure/loggers/logger.go new file mode 100644 index 0000000..fd6b110 --- /dev/null +++ b/pkg/context/shared/infrastructure/loggers/logger.go @@ -0,0 +1,23 @@ +package loggers + +import ( + "log" +) + +type Logger struct{} + +func (logger *Logger) Debug(message string) { + log.Print(message) +} + +func (logger *Logger) Error(message string) { + log.Print(message) +} + +func (logger *Logger) Fatal(message string) { + log.Fatal(message) +} + +func (logger *Logger) Info(message string) { + log.Print(message) +} diff --git a/pkg/context/shared/infrastructure/loggers/logger.mock.go b/pkg/context/shared/infrastructure/loggers/logger.mock.go new file mode 100644 index 0000000..16bbc9a --- /dev/null +++ b/pkg/context/shared/infrastructure/loggers/logger.mock.go @@ -0,0 +1,25 @@ +package loggers + +import ( + "github.com/stretchr/testify/mock" +) + +type LoggerMock struct { + mock.Mock +} + +func (logger *LoggerMock) Debug(message string) { + logger.Called(message) +} + +func (logger *LoggerMock) Error(message string) { + logger.Called(message) +} + +func (logger *LoggerMock) Fatal(message string) { + logger.Called(message) +} + +func (logger *LoggerMock) Info(message string) { + logger.Called(message) +} diff --git a/pkg/context/shared/infrastructure/persistences/mongo.go b/pkg/context/shared/infrastructure/persistences/mongo.go new file mode 100644 index 0000000..ecc2058 --- /dev/null +++ b/pkg/context/shared/infrastructure/persistences/mongo.go @@ -0,0 +1,93 @@ +package persistences + +import ( + "context" + "regexp" + "strings" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "golang.org/x/text/cases" + "golang.org/x/text/language" +) + +type MongoDB struct { + *mongo.Client + *mongo.Database +} + +func NewMongoDatabase(uri, databaseName string) (*MongoDB, error) { + var err error + + clientOptions := options.Client().ApplyURI(uri) + + client, err := mongo.Connect(context.Background(), clientOptions) + + if err != nil { + return nil, errors.NewInternal(&errors.Bubble{ + Where: "NewMongoDatabase", + What: "failure to create a mongodb client", + Who: err, + }) + } + + err = client.Ping(context.Background(), nil) + + if err != nil { + return nil, errors.NewInternal(&errors.Bubble{ + Where: "NewMongoDatabase", + What: "failure connecting to mongodb", + Who: err, + }) + } + + return &MongoDB{ + Client: client, + Database: client.Database(databaseName), + }, nil +} + +func HandleMongoDuplicateKeyError(err error) error { + re := regexp.MustCompile(`{ [A-Za-z0-9]+:`) + + rawField := re.FindString(err.Error()) + + toTitle := cases.Title(language.English) + + field := toTitle.String(strings.TrimSuffix(strings.Split(rawField, " ")[1], ":")) + + return errors.NewAlreadyExist(&errors.Bubble{ + Where: "HandleMongoDuplicateKeyError", + What: "already registered", + Why: errors.Meta{ + "Field": field, + }, + Who: err, + }) +} + +func HandleMongoDocumentNotFound(index string, err error) error { + return errors.NewNotExist(&errors.Bubble{ + Where: "HandleMongoDocumentNotFound", + What: "not found", + Why: errors.Meta{ + "Index": index, + }, + Who: err, + }) +} + +func CloseMongoDatabase(ctx context.Context, mdb *MongoDB) error { + err := mdb.Client.Disconnect(ctx) + + if err != nil { + return errors.NewInternal(&errors.Bubble{ + Where: "CloseMongoDatabase", + What: "failure to close connection with mongodb", + Who: err, + }) + } + + return nil +} diff --git a/pkg/context/shared/infrastructure/transports/smtp.go b/pkg/context/shared/infrastructure/transports/smtp.go new file mode 100644 index 0000000..70ef300 --- /dev/null +++ b/pkg/context/shared/infrastructure/transports/smtp.go @@ -0,0 +1,21 @@ +package transports + +import ( + "net/smtp" +) + +type SMTP struct { + smtp.Auth + MIMEHeaders, SMTPServerURL, Username, Password, ServerURL string +} + +func NewSMTP(host, port, username, password, serverURL string) *SMTP { + return &SMTP{ + Auth: smtp.PlainAuth("", username, password, host), + MIMEHeaders: "MIME-version: 1.0;\n" + "Content-Type: text/html; charset=\"UTF-8\";\n\n", + SMTPServerURL: host + ":" + port, + Username: username, + Password: password, + ServerURL: serverURL, + } +} diff --git a/pkg/context/user/application/create/command.go b/pkg/context/user/application/create/command.go new file mode 100644 index 0000000..1431c5a --- /dev/null +++ b/pkg/context/user/application/create/command.go @@ -0,0 +1,5 @@ +package create + +type Command struct { + Id, Email, Username, Password string +} diff --git a/pkg/context/user/application/create/command.handler.go b/pkg/context/user/application/create/command.handler.go new file mode 100644 index 0000000..8a4fef5 --- /dev/null +++ b/pkg/context/user/application/create/command.handler.go @@ -0,0 +1,37 @@ +package create + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/messages" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/domain/types" + "github.com/bastean/codexgo/pkg/context/user/domain/aggregate" +) + +type Handler struct { + models.UseCase[*aggregate.User, types.Empty] + messages.Broker +} + +func (handler *Handler) Handle(command *Command) error { + user, err := aggregate.NewUser(&aggregate.UserPrimitive{ + Id: command.Id, + Email: command.Email, + Username: command.Username, + Password: command.Password, + }) + + if err != nil { + return errors.BubbleUp(err, "Handle") + } + + _, err = handler.UseCase.Run(user) + + if err != nil { + return errors.BubbleUp(err, "Handle") + } + + handler.Broker.PublishMessages(user.PullMessages()) + + return nil +} diff --git a/pkg/context/user/application/create/command.handler_test.go b/pkg/context/user/application/create/command.handler_test.go new file mode 100644 index 0000000..4b95d39 --- /dev/null +++ b/pkg/context/user/application/create/command.handler_test.go @@ -0,0 +1,63 @@ +package create_test + +import ( + "testing" + + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/domain/types" + "github.com/bastean/codexgo/pkg/context/shared/infrastructure/communications" + "github.com/bastean/codexgo/pkg/context/user/application/create" + "github.com/bastean/codexgo/pkg/context/user/domain/aggregate" + "github.com/bastean/codexgo/pkg/context/user/infrastructure/persistence" + "github.com/stretchr/testify/suite" +) + +type CreateHandlerTestSuite struct { + suite.Suite + sut models.CommandHandler[*create.Command] + usecase models.UseCase[*aggregate.User, types.Empty] + repository *persistence.RepositoryMock + broker *communications.BrokerMock +} + +func (suite *CreateHandlerTestSuite) SetupTest() { + suite.broker = new(communications.BrokerMock) + + suite.repository = new(persistence.RepositoryMock) + + suite.usecase = &create.Create{ + Repository: suite.repository, + } + + suite.sut = &create.Handler{ + UseCase: suite.usecase, + Broker: suite.broker, + } +} + +func (suite *CreateHandlerTestSuite) TestCreate() { + command := create.RandomCommand() + + user, _ := aggregate.NewUser(&aggregate.UserPrimitive{ + Id: command.Id, + Email: command.Email, + Username: command.Username, + Password: command.Password, + }) + + messages := user.Messages + + suite.repository.On("Save", user) + + suite.broker.On("PublishMessages", messages) + + suite.NoError(suite.sut.Handle(command)) + + suite.repository.AssertExpectations(suite.T()) + + suite.broker.AssertExpectations(suite.T()) +} + +func TestUnitCreateHandlerSuite(t *testing.T) { + suite.Run(t, new(CreateHandlerTestSuite)) +} diff --git a/pkg/context/user/application/create/command.mother.go b/pkg/context/user/application/create/command.mother.go new file mode 100644 index 0000000..e4f7d24 --- /dev/null +++ b/pkg/context/user/application/create/command.mother.go @@ -0,0 +1,19 @@ +package create + +import ( + "github.com/bastean/codexgo/pkg/context/user/domain/valueobj" +) + +func RandomCommand() *Command { + id := valueobj.IdWithValidValue() + email := valueobj.EmailWithValidValue() + username := valueobj.UsernameWithValidValue() + password := valueobj.PasswordWithValidValue() + + return &Command{ + Id: id.Value(), + Email: email.Value(), + Username: username.Value(), + Password: password.Value(), + } +} diff --git a/pkg/context/user/application/create/create.go b/pkg/context/user/application/create/create.go new file mode 100644 index 0000000..f177532 --- /dev/null +++ b/pkg/context/user/application/create/create.go @@ -0,0 +1,22 @@ +package create + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/types" + "github.com/bastean/codexgo/pkg/context/user/domain/aggregate" + "github.com/bastean/codexgo/pkg/context/user/domain/model" +) + +type Create struct { + model.Repository +} + +func (create *Create) Run(user *aggregate.User) (types.Empty, error) { + err := create.Repository.Save(user) + + if err != nil { + return nil, errors.BubbleUp(err, "Run") + } + + return nil, nil +} diff --git a/pkg/context/user/application/created/created.consumer.go b/pkg/context/user/application/created/created.consumer.go new file mode 100644 index 0000000..ab568f1 --- /dev/null +++ b/pkg/context/user/application/created/created.consumer.go @@ -0,0 +1,49 @@ +package created + +import ( + "encoding/json" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/messages" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/domain/types" + "github.com/bastean/codexgo/pkg/context/user/domain/event" +) + +type Consumer struct { + models.UseCase[*event.CreatedSucceeded, types.Empty] + Queues []*messages.Queue +} + +func (consumer *Consumer) SubscribedTo() []*messages.Queue { + return consumer.Queues +} + +func (consumer *Consumer) On(message *messages.Message) error { + user := new(event.CreatedSucceeded) + + user.Attributes = new(event.CreatedSucceededAttributes) + + err := json.Unmarshal(message.Attributes, user.Attributes) + + if err != nil { + return errors.NewInternal(&errors.Bubble{ + Where: "On", + What: "failure to obtain message attributes", + Why: errors.Meta{ + "Id": message.Id, + "Routing Key": message.Type, + "Occurred On": message.OccurredOn, + }, + Who: err, + }) + } + + _, err = consumer.UseCase.Run(user) + + if err != nil { + return errors.BubbleUp(err, "On") + } + + return nil +} diff --git a/pkg/context/user/application/created/created.consumer_test.go b/pkg/context/user/application/created/created.consumer_test.go new file mode 100644 index 0000000..bbc2347 --- /dev/null +++ b/pkg/context/user/application/created/created.consumer_test.go @@ -0,0 +1,67 @@ +package created_test + +import ( + "encoding/json" + "testing" + + "github.com/bastean/codexgo/pkg/context/shared/domain/messages" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/domain/types" + "github.com/bastean/codexgo/pkg/context/user/application/created" + "github.com/bastean/codexgo/pkg/context/user/domain/event" + "github.com/bastean/codexgo/pkg/context/user/infrastructure/communication" + "github.com/stretchr/testify/suite" +) + +type CreatedConsumerTestSuite struct { + suite.Suite + sut messages.Consumer + usecase models.UseCase[*event.CreatedSucceeded, types.Empty] + transport *communication.TransportMock + queues []*messages.Queue +} + +func (suite *CreatedConsumerTestSuite) SetupTest() { + queueName := messages.NewRecipientName(&messages.RecipientNameComponents{ + Service: "queue", + Entity: "queue", + Action: "assert", + Event: "test", + Status: "succeeded", + }) + + suite.queues = append(suite.queues, &messages.Queue{ + Name: queueName, + }) + + suite.transport = new(communication.TransportMock) + + suite.usecase = &created.Created{ + Transport: suite.transport, + } + + suite.sut = &created.Consumer{ + UseCase: suite.usecase, + Queues: suite.queues, + } +} + +func (suite *CreatedConsumerTestSuite) TestCreatedSucceeded() { + message := event.RandomCreatedSucceeded() + + user := new(event.CreatedSucceeded) + + user.Attributes = new(event.CreatedSucceededAttributes) + + suite.NoError(json.Unmarshal(message.Attributes, user.Attributes)) + + suite.transport.On("Submit", user.Attributes) + + suite.NoError(suite.sut.On(message)) + + suite.transport.AssertExpectations(suite.T()) +} + +func TestUnitCreatedConsumerSuite(t *testing.T) { + suite.Run(t, new(CreatedConsumerTestSuite)) +} diff --git a/pkg/context/user/application/created/created.go b/pkg/context/user/application/created/created.go new file mode 100644 index 0000000..5414ece --- /dev/null +++ b/pkg/context/user/application/created/created.go @@ -0,0 +1,22 @@ +package created + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/domain/types" + "github.com/bastean/codexgo/pkg/context/user/domain/event" +) + +type Created struct { + models.Transport +} + +func (created *Created) Run(user *event.CreatedSucceeded) (types.Empty, error) { + err := created.Transport.Submit(user.Attributes) + + if err != nil { + return nil, errors.BubbleUp(err, "Run") + } + + return nil, nil +} diff --git a/pkg/context/user/application/delete/command.go b/pkg/context/user/application/delete/command.go new file mode 100644 index 0000000..0cf11b1 --- /dev/null +++ b/pkg/context/user/application/delete/command.go @@ -0,0 +1,5 @@ +package delete + +type Command struct { + Id, Password string +} diff --git a/pkg/context/user/application/delete/command.handler.go b/pkg/context/user/application/delete/command.handler.go new file mode 100644 index 0000000..87f171c --- /dev/null +++ b/pkg/context/user/application/delete/command.handler.go @@ -0,0 +1,38 @@ +package delete + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/domain/types" + "github.com/bastean/codexgo/pkg/context/user/domain/valueobj" +) + +type Input struct { + Id, Password models.ValueObject[string] +} + +type Handler struct { + models.UseCase[*Input, types.Empty] +} + +func (handler *Handler) Handle(command *Command) error { + id, errId := valueobj.NewId(command.Id) + password, errPassword := valueobj.NewPassword(command.Password) + + err := errors.Join(errId, errPassword) + + if err != nil { + return errors.BubbleUp(err, "Handle") + } + + _, err = handler.UseCase.Run(&Input{ + Id: id, + Password: password, + }) + + if err != nil { + return errors.BubbleUp(err, "Handle") + } + + return nil +} diff --git a/pkg/context/user/application/delete/command.handler_test.go b/pkg/context/user/application/delete/command.handler_test.go new file mode 100644 index 0000000..a25d5c7 --- /dev/null +++ b/pkg/context/user/application/delete/command.handler_test.go @@ -0,0 +1,64 @@ +package delete_test + +import ( + "testing" + + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/domain/types" + "github.com/bastean/codexgo/pkg/context/user/application/delete" + "github.com/bastean/codexgo/pkg/context/user/domain/aggregate" + "github.com/bastean/codexgo/pkg/context/user/domain/model" + "github.com/bastean/codexgo/pkg/context/user/infrastructure/cryptographic" + "github.com/bastean/codexgo/pkg/context/user/infrastructure/persistence" + "github.com/stretchr/testify/suite" +) + +type DeleteHandlerTestSuite struct { + suite.Suite + sut models.CommandHandler[*delete.Command] + usecase models.UseCase[*delete.Input, types.Empty] + hashing *cryptographic.HashingMock + repository *persistence.RepositoryMock +} + +func (suite *DeleteHandlerTestSuite) SetupTest() { + suite.repository = new(persistence.RepositoryMock) + + suite.hashing = new(cryptographic.HashingMock) + + suite.usecase = &delete.Delete{ + Repository: suite.repository, + Hashing: suite.hashing, + } + + suite.sut = &delete.Handler{ + UseCase: suite.usecase, + } +} + +func (suite *DeleteHandlerTestSuite) TestDelete() { + user := aggregate.RandomUser() + + command := &delete.Command{ + Id: user.Id.Value(), + Password: user.Password.Value(), + } + + criteria := &model.RepositorySearchCriteria{ + Id: user.Id, + } + + suite.repository.On("Search", criteria).Return(user) + + suite.hashing.On("IsNotEqual", user.Password.Value(), user.Password.Value()).Return(false) + + suite.repository.On("Delete", user.Id) + + suite.NoError(suite.sut.Handle(command)) + + suite.repository.AssertExpectations(suite.T()) +} + +func TestUnitDeleteHandlerSuite(t *testing.T) { + suite.Run(t, new(DeleteHandlerTestSuite)) +} diff --git a/pkg/context/user/application/delete/command.mother.go b/pkg/context/user/application/delete/command.mother.go new file mode 100644 index 0000000..8b22b0c --- /dev/null +++ b/pkg/context/user/application/delete/command.mother.go @@ -0,0 +1,15 @@ +package delete + +import ( + "github.com/bastean/codexgo/pkg/context/user/domain/valueobj" +) + +func RandomCommand() *Command { + id := valueobj.IdWithValidValue() + password := valueobj.PasswordWithValidValue() + + return &Command{ + Id: id.Value(), + Password: password.Value(), + } +} diff --git a/pkg/context/user/application/delete/delete.go b/pkg/context/user/application/delete/delete.go new file mode 100644 index 0000000..05dc0a4 --- /dev/null +++ b/pkg/context/user/application/delete/delete.go @@ -0,0 +1,37 @@ +package delete + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/types" + "github.com/bastean/codexgo/pkg/context/user/domain/model" + "github.com/bastean/codexgo/pkg/context/user/domain/service" +) + +type Delete struct { + model.Repository + model.Hashing +} + +func (delete *Delete) Run(input *Input) (types.Empty, error) { + user, err := delete.Repository.Search(&model.RepositorySearchCriteria{ + Id: input.Id, + }) + + if err != nil { + return nil, errors.BubbleUp(err, "Run") + } + + err = service.IsPasswordInvalid(delete.Hashing, user.Password.Value(), input.Password.Value()) + + if err != nil { + return nil, errors.BubbleUp(err, "Run") + } + + err = delete.Repository.Delete(user.Id) + + if err != nil { + return nil, errors.BubbleUp(err, "Run") + } + + return nil, nil +} diff --git a/pkg/context/user/application/login/login.go b/pkg/context/user/application/login/login.go new file mode 100644 index 0000000..d090289 --- /dev/null +++ b/pkg/context/user/application/login/login.go @@ -0,0 +1,31 @@ +package login + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/user/domain/aggregate" + "github.com/bastean/codexgo/pkg/context/user/domain/model" + "github.com/bastean/codexgo/pkg/context/user/domain/service" +) + +type Login struct { + model.Repository + model.Hashing +} + +func (login *Login) Run(input *Input) (*aggregate.User, error) { + user, err := login.Repository.Search(&model.RepositorySearchCriteria{ + Email: input.Email, + }) + + if err != nil { + return nil, errors.BubbleUp(err, "Run") + } + + err = service.IsPasswordInvalid(login.Hashing, user.Password.Value(), input.Password.Value()) + + if err != nil { + return nil, errors.BubbleUp(err, "Run") + } + + return user, nil +} diff --git a/pkg/context/user/application/login/query.go b/pkg/context/user/application/login/query.go new file mode 100644 index 0000000..f087799 --- /dev/null +++ b/pkg/context/user/application/login/query.go @@ -0,0 +1,5 @@ +package login + +type Query struct { + Email, Password string +} diff --git a/pkg/context/user/application/login/query.handler.go b/pkg/context/user/application/login/query.handler.go new file mode 100644 index 0000000..5f65ea7 --- /dev/null +++ b/pkg/context/user/application/login/query.handler.go @@ -0,0 +1,40 @@ +package login + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/user/domain/aggregate" + "github.com/bastean/codexgo/pkg/context/user/domain/valueobj" +) + +type Input struct { + Email, Password models.ValueObject[string] +} + +type Handler struct { + models.UseCase[*Input, *aggregate.User] +} + +func (handler *Handler) Handle(query *Query) (*Response, error) { + email, errEmail := valueobj.NewEmail(query.Email) + password, errPassword := valueobj.NewPassword(query.Password) + + err := errors.Join(errEmail, errPassword) + + if err != nil { + return nil, errors.BubbleUp(err, "Handle") + } + + user, err := handler.UseCase.Run(&Input{ + Email: email, + Password: password, + }) + + if err != nil { + return nil, errors.BubbleUp(err, "Handle") + } + + response := Response(*user.ToPrimitives()) + + return &response, nil +} diff --git a/pkg/context/user/application/login/query.handler_test.go b/pkg/context/user/application/login/query.handler_test.go new file mode 100644 index 0000000..5883145 --- /dev/null +++ b/pkg/context/user/application/login/query.handler_test.go @@ -0,0 +1,69 @@ +package login_test + +import ( + "testing" + + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/user/application/login" + "github.com/bastean/codexgo/pkg/context/user/domain/aggregate" + "github.com/bastean/codexgo/pkg/context/user/domain/model" + "github.com/bastean/codexgo/pkg/context/user/infrastructure/cryptographic" + "github.com/bastean/codexgo/pkg/context/user/infrastructure/persistence" + "github.com/stretchr/testify/suite" +) + +type LoginHandlerTestSuite struct { + suite.Suite + sut models.QueryHandler[*login.Query, *login.Response] + usecase models.UseCase[*login.Input, *aggregate.User] + hashing *cryptographic.HashingMock + repository *persistence.RepositoryMock +} + +func (suite *LoginHandlerTestSuite) SetupTest() { + suite.repository = new(persistence.RepositoryMock) + + suite.hashing = new(cryptographic.HashingMock) + + suite.usecase = &login.Login{ + Repository: suite.repository, + Hashing: suite.hashing, + } + + suite.sut = &login.Handler{ + UseCase: suite.usecase, + } +} + +func (suite *LoginHandlerTestSuite) TestLogin() { + user := aggregate.RandomUser() + + query := &login.Query{ + Email: user.Email.Value(), + Password: user.Password.Value(), + } + + criteria := &model.RepositorySearchCriteria{ + Email: user.Email, + } + + suite.repository.On("Search", criteria).Return(user) + + suite.hashing.On("IsNotEqual", user.Password.Value(), user.Password.Value()).Return(false) + + expected := user.ToPrimitives() + + actual, err := suite.sut.Handle(query) + + suite.NoError(err) + + suite.repository.AssertExpectations(suite.T()) + + suite.hashing.AssertExpectations(suite.T()) + + suite.EqualValues(expected, actual) +} + +func TestUnitLoginHandlerSuite(t *testing.T) { + suite.Run(t, new(LoginHandlerTestSuite)) +} diff --git a/pkg/context/user/application/login/query.mother.go b/pkg/context/user/application/login/query.mother.go new file mode 100644 index 0000000..0ac933f --- /dev/null +++ b/pkg/context/user/application/login/query.mother.go @@ -0,0 +1,15 @@ +package login + +import ( + "github.com/bastean/codexgo/pkg/context/user/domain/valueobj" +) + +func RandomQuery() *Query { + email := valueobj.EmailWithValidValue() + password := valueobj.PasswordWithValidValue() + + return &Query{ + Email: email.Value(), + Password: password.Value(), + } +} diff --git a/pkg/context/user/application/login/response.go b/pkg/context/user/application/login/response.go new file mode 100644 index 0000000..b7bf61e --- /dev/null +++ b/pkg/context/user/application/login/response.go @@ -0,0 +1,6 @@ +package login + +type Response struct { + Id, Email, Username, Password string + Verified bool +} diff --git a/pkg/context/user/application/read/query.go b/pkg/context/user/application/read/query.go new file mode 100644 index 0000000..0c83d00 --- /dev/null +++ b/pkg/context/user/application/read/query.go @@ -0,0 +1,5 @@ +package read + +type Query struct { + Id string +} diff --git a/pkg/context/user/application/read/query.handler.go b/pkg/context/user/application/read/query.handler.go new file mode 100644 index 0000000..87109d2 --- /dev/null +++ b/pkg/context/user/application/read/query.handler.go @@ -0,0 +1,30 @@ +package read + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/user/domain/aggregate" + "github.com/bastean/codexgo/pkg/context/user/domain/valueobj" +) + +type Handler struct { + models.UseCase[models.ValueObject[string], *aggregate.User] +} + +func (handler *Handler) Handle(query *Query) (*Response, error) { + id, err := valueobj.NewId(query.Id) + + if err != nil { + return nil, errors.BubbleUp(err, "Handle") + } + + user, err := handler.UseCase.Run(id) + + if err != nil { + return nil, errors.BubbleUp(err, "Handle") + } + + response := Response(*user.ToPrimitives()) + + return &response, nil +} diff --git a/pkg/context/user/application/read/query.handler_test.go b/pkg/context/user/application/read/query.handler_test.go new file mode 100644 index 0000000..29cca3f --- /dev/null +++ b/pkg/context/user/application/read/query.handler_test.go @@ -0,0 +1,59 @@ +package read_test + +import ( + "testing" + + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/user/application/read" + "github.com/bastean/codexgo/pkg/context/user/domain/aggregate" + "github.com/bastean/codexgo/pkg/context/user/domain/model" + "github.com/bastean/codexgo/pkg/context/user/infrastructure/persistence" + "github.com/stretchr/testify/suite" +) + +type ReadHandlerTestSuite struct { + suite.Suite + sut models.QueryHandler[*read.Query, *read.Response] + usecase models.UseCase[models.ValueObject[string], *aggregate.User] + repository *persistence.RepositoryMock +} + +func (suite *ReadHandlerTestSuite) SetupTest() { + suite.repository = new(persistence.RepositoryMock) + + suite.usecase = &read.Read{ + Repository: suite.repository, + } + + suite.sut = &read.Handler{ + UseCase: suite.usecase, + } +} + +func (suite *ReadHandlerTestSuite) TestLogin() { + user := aggregate.RandomUser() + + query := &read.Query{ + Id: user.Id.Value(), + } + + criteria := &model.RepositorySearchCriteria{ + Id: user.Id, + } + + suite.repository.On("Search", criteria).Return(user) + + expected := user.ToPrimitives() + + actual, err := suite.sut.Handle(query) + + suite.NoError(err) + + suite.repository.AssertExpectations(suite.T()) + + suite.EqualValues(expected, actual) +} + +func TestUnitReadHandlerSuite(t *testing.T) { + suite.Run(t, new(ReadHandlerTestSuite)) +} diff --git a/pkg/context/user/application/read/query.mother.go b/pkg/context/user/application/read/query.mother.go new file mode 100644 index 0000000..0bffba5 --- /dev/null +++ b/pkg/context/user/application/read/query.mother.go @@ -0,0 +1,13 @@ +package read + +import ( + "github.com/bastean/codexgo/pkg/context/user/domain/valueobj" +) + +func RandomQuery() *Query { + id := valueobj.IdWithValidValue() + + return &Query{ + Id: id.Value(), + } +} diff --git a/pkg/context/user/application/read/read.go b/pkg/context/user/application/read/read.go new file mode 100644 index 0000000..343e9c8 --- /dev/null +++ b/pkg/context/user/application/read/read.go @@ -0,0 +1,24 @@ +package read + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/user/domain/aggregate" + "github.com/bastean/codexgo/pkg/context/user/domain/model" +) + +type Read struct { + model.Repository +} + +func (read *Read) Run(id models.ValueObject[string]) (*aggregate.User, error) { + user, err := read.Repository.Search(&model.RepositorySearchCriteria{ + Id: id, + }) + + if err != nil { + return nil, errors.BubbleUp(err, "Run") + } + + return user, nil +} diff --git a/pkg/context/user/application/read/response.go b/pkg/context/user/application/read/response.go new file mode 100644 index 0000000..c1eb152 --- /dev/null +++ b/pkg/context/user/application/read/response.go @@ -0,0 +1,6 @@ +package read + +type Response struct { + Id, Email, Username, Password string + Verified bool +} diff --git a/pkg/context/user/application/update/command.go b/pkg/context/user/application/update/command.go new file mode 100644 index 0000000..8daf24f --- /dev/null +++ b/pkg/context/user/application/update/command.go @@ -0,0 +1,5 @@ +package update + +type Command struct { + Id, Email, Username, Password, UpdatedPassword string +} diff --git a/pkg/context/user/application/update/command.handler.go b/pkg/context/user/application/update/command.handler.go new file mode 100644 index 0000000..d34e410 --- /dev/null +++ b/pkg/context/user/application/update/command.handler.go @@ -0,0 +1,52 @@ +package update + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/domain/types" + "github.com/bastean/codexgo/pkg/context/user/domain/aggregate" + "github.com/bastean/codexgo/pkg/context/user/domain/valueobj" +) + +type Input struct { + User *aggregate.User + UpdatedPassword models.ValueObject[string] +} + +type Handler struct { + models.UseCase[*Input, types.Empty] +} + +func (handler *Handler) Handle(command *Command) error { + user, err := aggregate.NewUser(&aggregate.UserPrimitive{ + Id: command.Id, + Email: command.Email, + Username: command.Username, + Password: command.Password, + }) + + if err != nil { + return errors.BubbleUp(err, "Handle") + } + + var updatedPassword models.ValueObject[string] + + if command.UpdatedPassword != "" { + updatedPassword, err = valueobj.NewPassword(command.UpdatedPassword) + + if err != nil { + return errors.BubbleUp(err, "Handle") + } + } + + _, err = handler.UseCase.Run(&Input{ + User: user, + UpdatedPassword: updatedPassword, + }) + + if err != nil { + return errors.BubbleUp(err, "Handle") + } + + return nil +} diff --git a/pkg/context/user/application/update/command.handler_test.go b/pkg/context/user/application/update/command.handler_test.go new file mode 100644 index 0000000..fe8f52d --- /dev/null +++ b/pkg/context/user/application/update/command.handler_test.go @@ -0,0 +1,71 @@ +package update_test + +import ( + "testing" + + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/domain/types" + "github.com/bastean/codexgo/pkg/context/user/application/update" + "github.com/bastean/codexgo/pkg/context/user/domain/aggregate" + "github.com/bastean/codexgo/pkg/context/user/domain/model" + "github.com/bastean/codexgo/pkg/context/user/domain/valueobj" + "github.com/bastean/codexgo/pkg/context/user/infrastructure/cryptographic" + "github.com/bastean/codexgo/pkg/context/user/infrastructure/persistence" + "github.com/stretchr/testify/suite" +) + +type UpdateHandlerTestSuite struct { + suite.Suite + sut models.CommandHandler[*update.Command] + usecase models.UseCase[*update.Input, types.Empty] + hashing *cryptographic.HashingMock + repository *persistence.RepositoryMock +} + +func (suite *UpdateHandlerTestSuite) SetupTest() { + suite.repository = new(persistence.RepositoryMock) + + suite.hashing = new(cryptographic.HashingMock) + + suite.usecase = &update.Update{ + Repository: suite.repository, + Hashing: suite.hashing, + } + + suite.sut = &update.Handler{ + UseCase: suite.usecase, + } +} + +func (suite *UpdateHandlerTestSuite) TestUpdate() { + command := update.RandomCommand() + + user, _ := aggregate.NewUser(&aggregate.UserPrimitive{ + Id: command.Id, + Email: command.Email, + Username: command.Username, + Password: command.UpdatedPassword, + }) + + idVO, _ := valueobj.NewId(command.Id) + + criteria := &model.RepositorySearchCriteria{ + Id: idVO, + } + + suite.repository.On("Search", criteria).Return(user) + + suite.hashing.On("IsNotEqual", user.Password.Value(), command.Password).Return(false) + + suite.repository.On("Update", user) + + suite.NoError(suite.sut.Handle(command)) + + suite.repository.AssertExpectations(suite.T()) + + suite.hashing.AssertExpectations(suite.T()) +} + +func TestUnitUpdateHandlerSuite(t *testing.T) { + suite.Run(t, new(UpdateHandlerTestSuite)) +} diff --git a/pkg/context/user/application/update/command.mother.go b/pkg/context/user/application/update/command.mother.go new file mode 100644 index 0000000..a01a478 --- /dev/null +++ b/pkg/context/user/application/update/command.mother.go @@ -0,0 +1,21 @@ +package update + +import ( + "github.com/bastean/codexgo/pkg/context/user/domain/valueobj" +) + +func RandomCommand() *Command { + id := valueobj.IdWithValidValue() + email := valueobj.EmailWithValidValue() + username := valueobj.UsernameWithValidValue() + password := valueobj.PasswordWithValidValue() + updatedPassword := valueobj.PasswordWithValidValue() + + return &Command{ + Id: id.Value(), + Email: email.Value(), + Username: username.Value(), + Password: password.Value(), + UpdatedPassword: updatedPassword.Value(), + } +} diff --git a/pkg/context/user/application/update/update.go b/pkg/context/user/application/update/update.go new file mode 100644 index 0000000..6084818 --- /dev/null +++ b/pkg/context/user/application/update/update.go @@ -0,0 +1,43 @@ +package update + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/types" + "github.com/bastean/codexgo/pkg/context/user/domain/model" + "github.com/bastean/codexgo/pkg/context/user/domain/service" +) + +type Update struct { + model.Repository + model.Hashing +} + +func (update *Update) Run(input *Input) (types.Empty, error) { + user, err := update.Repository.Search(&model.RepositorySearchCriteria{ + Id: input.User.Id, + }) + + if err != nil { + return nil, errors.BubbleUp(err, "Run") + } + + err = service.IsPasswordInvalid(update.Hashing, user.Password.Value(), input.User.Password.Value()) + + if err != nil { + return nil, errors.BubbleUp(err, "Run") + } + + if input.UpdatedPassword != nil { + input.User.Password = input.UpdatedPassword + } + + input.User.Verified = user.Verified + + err = update.Repository.Update(input.User) + + if err != nil { + return nil, errors.BubbleUp(err, "Run") + } + + return nil, nil +} diff --git a/pkg/context/user/application/verify/command.go b/pkg/context/user/application/verify/command.go new file mode 100644 index 0000000..25b17f7 --- /dev/null +++ b/pkg/context/user/application/verify/command.go @@ -0,0 +1,5 @@ +package verify + +type Command struct { + Id string +} diff --git a/pkg/context/user/application/verify/command.handler.go b/pkg/context/user/application/verify/command.handler.go new file mode 100644 index 0000000..c03f2d5 --- /dev/null +++ b/pkg/context/user/application/verify/command.handler.go @@ -0,0 +1,28 @@ +package verify + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/domain/types" + "github.com/bastean/codexgo/pkg/context/user/domain/valueobj" +) + +type Handler struct { + models.UseCase[models.ValueObject[string], types.Empty] +} + +func (handler *Handler) Handle(command *Command) error { + idVO, err := valueobj.NewId(command.Id) + + if err != nil { + return errors.BubbleUp(err, "Handle") + } + + _, err = handler.UseCase.Run(idVO) + + if err != nil { + return errors.BubbleUp(err, "Handle") + } + + return nil +} diff --git a/pkg/context/user/application/verify/command.handler_test.go b/pkg/context/user/application/verify/command.handler_test.go new file mode 100644 index 0000000..94c3635 --- /dev/null +++ b/pkg/context/user/application/verify/command.handler_test.go @@ -0,0 +1,59 @@ +package verify_test + +import ( + "testing" + + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/domain/types" + "github.com/bastean/codexgo/pkg/context/user/application/verify" + "github.com/bastean/codexgo/pkg/context/user/domain/aggregate" + "github.com/bastean/codexgo/pkg/context/user/domain/model" + "github.com/bastean/codexgo/pkg/context/user/domain/valueobj" + "github.com/bastean/codexgo/pkg/context/user/infrastructure/persistence" + "github.com/stretchr/testify/suite" +) + +type VerifyHandlerTestSuite struct { + suite.Suite + sut models.CommandHandler[*verify.Command] + usecase models.UseCase[models.ValueObject[string], types.Empty] + repository *persistence.RepositoryMock +} + +func (suite *VerifyHandlerTestSuite) SetupTest() { + suite.repository = new(persistence.RepositoryMock) + + suite.usecase = &verify.Verify{ + Repository: suite.repository, + } + + suite.sut = &verify.Handler{ + UseCase: suite.usecase, + } +} + +func (suite *VerifyHandlerTestSuite) TestVerify() { + command := verify.RandomCommand() + + user := aggregate.RandomUser() + + idVO, _ := valueobj.NewId(command.Id) + + user.Id = idVO + + criteria := &model.RepositorySearchCriteria{ + Id: idVO, + } + + suite.repository.On("Search", criteria).Return(user) + + suite.repository.On("Verify", idVO) + + suite.NoError(suite.sut.Handle(command)) + + suite.repository.AssertExpectations(suite.T()) +} + +func TestUnitVerifyHandlerSuite(t *testing.T) { + suite.Run(t, new(VerifyHandlerTestSuite)) +} diff --git a/pkg/context/user/application/verify/command.mother.go b/pkg/context/user/application/verify/command.mother.go new file mode 100644 index 0000000..ef7f11a --- /dev/null +++ b/pkg/context/user/application/verify/command.mother.go @@ -0,0 +1,13 @@ +package verify + +import ( + "github.com/bastean/codexgo/pkg/context/user/domain/valueobj" +) + +func RandomCommand() *Command { + id := valueobj.IdWithValidValue() + + return &Command{ + Id: id.Value(), + } +} diff --git a/pkg/context/user/application/verify/verify.go b/pkg/context/user/application/verify/verify.go new file mode 100644 index 0000000..51030f9 --- /dev/null +++ b/pkg/context/user/application/verify/verify.go @@ -0,0 +1,34 @@ +package verify + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/domain/types" + "github.com/bastean/codexgo/pkg/context/user/domain/model" +) + +type Verify struct { + model.Repository +} + +func (verify *Verify) Run(id models.ValueObject[string]) (types.Empty, error) { + user, err := verify.Repository.Search(&model.RepositorySearchCriteria{ + Id: id, + }) + + if err != nil { + return nil, errors.BubbleUp(err, "Run") + } + + if user.Verified.Value() { + return nil, nil + } + + err = verify.Repository.Verify(id) + + if err != nil { + return nil, errors.BubbleUp(err, "Run") + } + + return nil, nil +} diff --git a/pkg/context/user/domain/aggregate/user.mother.go b/pkg/context/user/domain/aggregate/user.mother.go new file mode 100644 index 0000000..af5a72c --- /dev/null +++ b/pkg/context/user/domain/aggregate/user.mother.go @@ -0,0 +1,26 @@ +package aggregate + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/user/domain/valueobj" +) + +func RandomUser() *User { + id := valueobj.IdWithValidValue() + email := valueobj.EmailWithValidValue() + username := valueobj.UsernameWithValidValue() + password := valueobj.PasswordWithValidValue() + + user, err := NewUser(&UserPrimitive{ + Id: id.Value(), + Email: email.Value(), + Username: username.Value(), + Password: password.Value(), + }) + + if err != nil { + errors.Panic(err.Error(), "RandomUser") + } + + return user +} diff --git a/pkg/context/user/domain/aggregate/user.root.go b/pkg/context/user/domain/aggregate/user.root.go new file mode 100644 index 0000000..dd21433 --- /dev/null +++ b/pkg/context/user/domain/aggregate/user.root.go @@ -0,0 +1,91 @@ +package aggregate + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/aggregates" + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/user/domain/event" + "github.com/bastean/codexgo/pkg/context/user/domain/valueobj" +) + +type User struct { + *aggregates.AggregateRoot + Id, Email, Username, Password models.ValueObject[string] + Verified models.ValueObject[bool] +} + +type UserPrimitive struct { + Id, Email, Username, Password string + Verified bool +} + +func create(primitive *UserPrimitive) (*User, error) { + aggregateRoot := aggregates.NewAggregateRoot() + + idVO, errId := valueobj.NewId(primitive.Id) + emailVO, errEmail := valueobj.NewEmail(primitive.Email) + usernameVO, errUsername := valueobj.NewUsername(primitive.Username) + passwordVO, errPassword := valueobj.NewPassword(primitive.Password) + verifiedVO, errVerified := valueobj.NewVerified(primitive.Verified) + + err := errors.Join(errId, errEmail, errUsername, errPassword, errVerified) + + if err != nil { + return nil, errors.BubbleUp(err, "create") + } + + return &User{ + AggregateRoot: aggregateRoot, + Id: idVO, + Email: emailVO, + Username: usernameVO, + Password: passwordVO, + Verified: verifiedVO, + }, nil +} + +func (user *User) ToPrimitives() *UserPrimitive { + return &UserPrimitive{ + Id: user.Id.Value(), + Email: user.Email.Value(), + Username: user.Username.Value(), + Password: user.Password.Value(), + Verified: user.Verified.Value(), + } +} + +func FromPrimitives(primitive *UserPrimitive) (*User, error) { + user, err := create(primitive) + + if err != nil { + return nil, errors.BubbleUp(err, "FromPrimitives") + } + + return user, nil +} + +func NewUser(primitive *UserPrimitive) (*User, error) { + primitive.Verified = false + + user, err := create(primitive) + + if err != nil { + return nil, errors.BubbleUp(err, "NewUser") + } + + message, err := event.NewCreatedSucceeded(&event.CreatedSucceeded{ + Attributes: &event.CreatedSucceededAttributes{ + Id: user.Id.Value(), + Email: user.Email.Value(), + Username: user.Username.Value(), + }, + }) + + if err != nil { + return nil, errors.BubbleUp(err, "NewUser") + } + + user.RecordMessage(message) + + return user, nil +} diff --git a/pkg/context/user/domain/event/created.go b/pkg/context/user/domain/event/created.go new file mode 100644 index 0000000..8ab742c --- /dev/null +++ b/pkg/context/user/domain/event/created.go @@ -0,0 +1,42 @@ +package event + +import ( + "encoding/json" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/messages" +) + +var CreatedSucceededTypeRoutingKey = messages.NewRoutingKey(&messages.RoutingKeyComponents{ + Service: "user", + Version: "1", + Type: messages.Type.Event, + Entity: "user", + Event: "created", + Status: messages.Status.Succeeded, +}) + +type CreatedSucceededAttributes struct { + Id, Email, Username string +} + +type CreatedSucceeded struct { + Attributes *CreatedSucceededAttributes +} + +func NewCreatedSucceeded(event *CreatedSucceeded) (*messages.Message, error) { + attributes, err := json.Marshal(event.Attributes) + + if err != nil { + return nil, errors.NewInternal(&errors.Bubble{ + Where: "NewCreatedSucceeded", + What: "failure to create event message attributes", + Why: errors.Meta{ + "Routing Key": CreatedSucceededTypeRoutingKey, + }, + Who: err, + }) + } + + return messages.NewMessage(CreatedSucceededTypeRoutingKey, attributes, messages.Meta{}), nil +} diff --git a/pkg/context/user/domain/event/created.mother.go b/pkg/context/user/domain/event/created.mother.go new file mode 100644 index 0000000..cac8cc6 --- /dev/null +++ b/pkg/context/user/domain/event/created.mother.go @@ -0,0 +1,27 @@ +package event + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/messages" + "github.com/bastean/codexgo/pkg/context/user/domain/valueobj" +) + +func RandomCreatedSucceeded() *messages.Message { + id := valueobj.IdWithValidValue() + email := valueobj.EmailWithValidValue() + username := valueobj.UsernameWithValidValue() + + event, err := NewCreatedSucceeded(&CreatedSucceeded{ + Attributes: &CreatedSucceededAttributes{ + Id: id.Value(), + Email: email.Value(), + Username: username.Value(), + }, + }) + + if err != nil { + errors.Panic(err.Error(), "RandomCreatedSucceeded") + } + + return event +} diff --git a/pkg/context/user/domain/model/hashing.go b/pkg/context/user/domain/model/hashing.go new file mode 100644 index 0000000..9010d45 --- /dev/null +++ b/pkg/context/user/domain/model/hashing.go @@ -0,0 +1,6 @@ +package model + +type Hashing interface { + Hash(plain string) (string, error) + IsNotEqual(hashed, plain string) bool +} diff --git a/pkg/context/user/domain/model/repository.go b/pkg/context/user/domain/model/repository.go new file mode 100644 index 0000000..303b6c1 --- /dev/null +++ b/pkg/context/user/domain/model/repository.go @@ -0,0 +1,18 @@ +package model + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/user/domain/aggregate" +) + +type RepositorySearchCriteria struct { + Id, Email models.ValueObject[string] +} + +type Repository interface { + Save(user *aggregate.User) error + Verify(id models.ValueObject[string]) error + Update(user *aggregate.User) error + Delete(id models.ValueObject[string]) error + Search(criteria *RepositorySearchCriteria) (*aggregate.User, error) +} diff --git a/pkg/context/user/domain/service/password.go b/pkg/context/user/domain/service/password.go new file mode 100644 index 0000000..55d75b9 --- /dev/null +++ b/pkg/context/user/domain/service/password.go @@ -0,0 +1,17 @@ +package service + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/user/domain/model" +) + +func IsPasswordInvalid(hashing model.Hashing, hashed, plain string) error { + if hashing.IsNotEqual(hashed, plain) { + return errors.NewFailure(&errors.Bubble{ + Where: "IsPasswordInvalid", + What: "passwords do not match", + }) + } + + return nil +} diff --git a/pkg/context/user/domain/valueobj/email.go b/pkg/context/user/domain/valueobj/email.go new file mode 100644 index 0000000..d422a15 --- /dev/null +++ b/pkg/context/user/domain/valueobj/email.go @@ -0,0 +1,10 @@ +package valueobj + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/domain/valueobjs" +) + +func NewEmail(email string) (models.ValueObject[string], error) { + return valueobjs.NewEmail(email) +} diff --git a/pkg/context/user/domain/valueobj/email.mother.go b/pkg/context/user/domain/valueobj/email.mother.go new file mode 100644 index 0000000..db45b17 --- /dev/null +++ b/pkg/context/user/domain/valueobj/email.mother.go @@ -0,0 +1,25 @@ +package valueobj + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/domain/services" +) + +func EmailWithValidValue() models.ValueObject[string] { + value, err := NewEmail(services.Create.Email()) + + if err != nil { + errors.Panic(err.Error(), "EmailWithValidValue") + } + + return value +} + +func EmailWithInvalidValue() (string, error) { + value := "x" + + _, err := NewEmail(value) + + return value, err +} diff --git a/pkg/context/user/domain/valueobj/email_test.go b/pkg/context/user/domain/valueobj/email_test.go new file mode 100644 index 0000000..5491366 --- /dev/null +++ b/pkg/context/user/domain/valueobj/email_test.go @@ -0,0 +1,38 @@ +package valueobj_test + +import ( + "testing" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/user/domain/valueobj" + "github.com/stretchr/testify/suite" +) + +type EmailValueObjectTestSuite struct { + suite.Suite +} + +func (suite *EmailValueObjectTestSuite) SetupTest() {} + +func (suite *EmailValueObjectTestSuite) TestWithInvalidValue() { + value, err := valueobj.EmailWithInvalidValue() + + var actual *errors.InvalidValue + + suite.ErrorAs(err, &actual) + + expected := &errors.InvalidValue{Bubble: &errors.Bubble{ + When: actual.When, + Where: "NewEmail", + What: "invalid email format", + Why: errors.Meta{ + "Email": value, + }, + }} + + suite.EqualError(expected, actual.Error()) +} + +func TestUnitEmailValueObjectSuite(t *testing.T) { + suite.Run(t, new(EmailValueObjectTestSuite)) +} diff --git a/pkg/context/user/domain/valueobj/id.go b/pkg/context/user/domain/valueobj/id.go new file mode 100644 index 0000000..4735b52 --- /dev/null +++ b/pkg/context/user/domain/valueobj/id.go @@ -0,0 +1,10 @@ +package valueobj + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/domain/valueobjs" +) + +func NewId(id string) (models.ValueObject[string], error) { + return valueobjs.NewId(id) +} diff --git a/pkg/context/user/domain/valueobj/id.mother.go b/pkg/context/user/domain/valueobj/id.mother.go new file mode 100644 index 0000000..bb575d4 --- /dev/null +++ b/pkg/context/user/domain/valueobj/id.mother.go @@ -0,0 +1,26 @@ +package valueobj + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/domain/services" +) + +func IdWithValidValue() models.ValueObject[string] { + value, err := NewId(services.Create.UUID()) + + if err != nil { + errors.Panic(err.Error(), "IdWithValidValue") + } + + return value + +} + +func IdWithInvalidValue() (string, error) { + value := "x" + + _, err := NewId(value) + + return value, err +} diff --git a/pkg/context/user/domain/valueobj/id_test.go b/pkg/context/user/domain/valueobj/id_test.go new file mode 100644 index 0000000..7c9afad --- /dev/null +++ b/pkg/context/user/domain/valueobj/id_test.go @@ -0,0 +1,38 @@ +package valueobj_test + +import ( + "testing" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/user/domain/valueobj" + "github.com/stretchr/testify/suite" +) + +type IdValueObjectTestSuite struct { + suite.Suite +} + +func (suite *IdValueObjectTestSuite) SetupTest() {} + +func (suite *IdValueObjectTestSuite) TestWithInvalidValue() { + value, err := valueobj.IdWithInvalidValue() + + var actual *errors.InvalidValue + + suite.ErrorAs(err, &actual) + + expected := &errors.InvalidValue{Bubble: &errors.Bubble{ + When: actual.When, + Where: "NewId", + What: "invalid uuid4 format", + Why: errors.Meta{ + "Id": value, + }, + }} + + suite.EqualError(expected, actual.Error()) +} + +func TestUnitIdValueObjectSuite(t *testing.T) { + suite.Run(t, new(IdValueObjectTestSuite)) +} diff --git a/pkg/context/user/domain/valueobj/password.go b/pkg/context/user/domain/valueobj/password.go new file mode 100644 index 0000000..b725758 --- /dev/null +++ b/pkg/context/user/domain/valueobj/password.go @@ -0,0 +1,41 @@ +package valueobj + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/go-playground/validator/v10" +) + +const PasswordMinCharactersLength = "8" +const PasswordMaxCharactersLength = "64" + +type Password struct { + Password string `validate:"gte=8,lte=64"` +} + +func (value *Password) Value() string { + return value.Password +} + +func (value *Password) IsValid() error { + validate := validator.New(validator.WithRequiredStructEnabled()) + return validate.Struct(value) +} + +func NewPassword(value string) (models.ValueObject[string], error) { + valueObj := &Password{ + Password: value, + } + + if valueObj.IsValid() != nil { + return nil, errors.NewInvalidValue(&errors.Bubble{ + Where: "NewPassword", + What: "password must be between " + PasswordMinCharactersLength + " to " + PasswordMaxCharactersLength + " characters", + Why: errors.Meta{ + "Password": value, + }, + }) + } + + return valueObj, nil +} diff --git a/pkg/context/user/domain/valueobj/password.mother.go b/pkg/context/user/domain/valueobj/password.mother.go new file mode 100644 index 0000000..a9d8077 --- /dev/null +++ b/pkg/context/user/domain/valueobj/password.mother.go @@ -0,0 +1,25 @@ +package valueobj + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/domain/services" +) + +func PasswordWithValidValue() models.ValueObject[string] { + value, err := NewPassword(services.Create.Regex(`^[\W\w]{8,64}$`)) + + if err != nil { + errors.Panic(err.Error(), "PasswordWithValidValue") + } + + return value +} + +func PasswordWithInvalidLength() (string, error) { + value := "x" + + _, err := NewPassword(value) + + return value, err +} diff --git a/pkg/context/user/domain/valueobj/password_test.go b/pkg/context/user/domain/valueobj/password_test.go new file mode 100644 index 0000000..94f03e7 --- /dev/null +++ b/pkg/context/user/domain/valueobj/password_test.go @@ -0,0 +1,38 @@ +package valueobj_test + +import ( + "testing" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/user/domain/valueobj" + "github.com/stretchr/testify/suite" +) + +type PasswordValueObjectTestSuite struct { + suite.Suite +} + +func (suite *PasswordValueObjectTestSuite) SetupTest() {} + +func (suite *PasswordValueObjectTestSuite) TestWithInvalidLength() { + value, err := valueobj.PasswordWithInvalidLength() + + var actual *errors.InvalidValue + + suite.ErrorAs(err, &actual) + + expected := &errors.InvalidValue{Bubble: &errors.Bubble{ + When: actual.When, + Where: "NewPassword", + What: "password must be between " + "8" + " to " + "64" + " characters", + Why: errors.Meta{ + "Password": value, + }, + }} + + suite.EqualError(expected, actual.Error()) +} + +func TestUnitPasswordValueObjectSuite(t *testing.T) { + suite.Run(t, new(PasswordValueObjectTestSuite)) +} diff --git a/pkg/context/user/domain/valueobj/username.go b/pkg/context/user/domain/valueobj/username.go new file mode 100644 index 0000000..ca5c9c1 --- /dev/null +++ b/pkg/context/user/domain/valueobj/username.go @@ -0,0 +1,45 @@ +package valueobj + +import ( + "strings" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/go-playground/validator/v10" +) + +const UsernameMinCharactersLength = "2" +const UsernameMaxCharactersLength = "20" + +type Username struct { + Username string `validate:"gte=2,lte=20,alphanum"` +} + +func (value *Username) Value() string { + return value.Username +} + +func (value *Username) IsValid() error { + validate := validator.New(validator.WithRequiredStructEnabled()) + return validate.Struct(value) +} + +func NewUsername(value string) (models.ValueObject[string], error) { + value = strings.TrimSpace(value) + + valueObj := &Username{ + Username: value, + } + + if valueObj.IsValid() != nil { + return nil, errors.NewInvalidValue(&errors.Bubble{ + Where: "NewUsername", + What: "username must be between " + UsernameMinCharactersLength + " to " + UsernameMaxCharactersLength + " characters and be alphanumeric only", + Why: errors.Meta{ + "Username": value, + }, + }) + } + + return valueObj, nil +} diff --git a/pkg/context/user/domain/valueobj/username.mother.go b/pkg/context/user/domain/valueobj/username.mother.go new file mode 100644 index 0000000..0518d1d --- /dev/null +++ b/pkg/context/user/domain/valueobj/username.mother.go @@ -0,0 +1,33 @@ +package valueobj + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/domain/services" +) + +func UsernameWithValidValue() models.ValueObject[string] { + value, err := NewUsername(services.Create.Regex(`^[A-Za-z0-9]{2,20}$`)) + + if err != nil { + errors.Panic(err.Error(), "UsernameWithValidValue") + } + + return value +} + +func UsernameWithInvalidLength() (string, error) { + value := "x" + + _, err := NewUsername(value) + + return value, err +} + +func UsernameWithInvalidAlphanumeric() (string, error) { + value := "<>" + + _, err := NewUsername(value) + + return value, err +} diff --git a/pkg/context/user/domain/valueobj/username_test.go b/pkg/context/user/domain/valueobj/username_test.go new file mode 100644 index 0000000..0d2ce53 --- /dev/null +++ b/pkg/context/user/domain/valueobj/username_test.go @@ -0,0 +1,57 @@ +package valueobj_test + +import ( + "testing" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/user/domain/valueobj" + "github.com/stretchr/testify/suite" +) + +type UsernameValueObjectTestSuite struct { + suite.Suite +} + +func (suite *UsernameValueObjectTestSuite) SetupTest() {} + +func (suite *UsernameValueObjectTestSuite) TestWithInvalidLength() { + value, err := valueobj.UsernameWithInvalidLength() + + var actual *errors.InvalidValue + + suite.ErrorAs(err, &actual) + + expected := &errors.InvalidValue{Bubble: &errors.Bubble{ + When: actual.When, + Where: "NewUsername", + What: "username must be between " + "2" + " to " + "20" + " characters and be alphanumeric only", + Why: errors.Meta{ + "Username": value, + }, + }} + + suite.EqualError(expected, actual.Error()) +} + +func (suite *UsernameValueObjectTestSuite) TestWithInvalidAlphanumeric() { + value, err := valueobj.UsernameWithInvalidAlphanumeric() + + var actual *errors.InvalidValue + + suite.ErrorAs(err, &actual) + + expected := &errors.InvalidValue{Bubble: &errors.Bubble{ + When: actual.When, + Where: "NewUsername", + What: "username must be between " + "2" + " to " + "20" + " characters and be alphanumeric only", + Why: errors.Meta{ + "Username": value, + }, + }} + + suite.EqualError(expected, actual.Error()) +} + +func TestUnitUsernameValueObjectSuite(t *testing.T) { + suite.Run(t, new(UsernameValueObjectTestSuite)) +} diff --git a/pkg/context/user/domain/valueobj/verified.go b/pkg/context/user/domain/valueobj/verified.go new file mode 100644 index 0000000..440c289 --- /dev/null +++ b/pkg/context/user/domain/valueobj/verified.go @@ -0,0 +1,38 @@ +package valueobj + +import ( + "fmt" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" +) + +type Verified struct { + Verified bool +} + +func (value *Verified) Value() bool { + return value.Verified +} + +func (value *Verified) IsValid() error { + return nil +} + +func NewVerified(value bool) (models.ValueObject[bool], error) { + valueObj := &Verified{ + Verified: value, + } + + if valueObj.IsValid() != nil { + return nil, errors.NewInvalidValue(&errors.Bubble{ + Where: "NewVerified", + What: "invalid verified value", + Why: errors.Meta{ + "Verified": fmt.Sprintf("%t", value), + }, + }) + } + + return valueObj, nil +} diff --git a/pkg/context/user/infrastructure/communication/mail/confirmation.go b/pkg/context/user/infrastructure/communication/mail/confirmation.go new file mode 100644 index 0000000..88823d7 --- /dev/null +++ b/pkg/context/user/infrastructure/communication/mail/confirmation.go @@ -0,0 +1,57 @@ +package mail + +import ( + "bytes" + "context" + "fmt" + "net/smtp" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/infrastructure/transports" + "github.com/bastean/codexgo/pkg/context/user/domain/event" +) + +type Confirmation struct { + *transports.SMTP +} + +func (client *Confirmation) Submit(data any) error { + user, ok := data.(*event.CreatedSucceededAttributes) + + if !ok { + return errors.NewInternal(&errors.Bubble{ + Where: "Submit", + What: "failure in type assertion", + Why: errors.Meta{ + "Expected": new(event.CreatedSucceededAttributes), + "Actual": data, + }, + }) + } + + var message bytes.Buffer + + headers := fmt.Sprintf("From: %s\n"+"To: %s\n"+"Subject: Account Confirmation", client.Username, user.Email) + + _, _ = message.Write([]byte(fmt.Sprintf("%s\n%s\n", headers, client.MIMEHeaders))) + + link := fmt.Sprintf("%s/verify/%s", client.ServerURL, user.Id) + + ConfirmationTemplate(user.Username, link).Render(context.Background(), &message) + + err := smtp.SendMail(client.SMTPServerURL, client.Auth, client.Username, []string{user.Email}, message.Bytes()) + + if err != nil { + return errors.NewInternal(&errors.Bubble{ + Where: "Submit", + What: "failure to send an account confirmation mail", + Why: errors.Meta{ + "User Id": user.Id, + "SMTP Server URL": client.SMTPServerURL, + }, + Who: err, + }) + } + + return nil +} diff --git a/pkg/context/user/infrastructure/communication/mail/confirmation.templ b/pkg/context/user/infrastructure/communication/mail/confirmation.templ new file mode 100644 index 0000000..41daaa6 --- /dev/null +++ b/pkg/context/user/infrastructure/communication/mail/confirmation.templ @@ -0,0 +1,48 @@ +package mail + +templ ConfirmationTemplate(username, link string) { +
+
+
+ +
+
+

Hi { username }

+

+ Please confirm your account by clicking the button below +

+ + CONFIRM + + +
+
+
+} diff --git a/pkg/context/user/infrastructure/communication/mail/confirmation.transport_test.go b/pkg/context/user/infrastructure/communication/mail/confirmation.transport_test.go new file mode 100644 index 0000000..6882388 --- /dev/null +++ b/pkg/context/user/infrastructure/communication/mail/confirmation.transport_test.go @@ -0,0 +1,49 @@ +package mail_test + +import ( + "encoding/json" + "os" + "testing" + + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/infrastructure/transports" + "github.com/bastean/codexgo/pkg/context/user/domain/event" + "github.com/bastean/codexgo/pkg/context/user/infrastructure/communication/mail" + "github.com/stretchr/testify/suite" +) + +type MailConfirmationTransportTestSuite struct { + suite.Suite + sut models.Transport + smtp *transports.SMTP +} + +func (suite *MailConfirmationTransportTestSuite) SetupTest() { + suite.smtp = transports.NewSMTP( + os.Getenv("SMTP_HOST"), + os.Getenv("SMTP_PORT"), + os.Getenv("SMTP_USERNAME"), + os.Getenv("SMTP_PASSWORD"), + os.Getenv("URL"), + ) + + suite.sut = &mail.Confirmation{ + SMTP: suite.smtp, + } +} + +func (suite *MailConfirmationTransportTestSuite) TestSubmit() { + message := event.RandomCreatedSucceeded() + + user := new(event.CreatedSucceeded) + + user.Attributes = new(event.CreatedSucceededAttributes) + + suite.NoError(json.Unmarshal(message.Attributes, user.Attributes)) + + suite.NoError(suite.sut.Submit(user.Attributes)) +} + +func TestIntegrationMailConfirmationTransportSuite(t *testing.T) { + suite.Run(t, new(MailConfirmationTransportTestSuite)) +} diff --git a/pkg/context/user/infrastructure/communication/terminal/confirmation.go b/pkg/context/user/infrastructure/communication/terminal/confirmation.go new file mode 100644 index 0000000..a248649 --- /dev/null +++ b/pkg/context/user/infrastructure/communication/terminal/confirmation.go @@ -0,0 +1,35 @@ +package terminal + +import ( + "fmt" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/user/domain/event" +) + +type Confirmation struct { + models.Logger + ServerURL string +} + +func (client *Confirmation) Submit(data any) error { + user, ok := data.(*event.CreatedSucceededAttributes) + + if !ok { + return errors.NewInternal(&errors.Bubble{ + Where: "Submit", + What: "failure in type assertion", + Why: errors.Meta{ + "Expected": new(event.CreatedSucceededAttributes), + "Actual": data, + }, + }) + } + + link := fmt.Sprintf("Hi %s, please confirm your account through this link: %s/verify/%s", user.Username, client.ServerURL, user.Id) + + client.Logger.Info(link) + + return nil +} diff --git a/pkg/context/user/infrastructure/communication/terminal/confirmation.transport_test.go b/pkg/context/user/infrastructure/communication/terminal/confirmation.transport_test.go new file mode 100644 index 0000000..ea65ab2 --- /dev/null +++ b/pkg/context/user/infrastructure/communication/terminal/confirmation.transport_test.go @@ -0,0 +1,54 @@ +package terminal_test + +import ( + "encoding/json" + "fmt" + "os" + "testing" + + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/infrastructure/loggers" + "github.com/bastean/codexgo/pkg/context/user/domain/event" + "github.com/bastean/codexgo/pkg/context/user/infrastructure/communication/terminal" + "github.com/stretchr/testify/suite" +) + +type TerminalConfirmationTransportTestSuite struct { + suite.Suite + sut models.Transport + logger *loggers.LoggerMock + serverURL string +} + +func (suite *TerminalConfirmationTransportTestSuite) SetupTest() { + suite.logger = new(loggers.LoggerMock) + + suite.serverURL = os.Getenv("URL") + + suite.sut = &terminal.Confirmation{ + Logger: suite.logger, + ServerURL: suite.serverURL, + } +} + +func (suite *TerminalConfirmationTransportTestSuite) TestSubmit() { + message := event.RandomCreatedSucceeded() + + user := new(event.CreatedSucceeded) + + user.Attributes = new(event.CreatedSucceededAttributes) + + suite.NoError(json.Unmarshal(message.Attributes, user.Attributes)) + + link := fmt.Sprintf("Hi %s, please confirm your account through this link: %s/verify/%s", user.Attributes.Username, suite.serverURL, user.Attributes.Id) + + suite.logger.Mock.On("Info", link) + + suite.NoError(suite.sut.Submit(user.Attributes)) + + suite.logger.AssertExpectations(suite.T()) +} + +func TestIntegrationTerminalConfirmationTransportSuite(t *testing.T) { + suite.Run(t, new(TerminalConfirmationTransportTestSuite)) +} diff --git a/pkg/context/user/infrastructure/communication/transport.mock.go b/pkg/context/user/infrastructure/communication/transport.mock.go new file mode 100644 index 0000000..8d8faa6 --- /dev/null +++ b/pkg/context/user/infrastructure/communication/transport.mock.go @@ -0,0 +1,14 @@ +package communication + +import ( + "github.com/stretchr/testify/mock" +) + +type TransportMock struct { + mock.Mock +} + +func (transport *TransportMock) Submit(data any) error { + transport.Called(data) + return nil +} diff --git a/pkg/context/user/infrastructure/cryptographic/bcrypt.go b/pkg/context/user/infrastructure/cryptographic/bcrypt.go new file mode 100644 index 0000000..56a5382 --- /dev/null +++ b/pkg/context/user/infrastructure/cryptographic/bcrypt.go @@ -0,0 +1,28 @@ +package cryptographic + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "golang.org/x/crypto/bcrypt" +) + +type Bcrypt struct{} + +func (hashing *Bcrypt) Hash(plain string) (string, error) { + salt := 10 + bytes, err := bcrypt.GenerateFromPassword([]byte(plain), salt) + + if err != nil { + return "", errors.NewInternal(&errors.Bubble{ + Where: "Hash", + What: "failure to generate a hash", + Who: err, + }) + } + + return string(bytes), nil +} + +func (hashing *Bcrypt) IsNotEqual(hashed, plain string) bool { + err := bcrypt.CompareHashAndPassword([]byte(hashed), []byte(plain)) + return err != nil +} diff --git a/pkg/context/user/infrastructure/cryptographic/bcrypt.hashing_test.go b/pkg/context/user/infrastructure/cryptographic/bcrypt.hashing_test.go new file mode 100644 index 0000000..2d824db --- /dev/null +++ b/pkg/context/user/infrastructure/cryptographic/bcrypt.hashing_test.go @@ -0,0 +1,49 @@ +package cryptographic_test + +import ( + "testing" + + "github.com/bastean/codexgo/pkg/context/user/domain/model" + "github.com/bastean/codexgo/pkg/context/user/domain/valueobj" + "github.com/bastean/codexgo/pkg/context/user/infrastructure/cryptographic" + "github.com/stretchr/testify/suite" +) + +type BcryptHashingTestSuite struct { + suite.Suite + sut model.Hashing +} + +func (suite *BcryptHashingTestSuite) SetupTest() { + suite.sut = new(cryptographic.Bcrypt) +} + +func (suite *BcryptHashingTestSuite) TestHash() { + password := valueobj.PasswordWithValidValue() + + plain := password.Value() + + hashed, err := suite.sut.Hash(plain) + + suite.NoError(err) + + suite.NotEqual(plain, hashed) +} + +func (suite *BcryptHashingTestSuite) TestIsNotEqual() { + password := valueobj.PasswordWithValidValue() + + plain := password.Value() + + hashed, err := suite.sut.Hash(plain) + + suite.NoError(err) + + isNotEqual := suite.sut.IsNotEqual(hashed, plain) + + suite.False(isNotEqual) +} + +func TestIntegrationBcryptHashingSuite(t *testing.T) { + suite.Run(t, new(BcryptHashingTestSuite)) +} diff --git a/pkg/context/user/infrastructure/cryptographic/hashing.mock.go b/pkg/context/user/infrastructure/cryptographic/hashing.mock.go new file mode 100644 index 0000000..4c6ca84 --- /dev/null +++ b/pkg/context/user/infrastructure/cryptographic/hashing.mock.go @@ -0,0 +1,19 @@ +package cryptographic + +import ( + "github.com/stretchr/testify/mock" +) + +type HashingMock struct { + mock.Mock +} + +func (hashing *HashingMock) Hash(plain string) (string, error) { + args := hashing.Called(plain) + return args.Get(0).(string), nil +} + +func (hashing *HashingMock) IsNotEqual(hashed, plain string) bool { + args := hashing.Called(hashed, plain) + return args.Get(0).(bool) +} diff --git a/pkg/context/user/infrastructure/persistence/mongo.go b/pkg/context/user/infrastructure/persistence/mongo.go new file mode 100644 index 0000000..e65f074 --- /dev/null +++ b/pkg/context/user/infrastructure/persistence/mongo.go @@ -0,0 +1,215 @@ +package persistence + +import ( + "context" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/shared/infrastructure/persistences" + "github.com/bastean/codexgo/pkg/context/user/domain/aggregate" + "github.com/bastean/codexgo/pkg/context/user/domain/model" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +type UserDocument struct { + Id string `bson:"id,omitempty"` + Email string `bson:"email,omitempty"` + Username string `bson:"username,omitempty"` + Password string `bson:"password,omitempty"` + Verified bool `bson:"verified,omitempty"` +} + +type UserCollection struct { + collection *mongo.Collection + hashing model.Hashing +} + +func (db *UserCollection) Save(user *aggregate.User) error { + newUser := UserDocument(*user.ToPrimitives()) + + hashed, err := db.hashing.Hash(newUser.Password) + + if err != nil { + return errors.BubbleUp(err, "Save") + } + + newUser.Password = hashed + + _, err = db.collection.InsertOne(context.Background(), &newUser) + + if mongo.IsDuplicateKeyError(err) { + return errors.BubbleUp(persistences.HandleMongoDuplicateKeyError(err), "Save") + } + + if err != nil { + return errors.NewInternal(&errors.Bubble{ + Where: "Save", + What: "failure to save a user", + Why: errors.Meta{ + "Id": user.Id.Value(), + }, + Who: err, + }) + } + + return nil +} + +func (db *UserCollection) Verify(id models.ValueObject[string]) error { + filter := bson.D{{Key: "id", Value: id.Value()}} + + _, err := db.collection.UpdateOne(context.Background(), filter, bson.D{ + {Key: "$set", Value: bson.D{ + {Key: "verified", Value: true}, + }}, + }) + + if err != nil { + return errors.NewInternal(&errors.Bubble{ + Where: "Verify", + What: "failure to verify a user", + Why: errors.Meta{ + "Id": id.Value(), + }, + Who: err, + }) + } + + return nil +} + +func (db *UserCollection) Update(user *aggregate.User) error { + updatedUser := UserDocument(*user.ToPrimitives()) + + filter := bson.D{{Key: "id", Value: user.Id.Value()}} + + hashed, err := db.hashing.Hash(user.Password.Value()) + + if err != nil { + return errors.BubbleUp(err, "Update") + } + + updatedUser.Password = hashed + + _, err = db.collection.ReplaceOne(context.Background(), filter, &updatedUser) + + if err != nil { + return errors.NewInternal(&errors.Bubble{ + Where: "Update", + What: "failure to update a user", + Why: errors.Meta{ + "Id": user.Id.Value(), + }, + Who: err, + }) + } + + return nil +} + +func (db *UserCollection) Delete(id models.ValueObject[string]) error { + filter := bson.D{{Key: "id", Value: id.Value()}} + + _, err := db.collection.DeleteOne(context.Background(), filter) + + if err != nil { + return errors.NewInternal(&errors.Bubble{ + Where: "Delete", + What: "failure to delete a user", + Why: errors.Meta{ + "Id": id.Value(), + }, + Who: err, + }) + } + + return nil +} + +func (db *UserCollection) Search(criteria *model.RepositorySearchCriteria) (*aggregate.User, error) { + var filter bson.D + var index string + + switch { + case criteria.Id != nil: + filter = bson.D{{Key: "id", Value: criteria.Id.Value()}} + index = criteria.Id.Value() + case criteria.Email != nil: + filter = bson.D{{Key: "email", Value: criteria.Email.Value()}} + index = criteria.Email.Value() + } + + result := db.collection.FindOne(context.Background(), filter) + + if err := result.Err(); err != nil { + return nil, persistences.HandleMongoDocumentNotFound(index, err) + } + + primitive := new(aggregate.UserPrimitive) + + err := result.Decode(primitive) + + if err != nil { + return nil, errors.NewInternal(&errors.Bubble{ + Where: "Search", + What: "failure to decode a result", + Why: errors.Meta{ + "Index": index, + }, + Who: err, + }) + } + + user, err := aggregate.FromPrimitives(primitive) + + if err != nil { + return nil, errors.NewInternal(&errors.Bubble{ + Where: "Search", + What: "failure to create an aggregate from a primitive", + Why: errors.Meta{ + "Primitive": primitive, + "Index": index, + }, + Who: err, + }) + } + + return user, nil +} + +func NewMongoCollection(mdb *persistences.MongoDB, collectionName string, hashing model.Hashing) (model.Repository, error) { + collection := mdb.Database.Collection(collectionName) + + _, err := collection.Indexes().CreateMany(context.Background(), []mongo.IndexModel{ + { + Keys: bson.D{{Key: "id", Value: 1}}, + Options: options.Index().SetUnique(true), + }, + { + Keys: bson.D{{Key: "email", Value: 1}}, + Options: options.Index().SetUnique(true), + }, + { + Keys: bson.D{{Key: "username", Value: 1}}, + Options: options.Index().SetUnique(true), + }, + }) + + if err != nil { + return nil, errors.NewInternal(&errors.Bubble{ + Where: "NewMongoCollection", + What: "failure to create indexes for user collection", + Why: errors.Meta{ + "Collection": collectionName, + }, + Who: err, + }) + } + + return &UserCollection{ + collection: collection, + hashing: hashing, + }, nil +} diff --git a/pkg/context/user/infrastructure/persistence/mongo.repository_test.go b/pkg/context/user/infrastructure/persistence/mongo.repository_test.go new file mode 100644 index 0000000..d8be484 --- /dev/null +++ b/pkg/context/user/infrastructure/persistence/mongo.repository_test.go @@ -0,0 +1,137 @@ +package persistence_test + +import ( + "os" + "testing" + + "github.com/bastean/codexgo/pkg/context/shared/domain/errors" + "github.com/bastean/codexgo/pkg/context/shared/infrastructure/persistences" + "github.com/bastean/codexgo/pkg/context/user/domain/aggregate" + "github.com/bastean/codexgo/pkg/context/user/domain/model" + "github.com/bastean/codexgo/pkg/context/user/domain/valueobj" + "github.com/bastean/codexgo/pkg/context/user/infrastructure/cryptographic" + "github.com/bastean/codexgo/pkg/context/user/infrastructure/persistence" + "github.com/stretchr/testify/suite" +) + +type MongoRepositoryTestSuite struct { + suite.Suite + sut model.Repository + hashing *cryptographic.HashingMock +} + +func (suite *MongoRepositoryTestSuite) SetupTest() { + uri := os.Getenv("DATABASE_URI") + + databaseName := "codexgo-test" + + database, _ := persistences.NewMongoDatabase(uri, databaseName) + + collectionName := "users-test" + + suite.hashing = new(cryptographic.HashingMock) + + suite.sut, _ = persistence.NewMongoCollection(database, collectionName, suite.hashing) +} + +func (suite *MongoRepositoryTestSuite) TestSave() { + user := aggregate.RandomUser() + + suite.hashing.On("Hash", user.Password.Value()).Return(user.Password.Value()) + + suite.NoError(suite.sut.Save(user)) + + suite.hashing.AssertExpectations(suite.T()) +} + +func (suite *MongoRepositoryTestSuite) TestSaveDuplicate() { + user := aggregate.RandomUser() + + suite.hashing.On("Hash", user.Password.Value()).Return(user.Password.Value()) + + suite.NoError(suite.sut.Save(user)) + + err := suite.sut.Save(user) + + suite.hashing.AssertExpectations(suite.T()) + + var actual *errors.AlreadyExist + + suite.ErrorAs(err, &actual) + + expected := &errors.AlreadyExist{Bubble: &errors.Bubble{ + When: actual.When, + Where: "HandleMongoDuplicateKeyError", + What: "already registered", + Why: errors.Meta{ + "Field": "Id", + }, + Who: actual.Who, + }} + + suite.EqualError(expected, actual.Error()) +} + +func (suite *MongoRepositoryTestSuite) TestVerify() { + user := aggregate.RandomUser() + + suite.hashing.On("Hash", user.Password.Value()).Return(user.Password.Value()) + + suite.NoError(suite.sut.Save(user)) + + suite.NoError(suite.sut.Verify(user.Id)) +} + +func (suite *MongoRepositoryTestSuite) TestUpdate() { + user := aggregate.RandomUser() + + suite.hashing.On("Hash", user.Password.Value()).Return(user.Password.Value()) + + suite.NoError(suite.sut.Save(user)) + + password := valueobj.PasswordWithValidValue() + + user.Password = password + + suite.hashing.On("Hash", user.Password.Value()).Return(user.Password.Value()) + + suite.NoError(suite.sut.Update(user)) + + suite.hashing.AssertExpectations(suite.T()) +} + +func (suite *MongoRepositoryTestSuite) TestDelete() { + user := aggregate.RandomUser() + + suite.hashing.On("Hash", user.Password.Value()).Return(user.Password.Value()) + + suite.NoError(suite.sut.Save(user)) + + suite.NoError(suite.sut.Delete(user.Id)) +} + +func (suite *MongoRepositoryTestSuite) TestSearch() { + expected := aggregate.RandomUser() + + expected.PullMessages() + + suite.hashing.On("Hash", expected.Password.Value()).Return(expected.Password.Value()) + + suite.NoError(suite.sut.Save(expected)) + + criteria := &model.RepositorySearchCriteria{ + Id: expected.Id, + } + + user, err := suite.sut.Search(criteria) + + suite.NoError(err) + + actual := user + + suite.Equal(expected, actual) +} + +func TestIntegrationMongoRepositorySuite(t *testing.T) { + suite.Run(t, new(MongoRepositoryTestSuite)) +} diff --git a/pkg/context/user/infrastructure/persistence/repository.mock.go b/pkg/context/user/infrastructure/persistence/repository.mock.go new file mode 100644 index 0000000..def4f7c --- /dev/null +++ b/pkg/context/user/infrastructure/persistence/repository.mock.go @@ -0,0 +1,37 @@ +package persistence + +import ( + "github.com/bastean/codexgo/pkg/context/shared/domain/models" + "github.com/bastean/codexgo/pkg/context/user/domain/aggregate" + "github.com/bastean/codexgo/pkg/context/user/domain/model" + "github.com/stretchr/testify/mock" +) + +type RepositoryMock struct { + mock.Mock +} + +func (repository *RepositoryMock) Save(user *aggregate.User) error { + repository.Called(user) + return nil +} + +func (repository *RepositoryMock) Verify(id models.ValueObject[string]) error { + repository.Called(id) + return nil +} + +func (repository *RepositoryMock) Update(user *aggregate.User) error { + repository.Called(user) + return nil +} + +func (repository *RepositoryMock) Delete(id models.ValueObject[string]) error { + repository.Called(id) + return nil +} + +func (repository *RepositoryMock) Search(criteria *model.RepositorySearchCriteria) (*aggregate.User, error) { + args := repository.Called(criteria) + return args.Get(0).(*aggregate.User), nil +} diff --git a/scripts/copydeps/copydeps.go b/scripts/copydeps/copydeps.go new file mode 100644 index 0000000..759abfd --- /dev/null +++ b/scripts/copydeps/copydeps.go @@ -0,0 +1,103 @@ +package main + +import ( + "errors" + "fmt" + "log" + "os" + "path/filepath" + "regexp" + "strings" +) + +const regExpEveryMinFile = `^.+\.min\.(js|css)$` +const regExpEveryWoff2File = `^.+\.woff2$` + +const staticPath = "pkg/cmd/server/static/dist" + +const jquerySourcePath = "node_modules/jquery/dist" +const jqueryStaticPath = staticPath + "/jquery.com" + +const fomanticSourcePath = "node_modules/fomantic-ui/dist" +const fomanticStaticPath = staticPath + "/fomantic-ui.com" + +const lodashSourcePath = "node_modules/lodash" +const lodashStaticPath = staticPath + "/lodash.com" + +func Panic(who error, what, where string) { + log.Panicf("(%s): %s: [%s]", where, what, who) +} + +func CreateDirectory(path string) { + err := os.MkdirAll(path, os.ModePerm) + + if err != nil { + Panic(err, fmt.Sprintf("failed to create \"%s\"", path), "CreateDirectory") + } + + log.Printf("created: \"%s\"", path) +} + +func CopyFile(filename, sourcePath, targetPath string) { + data, err := os.ReadFile(filepath.Join(sourcePath, filepath.Base(filename))) + + if err != nil { + Panic(err, fmt.Sprintf("failed to read \"%s\" from \"%s\"", filename, sourcePath), "CopyFile") + } + + err = os.WriteFile(filepath.Join(targetPath, filepath.Base(filename)), data, os.ModePerm) + + if err != nil { + Panic(err, fmt.Sprintf("failed to write \"%s\" on \"%s\"", filename, targetPath), "CopyFile") + } + + log.Printf("created: \"%s\"", filepath.Join(targetPath, filepath.Base(filename))) +} + +func CopyDeps(filenames []string, sourcePath, targetPath string) { + files, err := os.ReadDir(sourcePath) + + if err != nil { + Panic(err, fmt.Sprintf("failed to copy \"%s\" from \"%s\"", filenames, sourcePath), "CopyDeps") + } + + CreateDirectory(targetPath) + + if strings.HasPrefix(filenames[0], "^") && strings.HasSuffix(filenames[0], "$") { + isMinFile := regexp.MustCompile(filenames[0]).MatchString + + for _, file := range files { + if isMinFile(file.Name()) { + CopyFile(file.Name(), sourcePath, targetPath) + } + } + + return + } + + for _, filename := range filenames { + for _, file := range files { + if filepath.Base(filename) == file.Name() { + CopyFile(filename, sourcePath, targetPath) + } + } + } +} + +func main() { + err := os.RemoveAll(staticPath) + + if err != nil && !errors.Is(err, os.ErrNotExist) { + Panic(err, fmt.Sprintf("failed to remove \"%s\"", staticPath), "main") + } + + CreateDirectory(staticPath) + + CopyDeps([]string{"jquery.min.js"}, jquerySourcePath, jqueryStaticPath) + + CopyDeps([]string{"semantic.min.js", "semantic.min.css"}, fomanticSourcePath, fomanticStaticPath) + CopyDeps([]string{regExpEveryMinFile}, filepath.Join(fomanticSourcePath, "components"), filepath.Join(fomanticStaticPath, "components")) + CopyDeps([]string{regExpEveryWoff2File}, filepath.Join(fomanticSourcePath, "themes/default/assets/fonts"), filepath.Join(fomanticStaticPath, "themes/default/assets/fonts")) + + CopyDeps([]string{"lodash.min.js"}, lodashSourcePath, lodashStaticPath) +} diff --git a/scripts/syncenv/syncenv.go b/scripts/syncenv/syncenv.go new file mode 100644 index 0000000..4644c64 --- /dev/null +++ b/scripts/syncenv/syncenv.go @@ -0,0 +1,215 @@ +package main + +import ( + "flag" + "fmt" + "log" + "os" + "path/filepath" + "regexp" + "strings" +) + +const cli = "syncenv" + +var envFilesDir string +var envFileModel string + +var envFileBackupRegex = regexp.MustCompile(`\.env\..*\.tmp`) + +func RestoreEnvFilesBackup() { + files, err := os.ReadDir(envFilesDir) + + if err != nil { + panic(err) + } + + for _, file := range files { + if envFileBackupRegex.Match([]byte(file.Name())) { + renamed, _ := strings.CutSuffix(file.Name(), ".tmp") + os.Rename(filepath.Join(envFilesDir, file.Name()), filepath.Join(envFilesDir, renamed)) + } + } +} + +func Panic(who error, where string) { + log.Println("Sync .env* failed!") + + log.Println("Restoring .env* from backups") + RestoreEnvFilesBackup() + + log.Println("Please, check 'Error' or undo changes with: make sync-env-reset") + + log.Panicf("Error: (%s): [%s]", where, who) +} + +func usage() { + fmt.Printf("Usage: %s [OPTIONS]\n", cli) + fmt.Printf("\nE.g.: %s -dir . -model .env.example\n\n", cli) + flag.PrintDefaults() +} + +func BackupEnvFiles() { + files, err := os.ReadDir(envFilesDir) + + if err != nil { + Panic(err, "BackupEnvFiles") + } + + for _, file := range files { + if strings.Contains(file.Name(), ".env") { + data, err := os.ReadFile(file.Name()) + + if err != nil { + Panic(err, "BackupEnvFiles") + } + + err = os.WriteFile(file.Name()+".tmp", data, 0644) + + if err != nil { + Panic(err, "BackupEnvFiles") + } + } + } +} + +func RemoveEnvFilesBackup() { + files, err := os.ReadDir(envFilesDir) + + if err != nil { + Panic(err, "RemoveEnvFilesBackup") + } + + for _, file := range files { + if envFileBackupRegex.Match([]byte(file.Name())) { + err = os.Remove(file.Name()) + + if err != nil { + Panic(err, "RemoveEnvFilesBackup") + } + } + } +} + +func GetEnvFiles() (envFiles []string) { + files, err := os.ReadDir(envFilesDir) + + if err != nil { + Panic(err, "GetEnvFiles") + } + + for _, file := range files { + if strings.Contains(file.Name(), ".env") && file.Name() != envFileModel { + envFiles = append(envFiles, file.Name()) + } + } + + return +} + +func GetEnvFileModelVars() []string { + dataBytes, err := os.ReadFile(envFileModel) + + if err != nil { + Panic(err, "GetEnvFileModelVars") + } + + enVars := strings.Split(string(dataBytes), "\n") + + for i, enVar := range enVars { + enVars[i] = strings.Split(enVar, "=")[0] + } + + return enVars +} + +func SyncEnv(envModelVars []string, envFile string) { + data, err := os.ReadFile(envFile) + + if err != nil { + Panic(err, "SyncEnv") + } + + envFileVars := strings.Split(string(data), "\n") + + envFileVarsCleaned := []string{} + + for _, envFileVar := range envFileVars { + if envFileVar == "" { + continue + } + + envFileVarsCleaned = append(envFileVarsCleaned, envFileVar) + } + + envFileUpdatedVars := "" + + updatedVar := false + + for i, envModelVar := range envModelVars { + updatedVar = false + + if i+1 == len(envModelVars) { + break + } + + if envModelVar == "" { + envFileUpdatedVars += "\n" + continue + } + + for _, envFileVar := range envFileVarsCleaned { + values := strings.SplitN(envFileVar, "=", 2) + enVarName := values[0] + enVarValue := values[1] + + if envModelVar == enVarName { + envFileUpdatedVars += envModelVar + "=" + enVarValue + "\n" + updatedVar = true + break + } + } + + if !updatedVar { + envFileUpdatedVars += envModelVar + "=" + "\n" + } + } + + file, err := os.Create(envFile) + + if err != nil { + Panic(err, "SyncEnv") + } + + _, err = file.WriteString(envFileUpdatedVars) + + if err != nil { + Panic(err, "SyncEnv") + } +} + +func main() { + flag.StringVar(&envFilesDir, "dir", ".", ".env files directory") + flag.StringVar(&envFileModel, "model", ".env.example", ".env file model") + + flag.Usage = usage + + flag.Parse() + + log.Println("Creating .env* backups") + BackupEnvFiles() + + log.Println("Searching .env*") + envFiles := GetEnvFiles() + envFileModelVars := GetEnvFileModelVars() + + log.Println("Syncing .env*") + for _, envFile := range envFiles { + SyncEnv(envFileModelVars, envFile) + } + + log.Println("Removing .env* backups") + RemoveEnvFilesBackup() + + log.Println("Sync .env* completed!") +} diff --git a/scripts/upgrade/upgrade.go b/scripts/upgrade/upgrade.go new file mode 100644 index 0000000..38b7ec1 --- /dev/null +++ b/scripts/upgrade/upgrade.go @@ -0,0 +1,72 @@ +package main + +import ( + "log" + "os/exec" +) + +func Panic(who error, where string) { + log.Println("Upgrade failed!") + + log.Println("Please, check 'Error' or undo changes with: make upgrade-reset") + + log.Panicf("Error: (%s): [%s]", where, who) +} + +func UpgradeGo() { + if err := exec.Command("make", "upgrade-go").Run(); err != nil { + Panic(err, "UpgradeGo") + } +} + +func UpgradeNode() { + if err := exec.Command("make", "upgrade-node").Run(); err != nil { + Panic(err, "UpgradeNode") + } +} + +func RunLint() { + if err := exec.Command("make", "lint-check").Run(); err != nil { + Panic(err, "RunLint") + } +} + +func RunTest() { + if err := exec.Command("make", "test-unit").Run(); err != nil { + Panic(err, "RunTest") + } +} + +func Commit() { + if err := exec.Command("git", "add", ".", "--update").Run(); err != nil { + Panic(err, "Commit") + } + + if err := exec.Command("git", "commit", "-m", "chore(deps): upgrade dependencies").Run(); err != nil { + Panic(err, "Commit") + } +} + +func main() { + log.Println("Upgrading dependencies") + + log.Println("Running Go Tidy") + RunLint() + + log.Println("Upgrading Go dependencies") + UpgradeGo() + + log.Println("Upgrading Node dependencies") + UpgradeNode() + + log.Println("Running Lint") + RunLint() + + log.Println("Running Test") + RunTest() + + log.Println("Commit changes") + Commit() + + log.Println("Upgrade completed!") +} diff --git a/test/.gitkeep b/test/.gitkeep new file mode 100644 index 0000000..e69de29