diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..f593d56 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,24 @@ + + +## Description + + + +## Screenshots + + + +## Testing instructions + + diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ee4cace..edd0af2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,5 +1,5 @@ name: Build -on: [pull_request, workflow_dispatch] +on: [pull_request, workflow_dispatch, workflow_call] concurrency: group: build-${{ github.event.number }} @@ -8,13 +8,39 @@ concurrency: jobs: cocoapods: name: CocoaPods - runs-on: macos-latest + runs-on: macos-13 steps: - name: Check out repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Install Dependencies run: bundle install - name: Run pod lib lint - run: bundle exec fastlane build + run: bundle exec fastlane build_pod + + spm: + name: Swift Package Manager + runs-on: macos-13 + steps: + - name: Check out repository + uses: actions/checkout@v3 + + - name: Install Dependencies + run: bundle install + + - name: Build SPM test app + run: bundle exec fastlane build_spm + + carthage: + name: Carthage + runs-on: macos-13 + steps: + - name: Check out repository + uses: actions/checkout@v3 + + - name: Install Dependencies + run: bundle install + + - name: Build Carthage test app + run: bundle exec fastlane build_carthage diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 1fe8901..652bbc1 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -1,5 +1,5 @@ name: Linting -on: [pull_request, workflow_dispatch] +on: [pull_request, workflow_dispatch, workflow_call] concurrency: group: lint-${{ github.event.number }} @@ -8,13 +8,13 @@ concurrency: jobs: linting: name: Linting - runs-on: macOS-latest + runs-on: macos-13 steps: - name: Check out repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Install Dependencies run: bundle install - name: Run Linting - run: bundle exec fastlane lint + run: bundle exec fastlane lint summary:$GITHUB_STEP_SUMMARY diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1132433..24ba996 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,22 +3,22 @@ on: workflow_dispatch: {} push: branches: - - release + - main jobs: linting: - uses: paypal/paypal-messages-ios/.github/workflows/linting.yml@release + uses: ./.github/workflows/linting.yml tests: - uses: paypal/paypal-messages-ios/.github/workflows/tests.yml@release + uses: ./.github/workflows/tests.yml build: - uses: paypal/paypal-messages-ios/.github/workflows/build.yml@release + uses: ./.github/workflows/build.yml release: name: Release needs: [linting, tests, build] - runs-on: macos-latest + runs-on: macos-13 permissions: contents: write @@ -33,19 +33,17 @@ jobs: fetch-depth: '0' persist-credentials: false - - name: Setup node - uses: actions/setup-node@v3 - with: - node-version: "lts/*" - - name: Install Dependencies run: | bundle install - npm i -g @semantic-release/exec @semantic-release/changelog @semantic-release/git conventional-changelog-conventionalcommits@6.1.0 + npm install - name: GitHub Release env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + DISTRIBUTION_CERTIFICATE_BASE64: ${{ secrets.DISTRIBUTION_CERTIFICATE_BASE64 }} + DISTRIBUTION_CERTIFICATE_PASSWORD: ${{ secrets.DISTRIBUTION_CERTIFICATE_PASSWORD }} + KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} run: npx semantic-release@21 - name: Publish to CocoaPods diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0ea4e41..2e61a22 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,5 +1,5 @@ name: Tests -on: [pull_request, workflow_dispatch] +on: [pull_request, workflow_dispatch, workflow_call] concurrency: group: tests-${{ github.event.number }} @@ -8,13 +8,13 @@ concurrency: jobs: tests: name: Tests - runs-on: macOS-latest + runs-on: macos-13-xlarge steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Install Dependencies run: bundle install - name: Run Unit Tests - run: bundle exec fastlane tests + run: bundle exec fastlane tests summary:$GITHUB_STEP_SUMMARY diff --git a/.gitignore b/.gitignore index abfbc19..8b594b3 100644 --- a/.gitignore +++ b/.gitignore @@ -31,7 +31,8 @@ Archives Pods # Carthage -Carthage/ +Carthage/* +!Carthage/PayPalMessages.json # SPM .swiftpm @@ -41,5 +42,8 @@ SampleApps/SPMTest/SPMTest.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Pa # Fastlane /fastlane/report.xml /fastlane/coverage -/fastlane/test_output/ +/fastlane/test_output +/fastlane/swiftlint +# Node +node_modules/ diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..38f11c6 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +registry=https://registry.npmjs.org diff --git a/.releaserc.json b/.releaserc.json index 7418b6a..d71198f 100644 --- a/.releaserc.json +++ b/.releaserc.json @@ -1,5 +1,6 @@ { - "branches": ["main"], + "branches": ["main", { "name": "develop", "prerelease": true }, { "name": "alpha", "prerelease": true }], + "tagFormat": "${version}", "plugins": [ [ "@semantic-release/commit-analyzer", @@ -44,22 +45,27 @@ "@semantic-release/exec", { "prepareCmd": "bundle exec fastlane release version:${nextRelease.version}", - "successCmd": "bundle exec fastlane sync" + "successCmd": "bundle exec fastlane sync channel:${nextRelease.channel}" } ], [ "@semantic-release/git", { - "assets": ["*"], + "assets": [ + "CHANGELOG.md", + "Package.swift", + "PayPalMessages.podspec", + "Carthage/PayPalMessages.json", + "Sources/**/BuildInfo.swift" + ], "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" } ], [ "@semantic-release/github", { - "assets": "dist/*" + "assets": ["build/PayPalMessages.framework.zip", "build/PayPalMessages.xcframework.zip"] } ] ] } - diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..cde8ea4 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,124 @@ +# Changelog + +## 1.0.0-alpha.1 (2024-04-22) + + +### Features + +* message and modal close button alternative a11y text ([#28](https://github.com/paypal/paypal-messages-ios/issues/28)) ([f017015](https://github.com/paypal/paypal-messages-ios/commit/f01701556f4dcf4b9ec8776caa50ab3550e4d820)) + + +### Bug Fixes + +* correctly init AnyCodable for modal event properties ([#10](https://github.com/paypal/paypal-messages-ios/issues/10)) ([d4a0839](https://github.com/paypal/paypal-messages-ios/commit/d4a08399b9a55d115730c5c30a42f74e6e5abac4)) +* disable opening modal until message rendered ([#4](https://github.com/paypal/paypal-messages-ios/issues/4)) ([3d09576](https://github.com/paypal/paypal-messages-ios/commit/3d095768746f75ea5079290e2d2210eb275cbab3)) +* ensure modal shared key removed from individual events ([#13](https://github.com/paypal/paypal-messages-ios/issues/13)) ([32ae124](https://github.com/paypal/paypal-messages-ios/commit/32ae124bf92e1c51b4947ee4d8efa08a62782de3)) +* logger uses updated message and modal properties ([#21](https://github.com/paypal/paypal-messages-ios/issues/21)) ([6b9e949](https://github.com/paypal/paypal-messages-ios/commit/6b9e949e01d0550ba578ed6c44fe656ef5a728e4)) +* message and modal accessibility improvements ([#7](https://github.com/paypal/paypal-messages-ios/issues/7)) ([86320e9](https://github.com/paypal/paypal-messages-ios/commit/86320e91c00f45e9ef71740d59a562e2037de33e)) +* move credential override off main thread ([#11](https://github.com/paypal/paypal-messages-ios/issues/11)) ([b30c2f8](https://github.com/paypal/paypal-messages-ios/commit/b30c2f81af5dbb60c28059eccbedcbd758971bd5)) +* pass env param to log functions ([#31](https://github.com/paypal/paypal-messages-ios/issues/31)) ([610d9e3](https://github.com/paypal/paypal-messages-ios/commit/610d9e32f0dcaeec220460997369334510b57bc4)) +* unrecoverable error state after supplying valid client id ([#5](https://github.com/paypal/paypal-messages-ios/issues/5)) ([da5fe52](https://github.com/paypal/paypal-messages-ios/commit/da5fe52ff240624564b5fe561fbd693df9f0f351)) + + +### Code Refactoring + +* add privacy manifest file and remove tracking IDs ([#30](https://github.com/paypal/paypal-messages-ios/issues/30)) ([8400d96](https://github.com/paypal/paypal-messages-ios/commit/8400d96c13f7ba481a00e521bff8135dcfa0df03)) +* expose proxy and remove environment default param ([#3](https://github.com/paypal/paypal-messages-ios/issues/3)) ([a8d36d8](https://github.com/paypal/paypal-messages-ios/commit/a8d36d8bf069cc4165448b887026eff7515752b6)) +* include default device ID and session ID values ([#25](https://github.com/paypal/paypal-messages-ios/issues/25)) ([e34fc94](https://github.com/paypal/paypal-messages-ios/commit/e34fc947433459b08c08ec6f7e164465d92ba589)) +* include response details when message failure ([#29](https://github.com/paypal/paypal-messages-ios/issues/29)) ([dd1c478](https://github.com/paypal/paypal-messages-ios/commit/dd1c478b4a9558c17d8285abbad6e121141add83)) +* log endpoint schema and route changes ([#12](https://github.com/paypal/paypal-messages-ios/issues/12)) ([31ba3b5](https://github.com/paypal/paypal-messages-ios/commit/31ba3b5d0f49ea46cc1d1c9615a3094328550fc0)) +* move stageTag and devTouchpoint options to Environment enum ([#15](https://github.com/paypal/paypal-messages-ios/issues/15)) ([d4a9d4a](https://github.com/paypal/paypal-messages-ios/commit/d4a9d4a7b02f863d305345f0e3be647c3c26e84d)) +* pass instance_id ([#9](https://github.com/paypal/paypal-messages-ios/issues/9)) ([6d0668b](https://github.com/paypal/paypal-messages-ios/commit/6d0668bccea0ecd5b3fd9fcc0a6b022f6da5fa2f)) +* pass message view model dependencies from message view ([#20](https://github.com/paypal/paypal-messages-ios/issues/20)) ([9a98326](https://github.com/paypal/paypal-messages-ios/commit/9a98326d336f53e75b2894f472c97ec643b7b0cc)) +* placement to pageType and textAlignment to textAlign ([#26](https://github.com/paypal/paypal-messages-ios/issues/26)) ([d2ffdd4](https://github.com/paypal/paypal-messages-ios/commit/d2ffdd4999ca2673be4705b8c034d29c3f4b7009)) +* remove currency references ([#14](https://github.com/paypal/paypal-messages-ios/issues/14)) ([751c903](https://github.com/paypal/paypal-messages-ios/commit/751c9039c9172cc6abb4820f5619365b26867c6b)) +* rename stage environment value to develop ([#27](https://github.com/paypal/paypal-messages-ios/issues/27)) ([83557df](https://github.com/paypal/paypal-messages-ios/commit/83557df382c9347528b0d563bb34a40c859a1356)) +* store merchant profile data by client ID and merchant ID ([#19](https://github.com/paypal/paypal-messages-ios/issues/19)) ([a502a4f](https://github.com/paypal/paypal-messages-ios/commit/a502a4f97387d8b39f7126f0560610336a630d7e)) + + +### Tests + +* expand unit tests ([#8](https://github.com/paypal/paypal-messages-ios/issues/8)) ([48e6f0f](https://github.com/paypal/paypal-messages-ios/commit/48e6f0f9c06c3111dc3af0ad4a0e54747b8718c5)) +* expose view model flush method for consistent tests ([#24](https://github.com/paypal/paypal-messages-ios/issues/24)) ([9c1406f](https://github.com/paypal/paypal-messages-ios/commit/9c1406f85ddde167a3d3ca4e38ae9201f606141f)) + + +### Continuous Integration + +* codesign xcframework build ([90599d0](https://github.com/paypal/paypal-messages-ios/commit/90599d010b29686fd0b2bc7f4d8ff883dbc8904f)) +* fix linting and test coverage ([#17](https://github.com/paypal/paypal-messages-ios/issues/17)) ([3eeebea](https://github.com/paypal/paypal-messages-ios/commit/3eeebea050de1fff07df42df87168b77dbd6611d)) +* initial GitHub Actions setup and test ([#1](https://github.com/paypal/paypal-messages-ios/issues/1)) ([43d9ff0](https://github.com/paypal/paypal-messages-ios/commit/43d9ff03e70e72d0676759cf88b761f4366715f8)) +* initial prerelease fixes ([#16](https://github.com/paypal/paypal-messages-ios/issues/16)) ([43cffed](https://github.com/paypal/paypal-messages-ios/commit/43cffedf83d0454c32dc7cf8a0d613c5bbe53d18)) +* prerelease prep ([#6](https://github.com/paypal/paypal-messages-ios/issues/6)) ([12cb440](https://github.com/paypal/paypal-messages-ios/commit/12cb4400675bfd0deb62bd8f8747abbfa8219063)) + +## [1.0.0-prerelease.6](https://github.com/paypal/paypal-messages-ios/compare/1.0.0-prerelease.5...1.0.0-prerelease.6) (2023-12-14) + + +### Bug Fixes + +* undo excluded archs from the project file ([367a390](https://github.com/paypal/paypal-messages-ios/commit/367a3904a64a22e9ace233db43619389bcd22666)) + +## [1.0.0-prerelease.5](https://github.com/paypal/paypal-messages-ios/compare/1.0.0-prerelease.4...1.0.0-prerelease.5) (2023-12-13) + + +### Bug Fixes + +* use xcframework in Package.swift ([7ab6e37](https://github.com/paypal/paypal-messages-ios/commit/7ab6e372017b1cd870b913ba41754afc2ad5fb51)) + +## [1.0.0-prerelease.4](https://github.com/paypal/paypal-messages-ios/compare/1.0.0-prerelease.3...1.0.0-prerelease.4) (2023-12-08) + + +### Bug Fixes + +* disable code signing ([8b51a79](https://github.com/paypal/paypal-messages-ios/commit/8b51a798615f880421a77ee9df6037c46aa90506)) +* inlcude Carthage json file and swift package checksum ([6a2aeae](https://github.com/paypal/paypal-messages-ios/commit/6a2aeae16c634ec0ff4a6ab3ead8323d27bf50ef)) +* manually build and assemble xcframework ([c1699f3](https://github.com/paypal/paypal-messages-ios/commit/c1699f3c69da9b582782a78afcd9c1da35a8c8ff)) + + +### Continuous Integration + +* temporarily disable release prereq jobs ([53d5ed7](https://github.com/paypal/paypal-messages-ios/commit/53d5ed7f366e01ed76c05c9b0ef2f4ff7e5d3d51)) + +## [1.0.0-prerelease.3](https://github.com/paypal/paypal-messages-ios/compare/v1.0.0-prerelease.2...1.0.0-prerelease.3) (2023-11-29) + + +### Bug Fixes + +* update git tag format ([877f7c2](https://github.com/paypal/paypal-messages-ios/commit/877f7c2020943c4c744a2b31bd568ea686561505)) + +## [1.0.0-prerelease.2](https://github.com/paypal/paypal-messages-ios/compare/v1.0.0-prerelease.1...v1.0.0-prerelease.2) (2023-11-28) + + +### Bug Fixes + +* explicit assets included with git release commit ([a058498](https://github.com/paypal/paypal-messages-ios/commit/a058498797e99717ffb549a9a25f3e5b63d5e7d8)) + +## 1.0.0-prerelease.1 (2023-11-22) + + +### Bug Fixes + +* correctly init AnyCodable for modal event properties ([#10](https://github.com/paypal/paypal-messages-ios/issues/10)) ([d4a0839](https://github.com/paypal/paypal-messages-ios/commit/d4a08399b9a55d115730c5c30a42f74e6e5abac4)) +* disable opening modal until message rendered ([#4](https://github.com/paypal/paypal-messages-ios/issues/4)) ([3d09576](https://github.com/paypal/paypal-messages-ios/commit/3d095768746f75ea5079290e2d2210eb275cbab3)) +* ensure modal shared key removed from individual events ([#13](https://github.com/paypal/paypal-messages-ios/issues/13)) ([32ae124](https://github.com/paypal/paypal-messages-ios/commit/32ae124bf92e1c51b4947ee4d8efa08a62782de3)) +* message and modal accessibility improvements ([#7](https://github.com/paypal/paypal-messages-ios/issues/7)) ([86320e9](https://github.com/paypal/paypal-messages-ios/commit/86320e91c00f45e9ef71740d59a562e2037de33e)) +* move credential override off main thread ([#11](https://github.com/paypal/paypal-messages-ios/issues/11)) ([b30c2f8](https://github.com/paypal/paypal-messages-ios/commit/b30c2f81af5dbb60c28059eccbedcbd758971bd5)) +* unrecoverable error state after supplying valid client id ([#5](https://github.com/paypal/paypal-messages-ios/issues/5)) ([da5fe52](https://github.com/paypal/paypal-messages-ios/commit/da5fe52ff240624564b5fe561fbd693df9f0f351)) + + +### Code Refactoring + +* expose proxy and remove environment default param ([#3](https://github.com/paypal/paypal-messages-ios/issues/3)) ([a8d36d8](https://github.com/paypal/paypal-messages-ios/commit/a8d36d8bf069cc4165448b887026eff7515752b6)) +* log endpoint schema and route changes ([#12](https://github.com/paypal/paypal-messages-ios/issues/12)) ([31ba3b5](https://github.com/paypal/paypal-messages-ios/commit/31ba3b5d0f49ea46cc1d1c9615a3094328550fc0)) +* pass instance_id ([#9](https://github.com/paypal/paypal-messages-ios/issues/9)) ([6d0668b](https://github.com/paypal/paypal-messages-ios/commit/6d0668bccea0ecd5b3fd9fcc0a6b022f6da5fa2f)) + + +### Tests + +* expand unit tests ([#8](https://github.com/paypal/paypal-messages-ios/issues/8)) ([48e6f0f](https://github.com/paypal/paypal-messages-ios/commit/48e6f0f9c06c3111dc3af0ad4a0e54747b8718c5)) + + +### Continuous Integration + +* add workflow_call hook for workflows ([13a0f81](https://github.com/paypal/paypal-messages-ios/commit/13a0f81edb177b3292bf5914960b152fdd97e931)) +* initial GitHub Actions setup and test ([#1](https://github.com/paypal/paypal-messages-ios/issues/1)) ([43d9ff0](https://github.com/paypal/paypal-messages-ios/commit/43d9ff03e70e72d0676759cf88b761f4366715f8)) +* prerelease prep ([#6](https://github.com/paypal/paypal-messages-ios/issues/6)) ([12cb440](https://github.com/paypal/paypal-messages-ios/commit/12cb4400675bfd0deb62bd8f8747abbfa8219063)) diff --git a/Carthage/PayPalMessages.json b/Carthage/PayPalMessages.json new file mode 100644 index 0000000..e636c27 --- /dev/null +++ b/Carthage/PayPalMessages.json @@ -0,0 +1,6 @@ +{ + "1.0.0-prerelease.4": "https://github.com/paypal/paypal-messages-ios/releases/download/1.0.0-prerelease.4/PayPalMessages.framework.zip?alt=https://github.com/paypal/paypal-messages-ios/releases/download/1.0.0-prerelease.4/PayPalMessages.xcframework.zip", + "1.0.0-prerelease.5": "https://github.com/paypal/paypal-messages-ios/releases/download/1.0.0-prerelease.5/PayPalMessages.framework.zip?alt=https://github.com/paypal/paypal-messages-ios/releases/download/1.0.0-prerelease.5/PayPalMessages.xcframework.zip", + "1.0.0-prerelease.6": "https://github.com/paypal/paypal-messages-ios/releases/download/1.0.0-prerelease.6/PayPalMessages.framework.zip?alt=https://github.com/paypal/paypal-messages-ios/releases/download/1.0.0-prerelease.6/PayPalMessages.xcframework.zip", + "1.0.0-alpha.1": "https://github.com/paypal/paypal-messages-ios/releases/download/1.0.0-alpha.1/PayPalMessages.framework.zip?alt=https://github.com/paypal/paypal-messages-ios/releases/download/1.0.0-alpha.1/PayPalMessages.xcframework.zip" +} diff --git a/Demo/Demo.xcodeproj/project.pbxproj b/Demo/Demo.xcodeproj/project.pbxproj index 0291979..2c3253f 100644 --- a/Demo/Demo.xcodeproj/project.pbxproj +++ b/Demo/Demo.xcodeproj/project.pbxproj @@ -7,11 +7,12 @@ objects = { /* Begin PBXBuildFile section */ + C67A5ACA2B2A5FE700BBF5F7 /* PayPalMessages.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C67A5AC92B2A5FE700BBF5F7 /* PayPalMessages.framework */; }; + C67A5ACB2B2A5FE700BBF5F7 /* PayPalMessages.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C67A5AC92B2A5FE700BBF5F7 /* PayPalMessages.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; C6E7C4922A38AC56003C05E4 /* DemoApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6E7C4912A38AC56003C05E4 /* DemoApp.swift */; }; C6E7C4942A38AC56003C05E4 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6E7C4932A38AC56003C05E4 /* ContentView.swift */; }; C6E7C4962A38AC5D003C05E4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C6E7C4952A38AC5D003C05E4 /* Assets.xcassets */; }; C6E7C4992A38AC5D003C05E4 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C6E7C4982A38AC5D003C05E4 /* Preview Assets.xcassets */; }; - C6E7C4A72A38ADC7003C05E4 /* PayPalMessages in Frameworks */ = {isa = PBXBuildFile; productRef = C6E7C4A62A38ADC7003C05E4 /* PayPalMessages */; }; F200FF022A86D7FB0002DE25 /* UIKitContentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F200FF012A86D7FB0002DE25 /* UIKitContentViewController.swift */; }; F200FF042A86D8080002DE25 /* UIKitContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F200FF032A86D8080002DE25 /* UIKitContentView.swift */; }; F200FF062A86D8170002DE25 /* SwiftUIContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F200FF052A86D8170002DE25 /* SwiftUIContentView.swift */; }; @@ -26,14 +27,29 @@ F200FF1C2A94E8A20002DE25 /* DefaultMessageConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = F200FF1B2A94E8A20002DE25 /* DefaultMessageConfig.swift */; }; /* End PBXBuildFile section */ +/* Begin PBXCopyFilesBuildPhase section */ + C67A5ACC2B2A5FE700BBF5F7 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + C67A5ACB2B2A5FE700BBF5F7 /* PayPalMessages.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ + C67A5AC52B2A5DA300BBF5F7 /* PayPalMessages.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = PayPalMessages.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + C67A5AC92B2A5FE700BBF5F7 /* PayPalMessages.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = PayPalMessages.framework; sourceTree = BUILT_PRODUCTS_DIR; }; C6CBCBDE2A4A14D200645B38 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; C6E7C48E2A38AC56003C05E4 /* Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Demo.app; sourceTree = BUILT_PRODUCTS_DIR; }; C6E7C4912A38AC56003C05E4 /* DemoApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoApp.swift; sourceTree = ""; }; C6E7C4932A38AC56003C05E4 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; C6E7C4952A38AC5D003C05E4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; C6E7C4982A38AC5D003C05E4 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; - C6E7C4A42A38AD96003C05E4 /* ios-native-messages */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = "ios-native-messages"; path = ..; sourceTree = ""; }; F200FF012A86D7FB0002DE25 /* UIKitContentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIKitContentViewController.swift; sourceTree = ""; }; F200FF032A86D8080002DE25 /* UIKitContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIKitContentView.swift; sourceTree = ""; }; F200FF052A86D8170002DE25 /* SwiftUIContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUIContentView.swift; sourceTree = ""; }; @@ -53,7 +69,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - C6E7C4A72A38ADC7003C05E4 /* PayPalMessages in Frameworks */, + C67A5ACA2B2A5FE700BBF5F7 /* PayPalMessages.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -63,7 +79,6 @@ C6E7C4852A38AC56003C05E4 = { isa = PBXGroup; children = ( - C6E7C4A32A38AD96003C05E4 /* Packages */, C6E7C4902A38AC56003C05E4 /* Demo */, C6E7C48F2A38AC56003C05E4 /* Products */, C6E7C4A52A38ADC7003C05E4 /* Frameworks */, @@ -104,17 +119,11 @@ path = "Preview Content"; sourceTree = ""; }; - C6E7C4A32A38AD96003C05E4 /* Packages */ = { - isa = PBXGroup; - children = ( - C6E7C4A42A38AD96003C05E4 /* ios-native-messages */, - ); - name = Packages; - sourceTree = ""; - }; C6E7C4A52A38ADC7003C05E4 /* Frameworks */ = { isa = PBXGroup; children = ( + C67A5AC92B2A5FE700BBF5F7 /* PayPalMessages.framework */, + C67A5AC52B2A5DA300BBF5F7 /* PayPalMessages.framework */, ); name = Frameworks; sourceTree = ""; @@ -152,6 +161,7 @@ C6E7C48A2A38AC56003C05E4 /* Sources */, C6E7C48B2A38AC56003C05E4 /* Frameworks */, C6E7C48C2A38AC56003C05E4 /* Resources */, + C67A5ACC2B2A5FE700BBF5F7 /* Embed Frameworks */, ); buildRules = ( ); @@ -159,7 +169,6 @@ ); name = Demo; packageProductDependencies = ( - C6E7C4A62A38ADC7003C05E4 /* PayPalMessages */, ); productName = Demo; productReference = C6E7C48E2A38AC56003C05E4 /* Demo.app */; @@ -260,6 +269,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + BUILD_LIBRARY_FOR_DISTRIBUTION = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; @@ -306,7 +316,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.1; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -320,6 +330,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + BUILD_LIBRARY_FOR_DISTRIBUTION = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; @@ -360,7 +371,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.1; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; @@ -452,13 +463,6 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ - -/* Begin XCSwiftPackageProductDependency section */ - C6E7C4A62A38ADC7003C05E4 /* PayPalMessages */ = { - isa = XCSwiftPackageProductDependency; - productName = PayPalMessages; - }; -/* End XCSwiftPackageProductDependency section */ }; rootObject = C6E7C4862A38AC56003C05E4 /* Project object */; } diff --git a/Demo/Demo.xcodeproj/xcshareddata/xcschemes/Demo.xcscheme b/Demo/Demo.xcodeproj/xcshareddata/xcschemes/Demo.xcscheme new file mode 100644 index 0000000..0ed6014 --- /dev/null +++ b/Demo/Demo.xcodeproj/xcshareddata/xcschemes/Demo.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Demo/Demo/DefaultMessageConfig.swift b/Demo/Demo/DefaultMessageConfig.swift index db4bb0b..fb11b02 100644 --- a/Demo/Demo/DefaultMessageConfig.swift +++ b/Demo/Demo/DefaultMessageConfig.swift @@ -12,7 +12,6 @@ let defaultMessageConfig: PayPalMessageConfig = { ) // Override defaults for ease of development config.data.ignoreCache = false - config.data.devTouchpoint = false return config }() diff --git a/Demo/Demo/Extensions/PayPalMessageExtensions.swift b/Demo/Demo/Extensions/PayPalMessageExtensions.swift index 5a7bd96..07dc45f 100644 --- a/Demo/Demo/Extensions/PayPalMessageExtensions.swift +++ b/Demo/Demo/Extensions/PayPalMessageExtensions.swift @@ -4,7 +4,7 @@ import PayPalMessages // MARK: - Enum Displaying Helpers typealias PayPalMessageEnumType = CaseIterable & CustomStringConvertible & Equatable -extension PayPalMessageTextAlignment: CustomStringConvertible { +extension PayPalMessageTextAlign: CustomStringConvertible { public var description: String { switch self { diff --git a/Demo/Demo/SwiftUIContentView.swift b/Demo/Demo/SwiftUIContentView.swift index 9556a4a..eb04a4a 100644 --- a/Demo/Demo/SwiftUIContentView.swift +++ b/Demo/Demo/SwiftUIContentView.swift @@ -9,16 +9,14 @@ struct SwiftUIContentView: View { @State private var logoType: PayPalMessageLogoType = defaultMessageConfig.style.logoType @State private var messageColor: PayPalMessageColor = defaultMessageConfig.style.color - @State private var textAlignment: PayPalMessageTextAlignment = defaultMessageConfig.style.textAlignment + @State private var textAlign: PayPalMessageTextAlign = defaultMessageConfig.style.textAlign @State private var clientID: String = defaultMessageConfig.data.clientID @State private var amount: Double? = defaultMessageConfig.data.amount - @State private var placement: PayPalMessagePlacement? = defaultMessageConfig.data.placement + @State private var pageType: PayPalMessagePageType? = defaultMessageConfig.data.pageType @State private var offerType: PayPalMessageOfferType? = defaultMessageConfig.data.offerType - @State private var stageTag: String = defaultMessageConfig.data.stageTag ?? "" @State private var buyerCountry: String = defaultMessageConfig.data.buyerCountry ?? "" @State private var ignoreCache: Bool = defaultMessageConfig.data.ignoreCache - @State private var devTouchpoint: Bool = defaultMessageConfig.data.devTouchpoint @State private var messageState: String = "" @State private var debounceTimerInterval: TimeInterval = 1 @@ -32,21 +30,22 @@ struct SwiftUIContentView: View { let messageConfig: PayPalMessageConfig = .init( data: .init( clientID: clientID, + environment: defaultMessageConfig.data.environment, amount: amount, - placement: placement, - offerType: offerType, - environment: .sandbox + pageType: pageType, + offerType: offerType ), style: .init( logoType: logoType, color: messageColor, - textAlignment: textAlignment + textAlign: textAlign ) ) - messageConfig.data.buyerCountry = buyerCountry + if !buyerCountry.isEmpty { + messageConfig.data.buyerCountry = buyerCountry + } messageConfig.data.ignoreCache = ignoreCache - messageConfig.data.devTouchpoint = devTouchpoint return messageConfig } @@ -101,8 +100,8 @@ struct SwiftUIContentView: View { } // Text Alignment - ReusablePicker(options: PayPalMessageTextAlignment.allCases, selectedOption: $textAlignment) - .onChange(of: textAlignment) { _ in + ReusablePicker(options: PayPalMessageTextAlign.allCases, selectedOption: $textAlign) + .onChange(of: textAlign) { _ in debounceConfigUpdate() } } @@ -143,52 +142,24 @@ struct SwiftUIContentView: View { debounceConfigUpdate() } } - - HStack { - // Stage Tag - ReusableTextView(text: "Stage Tag", font: .subheadline, weight: .semibold) - - ReusableTextField(text: $stageTag) - .onChange(of: stageTag) { _ in - debounceConfigUpdate() - } - } } HStack { - HStack { - // Ignore Cache - ReusableToggle(isOn: $ignoreCache, label: "ignoreCache") - - ReusableTextView( - text: "Ignore Cache", - font: .system(size: 14), - weight: .semibold, - padding: .init(top: 0, leading: 16, bottom: 0, trailing: 0) - ) - .onChange(of: ignoreCache) { _ in - debounceConfigUpdate() - } - } - HStack { - - // Dev Touchpoint - ReusableToggle(isOn: $devTouchpoint, label: "devTouchpoint") + // Ignore Cache + ReusableToggle(isOn: $ignoreCache, label: "ignoreCache") - ReusableTextView( - text: "Dev Touchpoint", - font: .system(size: 14), - weight: .semibold, - padding: .init(top: 0, leading: 16, bottom: 0, trailing: 0) - ) - .onChange(of: devTouchpoint) { _ in - debounceConfigUpdate() - } + ReusableTextView( + text: "Ignore Cache", + font: .system(size: 14), + weight: .semibold, + padding: .init(top: 0, leading: 16, bottom: 0, trailing: 0) + ) + .onChange(of: ignoreCache) { _ in + debounceConfigUpdate() } } Divider() - .overlay(.gray) // MARK: PayPal Message @@ -221,13 +192,11 @@ struct SwiftUIContentView: View { logoType = defaultStyle.logoType messageColor = defaultStyle.color - textAlignment = defaultStyle.textAlignment + textAlign = defaultStyle.textAlign offerType = defaultData.offerType amount = defaultData.amount buyerCountry = defaultData.buyerCountry ?? "" - stageTag = defaultData.stageTag ?? "" ignoreCache = defaultData.ignoreCache - devTouchpoint = defaultData.devTouchpoint clientID = defaultData.clientID } diff --git a/Demo/Demo/UIKitContentViewController.swift b/Demo/Demo/UIKitContentViewController.swift index fbceed5..24a6fbd 100644 --- a/Demo/Demo/UIKitContentViewController.swift +++ b/Demo/Demo/UIKitContentViewController.swift @@ -31,12 +31,8 @@ class UIKitContentViewController: UIViewController { lazy var buyerCountryLabel = getLabel(text: "Buyer Country") - lazy var stageTagLabel = getLabel(text: "Stage Tag") - lazy var ignoreCacheLabel = getLabel(text: "Ignore Cache") - lazy var devTouchpointLabel = getLabel(text: "Dev Touchpoint") - lazy var logoTypePicker: UISegmentedControl = getSegmentedControl( action: #selector(updatePayPalMessageMessage), forType: PayPalMessageLogoType.self @@ -49,7 +45,7 @@ class UIKitContentViewController: UIViewController { lazy var alignmentTypePicker: UISegmentedControl = getSegmentedControl( action: #selector(updatePayPalMessageMessage), - forType: PayPalMessageTextAlignment.self + forType: PayPalMessageTextAlign.self ) lazy var offerTypePicker: UISegmentedControl = getSegmentedControl( @@ -69,22 +65,11 @@ class UIKitContentViewController: UIViewController { autoCapitalizationType: .allCharacters ) - lazy var stageTagField: UITextField = getTextField( - action: #selector(updatePayPalMessageMessage), - keyboardType: .default, - autoCapitalizationType: .none - ) - lazy var ignoreCacheSwitch: UISwitch = getSwitch( isOn: defaultMessageConfig.data.ignoreCache, action: #selector(updatePayPalMessageMessage) ) - lazy var devTouchpointSwitch: UISwitch = getSwitch( - isOn: defaultMessageConfig.data.devTouchpoint, - action: #selector(updatePayPalMessageMessage) - ) - lazy var clientIDField: UITextField = getTextField( action: #selector(updatePayPalMessageMessage), keyboardType: .default, @@ -110,18 +95,7 @@ class UIKitContentViewController: UIViewController { }() lazy var stackView: UIStackView = { - let paypalMessageContainer = UIView() - - paypalMessageContainer.addSubview(paypalMessage) - paypalMessage.translatesAutoresizingMaskIntoConstraints = false - NSLayoutConstraint.activate([ - paypalMessage.leadingAnchor.constraint(equalTo: paypalMessageContainer.leadingAnchor), - paypalMessage.trailingAnchor.constraint(equalTo: paypalMessageContainer.trailingAnchor), - paypalMessage.topAnchor.constraint(equalTo: paypalMessageContainer.topAnchor), - paypalMessage.bottomAnchor.constraint(equalTo: paypalMessageContainer.bottomAnchor, constant: 20) - ]) - return getStackView( subviews: [ @@ -157,24 +131,15 @@ class UIKitContentViewController: UIViewController { ], axis: .horizontal ), - getStackView( - subviews: [ - stageTagLabel, - stageTagField - ], - axis: .horizontal - ), getStackView( subviews: [ ignoreCacheSwitch, - ignoreCacheLabel, - devTouchpointSwitch, - devTouchpointLabel + ignoreCacheLabel ], axis: .horizontal ), getSeparator(), - paypalMessageContainer + paypalMessage ], padding: 12 ) @@ -208,11 +173,9 @@ class UIKitContentViewController: UIViewController { private func loadDefaultSelections() { loadSegmentedIndex(item: defaultMessageConfig.style.logoType, picker: logoTypePicker) loadSegmentedIndex(item: defaultMessageConfig.style.color, picker: colorTypePicker) - loadSegmentedIndex(item: defaultMessageConfig.style.textAlignment, picker: alignmentTypePicker) + loadSegmentedIndex(item: defaultMessageConfig.style.textAlign, picker: alignmentTypePicker) buyerCountryField.text = defaultMessageConfig.data.buyerCountry - stageTagField.text = defaultMessageConfig.data.stageTag ignoreCacheSwitch.isOn = defaultMessageConfig.data.ignoreCache - devTouchpointSwitch.isOn = defaultMessageConfig.data.devTouchpoint if let amount = defaultMessageConfig.data.amount { amountTextField.text = String(format: "%f", amount) @@ -266,20 +229,19 @@ class UIKitContentViewController: UIViewController { let config = PayPalMessageConfig( data: .init( clientID: getCurrentClientID() ?? defaultMessageConfig.data.clientID, + environment: defaultMessageConfig.data.environment, amount: getCurrentAmount(), offerType: getCurrentOfferType() ), style: .init( logoType: getCurrentLogoType(), color: getCurrentMessageColor(), - textAlignment: getCurrentAlignment() + textAlign: getCurrentAlignment() ) ) config.data.buyerCountry = getCurrentBuyerCountry() config.data.ignoreCache = getCurrentIgnoreCache() - config.data.stageTag = getCurrentStageTag() - config.data.devTouchpoint = getCurrentDevTouchpoint() return config } @@ -293,8 +255,8 @@ class UIKitContentViewController: UIViewController { PayPalMessageColor.allCases[colorTypePicker.selectedSegmentIndex] } - private func getCurrentAlignment() -> PayPalMessageTextAlignment { - PayPalMessageTextAlignment.allCases[alignmentTypePicker.selectedSegmentIndex] + private func getCurrentAlignment() -> PayPalMessageTextAlign { + PayPalMessageTextAlign.allCases[alignmentTypePicker.selectedSegmentIndex] } private func getCurrentOfferType() -> PayPalMessageOfferType? { @@ -312,20 +274,10 @@ class UIKitContentViewController: UIViewController { return text } - private func getCurrentStageTag() -> String? { - guard let text = stageTagField.text, !text.isEmpty else { return nil } - - return text - } - private func getCurrentIgnoreCache() -> Bool { ignoreCacheSwitch.isOn } - private func getCurrentDevTouchpoint() -> Bool { - devTouchpointSwitch.isOn - } - private func getCurrentClientID() -> String? { guard let text = clientIDField.text, !text.isEmpty else { return nil } @@ -410,4 +362,3 @@ extension UIKitContentViewController: PayPalMessageViewEventDelegate { statusTextView.text = "Applied" } } -// swiftlint:disable:this file_length diff --git a/Gemfile.lock b/Gemfile.lock index 9ec71b3..51348de 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -16,16 +16,16 @@ GEM artifactory (3.0.15) atomos (0.1.3) aws-eventstream (1.2.0) - aws-partitions (1.811.0) - aws-sdk-core (3.181.0) + aws-partitions (1.829.0) + aws-sdk-core (3.184.0) aws-eventstream (~> 1, >= 1.0.2) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.5) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.71.0) - aws-sdk-core (~> 3, >= 3.177.0) + aws-sdk-kms (1.72.0) + aws-sdk-core (~> 3, >= 3.184.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.134.0) + aws-sdk-s3 (1.136.0) aws-sdk-core (~> 3, >= 3.181.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.6) @@ -85,7 +85,7 @@ GEM escape (0.0.4) ethon (0.16.0) ffi (>= 1.15.0) - excon (0.102.0) + excon (0.103.0) faraday (1.10.3) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) @@ -115,7 +115,7 @@ GEM faraday_middleware (1.2.0) faraday (~> 1.0) fastimage (2.2.7) - fastlane (2.214.0) + fastlane (2.216.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) @@ -136,6 +136,7 @@ GEM google-apis-playcustomapp_v1 (~> 0.1) google-cloud-storage (~> 1.31) highline (~> 2.0) + http-cookie (~> 1.0.5) json (< 3.0.0) jwt (>= 2.1.0, < 3) mini_magick (>= 4.9.4, < 5.0.0) @@ -147,7 +148,7 @@ GEM security (= 0.1.3) simctl (~> 1.6.3) terminal-notifier (>= 2.0.0, < 3.0.0) - terminal-table (>= 1.4.5, < 2.0.0) + terminal-table (~> 3) tty-screen (>= 0.6.3, < 1.0.0) tty-spinner (>= 0.8.0, < 1.0.0) word_wrap (~> 1.0.0) @@ -158,7 +159,7 @@ GEM fourflusher (2.3.1) fuzzy_match (2.0.4) gh_inspector (1.1.3) - google-apis-androidpublisher_v3 (0.48.0) + google-apis-androidpublisher_v3 (0.50.0) google-apis-core (>= 0.11.0, < 2.a) google-apis-core (0.11.1) addressable (~> 2.5, >= 2.5.1) @@ -189,10 +190,9 @@ GEM google-cloud-core (~> 1.6) googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) - googleauth (1.7.0) + googleauth (1.8.1) faraday (>= 0.17.3, < 3.a) jwt (>= 1.4, < 3.0) - memoist (~> 0.16) multi_json (~> 1.11) os (>= 0.9, < 2.0) signet (>= 0.16, < 2.a) @@ -205,7 +205,6 @@ GEM jmespath (1.6.2) json (2.6.3) jwt (2.7.1) - memoist (0.16.2) mini_magick (4.12.0) mini_mime (1.1.5) minitest (5.19.0) @@ -232,7 +231,7 @@ GEM ruby2_keywords (0.0.5) rubyzip (2.3.2) security (0.1.3) - signet (0.17.0) + signet (0.18.0) addressable (~> 2.8) faraday (>= 0.17.5, < 3.a) jwt (>= 1.5, < 3.0) @@ -242,8 +241,8 @@ GEM naturally slack-notifier (2.4.0) terminal-notifier (2.0.0) - terminal-table (1.8.0) - unicode-display_width (~> 1.1, >= 1.1.1) + terminal-table (3.0.2) + unicode-display_width (>= 1.1.1, < 3) trailblazer-option (0.1.2) tty-cursor (0.7.1) tty-screen (0.8.1) @@ -257,10 +256,10 @@ GEM unf (0.1.4) unf_ext unf_ext (0.0.8.2) - unicode-display_width (1.8.0) + unicode-display_width (2.4.2) webrick (1.8.1) word_wrap (1.0.0) - xcodeproj (1.22.0) + xcodeproj (1.23.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) diff --git a/Package.swift b/Package.swift index 0d8db3d..935371c 100644 --- a/Package.swift +++ b/Package.swift @@ -1,28 +1,21 @@ -// swift-tools-version: 5.7 -// The swift-tools-version declares the minimum version of Swift required to build this package. - +// swift-tools-version: 5.8 import PackageDescription +let version = "1.0.0-alpha.1" + let package = Package( name: "PayPalMessages", + platforms: [.iOS(.v14)], products: [ - // Products define the executables and libraries a package produces, and make them visible to other packages. .library( name: "PayPalMessages", targets: ["PayPalMessages"]) ], - dependencies: [ - // Dependencies declare other packages that this package depends on. - // .package(url: /* package url */, from: "1.0.0"), - ], targets: [ - // Targets are the basic building blocks of a package. A target can define a module or a test suite. - // Targets can depend on other targets in this package, and on products in packages this package depends on. - .target( + .binaryTarget( name: "PayPalMessages", - dependencies: []), - .testTarget( - name: "PayPalMessagesTests", - dependencies: ["PayPalMessages"]) - ] + url: "https://github.com/paypal/paypal-messages-ios/releases/download/\(version)/PayPalMessages.xcframework.zip", + checksum: "7bf501b2b303e51692d69e7b5532c7d4e447bd0604edcd55aebffb2ce5539451") + ], + swiftLanguageVersions: [.v5] ) diff --git a/PayPalMessages.podspec b/PayPalMessages.podspec index 9c694ae..9c0ae2d 100644 --- a/PayPalMessages.podspec +++ b/PayPalMessages.podspec @@ -1,18 +1,18 @@ Pod::Spec.new do |s| s.name = "PayPalMessages" - s.version = "0.1.0" + s.version = "1.0.0-alpha.1" s.summary = "The PayPal iOS SDK Messages Module: Promote offers to your customers such as Pay Later and PayPal Credit." s.homepage = "https://developer.paypal.com" s.license = "MIT" s.author = { "PayPal" => "sdks@paypal.com" } s.source = { :git => "https://github.com/paypal/paypal-messages-ios.git", :tag => s.version } - s.swift_version = "5.7" + s.swift_version = "5.8" s.platform = :ios, "14.0" s.compiler_flags = "-Wall -Werror -Wextra" s.source_files = "Sources/PayPalMessages/**/*.swift" s.resource_bundle = { - "PayPalMessages" => ['Sources/PayPalMessages/*.xcassets'] + "PayPalMessages" => ['Sources/PayPalMessages/*.xcassets', 'Sources/PayPalMessages/PrivacyInfo.xcprivacy'] } end diff --git a/PayPalMessages.xcodeproj/project.pbxproj b/PayPalMessages.xcodeproj/project.pbxproj index 6a6d57b..36d2b70 100644 --- a/PayPalMessages.xcodeproj/project.pbxproj +++ b/PayPalMessages.xcodeproj/project.pbxproj @@ -7,11 +7,15 @@ objects = { /* Begin PBXBuildFile section */ + C60F156A2B3C851100E16902 /* AnalyticsLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = C60F15692B3C851100E16902 /* AnalyticsLogger.swift */; }; + C61D84472B33348C00F372EF /* CloudEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C61D84462B33348C00F372EF /* CloudEvent.swift */; }; + C62FF8232B742C9400890823 /* ResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = C62FF8222B742C9400890823 /* ResponseError.swift */; }; + C62FF8252B74315B00890823 /* ResponseErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C62FF8242B74315B00890823 /* ResponseErrorTests.swift */; }; + C62FF8272B852E4000890823 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = C62FF8262B852E4000890823 /* PrivacyInfo.xcprivacy */; }; C635F4362A9645B10096F9FF /* PayPalMessages.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C635F42E2A9645B10096F9FF /* PayPalMessages.framework */; }; C635F4C12A964A020096F9FF /* PayPalMessageModalViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C635F48E2A964A020096F9FF /* PayPalMessageModalViewModel.swift */; }; - C635F4C22A964A020096F9FF /* ComponentLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = C635F4902A964A020096F9FF /* ComponentLogger.swift */; }; - C635F4C32A964A020096F9FF /* ComponentLoggerEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C635F4912A964A020096F9FF /* ComponentLoggerEvent.swift */; }; - C635F4C42A964A020096F9FF /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = C635F4922A964A020096F9FF /* Logger.swift */; }; + C635F4C32A964A020096F9FF /* AnalyticsEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C635F4912A964A020096F9FF /* AnalyticsEvent.swift */; }; + C635F4C42A964A020096F9FF /* AnalyticsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C635F4922A964A020096F9FF /* AnalyticsService.swift */; }; C635F4C52A964A020096F9FF /* AnyStringKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = C635F4932A964A020096F9FF /* AnyStringKey.swift */; }; C635F4C62A964A020096F9FF /* AnyCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C635F4942A964A020096F9FF /* AnyCodable.swift */; }; C635F4C72A964A020096F9FF /* PayPalMessageConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = C635F4962A964A020096F9FF /* PayPalMessageConfig.swift */; }; @@ -21,9 +25,9 @@ C635F4CB2A964A020096F9FF /* PayPalMessageOfferType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C635F49B2A964A020096F9FF /* PayPalMessageOfferType.swift */; }; C635F4CC2A964A020096F9FF /* BuildInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = C635F49C2A964A020096F9FF /* BuildInfo.swift */; }; C635F4CD2A964A020096F9FF /* Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C635F49D2A964A020096F9FF /* Environment.swift */; }; - C635F4CE2A964A020096F9FF /* PayPalMessageTextAlignment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C635F49E2A964A020096F9FF /* PayPalMessageTextAlignment.swift */; }; + C635F4CE2A964A020096F9FF /* PayPalMessageTextAlign.swift in Sources */ = {isa = PBXBuildFile; fileRef = C635F49E2A964A020096F9FF /* PayPalMessageTextAlign.swift */; }; C635F4CF2A964A020096F9FF /* PayPalMessageColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C635F49F2A964A020096F9FF /* PayPalMessageColor.swift */; }; - C635F4D02A964A020096F9FF /* PayPalMessagePlacement.swift in Sources */ = {isa = PBXBuildFile; fileRef = C635F4A02A964A020096F9FF /* PayPalMessagePlacement.swift */; }; + C635F4D02A964A020096F9FF /* PayPalMessagePageType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C635F4A02A964A020096F9FF /* PayPalMessagePageType.swift */; }; C635F4D12A964A020096F9FF /* ImageAsset.swift in Sources */ = {isa = PBXBuildFile; fileRef = C635F4A12A964A020096F9FF /* ImageAsset.swift */; }; C635F4D22A964A020096F9FF /* PayPalMessageError.swift in Sources */ = {isa = PBXBuildFile; fileRef = C635F4A22A964A020096F9FF /* PayPalMessageError.swift */; }; C635F4D32A964A020096F9FF /* HTTPHeaders.swift in Sources */ = {isa = PBXBuildFile; fileRef = C635F4A32A964A020096F9FF /* HTTPHeaders.swift */; }; @@ -42,7 +46,6 @@ C635F4E02A964A020096F9FF /* Fetch.swift in Sources */ = {isa = PBXBuildFile; fileRef = C635F4B22A964A020096F9FF /* Fetch.swift */; }; C635F4E12A964A020096F9FF /* UIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C635F4B42A964A020096F9FF /* UIView.swift */; }; C635F4E22A964A020096F9FF /* UIColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C635F4B52A964A020096F9FF /* UIColor.swift */; }; - C635F4E32A964A020096F9FF /* NSObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = C635F4B62A964A020096F9FF /* NSObject.swift */; }; C635F4E42A964A020096F9FF /* UserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = C635F4B72A964A020096F9FF /* UserDefaults.swift */; }; C635F4E52A964A020096F9FF /* UIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C635F4B82A964A020096F9FF /* UIViewController.swift */; }; C635F4E62A964A020096F9FF /* HTTPURLResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = C635F4B92A964A020096F9FF /* HTTPURLResponse.swift */; }; @@ -63,6 +66,15 @@ C635F5072A96524D0096F9FF /* PayPalMessageLoggerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C635F4FB2A96524D0096F9FF /* PayPalMessageLoggerTests.swift */; }; C635F5082A96524D0096F9FF /* MerchantProfileProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C635F4FC2A96524D0096F9FF /* MerchantProfileProviderTests.swift */; }; C635F5092A96524D0096F9FF /* PayPalMessageModalViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C635F4FD2A96524D0096F9FF /* PayPalMessageModalViewModelTests.swift */; }; + F23BF3832AB89AA30074FA00 /* CloseButtonTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F23BF3822AB89AA30074FA00 /* CloseButtonTests.swift */; }; + F23BF3852AB89F670074FA00 /* UIViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F23BF3842AB89F670074FA00 /* UIViewTests.swift */; }; + F23BF3872AB8AA470074FA00 /* AnyStringKeyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F23BF3862AB8AA470074FA00 /* AnyStringKeyTests.swift */; }; + F23BF38B2AB8BAAC0074FA00 /* AnyCodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F23BF38A2AB8BAAC0074FA00 /* AnyCodableTests.swift */; }; + F23BF38F2AB8D3A70074FA00 /* EnvironmentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F23BF38E2AB8D3A70074FA00 /* EnvironmentTests.swift */; }; + F23BF3912AB8D6E60074FA00 /* PayPalMessageModalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F23BF3902AB8D6E60074FA00 /* PayPalMessageModalTests.swift */; }; + F23BF3932AB8D8A70074FA00 /* PayPalMessageViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F23BF3922AB8D8A70074FA00 /* PayPalMessageViewTests.swift */; }; + F23BF3952AB9CEDA0074FA00 /* PayPalMessageResponseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F23BF3942AB9CEDA0074FA00 /* PayPalMessageResponseTests.swift */; }; + F27522982AE056670092A3BF /* PayPalMessageConfigTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F27522972AE056670092A3BF /* PayPalMessageConfigTests.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -76,12 +88,16 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + C60F15692B3C851100E16902 /* AnalyticsLogger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnalyticsLogger.swift; sourceTree = ""; }; + C61D84462B33348C00F372EF /* CloudEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudEvent.swift; sourceTree = ""; }; + C62FF8222B742C9400890823 /* ResponseError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResponseError.swift; sourceTree = ""; }; + C62FF8242B74315B00890823 /* ResponseErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResponseErrorTests.swift; sourceTree = ""; }; + C62FF8262B852E4000890823 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; C635F42E2A9645B10096F9FF /* PayPalMessages.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = PayPalMessages.framework; sourceTree = BUILT_PRODUCTS_DIR; }; C635F4352A9645B10096F9FF /* PayPalMessagesTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PayPalMessagesTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; C635F48E2A964A020096F9FF /* PayPalMessageModalViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PayPalMessageModalViewModel.swift; sourceTree = ""; }; - C635F4902A964A020096F9FF /* ComponentLogger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ComponentLogger.swift; sourceTree = ""; }; - C635F4912A964A020096F9FF /* ComponentLoggerEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ComponentLoggerEvent.swift; sourceTree = ""; }; - C635F4922A964A020096F9FF /* Logger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = ""; }; + C635F4912A964A020096F9FF /* AnalyticsEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnalyticsEvent.swift; sourceTree = ""; }; + C635F4922A964A020096F9FF /* AnalyticsService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnalyticsService.swift; sourceTree = ""; }; C635F4932A964A020096F9FF /* AnyStringKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyStringKey.swift; sourceTree = ""; }; C635F4942A964A020096F9FF /* AnyCodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyCodable.swift; sourceTree = ""; }; C635F4962A964A020096F9FF /* PayPalMessageConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PayPalMessageConfig.swift; sourceTree = ""; }; @@ -91,9 +107,9 @@ C635F49B2A964A020096F9FF /* PayPalMessageOfferType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PayPalMessageOfferType.swift; sourceTree = ""; }; C635F49C2A964A020096F9FF /* BuildInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BuildInfo.swift; sourceTree = ""; }; C635F49D2A964A020096F9FF /* Environment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Environment.swift; sourceTree = ""; }; - C635F49E2A964A020096F9FF /* PayPalMessageTextAlignment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PayPalMessageTextAlignment.swift; sourceTree = ""; }; + C635F49E2A964A020096F9FF /* PayPalMessageTextAlign.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PayPalMessageTextAlign.swift; sourceTree = ""; }; C635F49F2A964A020096F9FF /* PayPalMessageColor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PayPalMessageColor.swift; sourceTree = ""; }; - C635F4A02A964A020096F9FF /* PayPalMessagePlacement.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PayPalMessagePlacement.swift; sourceTree = ""; }; + C635F4A02A964A020096F9FF /* PayPalMessagePageType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PayPalMessagePageType.swift; sourceTree = ""; }; C635F4A12A964A020096F9FF /* ImageAsset.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageAsset.swift; sourceTree = ""; }; C635F4A22A964A020096F9FF /* PayPalMessageError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PayPalMessageError.swift; sourceTree = ""; }; C635F4A32A964A020096F9FF /* HTTPHeaders.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPHeaders.swift; sourceTree = ""; }; @@ -112,7 +128,6 @@ C635F4B22A964A020096F9FF /* Fetch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Fetch.swift; sourceTree = ""; }; C635F4B42A964A020096F9FF /* UIView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIView.swift; sourceTree = ""; }; C635F4B52A964A020096F9FF /* UIColor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIColor.swift; sourceTree = ""; }; - C635F4B62A964A020096F9FF /* NSObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSObject.swift; sourceTree = ""; }; C635F4B72A964A020096F9FF /* UserDefaults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDefaults.swift; sourceTree = ""; }; C635F4B82A964A020096F9FF /* UIViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIViewController.swift; sourceTree = ""; }; C635F4B92A964A020096F9FF /* HTTPURLResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPURLResponse.swift; sourceTree = ""; }; @@ -136,6 +151,15 @@ C635F4FB2A96524D0096F9FF /* PayPalMessageLoggerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PayPalMessageLoggerTests.swift; sourceTree = ""; }; C635F4FC2A96524D0096F9FF /* MerchantProfileProviderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MerchantProfileProviderTests.swift; sourceTree = ""; }; C635F4FD2A96524D0096F9FF /* PayPalMessageModalViewModelTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PayPalMessageModalViewModelTests.swift; sourceTree = ""; }; + F23BF3822AB89AA30074FA00 /* CloseButtonTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloseButtonTests.swift; sourceTree = ""; }; + F23BF3842AB89F670074FA00 /* UIViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIViewTests.swift; sourceTree = ""; }; + F23BF3862AB8AA470074FA00 /* AnyStringKeyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyStringKeyTests.swift; sourceTree = ""; }; + F23BF38A2AB8BAAC0074FA00 /* AnyCodableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyCodableTests.swift; sourceTree = ""; }; + F23BF38E2AB8D3A70074FA00 /* EnvironmentTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnvironmentTests.swift; sourceTree = ""; }; + F23BF3902AB8D6E60074FA00 /* PayPalMessageModalTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayPalMessageModalTests.swift; sourceTree = ""; }; + F23BF3922AB8D8A70074FA00 /* PayPalMessageViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayPalMessageViewTests.swift; sourceTree = ""; }; + F23BF3942AB9CEDA0074FA00 /* PayPalMessageResponseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayPalMessageResponseTests.swift; sourceTree = ""; }; + F27522972AE056670092A3BF /* PayPalMessageConfigTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayPalMessageConfigTests.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -193,11 +217,12 @@ C635F4BB2A964A020096F9FF /* Delegates */, C635F49A2A964A020096F9FF /* Enums */, C635F4B32A964A020096F9FF /* Extensions */, - C635F48F2A964A020096F9FF /* Logger */, + C635F48F2A964A020096F9FF /* Analytics */, C635F4A52A964A020096F9FF /* IO */, C635F4AC2A964A020096F9FF /* Utils */, C635F4BE2A964A020096F9FF /* Views */, C635F4AB2A964A020096F9FF /* Assets.xcassets */, + C62FF8262B852E4000890823 /* PrivacyInfo.xcprivacy */, C635F4C02A964A020096F9FF /* PayPalMessageModal.swift */, C635F48E2A964A020096F9FF /* PayPalMessageModalViewModel.swift */, C635F4982A964A020096F9FF /* PayPalMessageView.swift */, @@ -206,16 +231,17 @@ path = PayPalMessages; sourceTree = ""; }; - C635F48F2A964A020096F9FF /* Logger */ = { + C635F48F2A964A020096F9FF /* Analytics */ = { isa = PBXGroup; children = ( - C635F4902A964A020096F9FF /* ComponentLogger.swift */, - C635F4912A964A020096F9FF /* ComponentLoggerEvent.swift */, - C635F4922A964A020096F9FF /* Logger.swift */, + C60F15692B3C851100E16902 /* AnalyticsLogger.swift */, + C635F4912A964A020096F9FF /* AnalyticsEvent.swift */, + C635F4922A964A020096F9FF /* AnalyticsService.swift */, C635F4932A964A020096F9FF /* AnyStringKey.swift */, C635F4942A964A020096F9FF /* AnyCodable.swift */, + C61D84462B33348C00F372EF /* CloudEvent.swift */, ); - path = Logger; + path = Analytics; sourceTree = ""; }; C635F4952A964A020096F9FF /* Config */ = { @@ -233,9 +259,9 @@ C635F49B2A964A020096F9FF /* PayPalMessageOfferType.swift */, C635F49C2A964A020096F9FF /* BuildInfo.swift */, C635F49D2A964A020096F9FF /* Environment.swift */, - C635F49E2A964A020096F9FF /* PayPalMessageTextAlignment.swift */, + C635F49E2A964A020096F9FF /* PayPalMessageTextAlign.swift */, C635F49F2A964A020096F9FF /* PayPalMessageColor.swift */, - C635F4A02A964A020096F9FF /* PayPalMessagePlacement.swift */, + C635F4A02A964A020096F9FF /* PayPalMessagePageType.swift */, C635F4A12A964A020096F9FF /* ImageAsset.swift */, C635F4A22A964A020096F9FF /* PayPalMessageError.swift */, C635F4A32A964A020096F9FF /* HTTPHeaders.swift */, @@ -248,10 +274,10 @@ isa = PBXGroup; children = ( C635F4A62A964A020096F9FF /* MessageRequest.swift */, + C635F4AA2A964A020096F9FF /* MessageResponse.swift */, C635F4A72A964A020096F9FF /* MerchantProfileProvider.swift */, C635F4A82A964A020096F9FF /* MerchantProfileRequest.swift */, - C635F4A92A964A020096F9FF /* MerchantProfileData.swift */, - C635F4AA2A964A020096F9FF /* MessageResponse.swift */, + C62FF8222B742C9400890823 /* ResponseError.swift */, ); path = IO; sourceTree = ""; @@ -261,6 +287,7 @@ children = ( C635F4AD2A964A020096F9FF /* PayPalMessageViewParameters.swift */, C635F4AE2A964A020096F9FF /* Log.swift */, + C635F4A92A964A020096F9FF /* MerchantProfileData.swift */, C635F4AF2A964A020096F9FF /* Proxy.swift */, C635F4B02A964A020096F9FF /* PayPalMessageAttributedStringBuilder.swift */, C635F4B12A964A020096F9FF /* PayPalMessageViewParametersBuilder.swift */, @@ -274,7 +301,6 @@ children = ( C635F4B42A964A020096F9FF /* UIView.swift */, C635F4B52A964A020096F9FF /* UIColor.swift */, - C635F4B62A964A020096F9FF /* NSObject.swift */, C635F4B72A964A020096F9FF /* UserDefaults.swift */, C635F4B82A964A020096F9FF /* UIViewController.swift */, C635F4B92A964A020096F9FF /* HTTPURLResponse.swift */, @@ -318,6 +344,16 @@ C635F4FB2A96524D0096F9FF /* PayPalMessageLoggerTests.swift */, C635F4FC2A96524D0096F9FF /* MerchantProfileProviderTests.swift */, C635F4FD2A96524D0096F9FF /* PayPalMessageModalViewModelTests.swift */, + F23BF3822AB89AA30074FA00 /* CloseButtonTests.swift */, + F23BF3842AB89F670074FA00 /* UIViewTests.swift */, + F23BF3862AB8AA470074FA00 /* AnyStringKeyTests.swift */, + F23BF38A2AB8BAAC0074FA00 /* AnyCodableTests.swift */, + F23BF38E2AB8D3A70074FA00 /* EnvironmentTests.swift */, + F23BF3902AB8D6E60074FA00 /* PayPalMessageModalTests.swift */, + F23BF3922AB8D8A70074FA00 /* PayPalMessageViewTests.swift */, + F23BF3942AB9CEDA0074FA00 /* PayPalMessageResponseTests.swift */, + F27522972AE056670092A3BF /* PayPalMessageConfigTests.swift */, + C62FF8242B74315B00890823 /* ResponseErrorTests.swift */, ); path = PayPalMessagesTests; sourceTree = ""; @@ -427,6 +463,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + C62FF8272B852E4000890823 /* PrivacyInfo.xcprivacy in Resources */, C635F4DA2A964A020096F9FF /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -451,38 +488,39 @@ C635F4D82A964A020096F9FF /* MerchantProfileData.swift in Sources */, C635F4DC2A964A020096F9FF /* Log.swift in Sources */, C635F4C92A964A020096F9FF /* PayPalMessageView.swift in Sources */, + C61D84472B33348C00F372EF /* CloudEvent.swift in Sources */, C635F4EB2A964A020096F9FF /* PayPalMessageModal.swift in Sources */, C635F4D12A964A020096F9FF /* ImageAsset.swift in Sources */, C635F4C82A964A020096F9FF /* PayPalMessageModalConfig.swift in Sources */, C635F4E22A964A020096F9FF /* UIColor.swift in Sources */, C635F4D92A964A020096F9FF /* MessageResponse.swift in Sources */, C635F4D22A964A020096F9FF /* PayPalMessageError.swift in Sources */, - C635F4CE2A964A020096F9FF /* PayPalMessageTextAlignment.swift in Sources */, + C635F4CE2A964A020096F9FF /* PayPalMessageTextAlign.swift in Sources */, C635F4D72A964A020096F9FF /* MerchantProfileRequest.swift in Sources */, C635F4CB2A964A020096F9FF /* PayPalMessageOfferType.swift in Sources */, C635F4E72A964A020096F9FF /* CGFloat.swift in Sources */, C635F4D52A964A020096F9FF /* MessageRequest.swift in Sources */, + C60F156A2B3C851100E16902 /* AnalyticsLogger.swift in Sources */, C635F4E82A964A020096F9FF /* PayPalMessageModalDelegates.swift in Sources */, C635F4C12A964A020096F9FF /* PayPalMessageModalViewModel.swift in Sources */, C635F4D32A964A020096F9FF /* HTTPHeaders.swift in Sources */, - C635F4C22A964A020096F9FF /* ComponentLogger.swift in Sources */, - C635F4C32A964A020096F9FF /* ComponentLoggerEvent.swift in Sources */, + C635F4C32A964A020096F9FF /* AnalyticsEvent.swift in Sources */, C635F4CA2A964A020096F9FF /* PayPalMessageViewModel.swift in Sources */, C635F4E02A964A020096F9FF /* Fetch.swift in Sources */, C635F4EA2A964A020096F9FF /* CloseButton.swift in Sources */, C635F4DF2A964A020096F9FF /* PayPalMessageViewParametersBuilder.swift in Sources */, C635F4C52A964A020096F9FF /* AnyStringKey.swift in Sources */, C635F4CD2A964A020096F9FF /* Environment.swift in Sources */, - C635F4E32A964A020096F9FF /* NSObject.swift in Sources */, C635F4D42A964A020096F9FF /* PayPalMessageLogoType.swift in Sources */, C635F4DE2A964A020096F9FF /* PayPalMessageAttributedStringBuilder.swift in Sources */, C635F4E42A964A020096F9FF /* UserDefaults.swift in Sources */, - C635F4C42A964A020096F9FF /* Logger.swift in Sources */, + C635F4C42A964A020096F9FF /* AnalyticsService.swift in Sources */, C635F4C62A964A020096F9FF /* AnyCodable.swift in Sources */, - C635F4D02A964A020096F9FF /* PayPalMessagePlacement.swift in Sources */, + C635F4D02A964A020096F9FF /* PayPalMessagePageType.swift in Sources */, C635F4E92A964A020096F9FF /* PayPalMessageDelegates.swift in Sources */, C635F4CC2A964A020096F9FF /* BuildInfo.swift in Sources */, C635F4E62A964A020096F9FF /* HTTPURLResponse.swift in Sources */, + C62FF8232B742C9400890823 /* ResponseError.swift in Sources */, C635F4DD2A964A020096F9FF /* Proxy.swift in Sources */, C635F4CF2A964A020096F9FF /* PayPalMessageColor.swift in Sources */, C635F4C72A964A020096F9FF /* PayPalMessageConfig.swift in Sources */, @@ -494,13 +532,23 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + F23BF3852AB89F670074FA00 /* UIViewTests.swift in Sources */, + F23BF3912AB8D6E60074FA00 /* PayPalMessageModalTests.swift in Sources */, + F23BF3832AB89AA30074FA00 /* CloseButtonTests.swift in Sources */, C635F5022A96524D0096F9FF /* PayPalMessageModalMocks.swift in Sources */, + F23BF3952AB9CEDA0074FA00 /* PayPalMessageResponseTests.swift in Sources */, + F23BF38F2AB8D3A70074FA00 /* EnvironmentTests.swift in Sources */, + F23BF38B2AB8BAAC0074FA00 /* AnyCodableTests.swift in Sources */, C635F5012A96524D0096F9FF /* PayPalMessageLogSenderMock.swift in Sources */, C635F5062A96524D0096F9FF /* PayPalMessageViewModelTests.swift in Sources */, + C62FF8252B74315B00890823 /* ResponseErrorTests.swift in Sources */, C635F5082A96524D0096F9FF /* MerchantProfileProviderTests.swift in Sources */, + F27522982AE056670092A3BF /* PayPalMessageConfigTests.swift in Sources */, C635F5002A96524D0096F9FF /* PayPalMessageViewMock.swift in Sources */, C635F5032A96524D0096F9FF /* PayPalMessageMerchantProviderMock.swift in Sources */, + F23BF3872AB8AA470074FA00 /* AnyStringKeyTests.swift in Sources */, C635F4FF2A96524D0096F9FF /* MerchantProfileRequestMock.swift in Sources */, + F23BF3932AB8D8A70074FA00 /* PayPalMessageViewTests.swift in Sources */, C635F5042A96524D0096F9FF /* PayPalMessageAttributedStringTests.swift in Sources */, C635F4FE2A96524D0096F9FF /* PayPalMessageRequestMock.swift in Sources */, C635F5092A96524D0096F9FF /* PayPalMessageModalViewModelTests.swift in Sources */, @@ -524,6 +572,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + BUILD_LIBRARY_FOR_DISTRIBUTION = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; @@ -570,11 +619,12 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.1; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; + SKIP_INSTALL = NO; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; @@ -584,6 +634,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + BUILD_LIBRARY_FOR_DISTRIBUTION = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; @@ -624,10 +675,11 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.1; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; + SKIP_INSTALL = NO; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; VALIDATE_PRODUCT = YES; @@ -637,6 +689,7 @@ C635F43D2A9645B10096F9FF /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + BUILD_LIBRARY_FOR_DISTRIBUTION = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; @@ -655,7 +708,7 @@ MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.paypal.PayPalMessages.PayPalMessages; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; + SKIP_INSTALL = NO; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -668,6 +721,7 @@ C635F43E2A9645B10096F9FF /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + BUILD_LIBRARY_FOR_DISTRIBUTION = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; @@ -686,7 +740,7 @@ MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.paypal.PayPalMessages.PayPalMessages; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; + SKIP_INSTALL = NO; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -699,12 +753,14 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + BUILD_LIBRARY_FOR_DISTRIBUTION = YES; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.paypal.PayPalMessages.PayPalMessagesTests; PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -715,12 +771,14 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + BUILD_LIBRARY_FOR_DISTRIBUTION = YES; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.paypal.PayPalMessages.PayPalMessagesTests; PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; diff --git a/PayPalMessages.xcodeproj/xcshareddata/xcschemes/PayPalMessages.xcscheme b/PayPalMessages.xcodeproj/xcshareddata/xcschemes/PayPalMessages.xcscheme index 9e0bc20..27766cb 100644 --- a/PayPalMessages.xcodeproj/xcshareddata/xcschemes/PayPalMessages.xcscheme +++ b/PayPalMessages.xcodeproj/xcshareddata/xcschemes/PayPalMessages.xcscheme @@ -28,17 +28,6 @@ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES"> - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/README.md b/README.md index 59b7a18..b9b33f2 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,52 @@ -# PayPalMessages +# PayPal iOS SDK Messages Module -A description of this package. +Welcome to the PayPal iOS SDK Messages Module. This package facilitates rendering PayPal messages to promote offers such as Pay Later and PayPal Credit to customers. **It is recommended to integrate this package using the [PayPal iOS SDK](https://github.com/paypal/paypal-ios)**. + +**The PayPalMessages package permits a deployment target of iOS 14.0 or higher**. It requires Xcode 14.3+ and Swift 5.8+. + +## Support + +### Languages +This SDK supports Swift 5.8+. This SDK is written in Swift. + +### Package Managers + +This SDK module supports: +- CocoaPods +- Swift Package Manager +- Carthage + +### UI Frameworks + +This package supports: +- UIKit +- SwiftUI + +## Client ID + +In order to display PayPal messages within your iOS application, a Client ID is required. This can be found in your [PayPal Developer Dashboard](https://developer.paypal.com/api/rest/#link-getstarted). + +## Demo +1. Open the `PayPalMessages.xcworkspace` in Xcode +2. Resolve the Swift Package Manager packages if needed: `File` > `Packages` > `Resolve Package Versions` or by running `swift package resolve` in Terminal +3. Update the placeholder `clientID` in the default message configuration found in `Demo/DefaultMessageConfig` to your sandbox client ID. +4. Select the `Demo` scheme, and then run. + +Xcode 14.3+ is required to run the demo app. + +## Testing + +This project uses the `XCTest` framework provided by Xcode. +To run tests in Xcode, select the `PayPalMessagesTest` scheme and then run. + +## CI + +GitHub Actions CI will run all tests and build commands on each PR. This project also takes advantage of `Fastlane` to run tests, lint via `SwiftLint`, build, and release. + +## Release Process + +This SDK follows Semantic Versioning through the use of [Semantic Release](https://github.com/semantic-release/semantic-release). The release process will be automated via GitHub Actions. + +## Feedback + +PayPal iOS SDK Messages is in active development and we welcome your feedback! [Submit feedback or report an issue](https://github.com/paypal/paypal-messages-ios/issues). diff --git a/Sources/PayPalMessages/Logger/ComponentLoggerEvent.swift b/Sources/PayPalMessages/Analytics/AnalyticsEvent.swift similarity index 85% rename from Sources/PayPalMessages/Logger/ComponentLoggerEvent.swift rename to Sources/PayPalMessages/Analytics/AnalyticsEvent.swift index f3281b3..b11ff09 100644 --- a/Sources/PayPalMessages/Logger/ComponentLoggerEvent.swift +++ b/Sources/PayPalMessages/Analytics/AnalyticsEvent.swift @@ -1,6 +1,6 @@ import Foundation -enum ComponentLoggerEvent: Encodable { +enum AnalyticsEvent: Encodable { case messageRender(renderDuration: Int, requestDuration: Int) case messageClick(linkName: String, linkSrc: String) case messageError(errorName: String, errorDescription: String) @@ -10,8 +10,8 @@ enum ComponentLoggerEvent: Encodable { case eventType = "event_type" case renderDuration = "render_duration" case requestDuration = "request_duration" - case linkName = "link_name" - case linkSrc = "link_src" + case linkName = "page_view_link_name" + case linkSrc = "page_view_link_source" case errorName = "error_name" case errorDescription = "error_description" } @@ -22,8 +22,8 @@ enum ComponentLoggerEvent: Encodable { var container = encoder.container(keyedBy: StaticKey.self) try container.encode("message_rendered", forKey: .eventType) - try container.encode(renderDuration, forKey: .renderDuration) - try container.encode(requestDuration, forKey: .requestDuration) + try container.encode(renderDuration.description, forKey: .renderDuration) + try container.encode(requestDuration.description, forKey: .requestDuration) case let .messageClick(linkName, linkSrc): var container = encoder.container(keyedBy: StaticKey.self) diff --git a/Sources/PayPalMessages/Analytics/AnalyticsLogger.swift b/Sources/PayPalMessages/Analytics/AnalyticsLogger.swift new file mode 100644 index 0000000..c51abda --- /dev/null +++ b/Sources/PayPalMessages/Analytics/AnalyticsLogger.swift @@ -0,0 +1,101 @@ +import Foundation +import UIKit + +class Weak { + + weak var value: T? + + init(_ value: T?) { + self.value = value + } +} + +class AnalyticsLogger: Encodable { + + // Global Details + static var integrationVersion: String? + static var integrationName: String? + + var component: Component + + var instanceId: String + + // Includes things like fdata, experience IDs, debug IDs, and the like + var dynamicData: [String: AnyCodable] = [:] + + // Events tied to the component + var events: [AnalyticsEvent] = [] + + enum Component { + case message(Weak) + case modal(Weak) + } + + init(_ component: Component) { + self.instanceId = UUID().uuidString + self.component = component + + AnalyticsService.shared.addLogger(self) + } + + deinit {} + + enum StaticKey: String, CodingKey { + // Integration Details + case offerType = "offer_type" + case amount = "amount" + case pageType = "page_type" + case buyerCountryCode = "buyer_country_code" + case channel = "presentment_channel" + // Message Only + case styleLogoType = "style_logo_type" + case styleColor = "style_color" + case styleTextAlign = "style_text_align" + // Other Details + case type = "type" + case instanceId = "instance_id" + // Component Events + case events = "component_events" + } + + func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StaticKey.self) + + try container.encode(instanceId, forKey: .instanceId) + try container.encode(events, forKey: .events) + try dynamicData.encode(to: encoder) + + switch component { + case .message(let weakMessage): + guard let message = weakMessage.value else { return } + + try container.encode("message", forKey: .type) + try container.encodeIfPresent(message.offerType?.rawValue, forKey: .offerType) + try container.encodeIfPresent(message.amount?.description, forKey: .amount) + try container.encodeIfPresent(message.pageType?.rawValue, forKey: .pageType) + try container.encodeIfPresent(message.buyerCountry, forKey: .buyerCountryCode) + try container.encodeIfPresent(message.channel, forKey: .channel) + try container.encodeIfPresent(message.logoType.rawValue, forKey: .styleLogoType) + try container.encodeIfPresent(message.color.rawValue, forKey: .styleColor) + try container.encodeIfPresent(message.textAlign.rawValue, forKey: .styleTextAlign) + + case .modal(let weakModal): + guard let modal = weakModal.value else { return } + + try container.encode("modal", forKey: .type) + try container.encodeIfPresent(modal.offerType?.rawValue, forKey: .offerType) + try container.encodeIfPresent(modal.amount?.description, forKey: .amount) + try container.encodeIfPresent(modal.pageType?.rawValue, forKey: .pageType) + try container.encodeIfPresent(modal.buyerCountry, forKey: .buyerCountryCode) + try container.encodeIfPresent(modal.channel, forKey: .channel) + } + } + + func addEvent(_ event: AnalyticsEvent) { + self.events.append(event) + } + + func clearEvents() { + events.removeAll() + } +} diff --git a/Sources/PayPalMessages/Analytics/AnalyticsService.swift b/Sources/PayPalMessages/Analytics/AnalyticsService.swift new file mode 100644 index 0000000..7f0317c --- /dev/null +++ b/Sources/PayPalMessages/Analytics/AnalyticsService.swift @@ -0,0 +1,72 @@ +import Foundation + +class AnalyticsService { + + static let shared = AnalyticsService() + + // Integration Details + let timerInterval: Double = 5 + var timer: Timer? + var sender: LogSendable = LogSender() + var loggers: [AnalyticsLogger] = [] + + + private init() { + timer = Timer.scheduledTimer( + withTimeInterval: timerInterval, + repeats: true + ) { _ in + self.flushEvents() + } + } + + deinit { + timer?.invalidate() + flushEvents() + } + + func addLogger(_ logger: AnalyticsLogger) { + loggers.append(logger) + } + + func clearEvents() { + for logger in loggers { + logger.clearEvents() + } + } + + func flushEvents() { + let cloudEvents = CloudEvent.create(from: loggers) + + guard !cloudEvents.isEmpty else { return } + + for cloudEvent in cloudEvents { + if let cloudEventData = try? JSONEncoder().encode(cloudEvent) { + sender.send(cloudEventData, to: cloudEvent.environment) + } + } + + clearEvents() + } +} + +protocol LogSendable { + func send(_ data: Data, to environment: Environment) +} + +class LogSender: LogSendable { + + func send(_ data: Data, to environment: Environment) { + guard let url = environment.url(.log) else { return } + let headers: [HTTPHeader: String] = [ + .acceptLanguage: "en_US", + .accept: "application/json", + .contentType: "application/cloudevents+json" + ] + + log(.debug, "log_payload", with: data, for: environment) + + fetch(url, method: .post, headers: headers, body: data, session: environment.urlSession) { _, _, _ in } + } + deinit {} +} diff --git a/Sources/PayPalMessages/Logger/AnyCodable.swift b/Sources/PayPalMessages/Analytics/AnyCodable.swift similarity index 100% rename from Sources/PayPalMessages/Logger/AnyCodable.swift rename to Sources/PayPalMessages/Analytics/AnyCodable.swift diff --git a/Sources/PayPalMessages/Logger/AnyStringKey.swift b/Sources/PayPalMessages/Analytics/AnyStringKey.swift similarity index 100% rename from Sources/PayPalMessages/Logger/AnyStringKey.swift rename to Sources/PayPalMessages/Analytics/AnyStringKey.swift diff --git a/Sources/PayPalMessages/Analytics/CloudEvent.swift b/Sources/PayPalMessages/Analytics/CloudEvent.swift new file mode 100644 index 0000000..ac5dd35 --- /dev/null +++ b/Sources/PayPalMessages/Analytics/CloudEvent.swift @@ -0,0 +1,148 @@ +import Foundation + +class CloudEvent: Encodable { + + let specVersion = "1.0" + let type = "com.paypal.credit.upstream-presentment.v1" + let source = "urn:paypal:event-src:v1:ios:messages" + let dataContentType = "application/json" + let dataSchema = "ppaas:events.credit.FinancingPresentmentAsyncAPISpecification/v1/schema/json/credit_upstream_presentment_event.json" + + let id: String + let time: String + + let environment: Environment + let clientID: String + let merchantID: String? + let partnerAttributionID: String? + let merchantProfileHash: String? + + var loggers: [AnalyticsLogger] + + /// Creates CloudEvents for each set of client ID + merchant ID + partner attribution ID + static func create(from loggers: [AnalyticsLogger]) -> [CloudEvent] { + var map: [String: CloudEvent] = [:] + + for logger in loggers { + if logger.events.isEmpty { + continue + } + + let environment: Environment + let clientID: String + let merchantID: String? + let partnerAttributionID: String? + let merchantProfileHash: String? + + switch logger.component { + case .message(let weakMessage): + guard let message = weakMessage.value else { continue } + + environment = message.environment + clientID = message.clientID + merchantID = message.merchantID + partnerAttributionID = message.partnerAttributionID + merchantProfileHash = message.merchantProfileHash + + case .modal(let weakModal): + guard let modal = weakModal.value else { continue } + + environment = modal.environment + clientID = modal.clientID + merchantID = modal.merchantID + partnerAttributionID = modal.partnerAttributionID + merchantProfileHash = modal.merchantProfileHash + } + + let key = "\(clientID)_\(merchantID ?? "nil")_\(partnerAttributionID ?? "nil")" + + if let cloudEvent = map[key] { + cloudEvent.loggers.append(logger) + } else { + map[key] = CloudEvent( + logger: logger, + environment: environment, + clientID: clientID, + merchantID: merchantID, + partnerAttributionID: partnerAttributionID, + merchantProfileHash: merchantProfileHash + ) + } + } + + return Array(map.values) + } + + private init( + logger: AnalyticsLogger, + environment: Environment, + clientID: String, + merchantID: String?, + partnerAttributionID: String?, + merchantProfileHash: String? + ) { + self.time = ISO8601DateFormatter().string(from: Date()) + self.id = UUID().uuidString + self.loggers = [logger] + self.environment = environment + self.clientID = clientID + self.merchantID = merchantID + self.partnerAttributionID = partnerAttributionID + self.merchantProfileHash = merchantProfileHash + } + + + func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CloudEventKey.self) + + try container.encode(specVersion, forKey: .specversion) + try container.encode(id, forKey: .id) + try container.encode(type, forKey: .type) + try container.encode(source, forKey: .source) + try container.encode(dataContentType, forKey: .datacontenttype) + try container.encode(dataSchema, forKey: .dataschema) + try container.encode(time, forKey: .time) + + var dataContainer = container.nestedContainer(keyedBy: IntegrationKey.self, forKey: .data) + + try dataContainer.encodeIfPresent(AnalyticsLogger.integrationVersion, forKey: .integrationVersion) + try dataContainer.encodeIfPresent(AnalyticsLogger.integrationName, forKey: .integrationName) + + try dataContainer.encode(BuildInfo.integrationType, forKey: .integrationType) + try dataContainer.encode(BuildInfo.version, forKey: .libVersion) + + try dataContainer.encode(clientID, forKey: .clientID) + try dataContainer.encodeIfPresent(merchantID, forKey: .merchantID) + try dataContainer.encodeIfPresent(partnerAttributionID, forKey: .partnerAttributionID) + try dataContainer.encodeIfPresent(merchantProfileHash, forKey: .merchantProfileHash) + + try dataContainer.encodeIfPresent(loggers, forKey: .components) + } + + enum CloudEventKey: CodingKey { + case specversion + case id + case type + case source + case datacontenttype + case dataschema + case time + case data + } + + enum IntegrationKey: String, CodingKey { + // Integration Details + case clientID = "client_id" + case merchantID = "merchant_id" + case partnerAttributionID = "partner_attribution_id" + case merchantProfileHash = "merchant_profile_hash" + // Global Details + case integrationVersion = "integration_version" + case integrationName = "integration_name" + // Build Details + case libVersion = "lib_version" + case integrationType = "integration_type" + // Component Details + case components = "components" + } +} diff --git a/Sources/PayPalMessages/Config/PayPalMessageConfig.swift b/Sources/PayPalMessages/Config/PayPalMessageConfig.swift index 3f18ad4..8774b04 100644 --- a/Sources/PayPalMessages/Config/PayPalMessageConfig.swift +++ b/Sources/PayPalMessages/Config/PayPalMessageConfig.swift @@ -13,50 +13,52 @@ public class PayPalMessageData: NSObject { /// Price expressed in cents amount based on the current context (i.e. individual product price vs total cart price) public var amount: Double? /// Message screen location (e.g. product, cart, home) - public var placement: PayPalMessagePlacement? + public var pageType: PayPalMessagePageType? /// Preferred message offer to display public var offerType: PayPalMessageOfferType? /// Consumer's country (Integrations must be approved by PayPal to use this option) public var buyerCountry: String? + /// Message content channel + public var channel: String /// Skips the caching layer public var ignoreCache = false - /// Uses the content set that is currently under active development. For development purposes only. - public var devTouchpoint = false - /// Allows the message to pull up a development build of the web modal. For development purposes only. - public var stageTag: String? /// Standard integration public init( clientID: String, + environment: Environment, amount: Double? = nil, - placement: PayPalMessagePlacement? = nil, + pageType: PayPalMessagePageType? = nil, offerType: PayPalMessageOfferType? = nil, - environment: Environment = .live + channel: String = BuildInfo.channel ) { self.clientID = clientID self.amount = amount - self.placement = placement + self.pageType = pageType self.offerType = offerType self.environment = environment + self.channel = channel } /// Partner integration public init( clientID: String, merchantID: String, + environment: Environment, partnerAttributionID: String, amount: Double? = nil, - placement: PayPalMessagePlacement? = nil, + pageType: PayPalMessagePageType? = nil, offerType: PayPalMessageOfferType? = nil, - environment: Environment = .live + channel: String = BuildInfo.channel ) { self.clientID = clientID self.merchantID = merchantID self.partnerAttributionID = partnerAttributionID self.amount = amount - self.placement = placement + self.pageType = pageType self.offerType = offerType self.environment = environment + self.channel = channel } deinit {} @@ -69,16 +71,16 @@ public class PayPalMessageStyle: NSObject { /// Text and logo color public var color: PayPalMessageColor /// Text alignment - public var textAlignment: PayPalMessageTextAlignment + public var textAlign: PayPalMessageTextAlign public init( logoType: PayPalMessageLogoType = .inline, color: PayPalMessageColor = .black, - textAlignment: PayPalMessageTextAlignment = .right + textAlign: PayPalMessageTextAlign = .right ) { self.logoType = logoType self.color = color - self.textAlignment = textAlignment + self.textAlign = textAlign } deinit {} @@ -103,13 +105,9 @@ public class PayPalMessageConfig: NSObject { public static func setGlobalAnalytics( integrationName: String, - integrationVersion: String, - deviceID: String? = nil, - sessionID: String? = nil + integrationVersion: String ) { - Logger.integrationName = integrationName - Logger.integrationVersion = integrationVersion - Logger.deviceID = deviceID - Logger.sessionID = sessionID + AnalyticsLogger.integrationName = integrationName + AnalyticsLogger.integrationVersion = integrationVersion } } diff --git a/Sources/PayPalMessages/Config/PayPalMessageModalConfig.swift b/Sources/PayPalMessages/Config/PayPalMessageModalConfig.swift index 05c417d..bbc40e6 100644 --- a/Sources/PayPalMessages/Config/PayPalMessageModalConfig.swift +++ b/Sources/PayPalMessages/Config/PayPalMessageModalConfig.swift @@ -9,6 +9,7 @@ class ModalCloseButtonConfig: NSObject { var availableHeight: Int var color: UIColor var colorType: String + var alternativeText: String init( width: Int? = nil, @@ -16,7 +17,8 @@ class ModalCloseButtonConfig: NSObject { availableWidth: Int? = nil, availableHeight: Int? = nil, color: UIColor? = nil, - colorType: String? = nil + colorType: String? = nil, + alternativeText: String? = nil ) { self.width = width ?? 26 self.height = height ?? 26 @@ -24,6 +26,7 @@ class ModalCloseButtonConfig: NSObject { self.availableHeight = availableHeight ?? 60 self.color = color ?? UIColor(hexString: "#001435") self.colorType = colorType ?? "dark" + self.alternativeText = alternativeText ?? "PayPal learn more modal close" } deinit {} @@ -36,56 +39,53 @@ class PayPalMessageModalDataConfig: NSObject { var partnerAttributionID: String? var environment: Environment var amount: Double? - var currency: String? var buyerCountry: String? var offerType: PayPalMessageOfferType? - var placement: PayPalMessagePlacement? - var channel: String? + var pageType: PayPalMessagePageType? + var channel: String var ignoreCache: Bool? // swiftlint:disable:this discouraged_optional_boolean - var devTouchpoint: Bool? // swiftlint:disable:this discouraged_optional_boolean - var stageTag: String? var modalCloseButton: ModalCloseButtonConfig /// Standard integration init( clientID: String, + environment: Environment, amount: Double? = nil, - currency: String? = nil, - placement: PayPalMessagePlacement? = nil, + pageType: PayPalMessagePageType? = nil, offerType: PayPalMessageOfferType? = nil, - modalCloseButton: ModalCloseButtonConfig = ModalCloseButtonConfig(), - environment: Environment = .live + channel: String = BuildInfo.channel, + modalCloseButton: ModalCloseButtonConfig = ModalCloseButtonConfig() ) { self.clientID = clientID self.amount = amount - self.currency = currency - self.placement = placement + self.pageType = pageType self.offerType = offerType self.modalCloseButton = modalCloseButton self.environment = environment + self.channel = channel } /// Partner integration init( clientID: String, merchantID: String, + environment: Environment, partnerAttributionID: String, amount: Double? = nil, - currency: String? = nil, - placement: PayPalMessagePlacement? = nil, + pageType: PayPalMessagePageType? = nil, offerType: PayPalMessageOfferType? = nil, - modalCloseButton: ModalCloseButtonConfig = ModalCloseButtonConfig(), - environment: Environment = .live + channel: String = BuildInfo.channel, + modalCloseButton: ModalCloseButtonConfig = ModalCloseButtonConfig() ) { self.clientID = clientID self.merchantID = merchantID self.partnerAttributionID = partnerAttributionID self.amount = amount - self.currency = currency - self.placement = placement + self.pageType = pageType self.offerType = offerType self.modalCloseButton = modalCloseButton self.environment = environment + self.channel = channel } deinit {} @@ -105,15 +105,11 @@ class PayPalMessageModalConfig: NSObject, Encodable { public static func setGlobalAnalytics( integrationName: String, - integrationVersion: String, - deviceID: String? = nil, - sessionID: String? = nil + integrationVersion: String ) { PayPalMessageConfig.setGlobalAnalytics( integrationName: integrationName, - integrationVersion: integrationVersion, - deviceID: deviceID, - sessionID: sessionID + integrationVersion: integrationVersion ) } @@ -122,14 +118,11 @@ class PayPalMessageModalConfig: NSObject, Encodable { case merchantID = "merchant_id" case partnerAttributionID = "partner_attribution_id" case amount - case currency case buyerCountry case offerType = "offer" case channel - case placement + case pageType case ignoreCache - case devTouchpoint - case stageTag } func encode(to encoder: Encoder) throws { @@ -139,13 +132,10 @@ class PayPalMessageModalConfig: NSObject, Encodable { try container.encodeIfPresent(data.merchantID, forKey: .merchantID) try container.encodeIfPresent(data.partnerAttributionID, forKey: .partnerAttributionID) try container.encodeIfPresent(data.amount, forKey: .amount) - try container.encodeIfPresent(data.currency, forKey: .currency) try container.encodeIfPresent(data.buyerCountry, forKey: .buyerCountry) try container.encodeIfPresent(data.offerType?.rawValue, forKey: .offerType) try container.encodeIfPresent(data.channel, forKey: .channel) - try container.encodeIfPresent(data.placement?.rawValue, forKey: .placement) + try container.encodeIfPresent(data.pageType?.rawValue, forKey: .pageType) try container.encodeIfPresent(data.ignoreCache, forKey: .ignoreCache) - try container.encodeIfPresent(data.devTouchpoint, forKey: .devTouchpoint) - try container.encodeIfPresent(data.stageTag, forKey: .stageTag) } } diff --git a/Sources/PayPalMessages/Enums/BuildInfo.swift b/Sources/PayPalMessages/Enums/BuildInfo.swift index db1547d..c2210e4 100644 --- a/Sources/PayPalMessages/Enums/BuildInfo.swift +++ b/Sources/PayPalMessages/Enums/BuildInfo.swift @@ -2,7 +2,9 @@ // If any of the names are changed the CI should be updated as well. public enum BuildInfo { /// Library version - public static let version: String = "0.1.0" + public internal(set) static var version: String = "1.0.0-alpha.1" /// Message rendering environment public static let integrationType: String = "NATIVE_IOS" + /// Default message content channel + public static let channel: String = "UPSTREAM" } diff --git a/Sources/PayPalMessages/Enums/Environment.swift b/Sources/PayPalMessages/Enums/Environment.swift index 362242b..37c36b8 100644 --- a/Sources/PayPalMessages/Enums/Environment.swift +++ b/Sources/PayPalMessages/Enums/Environment.swift @@ -1,8 +1,7 @@ import Foundation public enum Environment: Equatable { - case local(port: String = "8443") - case stage(host: String) + case develop(host: String, devTouchpoint: Bool = false, stageTag: String? = nil) case sandbox case live @@ -12,10 +11,8 @@ public enum Environment: Equatable { return "production" case .sandbox: return "sandbox" - case .stage: - return "stage" - case .local: - return "local" + case .develop: + return "develop" } } @@ -23,7 +20,7 @@ public enum Environment: Equatable { switch self { case .live, .sandbox: return true - case .stage, .local: + case .develop: return false } } @@ -32,7 +29,7 @@ public enum Environment: Equatable { switch self { case .live, .sandbox: return URLSession.shared - case .stage, .local: + case .develop: return URLSession( configuration: .default, delegate: DevelopmentSession(), @@ -44,9 +41,7 @@ public enum Environment: Equatable { // swiftlint:disable force_unwrapping private var baseURL: URL { switch self { - case .local(let port): - return URL(string: "https://localhost.paypal.com:\(port)")! - case .stage(let host): + case .develop(let host, _, _): return URL(string: "https://www.\(host)")! case .sandbox: return URL(string: "https://www.sandbox.paypal.com")! @@ -54,28 +49,59 @@ public enum Environment: Equatable { return URL(string: "https://www.paypal.com")! } } + + // swiftlint:disable force_unwrapping + private var loggerBaseURL: URL { + switch self { + case .develop(let host, _, _): + return URL(string: "https://api.\(host)")! + case .sandbox: + return URL(string: "https://api.sandbox.paypal.com")! + case .live: + return URL(string: "https://api.paypal.com")! + } + } + // swiftlint:enable force_unwrapping enum PayPalMessagePath: String { case message = "/credit-presentment/native/message" case modal = "/credit-presentment/lander/modal" case merchantProfile = "/credit-presentment/merchant-profile" - case log = "/credit-presentment/glog" + case log = "/v1/credit/upstream-messaging-events" } func url(_ path: PayPalMessagePath, _ queryParams: [String: String?]? = nil) -> URL? { var parts = URLComponents() - var queryItems: [URLQueryItem]? + var queryItems = queryParams?.compactMap { key, value in + value != nil ? URLQueryItem(name: key, value: value) : nil + } ?? [] + + let basePath: URL + if path == .log { + basePath = loggerBaseURL + } else { + basePath = baseURL - if let queryParams, !queryParams.isEmpty { - queryItems = queryParams.map { URLQueryItem(name: $0.key, value: $0.value) } + // Append dev_touchpoint and stage_tag query parameters only for .develop case + if case .develop(_, let devTouchpoint, let stageTag) = self { + if devTouchpoint { + queryItems.append(URLQueryItem(name: "dev_touchpoint", value: "\(devTouchpoint)")) + } + if let stageTag, !stageTag.isEmpty { + queryItems.append(URLQueryItem(name: "stage_tag", value: stageTag)) + } + } } - parts.scheme = baseURL.scheme - parts.host = baseURL.host - parts.port = baseURL.port + parts.scheme = basePath.scheme + parts.host = basePath.host parts.path = path.rawValue - parts.queryItems = queryItems + + if !queryItems.isEmpty { + parts.queryItems = queryItems + } + return parts.url } diff --git a/Sources/PayPalMessages/Enums/HTTPHeaders.swift b/Sources/PayPalMessages/Enums/HTTPHeaders.swift index 0e657b3..fb66e51 100644 --- a/Sources/PayPalMessages/Enums/HTTPHeaders.swift +++ b/Sources/PayPalMessages/Enums/HTTPHeaders.swift @@ -5,6 +5,7 @@ enum HTTPHeader: String { case accept = "Accept" case acceptLanguage = "Accept-Language" + case contentType = "Content-Type" // MARK: - PayPal Specific Headers diff --git a/Sources/PayPalMessages/Enums/PayPalMessageError.swift b/Sources/PayPalMessages/Enums/PayPalMessageError.swift index e05498f..c5d8668 100644 --- a/Sources/PayPalMessages/Enums/PayPalMessageError.swift +++ b/Sources/PayPalMessages/Enums/PayPalMessageError.swift @@ -1,10 +1,10 @@ public enum PayPalMessageError: Error, Equatable { case invalidURL - case invalidResponse(paypalDebugID: String? = nil) + case invalidResponse(paypalDebugID: String? = nil, issue: String? = nil, description: String? = nil) public var paypalDebugId: String? { switch self { - case .invalidResponse(let paypalDebugID): + case .invalidResponse(let paypalDebugID, _, _): return paypalDebugID default: @@ -12,16 +12,25 @@ public enum PayPalMessageError: Error, Equatable { } } - public var description: String? { + public var issue: String? { switch self { case .invalidURL: return "InvalidURL" - case .invalidResponse: - return "InvalidResponse" + case .invalidResponse(_, let issue, _): + return issue ?? "InvalidResponse" + } + } + + public var description: String? { + switch self { + case .invalidURL: + return nil + case .invalidResponse(_, _, let description): + return description } } static public func == (lhs: PayPalMessageError, rhs: PayPalMessageError) -> Bool { - lhs.paypalDebugId == rhs.paypalDebugId && lhs.description == rhs.description + lhs.paypalDebugId == rhs.paypalDebugId && lhs.issue == rhs.issue && lhs.description == rhs.description } } diff --git a/Sources/PayPalMessages/Enums/PayPalMessagePageType.swift b/Sources/PayPalMessages/Enums/PayPalMessagePageType.swift new file mode 100644 index 0000000..e6a32c6 --- /dev/null +++ b/Sources/PayPalMessages/Enums/PayPalMessagePageType.swift @@ -0,0 +1,17 @@ +/// Message location within an application +public enum PayPalMessagePageType: String, CaseIterable { + /// Home view + case home + /// Multiple products listing view + case productListing = "product-listing" + /// Individual product details view + case productDetails = "product-details" + /// Shopping cart view + case cart + /// Popover shopping cart view that covers part of the view + case miniCart = "mini-cart" + /// Checkout view + case checkout + /// Search results + case searchResults = "search-results" +} diff --git a/Sources/PayPalMessages/Enums/PayPalMessagePlacement.swift b/Sources/PayPalMessages/Enums/PayPalMessagePlacement.swift deleted file mode 100644 index 2e6bfd7..0000000 --- a/Sources/PayPalMessages/Enums/PayPalMessagePlacement.swift +++ /dev/null @@ -1,13 +0,0 @@ -/// Message location within an application -public enum PayPalMessagePlacement: String, CaseIterable { - /// Home view - case home - /// Category view displaying multiple products - case category - /// Individual product view - case product - /// Shopping cart view - case cart - /// Checkout view - case payment -} diff --git a/Sources/PayPalMessages/Enums/PayPalMessageTextAlignment.swift b/Sources/PayPalMessages/Enums/PayPalMessageTextAlign.swift similarity index 75% rename from Sources/PayPalMessages/Enums/PayPalMessageTextAlignment.swift rename to Sources/PayPalMessages/Enums/PayPalMessageTextAlign.swift index 95190b7..be609b3 100644 --- a/Sources/PayPalMessages/Enums/PayPalMessageTextAlignment.swift +++ b/Sources/PayPalMessages/Enums/PayPalMessageTextAlign.swift @@ -1,5 +1,5 @@ /// Text alignment option for a PayPal Message -public enum PayPalMessageTextAlignment: String, CaseIterable { +public enum PayPalMessageTextAlign: String, CaseIterable { /// Text aligned to the left case left /// Text aligned to the center diff --git a/Sources/PayPalMessages/Extensions/NSObject.swift b/Sources/PayPalMessages/Extensions/NSObject.swift deleted file mode 100644 index 810347d..0000000 --- a/Sources/PayPalMessages/Extensions/NSObject.swift +++ /dev/null @@ -1,3 +0,0 @@ -import Foundation - -extension NSObject: ProxyContainer {} diff --git a/Sources/PayPalMessages/Extensions/UIColor.swift b/Sources/PayPalMessages/Extensions/UIColor.swift index 6c23f93..3a116de 100644 --- a/Sources/PayPalMessages/Extensions/UIColor.swift +++ b/Sources/PayPalMessages/Extensions/UIColor.swift @@ -10,10 +10,10 @@ extension UIColor { let scanner = Scanner(string: hexString as String) if hexString.hasPrefix("#") { - scanner.scanLocation = 1 + scanner.currentIndex = scanner.string.index(after: scanner.currentIndex) } - var color: UInt32 = 0 - scanner.scanHexInt32(&color) + var color: UInt64 = 0 + scanner.scanHexInt64(&color) let mask = 0x000000FF let redValue = Int(color >> 16) & mask diff --git a/Sources/PayPalMessages/Extensions/UIViewController.swift b/Sources/PayPalMessages/Extensions/UIViewController.swift index 297a89d..8023757 100644 --- a/Sources/PayPalMessages/Extensions/UIViewController.swift +++ b/Sources/PayPalMessages/Extensions/UIViewController.swift @@ -3,7 +3,13 @@ import UIKit extension UIViewController { static func getPresentingViewController() -> UIViewController? { - if var rootViewController = UIApplication.shared.keyWindow?.rootViewController { + let keyWindow = UIApplication + .shared + .connectedScenes + .flatMap { ($0 as? UIWindowScene)?.windows ?? [] } + .last { $0.isKeyWindow } + + if var rootViewController = keyWindow?.rootViewController { while let presentedViewController = rootViewController.presentedViewController { rootViewController = presentedViewController } diff --git a/Sources/PayPalMessages/Extensions/UserDefaults.swift b/Sources/PayPalMessages/Extensions/UserDefaults.swift index be66444..09cf687 100644 --- a/Sources/PayPalMessages/Extensions/UserDefaults.swift +++ b/Sources/PayPalMessages/Extensions/UserDefaults.swift @@ -7,12 +7,11 @@ extension UserDefaults { } // holds the data for a merchant profile, of type PayPalMessageMerchantData - static var merchantProfileData: Data? { - get { - standard.data(forKey: Key.merchantProfileData.rawValue) - } - set { - standard.set(newValue, forKey: Key.merchantProfileData.rawValue) - } + static func getMerchantProfileData(forClientID clientID: String, merchantID: String?) -> Data? { + return standard.data(forKey: "\(Key.merchantProfileData.rawValue).\(clientID).\(merchantID ?? "default")") + } + + static func setMerchantProfileData(_ value: Data?, forClientID clientID: String, merchantID: String?) { + standard.set(value, forKey: "\(Key.merchantProfileData.rawValue).\(clientID).\(merchantID ?? "default")") } } diff --git a/Sources/PayPalMessages/IO/MerchantProfileProvider.swift b/Sources/PayPalMessages/IO/MerchantProfileProvider.swift index 1c93a84..43323fc 100644 --- a/Sources/PayPalMessages/IO/MerchantProfileProvider.swift +++ b/Sources/PayPalMessages/IO/MerchantProfileProvider.swift @@ -4,6 +4,7 @@ protocol MerchantProfileHashGetable { func getMerchantProfileHash( environment: Environment, clientID: String, + merchantID: String?, onCompletion: @escaping (String?) -> Void ) } @@ -25,14 +26,15 @@ class MerchantProfileProvider: MerchantProfileHashGetable { func getMerchantProfileHash( environment: Environment, clientID: String, + merchantID: String?, onCompletion: @escaping (String?) -> Void ) { let currentDate = Date() // hash must be inside ttl and non-null - guard let merchantProfileData = getCachedMerchantProfileData(), + guard let merchantProfileData = getCachedMerchantProfileData(clientID: clientID, merchantID: merchantID), currentDate < merchantProfileData.ttlHard else { - requestMerchantProfile(environment: environment, clientID: clientID) { merchantProfiledData in + requestMerchantProfile(environment: environment, clientID: clientID, merchantID: merchantID) { merchantProfiledData in guard let merchantProfiledData = merchantProfiledData else { onCompletion(nil) return @@ -46,7 +48,7 @@ class MerchantProfileProvider: MerchantProfileHashGetable { // if date is outside soft-ttl window, re-request data if currentDate > merchantProfileData.ttlSoft { // ignores the response as it will return hashed value - requestMerchantProfile(environment: environment, clientID: clientID) { _ in } + requestMerchantProfile(environment: environment, clientID: clientID, merchantID: merchantID) { _ in } } onCompletion(merchantProfileData.disabled ? nil : merchantProfileData.hash) @@ -57,17 +59,22 @@ class MerchantProfileProvider: MerchantProfileHashGetable { private func requestMerchantProfile( environment: Environment, clientID: String, + merchantID: String?, onCompletion: @escaping (MerchantProfileData?) -> Void ) { - merchantProfileRequest.fetchMerchantProfile(environment: environment, clientID: clientID) { [weak self] result in + merchantProfileRequest.fetchMerchantProfile( + environment: environment, + clientID: clientID, + merchantID: merchantID + ) { [weak self] result in switch result { case .success(let merchantProfileData): - log(.info, "Merchant Request Hash succeeded with \(merchantProfileData.hash)") - self?.setCachedMerchantProfileData(merchantProfileData) + log(.debug, "Merchant Request Hash succeeded with \(merchantProfileData.hash)", for: environment) + self?.setCachedMerchantProfileData(merchantProfileData, clientID: clientID, merchantID: merchantID) onCompletion(merchantProfileData) case .failure(let error): - log(.info, "Merchant Request Hash failed with \(error.localizedDescription)") + log(.debug, "Merchant Request Hash failed with \(error.localizedDescription)", for: environment) onCompletion(nil) } } @@ -75,16 +82,16 @@ class MerchantProfileProvider: MerchantProfileHashGetable { // MARK: - User Defaults Methods - private func getCachedMerchantProfileData() -> MerchantProfileData? { - guard let cachedData = UserDefaults.merchantProfileData else { + private func getCachedMerchantProfileData(clientID: String, merchantID: String?) -> MerchantProfileData? { + guard let cachedData = UserDefaults.getMerchantProfileData(forClientID: clientID, merchantID: merchantID) else { return nil } return try? JSONDecoder().decode(MerchantProfileData.self, from: cachedData) } - private func setCachedMerchantProfileData(_ data: MerchantProfileData) { + private func setCachedMerchantProfileData(_ data: MerchantProfileData, clientID: String, merchantID: String?) { let encodedData = try? JSONEncoder().encode(data) - UserDefaults.merchantProfileData = encodedData + UserDefaults.setMerchantProfileData(encodedData, forClientID: clientID, merchantID: merchantID) } } diff --git a/Sources/PayPalMessages/IO/MerchantProfileRequest.swift b/Sources/PayPalMessages/IO/MerchantProfileRequest.swift index 7a04476..dbb6de2 100644 --- a/Sources/PayPalMessages/IO/MerchantProfileRequest.swift +++ b/Sources/PayPalMessages/IO/MerchantProfileRequest.swift @@ -4,6 +4,7 @@ protocol MerchantProfileRequestable { func fetchMerchantProfile( environment: Environment, clientID: String, + merchantID: String?, onCompletion: @escaping (Result) -> Void ) } @@ -27,14 +28,15 @@ class MerchantProfileRequest: MerchantProfileRequestable { func fetchMerchantProfile( environment: Environment, clientID: String, + merchantID: String?, onCompletion: @escaping (Result) -> Void ) { - guard let url = environment.url(.merchantProfile, ["client_id": clientID]) else { + guard let url = environment.url(.merchantProfile, ["client_id": clientID, "merchant_id": merchantID]) else { onCompletion(.failure(RequestError.invalidClientID)) return } - log(.info, "fetcheMerchantProfile URL is \(url)") + log(.debug, "fetcheMerchantProfile URL is \(url)", for: environment) fetch(url, headers: headers, session: environment.urlSession) { data, _, error in guard let data = data, error == nil else { diff --git a/Sources/PayPalMessages/IO/MessageRequest.swift b/Sources/PayPalMessages/IO/MessageRequest.swift index 526752d..c5964a2 100644 --- a/Sources/PayPalMessages/IO/MessageRequest.swift +++ b/Sources/PayPalMessages/IO/MessageRequest.swift @@ -11,13 +11,12 @@ struct MessageRequestParameters { let partnerAttributionID: String? let logoType: PayPalMessageLogoType let buyerCountry: String? - let placement: PayPalMessagePlacement? + let pageType: PayPalMessagePageType? let amount: Double? let offerType: PayPalMessageOfferType? let merchantProfileHash: String? let ignoreCache: Bool - let devTouchpoint: Bool - let stageTag: String? + let instanceID: String } protocol MessageRequestable { @@ -44,16 +43,16 @@ class MessageRequest: MessageRequestable { "partner_attribution_id": parameters.partnerAttributionID, "logo_type": parameters.logoType.rawValue, "buyer_country": parameters.buyerCountry, - "placement": parameters.placement?.rawValue, + "page_type": parameters.pageType?.rawValue, "amount": parameters.amount?.description, "offer": parameters.offerType?.rawValue, "merchant_config": parameters.merchantProfileHash, - "stage_tag": parameters.stageTag, "ignore_cache": parameters.ignoreCache.description, - "dev_touchpoint": parameters.devTouchpoint.description, - "integration_version": Logger.integrationVersion, - "device_id": Logger.deviceID, - "session_id": Logger.sessionID + "instance_id": parameters.instanceID, + "version": BuildInfo.version, + "integration_type": BuildInfo.integrationType, + "integration_version": AnalyticsLogger.integrationVersion, + "integration_name": AnalyticsLogger.integrationName ].filter { guard let value = $0.value else { return false } @@ -73,29 +72,39 @@ class MessageRequest: MessageRequestable { } let startingTimestamp = Date() - log(.info, "fetchMessage URL is \(url)") + log(.debug, "fetchMessage URL is \(url)", for: parameters.environment) + fetch(url, headers: headers, session: parameters.environment.urlSession) { data, response, _ in + let requestDuration = startingTimestamp.timeIntervalSinceNow + guard let response = response as? HTTPURLResponse else { onCompletion(.failure(.invalidResponse())) return } - let requestDuration = startingTimestamp.timeIntervalSinceNow - guard response.statusCode == 200, - let data, - var messageResponse = try? JSONDecoder().decode( - MessageResponse.self, - from: data - ) else { - onCompletion(.failure( - .invalidResponse(paypalDebugID: response.paypalDebugID) - )) - return - } + switch response.statusCode { + case 200: + guard let data, var messageResponse = try? JSONDecoder().decode(MessageResponse.self, from: data) else { + onCompletion(.failure(.invalidResponse(paypalDebugID: response.paypalDebugID))) + return + } + + messageResponse.requestDuration = requestDuration - messageResponse.requestDuration = requestDuration + onCompletion(.success(messageResponse)) - onCompletion(.success(messageResponse)) + default: + guard let data, let responseError = try? JSONDecoder().decode(ResponseError.self, from: data) else { + onCompletion(.failure(.invalidResponse(paypalDebugID: response.paypalDebugID))) + return + } + + onCompletion(.failure(.invalidResponse( + paypalDebugID: responseError.paypalDebugID, + issue: responseError.issue, + description: responseError.description + ))) + } } } } diff --git a/Sources/PayPalMessages/IO/MessageResponse.swift b/Sources/PayPalMessages/IO/MessageResponse.swift index c79f287..a2345a0 100644 --- a/Sources/PayPalMessages/IO/MessageResponse.swift +++ b/Sources/PayPalMessages/IO/MessageResponse.swift @@ -13,11 +13,14 @@ struct MessageResponse: Decodable { let modalCloseButtonAvailHeight: Int let modalCloseButtonColor: String let modalCloseButtonColorType: String + let modalCloseButtonAlternativeText: String let defaultMainContent: String + let defaultMainAlternative: String? let defaultDisclaimer: String let genericMainContent: String + let genericMainAlternative: String? let genericDisclaimer: String let logoPlaceholder: String @@ -32,8 +35,10 @@ struct MessageResponse: Decodable { offerType: PayPalMessageResponseOfferType, productGroup: PayPalMessageResponseProductGroup, defaultMainContent: String, + defaultMainAlternative: String?, defaultDisclaimer: String, genericMainContent: String, + genericMainAlternative: String?, genericDisclaimer: String, logoPlaceholder: String, modalCloseButtonWidth: Int, @@ -42,13 +47,16 @@ struct MessageResponse: Decodable { modalCloseButtonAvailHeight: Int, modalCloseButtonColor: String, modalCloseButtonColorType: String, + modalCloseButtonAlternativeText: String, trackingData: [String: AnyCodable] = [:] ) { self.offerType = offerType self.productGroup = productGroup self.defaultMainContent = defaultMainContent + self.defaultMainAlternative = defaultMainAlternative self.defaultDisclaimer = defaultDisclaimer self.genericMainContent = genericMainContent + self.genericMainAlternative = genericMainAlternative self.genericDisclaimer = genericDisclaimer self.logoPlaceholder = logoPlaceholder self.modalCloseButtonWidth = modalCloseButtonWidth @@ -57,6 +65,7 @@ struct MessageResponse: Decodable { self.modalCloseButtonAvailHeight = modalCloseButtonAvailHeight self.modalCloseButtonColor = modalCloseButtonColor self.modalCloseButtonColorType = modalCloseButtonColorType + self.modalCloseButtonAlternativeText = modalCloseButtonAlternativeText self.trackingData = trackingData } @@ -80,6 +89,10 @@ struct MessageResponse: Decodable { String.self, forKey: .main ) + defaultMainAlternative = try defaultContentContainer.decodeIfPresent( + String.self, + forKey: .mainAlternative + ) defaultDisclaimer = try defaultContentContainer.decode( String.self, forKey: .disclaimer @@ -96,6 +109,10 @@ struct MessageResponse: Decodable { String.self, forKey: .main ) + genericMainAlternative = try genericContentContainer.decodeIfPresent( + String.self, + forKey: .mainAlternative + ) genericDisclaimer = try genericContentContainer.decode( String.self, forKey: .disclaimer @@ -167,6 +184,11 @@ struct MessageResponse: Decodable { forKey: .modalCloseButtonColorType ) + modalCloseButtonAlternativeText = try modalCloseButton.decode( + String.self, + forKey: .modalCloseButtonAlternativeText + ) + // MARK: - Tracking Keys let anyMetaContainer = try container.nestedContainer( @@ -209,6 +231,7 @@ struct MessageResponse: Decodable { case modalCloseButtonAvailHeight = "available_height" case modalCloseButtonColor = "color" case modalCloseButtonColorType = "color_type" + case modalCloseButtonAlternativeText = "alternative_text" } enum ContentContainerKeys: String, CodingKey { @@ -218,6 +241,7 @@ struct MessageResponse: Decodable { enum ContentKeys: String, CodingKey { case main + case mainAlternative = "main_alternative" case disclaimer } diff --git a/Sources/PayPalMessages/IO/ResponseError.swift b/Sources/PayPalMessages/IO/ResponseError.swift new file mode 100644 index 0000000..78dc1fb --- /dev/null +++ b/Sources/PayPalMessages/IO/ResponseError.swift @@ -0,0 +1,42 @@ +import Foundation + +struct ResponseError: Decodable { + + let paypalDebugID: String + let issue: String? + let description: String? + + init(paypalDebugID: String, issue: String?, description: String?) { + self.paypalDebugID = paypalDebugID + self.issue = issue + self.description = description + } + + enum CodingKeys: String, CodingKey { + case paypalDebugID = "debug_id" + case details + } + + enum DetailsKeys: CodingKey { + case issue + case description + } + + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + paypalDebugID = try container.decode(String.self, forKey: .paypalDebugID) + + guard var detailsContainer = try? container.nestedUnkeyedContainer(forKey: .details) else { + issue = nil + description = nil + + return + } + + let detailContainer = try detailsContainer.nestedContainer(keyedBy: DetailsKeys.self) + + issue = try detailContainer.decode(String.self, forKey: .issue) + description = try detailContainer.decode(String.self, forKey: .description) + } +} diff --git a/Sources/PayPalMessages/Logger/ComponentLogger.swift b/Sources/PayPalMessages/Logger/ComponentLogger.swift deleted file mode 100644 index 2b90a8a..0000000 --- a/Sources/PayPalMessages/Logger/ComponentLogger.swift +++ /dev/null @@ -1,103 +0,0 @@ -import Foundation - -class ComponentLogger: Encodable { - - // Integration Details - var offerType: PayPalMessageOfferType? - var amount: Double? - var placement: PayPalMessagePlacement? - var buyerCountryCode: String? - var channel: String? - - // Message Only - var styleLogoType: PayPalMessageLogoType? - var styleColor: PayPalMessageColor? - var styleTextAlign: PayPalMessageTextAlignment? - - // Other Details - var type: PayPalMessageComponentLoggerType - var instanceId: String - - // Includes things like fdata, experience IDs, debug IDs, and the like - // See the Confluence page above for more info - var dynamicData: [String: AnyCodable] = [:] - - // Events tied to the component - var events: [ComponentLoggerEvent] = [] - - enum PayPalMessageComponentLoggerType: String, Encodable { - case message - case modal - } - - init( - type: PayPalMessageComponentLoggerType, - offerType: PayPalMessageOfferType?, - amount: Double?, - placement: PayPalMessagePlacement?, - channel: String?, - buyerCountryCode: String?, - // Message only - styleColor: PayPalMessageColor? = nil, - styleLogoType: PayPalMessageLogoType? = nil, - styleTextAlign: PayPalMessageTextAlignment? = nil - ) { - self.instanceId = UUID().uuidString - self.type = type - self.offerType = offerType - self.amount = amount - self.placement = placement - self.buyerCountryCode = buyerCountryCode - self.styleColor = styleColor - self.styleLogoType = styleLogoType - self.styleTextAlign = styleTextAlign - } - - deinit {} - - enum StaticKey: String, CodingKey { - // Integration Details - case offerType = "offer_type" - case amount = "amount" - case placement = "placement" - case buyerCountryCode = "buyer_country_code" - case channel = "channel" - // Message Only - case styleLogoType = "style_logo_type" - case styleColor = "style_color" - case styleTextAlign = "style_text_align" - // Other Details - case type = "type" - case instanceId = "instance_id" - // Component Events - case events = "events" - } - - func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: StaticKey.self) - - try container.encodeIfPresent(offerType?.rawValue, forKey: .offerType) - try container.encodeIfPresent(amount, forKey: .amount) - try container.encodeIfPresent(placement?.rawValue, forKey: .placement) - try container.encodeIfPresent(buyerCountryCode, forKey: .buyerCountryCode) - try container.encodeIfPresent(channel, forKey: .channel) - try container.encodeIfPresent(styleLogoType?.rawValue, forKey: .styleLogoType) - try container.encodeIfPresent(styleColor?.rawValue, forKey: .styleColor) - try container.encodeIfPresent(styleTextAlign?.rawValue, forKey: .styleTextAlign) - - try container.encode(type, forKey: .type) - try container.encode(instanceId, forKey: .instanceId) - - try dynamicData.encode(to: encoder) - - try container.encode(events, forKey: .events) - } - - func addEvent(_ event: ComponentLoggerEvent) { - self.events.append(event) - } - - func clearEvents() { - events.removeAll() - } -} diff --git a/Sources/PayPalMessages/Logger/Logger.swift b/Sources/PayPalMessages/Logger/Logger.swift deleted file mode 100644 index 969f3eb..0000000 --- a/Sources/PayPalMessages/Logger/Logger.swift +++ /dev/null @@ -1,202 +0,0 @@ -import Foundation - -class Logger: Encodable { - - // Integration Details - let environment: Environment - let clientID: String - var merchantID: String? - var partnerAttributionID: String? // Currently not supported via Checkout config - var merchantProfileHash: String? - - var components: [ComponentLogger] = [] - - let timerInterval: Double = 5 - var timer: Timer? - var sender: LogSendable = LogSender() - - // Global Details - static var deviceID: String? - static var sessionID: String? - static var integrationVersion: String? - static var integrationName: String? - - private static var loggers: [String: Logger] = [:] - - private init( - clientID: String, - merchantID: String?, - partnerAttributionID: String?, - environment: Environment - ) { - self.clientID = clientID - self.merchantID = merchantID - self.partnerAttributionID = partnerAttributionID - self.environment = environment - - timer = Timer.scheduledTimer( - withTimeInterval: timerInterval, - repeats: true - ) { _ in - self.flushEvents() - } - } - - deinit { - timer?.invalidate() - flushEvents() - } - - static func get( - for clientID: String, - _ merchantID: String? = nil, - _ partnerAttributionID: String? = nil, - in environment: Environment - ) -> Logger { - let key = [environment.rawValue, clientID, merchantID ?? "nil", partnerAttributionID ?? "nil"] - .joined(separator: "_") - if let logger = Logger.loggers[key] { - return logger - } - - let logger = Logger( - clientID: clientID, - merchantID: merchantID, - partnerAttributionID: partnerAttributionID, - environment: environment - ) - Logger.loggers[key] = logger - - return logger - } - - static func createMessageLogger( - environment: Environment, - clientID: String, - merchantID: String? = nil, - partnerAttributionID: String? = nil, - offerType: PayPalMessageOfferType? = nil, - amount: Double? = nil, - placement: PayPalMessagePlacement? = nil, - buyerCountryCode: String? = nil, - channel: String? = nil, - styleColor: PayPalMessageColor, - styleLogoType: PayPalMessageLogoType, - styleTextAlign: PayPalMessageTextAlignment - ) -> ComponentLogger { - let logger = ComponentLogger( - type: .message, - offerType: offerType, - amount: amount, - placement: placement, - channel: channel, - buyerCountryCode: buyerCountryCode, - styleColor: styleColor, - styleLogoType: styleLogoType, - styleTextAlign: styleTextAlign - ) - Logger.get(for: clientID, merchantID, partnerAttributionID, in: environment).components.append(logger) - return logger - } - - static func createModalLogger( - environment: Environment, - clientID: String, - merchantID: String? = nil, - partnerAttributionID: String? = nil, - offerType: PayPalMessageOfferType? = nil, - amount: Double? = nil, - placement: PayPalMessagePlacement? = nil, - buyerCountryCode: String? = nil, - channel: String? = nil - ) -> ComponentLogger { - let logger = ComponentLogger( - type: .modal, - offerType: offerType, - amount: amount, - placement: placement, - channel: channel, - buyerCountryCode: buyerCountryCode - ) - Logger.get(for: clientID, merchantID, partnerAttributionID, in: environment).components.append(logger) - return logger - } - - enum StaticKey: String, CodingKey { - // Integration Details - case clientID = "client_id" - case merchantID = "merchant_id" - case partnerAttributionID = "partner_attribution_id" - case merchantProfileHash = "merchant_profile_hash" - // Global Details - case deviceID = "device_id" - case sessionID = "session_id" - case integrationVersion = "integration_version" - case integrationName = "integration_name" - // Build Details - case libVersion = "lib_version" - case integrationType = "integration_type" - // Component Details - case components = "components" - } - - func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: StaticKey.self) - - try container.encodeIfPresent(clientID, forKey: .clientID) - try container.encodeIfPresent(merchantID, forKey: .merchantID) - try container.encodeIfPresent(partnerAttributionID, forKey: .partnerAttributionID) - try container.encodeIfPresent(merchantProfileHash, forKey: .merchantProfileHash) - - try container.encodeIfPresent(Logger.deviceID, forKey: .deviceID) - try container.encodeIfPresent(Logger.sessionID, forKey: .sessionID) - try container.encodeIfPresent(Logger.integrationVersion, forKey: .integrationVersion) - try container.encodeIfPresent(Logger.integrationName, forKey: .integrationName) - - try container.encodeIfPresent(BuildInfo.integrationType, forKey: .integrationType) - try container.encodeIfPresent(BuildInfo.version, forKey: .libVersion) - - let componentsWithEvents = components.filter { !$0.events.isEmpty } - try container.encodeIfPresent(componentsWithEvents, forKey: .components) - } - - func hasEvents() -> Bool { - components.contains { !$0.events.isEmpty } - } - - func clearEvents() { - for component in components { - component.clearEvents() - } - } - - func flushEvents() { - guard hasEvents() else { return } - guard let data = try? JSONEncoder().encode(self) else { return } - - sender.send(data, to: environment) - - clearEvents() - } -} - -protocol LogSendable { - func send(_ data: Data, to environment: Environment) -} - -class LogSender: LogSendable { - - func send(_ data: Data, to environment: Environment) { - guard let url = environment.url(.log) else { return } - let headers: [HTTPHeader: String] = [ - .acceptLanguage: "en_US", - .requestedBy: "native-checkout-sdk", - .accept: "application/json" - ] - - log(.debug, "log_payload", with: data, for: environment) - - fetch(url, method: .post, headers: headers, body: data, session: environment.urlSession) { _, _, _ in } - } - deinit {} -} diff --git a/Sources/PayPalMessages/PayPalMessageModal.swift b/Sources/PayPalMessages/PayPalMessageModal.swift index 70ea8b6..b2e9081 100644 --- a/Sources/PayPalMessages/PayPalMessageModal.swift +++ b/Sources/PayPalMessages/PayPalMessageModal.swift @@ -4,6 +4,8 @@ import WebKit final class PayPalMessageModal: UIViewController, WKUIDelegate { + typealias Proxy = AnyProxy + // MARK: - Properties /// Delegate property in charge of announcing rendering and fetching events. @@ -17,15 +19,18 @@ final class PayPalMessageModal: UIViewController, WKUIDelegate { @Proxy(\.viewModel.clientID) var clientID: String + @Proxy(\.viewModel.merchantID) + var merchantID: String? + + @Proxy(\.viewModel.partnerAttributionID) + var partnerAttributionID: String? + @Proxy(\.viewModel.environment) var environment: Environment @Proxy(\.viewModel.amount) var amount: Double? - @Proxy(\.viewModel.currency) - var currency: String? - @Proxy(\.viewModel.buyerCountry) var buyerCountry: String? @@ -34,34 +39,31 @@ final class PayPalMessageModal: UIViewController, WKUIDelegate { // Content channel @Proxy(\.viewModel.channel) - var channel: String? + var channel: String // Location within the application - @Proxy(\.viewModel.placement) - var placement: PayPalMessagePlacement? + @Proxy(\.viewModel.pageType) + var pageType: PayPalMessagePageType? // Skip Juno cache @Proxy(\.viewModel.ignoreCache) var ignoreCache: Bool? - // Development content - @Proxy(\.viewModel.devTouchpoint) - var devTouchpoint: Bool? - - // Custom development stage modal bundle - @Proxy(\.viewModel.stageTag) - var stageTag: String? - // Standalone modal @Proxy(\.viewModel.integrationIdentifier) var integrationIdentifier: String? + @Proxy(\.viewModel.merchantProfileHash) + var merchantProfileHash: String? + // Modal close button var modalCloseButtonConfig: ModalCloseButtonConfig // MARK: - Private Properties - private let viewModel: PayPalMessageModalViewModel + // swiftlint:disable:next implicitly_unwrapped_optional + private var viewModel: PayPalMessageModalViewModel! + /// Flag set when modal webview has successfully loaded the first time which will prevent /// reloading the webview after reopening the modal after an error state private var hasSuccessfullyLoaded = false @@ -90,17 +92,17 @@ final class PayPalMessageModal: UIViewController, WKUIDelegate { stateDelegate: PayPalMessageModalStateDelegate? = nil, eventDelegate: PayPalMessageModalEventDelegate? = nil ) { - viewModel = PayPalMessageModalViewModel( + self.modalCloseButtonConfig = config.data.modalCloseButton + + super.init(nibName: nil, bundle: nil) + + self.viewModel = PayPalMessageModalViewModel( config: config, webView: webView, stateDelegate: stateDelegate, - eventDelegate: eventDelegate + eventDelegate: eventDelegate, + modal: self ) - modalCloseButtonConfig = config.data.modalCloseButton - - super.init(nibName: nil, bundle: nil) - // Used to pass the modal reference into the delegate functions - viewModel.modal = self modalTransitionStyle = .coverVertical modalPresentationStyle = .formSheet @@ -256,6 +258,8 @@ final class PayPalMessageModal: UIViewController, WKUIDelegate { } closeButton.translatesAutoresizingMaskIntoConstraints = false + closeButton.isAccessibilityElement = true + closeButton.accessibilityLabel = modalCloseButtonConfig.alternativeText view.addSubview(closeButton) @@ -306,12 +310,12 @@ final class PayPalMessageModal: UIViewController, WKUIDelegate { } guard let presentingViewController = UIViewController.getPresentingViewController() else { - log(.error, "Unable to retrieve presenting view controller") + log(.error, "Unable to retrieve presenting view controller", for: environment) return } if presentingViewController == self { - log(.warn, "Modal is already presenting") + log(.warn, "Modal is already presenting", for: environment) return } diff --git a/Sources/PayPalMessages/PayPalMessageModalViewModel.swift b/Sources/PayPalMessages/PayPalMessageModalViewModel.swift index 92aaf81..715c047 100644 --- a/Sources/PayPalMessages/PayPalMessageModalViewModel.swift +++ b/Sources/PayPalMessages/PayPalMessageModalViewModel.swift @@ -8,8 +8,8 @@ class PayPalMessageModalViewModel: NSObject, WKNavigationDelegate, WKScriptMessa weak var stateDelegate: PayPalMessageModalStateDelegate? /// Delegate property in charge of interaction-related events. weak var eventDelegate: PayPalMessageModalEventDelegate? - - var modal: PayPalMessageModal? + /// modal view controller passed into logger and delegate functions + weak var modal: PayPalMessageModal? var environment: Environment { didSet { queueUpdate(from: oldValue, to: environment) } @@ -30,9 +30,6 @@ class PayPalMessageModalViewModel: NSObject, WKNavigationDelegate, WKScriptMessa var amount: Double? { didSet { queueUpdate(from: oldValue, to: amount) } } - var currency: String? { - didSet { queueUpdate(from: oldValue, to: currency) } - } var buyerCountry: String? { didSet { queueUpdate(from: oldValue, to: buyerCountry) } } @@ -40,28 +37,25 @@ class PayPalMessageModalViewModel: NSObject, WKNavigationDelegate, WKScriptMessa didSet { queueUpdate(from: oldValue, to: offerType) } } // Content channel - var channel: String? { + var channel: String { didSet { queueUpdate(from: oldValue, to: channel) } } // Location within the application - var placement: PayPalMessagePlacement? { - didSet { queueUpdate(from: oldValue, to: placement) } + var pageType: PayPalMessagePageType? { + didSet { queueUpdate(from: oldValue, to: pageType) } } // Skip Juno cache var ignoreCache: Bool? { // swiftlint:disable:this discouraged_optional_boolean didSet { queueUpdate(from: oldValue, to: ignoreCache) } } - // Development content - var devTouchpoint: Bool? { // swiftlint:disable:this discouraged_optional_boolean - didSet { queueUpdate(from: oldValue, to: devTouchpoint) } - } - // Custom development stage modal bundle - var stageTag: String? { - didSet { queueUpdate(from: oldValue, to: stageTag) } - } + + // Standalone modal var integrationIdentifier: String? + var merchantProfileHash: String? + + // MARK: - Computed Private Properties private var url: URL? { @@ -71,20 +65,16 @@ class PayPalMessageModalViewModel: NSObject, WKNavigationDelegate, WKScriptMessa "merchant_id": merchantID, "partner_attribution_id": partnerAttributionID, "amount": amount?.description, - "currency": currency, "buyer_country": buyerCountry, "offer": offerType?.rawValue, "channel": channel, - "placement": placement?.rawValue, - "integration_type": integrationType, + "page_type": pageType?.rawValue, + "version": BuildInfo.version, + "integration_type": BuildInfo.integrationType, "integration_identifier": integrationIdentifier, - // Dev options "ignore_cache": ignoreCache?.description, - "dev_touchpoint": devTouchpoint?.description, - "stage_tag": stageTag, - "integration_version": Logger.integrationVersion, - "device_id": Logger.deviceID, - "session_id": Logger.sessionID, + "integration_version": AnalyticsLogger.integrationVersion, + "integration_name": AnalyticsLogger.integrationName, "features": "native-modal" ].filter { guard let value = $0.value else { return false } @@ -101,7 +91,6 @@ class PayPalMessageModalViewModel: NSObject, WKNavigationDelegate, WKScriptMessa // MARK: - Private Properties - private let integrationType: String = "NATIVE_IOS" /// Config update queue debounce time interval private let queueTimeInterval: TimeInterval = 0.01 private let webView: WKWebView @@ -110,7 +99,7 @@ class PayPalMessageModalViewModel: NSObject, WKNavigationDelegate, WKScriptMessa /// Completion callback called after webview has loaded and is ready to be viewed private var loadCompletionHandler: LoadCompletionHandler? - let logger: ComponentLogger + let logger: AnalyticsLogger // MARK: - Initializers @@ -118,36 +107,26 @@ class PayPalMessageModalViewModel: NSObject, WKNavigationDelegate, WKScriptMessa config: PayPalMessageModalConfig, webView: WKWebView, stateDelegate: PayPalMessageModalStateDelegate? = nil, - eventDelegate: PayPalMessageModalEventDelegate? = nil + eventDelegate: PayPalMessageModalEventDelegate? = nil, + modal: PayPalMessageModal ) { environment = config.data.environment clientID = config.data.clientID merchantID = config.data.merchantID partnerAttributionID = config.data.partnerAttributionID amount = config.data.amount - currency = config.data.currency offerType = config.data.offerType buyerCountry = config.data.buyerCountry channel = config.data.channel - placement = config.data.placement + pageType = config.data.pageType ignoreCache = config.data.ignoreCache - devTouchpoint = config.data.devTouchpoint - stageTag = config.data.stageTag self.webView = webView self.stateDelegate = stateDelegate self.eventDelegate = eventDelegate + self.modal = modal - self.logger = Logger.createModalLogger( - environment: environment, - clientID: clientID, - merchantID: merchantID, - partnerAttributionID: partnerAttributionID, - offerType: offerType, - amount: amount, - placement: placement, - buyerCountryCode: buyerCountry - ) + self.logger = AnalyticsLogger(.modal(Weak(modal))) super.init() @@ -166,32 +145,26 @@ class PayPalMessageModalViewModel: NSObject, WKNavigationDelegate, WKScriptMessa merchantID = config.data.merchantID partnerAttributionID = config.data.partnerAttributionID amount = config.data.amount - currency = config.data.currency offerType = config.data.offerType buyerCountry = config.data.buyerCountry channel = config.data.channel - placement = config.data.placement + pageType = config.data.pageType ignoreCache = config.data.ignoreCache - devTouchpoint = config.data.devTouchpoint - stageTag = config.data.stageTag } func makeConfig() -> PayPalMessageModalConfig { let config = PayPalMessageModalConfig(data: .init( clientID: self.clientID, + environment: self.environment, amount: self.amount, - currency: self.currency, - placement: self.placement, - offerType: self.offerType, - environment: self.environment + pageType: self.pageType, + offerType: self.offerType )) config.data.merchantID = merchantID config.data.partnerAttributionID = partnerAttributionID config.data.buyerCountry = buyerCountry config.data.channel = channel - config.data.stageTag = stageTag - config.data.devTouchpoint = devTouchpoint config.data.ignoreCache = ignoreCache return config @@ -203,7 +176,7 @@ class PayPalMessageModalViewModel: NSObject, WKNavigationDelegate, WKScriptMessa loadCompletionHandler = completionHandler - log(.info, "Load modal webview URL: \(safeUrl)") + log(.debug, "Load modal webview URL: \(safeUrl)", for: environment) webView.load(URLRequest(url: safeUrl)) } @@ -224,17 +197,24 @@ class PayPalMessageModalViewModel: NSObject, WKNavigationDelegate, WKScriptMessa withTimeInterval: queueTimeInterval, repeats: false ) { _ in - guard let jsonData = try? JSONEncoder().encode(self.makeConfig()), - let jsonString = String(data: jsonData, encoding: .utf8) else { return } + self.flushUpdates() + } + } - log(.info, "Update props: \(jsonString)") + // Exposed internally for tests + func flushUpdates() { + guard let jsonData = try? JSONEncoder().encode(self.makeConfig()), + let jsonString = String(data: jsonData, encoding: .utf8) else { return } - self.webView.evaluateJavaScript( - "window.actions.updateProps(\(jsonString))" - ) { _, _ in - // TODO: Does the JS error text get returned here? - } + log(.debug, "Update props: \(jsonString)", for: environment) + + self.webView.evaluateJavaScript( + "window.actions.updateProps(\(jsonString))" + ) { _, _ in + // TODO: Does the JS error text get returned here? } + + queuedTimer?.invalidate() } func userContentController( @@ -245,37 +225,39 @@ class PayPalMessageModalViewModel: NSObject, WKNavigationDelegate, WKScriptMessa let bodyData = bodyString.data(using: .utf8), let json = try? JSONSerialization.jsonObject(with: bodyData) as? [String: Any], let eventName = json["name"] as? String, - let eventArgs = json["args"] as? [[String: Any]] else { - log(.error, "Unable to parse modal event body") + var eventArgs = json["args"] as? [[String: Any]] else { + log(.error, "Unable to parse modal event body", for: environment) return } - log(.info, "Modal event: [\(eventName)] \(eventArgs)") + log(.debug, "Modal event: [\(eventName)] \(eventArgs)", for: environment) guard !eventArgs.isEmpty else { return } - let shared = eventArgs[0]["__shared__"] as? [String: Any] ?? [:] - for (key, value) in shared { - logger.dynamicData[key] = AnyCodable(value) + // If __shared__ exists, remove it from the individual event and include it as + // part of the component level logger dynamic data + if let shared = eventArgs[0].removeValue(forKey: "__shared__") as? [String: Any] { + for (key, value) in shared { + logger.dynamicData[key] = AnyCodable(value) + } } var encodableDict: [String: AnyCodable] = [:] for (key, value) in eventArgs[0] { - encodableDict[key] = value as? AnyCodable + encodableDict[key] = AnyCodable(value) } logger.addEvent(.dynamic(data: encodableDict)) switch eventName { case "onCalculate": - if let amount = eventArgs[0]["amount"] as? Double, - let modal = modal { + if let modal, let amount = eventArgs[0]["amount"] as? Double { eventDelegate?.onCalculate(modal, data: .init(value: amount)) } case "onClick": - if let src = eventArgs[0]["link_src"] as? String, - let linkName = eventArgs[0]["link_name"] as? String, - let modal { + if let modal, + let src = eventArgs[0]["page_view_link_source"] as? String, + let linkName = eventArgs[0]["page_view_link_name"] as? String { eventDelegate?.onClick(modal, data: .init(linkName: linkName, linkSrc: src)) } @@ -291,17 +273,22 @@ class PayPalMessageModalViewModel: NSObject, WKNavigationDelegate, WKScriptMessa didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void ) { - guard let serverTrust = challenge.protectionSpace.serverTrust else { - return completionHandler(.useCredential, nil) - } switch environment { - case .local, .stage: - // Allow webview to connect to webpage using invalid local HTTPS certs - let exceptions = SecTrustCopyExceptions(serverTrust) - SecTrustSetExceptions(serverTrust, exceptions) - default: break + case .live, .sandbox: + completionHandler(.performDefaultHandling, nil) + case .develop: + guard let serverTrust = challenge.protectionSpace.serverTrust else { + return completionHandler(.performDefaultHandling, nil) + } + // Credential override methods warn when run on the main thread + DispatchQueue.global(qos: .background).async { + // Allow webview to connect to webpage using self-signed HTTPS certs + let exceptions = SecTrustCopyExceptions(serverTrust) + SecTrustSetExceptions(serverTrust, exceptions) + + completionHandler(.useCredential, URLCredential(trust: serverTrust)) + } } - completionHandler(.useCredential, URLCredential(trust: serverTrust)) } func webView( diff --git a/Sources/PayPalMessages/PayPalMessageView.swift b/Sources/PayPalMessages/PayPalMessageView.swift index f052d26..22cbfa6 100644 --- a/Sources/PayPalMessages/PayPalMessageView.swift +++ b/Sources/PayPalMessages/PayPalMessageView.swift @@ -3,7 +3,10 @@ import SwiftUI public final class PayPalMessageView: UIControl { + public typealias Proxy = AnyProxy + // MARK: - Properties + /// Delegate property in charge of announcing rendering and fetching events. @Proxy(\.viewModel.stateDelegate) public var stateDelegate: PayPalMessageViewStateDelegate? @@ -28,9 +31,9 @@ public final class PayPalMessageView: UIControl { @Proxy(\.viewModel.amount) public var amount: Double? - /// Read-write property that holds the message placement. - @Proxy(\.viewModel.placement) - public var placement: PayPalMessagePlacement? + /// Read-write property that holds the message pageType. + @Proxy(\.viewModel.pageType) + public var pageType: PayPalMessagePageType? /// Read-write property that holds the message offer type. @Proxy(\.viewModel.offerType) @@ -40,6 +43,9 @@ public final class PayPalMessageView: UIControl { @Proxy(\.viewModel.buyerCountry) public var buyerCountry: String? + @Proxy(\.viewModel.channel) + public var channel: String + /// Read-write property that holds the message's logo style. @Proxy(\.viewModel.logoType) public var logoType: PayPalMessageLogoType @@ -49,28 +55,23 @@ public final class PayPalMessageView: UIControl { public var color: PayPalMessageColor /// Read-write property that holds the message's alignment. - @Proxy(\.viewModel.alignment) - public var alignment: PayPalMessageTextAlignment + @Proxy(\.viewModel.textAlign) + public var textAlign: PayPalMessageTextAlign /// Read-write property that holds the cache status @Proxy(\.viewModel.ignoreCache) public var ignoreCache: Bool - /// Read-write property that holds the development stage tag - @Proxy(\.viewModel.stageTag) - public var stageTag: String? - - /// Read-write property that holds the development content status - @Proxy(\.viewModel.devTouchpoint) - public var devTouchpoint: Bool - /// Private property that holds the message configuration. /// We are using set/get methods for accessing to discourage attempting to edit parts of the config to make changes @Proxy(\.viewModel.config) private var config: PayPalMessageConfig - /// Associated ViewModel that performs the update and fetch operations. - private let viewModel: PayPalMessageViewModel + @Proxy(\.viewModel.merchantProfileHash) + var merchantProfileHash: String? + + // swiftlint:disable:next implicitly_unwrapped_optional + private var viewModel: PayPalMessageViewModel! // MARK: - Subviews @@ -104,25 +105,41 @@ public final class PayPalMessageView: UIControl { /// - config: Config object that holds all of the required parameters for the message view. /// - stateDelegate: Delegate property in charge of announcing rendering and fetching events. /// - eventDelegate: Delegate property in charge of interaction-related events. - public required init( + public convenience init( config: PayPalMessageConfig, stateDelegate: PayPalMessageViewStateDelegate? = nil, eventDelegate: PayPalMessageViewEventDelegate? = nil ) { - self.viewModel = PayPalMessageViewModel(config: config) + self.init( + config: config, + stateDelegate: stateDelegate, + eventDelegate: eventDelegate, + requester: MessageRequest(), + merchantProfileProvider: MerchantProfileProvider() + ) + } + internal init( + config: PayPalMessageConfig, + stateDelegate: PayPalMessageViewStateDelegate? = nil, + eventDelegate: PayPalMessageViewEventDelegate? = nil, + requester: MessageRequestable, + merchantProfileProvider: MerchantProfileHashGetable + ) { super.init(frame: .zero) - self.stateDelegate = stateDelegate - self.eventDelegate = eventDelegate + viewModel = PayPalMessageViewModel( + config: config, + requester: requester, + merchantProfileProvider: merchantProfileProvider, + stateDelegate: stateDelegate, + eventDelegate: eventDelegate, + delegate: self, + messageView: self + ) - configDelegates() configViews() configTouchTarget() - - // Manually fetch the content instead of immediately as part of the view model constructor - // so that the delegates and message instance can be passed in before any callbacks fire - self.viewModel.queueMessageContentUpdate(fireImmediately: true) } @available(*, unavailable) @@ -157,7 +174,7 @@ public final class PayPalMessageView: UIControl { override public func awakeFromNib() { super.awakeFromNib() - refreshContent() + refreshContent(messageParameters: viewModel.messageParameters) } override public var intrinsicContentSize: CGSize { @@ -170,13 +187,6 @@ public final class PayPalMessageView: UIControl { // MARK: - Config Functions - private func configDelegates() { - viewModel.stateDelegate = stateDelegate - viewModel.eventDelegate = eventDelegate - viewModel.delegate = self - viewModel.messageView = self - } - private func configViews() { backgroundColor = .clear layer.masksToBounds = true @@ -185,7 +195,6 @@ public final class PayPalMessageView: UIControl { addSubview(containerView) configConstraints() - configAccessibility() } private func configConstraints() { @@ -232,11 +241,15 @@ public final class PayPalMessageView: UIControl { extension PayPalMessageView: PayPalMessageViewModelDelegate { /// Recreates the message content from the existing data. **Does not triggers a networking event.** - func refreshContent() { - let params = viewModel.messageParameters - messageLabel.attributedText = PayPalMessageAttributedStringBuilder().makeMessageString(params) + func refreshContent(messageParameters: PayPalMessageViewParameters?) { + messageLabel.attributedText = PayPalMessageAttributedStringBuilder().makeMessageString(messageParameters) // Force recalculation for layout invalidateIntrinsicContentSize() + + // Update accessibility properties + self.accessibilityLabel = messageParameters?.accessibilityLabel ?? "" + self.accessibilityTraits = messageParameters?.accessibilityTraits ?? .none + self.isAccessibilityElement = messageParameters?.isAccessibilityElement ?? false } } @@ -247,13 +260,7 @@ extension PayPalMessageView { /// Called when the accessibility or orientation traits have changed. Reloads the content accordingly. override public func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) - refreshContent() - } - - private func configAccessibility() { - accessibilityTraits = .link - isAccessibilityElement = true - accessibilityLabel = Constants.accessibilityLabel + refreshContent(messageParameters: viewModel.messageParameters) } } @@ -262,7 +269,6 @@ extension PayPalMessageView { extension PayPalMessageView { private enum Constants { - static let accessibilityLabel: String = "PayPalMessageView" static let highlightedAnimationDuration: CGFloat = 1.0 static let highlightedAlpha: CGFloat = 0.75 static let regularAlpha: CGFloat = 1.0 diff --git a/Sources/PayPalMessages/PayPalMessageViewModel.swift b/Sources/PayPalMessages/PayPalMessageViewModel.swift index 92787f4..ea02955 100644 --- a/Sources/PayPalMessages/PayPalMessageViewModel.swift +++ b/Sources/PayPalMessages/PayPalMessageViewModel.swift @@ -2,7 +2,7 @@ import UIKit protocol PayPalMessageViewModelDelegate: AnyObject { /// Requests the delegate to perform a content refresh. - func refreshContent() + func refreshContent(messageParameters: PayPalMessageViewParameters?) } // swiftlint:disable:next type_body_length @@ -39,8 +39,8 @@ class PayPalMessageViewModel: PayPalMessageModalEventDelegate { } /// Changing its value will cause the message content being refetched only if an update is detected. - var placement: PayPalMessagePlacement? { - didSet { queueUpdate(from: oldValue, to: placement) } + var pageType: PayPalMessagePageType? { + didSet { queueUpdate(from: oldValue, to: pageType) } } /// Changing its value will cause the message content being refetched only if an update is detected. @@ -58,6 +58,10 @@ class PayPalMessageViewModel: PayPalMessageModalEventDelegate { didSet { queueUpdate(from: oldValue, to: buyerCountry) } } + var channel: String { + didSet { queueUpdate(from: oldValue, to: channel )} + } + /// Changing its value will cause the message content being refetched only if an update is detected. var logoType: PayPalMessageLogoType { didSet { queueUpdate(from: oldValue, to: logoType) } @@ -69,21 +73,18 @@ class PayPalMessageViewModel: PayPalMessageModalEventDelegate { } /// Changing its value will not cause the message content being refetched. It will only trigger an UI update. - var alignment: PayPalMessageTextAlignment { - didSet { queueUpdate(from: oldValue, to: alignment, requiresFetch: false) } + var textAlign: PayPalMessageTextAlign { + didSet { queueUpdate(from: oldValue, to: textAlign, requiresFetch: false) } } var ignoreCache: Bool { didSet { queueUpdate(from: oldValue, to: ignoreCache) } } - var stageTag: String? { - didSet { queueUpdate(from: oldValue, to: stageTag) } - } + var merchantProfileHash: String? - var devTouchpoint: Bool { - didSet { queueUpdate(from: oldValue, to: devTouchpoint) } - } + /// Update the messageView's interactivity based on the boolean flag. Disabled by default. + var isMessageViewInteractive = false /// returns the parameters for the style and content the message's Attributed String according to the server response var messageParameters: PayPalMessageViewParameters? { makeViewParameters() } @@ -108,7 +109,7 @@ class PayPalMessageViewModel: PayPalMessageModalEventDelegate { private let requester: MessageRequestable /// helper class to build the parameters for the PayPalMessageView - private let parameterBuilder: PayPalMessageViewParametersBuilder + private let parameterBuilder = PayPalMessageViewParametersBuilder() /// obtains the Merchant Hash and requests it if necessary private let merchantProfileProvider: MerchantProfileHashGetable @@ -117,71 +118,58 @@ class PayPalMessageViewModel: PayPalMessageModalEventDelegate { private var modal: PayPalMessageModal? /// Tracking logger - let logger: ComponentLogger + private let logger: AnalyticsLogger // MARK: - Inits and Setters init( config: PayPalMessageConfig, - requester: MessageRequestable = MessageRequest(), - parameterBuilder: PayPalMessageViewParametersBuilder = PayPalMessageViewParametersBuilder(), - merchantProfileProvider: MerchantProfileHashGetable = MerchantProfileProvider(), - delegate: PayPalMessageViewModelDelegate? = nil, - eventDelegate: PayPalMessageViewEventDelegate? = nil, + requester: MessageRequestable, + merchantProfileProvider: MerchantProfileHashGetable, stateDelegate: PayPalMessageViewStateDelegate? = nil, - messageView: PayPalMessageView? = nil + eventDelegate: PayPalMessageViewEventDelegate? = nil, + delegate: PayPalMessageViewModelDelegate? = nil, + messageView: PayPalMessageView ) { self.clientID = config.data.clientID self.merchantID = config.data.merchantID self.partnerAttributionID = config.data.partnerAttributionID self.environment = config.data.environment self.amount = config.data.amount - self.placement = config.data.placement + self.pageType = config.data.pageType self.offerType = config.data.offerType self.buyerCountry = config.data.buyerCountry + self.channel = config.data.channel self.color = config.style.color self.logoType = config.style.logoType - self.alignment = config.style.textAlignment + self.textAlign = config.style.textAlign self.ignoreCache = config.data.ignoreCache - self.stageTag = config.data.stageTag - self.devTouchpoint = config.data.devTouchpoint self.requester = requester - self.parameterBuilder = parameterBuilder self.merchantProfileProvider = merchantProfileProvider self.delegate = delegate self.eventDelegate = eventDelegate self.stateDelegate = stateDelegate self.messageView = messageView - self.logger = Logger.createMessageLogger( - environment: environment, - clientID: clientID, - merchantID: merchantID, - partnerAttributionID: partnerAttributionID, - offerType: offerType, - amount: amount, - placement: placement, - buyerCountryCode: buyerCountry, - styleColor: color, - styleLogoType: logoType, - styleTextAlign: alignment - ) + self.logger = AnalyticsLogger(.message(Weak(messageView))) + + queueMessageContentUpdate(fireImmediately: true) } deinit {} private func updateConfig(_ config: PayPalMessageConfig) { + self.clientID = config.data.clientID self.amount = config.data.amount - self.placement = config.data.placement + self.pageType = config.data.pageType self.offerType = config.data.offerType self.buyerCountry = config.data.buyerCountry + self.channel = config.data.channel self.color = config.style.color self.logoType = config.style.logoType - self.alignment = config.style.textAlignment + self.textAlign = config.style.textAlign self.ignoreCache = config.data.ignoreCache - self.stageTag = config.data.stageTag - self.devTouchpoint = config.data.devTouchpoint } // MARK: - Fetch Methods @@ -197,7 +185,7 @@ class PayPalMessageViewModel: PayPalMessageModalEventDelegate { } /// When the message is being fetch from a Property update, it considers whether an update is not being currently executed or requested - func queueMessageContentUpdate(requiresFetch: Bool = true, fireImmediately: Bool = false) { + private func queueMessageContentUpdate(requiresFetch: Bool = true, fireImmediately: Bool = false) { renderStart = Date() if requiresFetch { @@ -210,12 +198,7 @@ class PayPalMessageViewModel: PayPalMessageModalEventDelegate { withTimeInterval: queueTimeInterval, repeats: false ) { _ in - if self.fetchMessageContentPending { - self.fetchMessageContent() - self.fetchMessageContentPending = false - } else { - self.delegate?.refreshContent() - } + self.flushUpdates() } if fireImmediately { @@ -223,16 +206,34 @@ class PayPalMessageViewModel: PayPalMessageModalEventDelegate { } } + // Exposed internally for tests + func flushUpdates() { + if fetchMessageContentPending { + fetchMessageContent() + fetchMessageContentPending = false + } else { + delegate?.refreshContent(messageParameters: self.messageParameters) + } + + queuedTimer?.invalidate() + } + /// Refreshes the Message content only if there's a new amount or logo type set private func fetchMessageContent() { if let stateDelegate, let messageView { stateDelegate.onLoading(messageView) } - merchantProfileProvider.getMerchantProfileHash(environment: environment, clientID: clientID) { [weak self] profileHash in + merchantProfileProvider.getMerchantProfileHash( + environment: environment, + clientID: clientID, + merchantID: merchantID + ) { [weak self] profileHash in guard let self else { return } - let parameters = self.makeRequestParameters(merchantProfileHash: profileHash) + self.merchantProfileHash = profileHash + + let parameters = self.makeRequestParameters() self.requester.fetchMessage(parameters: parameters) { [weak self] result in switch result { @@ -251,17 +252,19 @@ class PayPalMessageViewModel: PayPalMessageModalEventDelegate { private func onMessageRequestFailed(error: PayPalMessageError) { messageResponse = nil - let errorDescription = error.description ?? "" self.logger.addEvent(.messageError( - errorName: "\(error)", - errorDescription: errorDescription + errorName: error.issue ?? "\(error)", + errorDescription: error.description ?? "" )) if let stateDelegate, let messageView { stateDelegate.onError(messageView, error: error) } - delegate?.refreshContent() + // Disable the tap gesture + isMessageViewInteractive = false + + delegate?.refreshContent(messageParameters: messageParameters) } private func onMessageRequestReceived(response: MessageResponse) { @@ -272,24 +275,28 @@ class PayPalMessageViewModel: PayPalMessageModalEventDelegate { stateDelegate.onSuccess(messageView) } - delegate?.refreshContent() + delegate?.refreshContent(messageParameters: messageParameters) - // How to get renderDuration? - // Is this the correct way to get requestDuration? logger.addEvent(.messageRender( // Convert to milliseconds renderDuration: Int((renderStart?.timeIntervalSinceNow ?? 1 / 1000) * -1000), requestDuration: Int((messageResponse?.requestDuration ?? 1 / 1000) * -1000) )) - modal?.setConfig(makeModalConfig()) + // Enable the tap gesture + isMessageViewInteractive = true + + if let modal { + modal.merchantProfileHash = merchantProfileHash + modal.setConfig(makeModalConfig()) + } - log(.info, "onMessageRequestReceived is \(String(describing: response.defaultMainContent))") + log(.debug, "onMessageRequestReceived is \(String(describing: response.defaultMainContent))", for: environment) } // MARK: - Message Request Builder - private func makeRequestParameters(merchantProfileHash: String?) -> MessageRequestParameters { + private func makeRequestParameters() -> MessageRequestParameters { .init( environment: environment, clientID: clientID, @@ -297,13 +304,12 @@ class PayPalMessageViewModel: PayPalMessageModalEventDelegate { partnerAttributionID: partnerAttributionID, logoType: logoType, buyerCountry: buyerCountry, - placement: placement, + pageType: pageType, amount: amount, offerType: offerType, merchantProfileHash: merchantProfileHash, ignoreCache: ignoreCache, - devTouchpoint: devTouchpoint, - stageTag: stageTag + instanceID: logger.instanceId ) } @@ -315,10 +321,12 @@ class PayPalMessageViewModel: PayPalMessageModalEventDelegate { return parameterBuilder .makeParameters( message: response.defaultMainContent, + messageAlternative: response.defaultMainAlternative, + offerType: response.offerType, linkDescription: response.defaultDisclaimer, logoPlaceholder: response.logoPlaceholder, logoType: logoType, - payPalAlignment: alignment, + payPalAlign: textAlign, payPalColor: color, productGroup: response.productGroup ) @@ -330,23 +338,21 @@ class PayPalMessageViewModel: PayPalMessageModalEventDelegate { let config = PayPalMessageConfig( data: .init( clientID: clientID, + environment: environment, amount: amount, - placement: placement, - offerType: offerType, - environment: environment + pageType: pageType, + offerType: offerType ), style: .init( logoType: logoType, color: color, - textAlignment: alignment + textAlign: textAlign ) ) config.data.merchantID = merchantID config.data.partnerAttributionID = partnerAttributionID config.data.buyerCountry = buyerCountry config.data.ignoreCache = ignoreCache - config.data.stageTag = stageTag - config.data.devTouchpoint = devTouchpoint return config } @@ -367,18 +373,18 @@ class PayPalMessageViewModel: PayPalMessageModalEventDelegate { availableWidth: messageResponse?.modalCloseButtonAvailWidth, availableHeight: messageResponse?.modalCloseButtonAvailHeight, color: color, - colorType: messageResponse?.modalCloseButtonColorType + colorType: messageResponse?.modalCloseButtonColorType, + alternativeText: messageResponse?.modalCloseButtonAlternativeText ) let config = PayPalMessageModalConfig( data: .init( clientID: clientID, + environment: environment, amount: amount, - // currency: currency, TODO: Implement? - placement: placement, + pageType: pageType, offerType: offerType, - modalCloseButton: modalCloseButton, - environment: environment + modalCloseButton: modalCloseButton ) ) // Partner options @@ -389,30 +395,32 @@ class PayPalMessageViewModel: PayPalMessageModalEventDelegate { config.data.modalCloseButton = modalCloseButton // Dev options config.data.ignoreCache = ignoreCache - config.data.devTouchpoint = devTouchpoint - config.data.stageTag = stageTag return config } func showModal() { + guard isMessageViewInteractive else { + return + } + if let eventDelegate, let messageView { eventDelegate.onClick(messageView) } logger.addEvent(.messageClick( - linkName: messageResponse?.defaultDisclaimer ?? "Learn More", + linkName: messageResponse?.defaultDisclaimer ?? "Learn more", linkSrc: "learn_more" )) if modal == nil { - modal = PayPalMessageModal( - config: makeModalConfig(), - eventDelegate: self - ) + modal = PayPalMessageModal(config: makeModalConfig(), eventDelegate: self) } - modal?.show() + if let modal { + modal.merchantProfileHash = merchantProfileHash + modal.show() + } } // MARK: Modal Event Delegate Functions diff --git a/Sources/PayPalMessages/PrivacyInfo.xcprivacy b/Sources/PayPalMessages/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..c43df25 --- /dev/null +++ b/Sources/PayPalMessages/PrivacyInfo.xcprivacy @@ -0,0 +1,36 @@ + + + + + NSPrivacyCollectedDataTypes + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeProductInteraction + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + CA92.1 + + + + NSPrivacyTrackingDomains + + NSPrivacyTracking + + + diff --git a/Sources/PayPalMessages/Utils/Log.swift b/Sources/PayPalMessages/Utils/Log.swift index 714c0c6..6b3a76e 100644 --- a/Sources/PayPalMessages/Utils/Log.swift +++ b/Sources/PayPalMessages/Utils/Log.swift @@ -7,7 +7,7 @@ enum LogLevel: Int { case error } -func log(_ level: LogLevel, _ message: String, with data: Data? = nil, for environment: Environment = .live) { +func log(_ level: LogLevel, _ message: String, with data: Data? = nil, for environment: Environment) { if level == .debug && environment.isProduction { return } diff --git a/Sources/PayPalMessages/IO/MerchantProfileData.swift b/Sources/PayPalMessages/Utils/MerchantProfileData.swift similarity index 100% rename from Sources/PayPalMessages/IO/MerchantProfileData.swift rename to Sources/PayPalMessages/Utils/MerchantProfileData.swift diff --git a/Sources/PayPalMessages/Utils/PayPalMessageAttributedStringBuilder.swift b/Sources/PayPalMessages/Utils/PayPalMessageAttributedStringBuilder.swift index de47935..71e6f98 100644 --- a/Sources/PayPalMessages/Utils/PayPalMessageAttributedStringBuilder.swift +++ b/Sources/PayPalMessages/Utils/PayPalMessageAttributedStringBuilder.swift @@ -125,7 +125,7 @@ final class PayPalMessageAttributedStringBuilder { ) -> NSMutableParagraphStyle { let style = NSMutableParagraphStyle() style.lineSpacing = getAccessibilityScaledValue(Constants.lineSpacing) - style.alignment = parameters.textAlignment + style.alignment = parameters.textAlign return style } diff --git a/Sources/PayPalMessages/Utils/PayPalMessageViewParameters.swift b/Sources/PayPalMessages/Utils/PayPalMessageViewParameters.swift index bf4a46b..7005eea 100644 --- a/Sources/PayPalMessages/Utils/PayPalMessageViewParameters.swift +++ b/Sources/PayPalMessages/Utils/PayPalMessageViewParameters.swift @@ -14,5 +14,9 @@ struct PayPalMessageViewParameters { let linkColor: UIColor let linkUnderlineColor: UIColor - let textAlignment: NSTextAlignment + let textAlign: NSTextAlignment + + let accessibilityLabel: String + let accessibilityTraits: UIAccessibilityTraits + let isAccessibilityElement: Bool } diff --git a/Sources/PayPalMessages/Utils/PayPalMessageViewParametersBuilder.swift b/Sources/PayPalMessages/Utils/PayPalMessageViewParametersBuilder.swift index 936304d..57b4f81 100644 --- a/Sources/PayPalMessages/Utils/PayPalMessageViewParametersBuilder.swift +++ b/Sources/PayPalMessages/Utils/PayPalMessageViewParametersBuilder.swift @@ -5,10 +5,12 @@ struct PayPalMessageViewParametersBuilder { // swiftlint:disable:next function_parameter_count func makeParameters( message: String, + messageAlternative: String?, + offerType: PayPalMessageResponseOfferType, linkDescription: String, logoPlaceholder: String, logoType: PayPalMessageLogoType, - payPalAlignment: PayPalMessageTextAlignment, + payPalAlign: PayPalMessageTextAlign, payPalColor: PayPalMessageColor, productGroup: PayPalMessageResponseProductGroup ) -> PayPalMessageViewParameters { @@ -23,6 +25,15 @@ struct PayPalMessageViewParametersBuilder { productGroup: productGroup ) + let brandingText = productGroup == .paypalCredit ? "PayPal Credit" : "PayPal" + var accessibilityLabel = (messageAlternative ?? message).replacingOccurrences(of: logoPlaceholder, with: brandingText) + + accessibilityLabel += " \(linkDescription)" + + if !message.contains(logoPlaceholder) { + accessibilityLabel = "\(brandingText) - \(accessibilityLabel)" + } + return PayPalMessageViewParameters( message: message, messageColor: getLabelColor(payPalColor), @@ -33,7 +44,10 @@ struct PayPalMessageViewParametersBuilder { linkDescription: linkDescription, linkColor: getLinkColor(payPalColor), linkUnderlineColor: getUnderlineLinkColor(payPalColor), - textAlignment: getAlignment(payPalAlignment) + textAlign: getAlignment(payPalAlign), + accessibilityLabel: accessibilityLabel, + accessibilityTraits: .button, + isAccessibilityElement: true ) } @@ -165,8 +179,8 @@ struct PayPalMessageViewParametersBuilder { } } - private func getAlignment(_ textAlignment: PayPalMessageTextAlignment) -> NSTextAlignment { - switch textAlignment { + private func getAlignment(_ textAlign: PayPalMessageTextAlign) -> NSTextAlignment { + switch textAlign { case .left: return .left diff --git a/Sources/PayPalMessages/Utils/Proxy.swift b/Sources/PayPalMessages/Utils/Proxy.swift index d4aefe2..45c11e6 100644 --- a/Sources/PayPalMessages/Utils/Proxy.swift +++ b/Sources/PayPalMessages/Utils/Proxy.swift @@ -37,8 +37,3 @@ public struct AnyProxy { self.keyPath = keyPath } } - -// Simple protocol that can be exteneded onto other types to infer the EnclosingType of AnyProxy -public protocol ProxyContainer { - typealias Proxy = AnyProxy -} diff --git a/TestApps/CarthageTest/Cartfile b/TestApps/CarthageTest/Cartfile new file mode 100644 index 0000000..6768e7a --- /dev/null +++ b/TestApps/CarthageTest/Cartfile @@ -0,0 +1 @@ +github "paypal/paypal-messages-ios" "main" diff --git a/TestApps/CarthageTest/CarthageTest.xcodeproj/project.pbxproj b/TestApps/CarthageTest/CarthageTest.xcodeproj/project.pbxproj new file mode 100644 index 0000000..27d30e2 --- /dev/null +++ b/TestApps/CarthageTest/CarthageTest.xcodeproj/project.pbxproj @@ -0,0 +1,377 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 56; + objects = { + +/* Begin PBXBuildFile section */ + C6216E1A2ACB3A1100AF03D2 /* CarthageTestApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6216E192ACB3A1100AF03D2 /* CarthageTestApp.swift */; }; + C6216E1C2ACB3A1100AF03D2 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6216E1B2ACB3A1100AF03D2 /* ContentView.swift */; }; + C6216E1E2ACB3A1400AF03D2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C6216E1D2ACB3A1400AF03D2 /* Assets.xcassets */; }; + C6216E212ACB3A1400AF03D2 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C6216E202ACB3A1400AF03D2 /* Preview Assets.xcassets */; }; + C6216E2D2ACB3B8100AF03D2 /* PayPalMessages.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = C6216E2C2ACB3B8100AF03D2 /* PayPalMessages.xcframework */; }; + C6216E2E2ACB3B8100AF03D2 /* PayPalMessages.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C6216E2C2ACB3B8100AF03D2 /* PayPalMessages.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + C6216E2F2ACB3B8100AF03D2 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + C6216E2E2ACB3B8100AF03D2 /* PayPalMessages.xcframework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + C6216E162ACB3A1100AF03D2 /* CarthageTest.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CarthageTest.app; sourceTree = BUILT_PRODUCTS_DIR; }; + C6216E192ACB3A1100AF03D2 /* CarthageTestApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarthageTestApp.swift; sourceTree = ""; }; + C6216E1B2ACB3A1100AF03D2 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + C6216E1D2ACB3A1400AF03D2 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + C6216E202ACB3A1400AF03D2 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + C6216E2C2ACB3B8100AF03D2 /* PayPalMessages.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = PayPalMessages.xcframework; path = Carthage/Build/PayPalMessages.xcframework; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + C6216E132ACB3A1100AF03D2 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C6216E2D2ACB3B8100AF03D2 /* PayPalMessages.xcframework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + C6216E0D2ACB3A1100AF03D2 = { + isa = PBXGroup; + children = ( + C6216E182ACB3A1100AF03D2 /* CarthageTest */, + C6216E172ACB3A1100AF03D2 /* Products */, + C6216E272ACB3A6600AF03D2 /* Frameworks */, + ); + sourceTree = ""; + }; + C6216E172ACB3A1100AF03D2 /* Products */ = { + isa = PBXGroup; + children = ( + C6216E162ACB3A1100AF03D2 /* CarthageTest.app */, + ); + name = Products; + sourceTree = ""; + }; + C6216E182ACB3A1100AF03D2 /* CarthageTest */ = { + isa = PBXGroup; + children = ( + C6216E192ACB3A1100AF03D2 /* CarthageTestApp.swift */, + C6216E1B2ACB3A1100AF03D2 /* ContentView.swift */, + C6216E1D2ACB3A1400AF03D2 /* Assets.xcassets */, + C6216E1F2ACB3A1400AF03D2 /* Preview Content */, + ); + path = CarthageTest; + sourceTree = ""; + }; + C6216E1F2ACB3A1400AF03D2 /* Preview Content */ = { + isa = PBXGroup; + children = ( + C6216E202ACB3A1400AF03D2 /* Preview Assets.xcassets */, + ); + path = "Preview Content"; + sourceTree = ""; + }; + C6216E272ACB3A6600AF03D2 /* Frameworks */ = { + isa = PBXGroup; + children = ( + C6216E2C2ACB3B8100AF03D2 /* PayPalMessages.xcframework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + C6216E152ACB3A1100AF03D2 /* CarthageTest */ = { + isa = PBXNativeTarget; + buildConfigurationList = C6216E242ACB3A1400AF03D2 /* Build configuration list for PBXNativeTarget "CarthageTest" */; + buildPhases = ( + C6216E122ACB3A1100AF03D2 /* Sources */, + C6216E132ACB3A1100AF03D2 /* Frameworks */, + C6216E142ACB3A1100AF03D2 /* Resources */, + C6216E2F2ACB3B8100AF03D2 /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = CarthageTest; + productName = CarthageTest; + productReference = C6216E162ACB3A1100AF03D2 /* CarthageTest.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + C6216E0E2ACB3A1100AF03D2 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1500; + LastUpgradeCheck = 1500; + TargetAttributes = { + C6216E152ACB3A1100AF03D2 = { + CreatedOnToolsVersion = 15.0; + }; + }; + }; + buildConfigurationList = C6216E112ACB3A1100AF03D2 /* Build configuration list for PBXProject "CarthageTest" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = C6216E0D2ACB3A1100AF03D2; + productRefGroup = C6216E172ACB3A1100AF03D2 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + C6216E152ACB3A1100AF03D2 /* CarthageTest */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + C6216E142ACB3A1100AF03D2 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C6216E212ACB3A1400AF03D2 /* Preview Assets.xcassets in Resources */, + C6216E1E2ACB3A1400AF03D2 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + C6216E122ACB3A1100AF03D2 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C6216E1C2ACB3A1100AF03D2 /* ContentView.swift in Sources */, + C6216E1A2ACB3A1100AF03D2 /* CarthageTestApp.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + C6216E222ACB3A1400AF03D2 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + C6216E232ACB3A1400AF03D2 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + C6216E252ACB3A1400AF03D2 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"CarthageTest/Preview Content\""; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.paypal.PayPalMessages.CarthageTest; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + C6216E262ACB3A1400AF03D2 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"CarthageTest/Preview Content\""; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.paypal.PayPalMessages.CarthageTest; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + C6216E112ACB3A1100AF03D2 /* Build configuration list for PBXProject "CarthageTest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C6216E222ACB3A1400AF03D2 /* Debug */, + C6216E232ACB3A1400AF03D2 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C6216E242ACB3A1400AF03D2 /* Build configuration list for PBXNativeTarget "CarthageTest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C6216E252ACB3A1400AF03D2 /* Debug */, + C6216E262ACB3A1400AF03D2 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = C6216E0E2ACB3A1100AF03D2 /* Project object */; +} diff --git a/TestApps/CarthageTest/CarthageTest.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/TestApps/CarthageTest/CarthageTest.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/TestApps/CarthageTest/CarthageTest.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/TestApps/CarthageTest/CarthageTest.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/TestApps/CarthageTest/CarthageTest.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/TestApps/CarthageTest/CarthageTest.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/TestApps/CarthageTest/CarthageTest/Assets.xcassets/AccentColor.colorset/Contents.json b/TestApps/CarthageTest/CarthageTest/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/TestApps/CarthageTest/CarthageTest/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/TestApps/CarthageTest/CarthageTest/Assets.xcassets/AppIcon.appiconset/Contents.json b/TestApps/CarthageTest/CarthageTest/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..13613e3 --- /dev/null +++ b/TestApps/CarthageTest/CarthageTest/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,13 @@ +{ + "images" : [ + { + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/TestApps/CarthageTest/CarthageTest/Assets.xcassets/Contents.json b/TestApps/CarthageTest/CarthageTest/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/TestApps/CarthageTest/CarthageTest/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/TestApps/CarthageTest/CarthageTest/CarthageTestApp.swift b/TestApps/CarthageTest/CarthageTest/CarthageTestApp.swift new file mode 100644 index 0000000..07f515c --- /dev/null +++ b/TestApps/CarthageTest/CarthageTest/CarthageTestApp.swift @@ -0,0 +1,10 @@ +import SwiftUI + +@main +struct CarthageTestApp: App { + var body: some Scene { + WindowGroup { + ContentView() + } + } +} diff --git a/TestApps/CarthageTest/CarthageTest/ContentView.swift b/TestApps/CarthageTest/CarthageTest/ContentView.swift new file mode 100644 index 0000000..1af5552 --- /dev/null +++ b/TestApps/CarthageTest/CarthageTest/ContentView.swift @@ -0,0 +1,28 @@ +import SwiftUI +import PayPalMessages + +struct ContentView: View { + var message = PayPalMessageView( + config: .init( + data: .init( + clientID: "test_app", + environment: .sandbox + ) + ) + ) + + var body: some View { + VStack { + Image(systemName: "globe") + .imageScale(.large) + Text("Hello, world!") + } + .padding() + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/TestApps/CarthageTest/CarthageTest/Preview Content/Preview Assets.xcassets/Contents.json b/TestApps/CarthageTest/CarthageTest/Preview Content/Preview Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/TestApps/CarthageTest/CarthageTest/Preview Content/Preview Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/TestApps/SPMTest/SPMTest.xcodeproj/project.pbxproj b/TestApps/SPMTest/SPMTest.xcodeproj/project.pbxproj new file mode 100644 index 0000000..3145c05 --- /dev/null +++ b/TestApps/SPMTest/SPMTest.xcodeproj/project.pbxproj @@ -0,0 +1,376 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 56; + objects = { + +/* Begin PBXBuildFile section */ + C623E7192ADDB67200511176 /* PayPalMessages in Frameworks */ = {isa = PBXBuildFile; productRef = C623E7182ADDB67200511176 /* PayPalMessages */; }; + C6A448DD2AC76E1F005A01CC /* SPMTestApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6A448DC2AC76E1F005A01CC /* SPMTestApp.swift */; }; + C6A448DF2AC76E1F005A01CC /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6A448DE2AC76E1F005A01CC /* ContentView.swift */; }; + C6A448E12AC76E22005A01CC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C6A448E02AC76E22005A01CC /* Assets.xcassets */; }; + C6A448E42AC76E22005A01CC /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C6A448E32AC76E22005A01CC /* Preview Assets.xcassets */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + C6A448D92AC76E1F005A01CC /* SPMTest.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SPMTest.app; sourceTree = BUILT_PRODUCTS_DIR; }; + C6A448DC2AC76E1F005A01CC /* SPMTestApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPMTestApp.swift; sourceTree = ""; }; + C6A448DE2AC76E1F005A01CC /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + C6A448E02AC76E22005A01CC /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + C6A448E32AC76E22005A01CC /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + C6A448D62AC76E1F005A01CC /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C623E7192ADDB67200511176 /* PayPalMessages in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + C6A448D02AC76E1F005A01CC = { + isa = PBXGroup; + children = ( + C6A448DB2AC76E1F005A01CC /* SPMTest */, + C6A448DA2AC76E1F005A01CC /* Products */, + ); + sourceTree = ""; + }; + C6A448DA2AC76E1F005A01CC /* Products */ = { + isa = PBXGroup; + children = ( + C6A448D92AC76E1F005A01CC /* SPMTest.app */, + ); + name = Products; + sourceTree = ""; + }; + C6A448DB2AC76E1F005A01CC /* SPMTest */ = { + isa = PBXGroup; + children = ( + C6A448DC2AC76E1F005A01CC /* SPMTestApp.swift */, + C6A448DE2AC76E1F005A01CC /* ContentView.swift */, + C6A448E02AC76E22005A01CC /* Assets.xcassets */, + C6A448E22AC76E22005A01CC /* Preview Content */, + ); + path = SPMTest; + sourceTree = ""; + }; + C6A448E22AC76E22005A01CC /* Preview Content */ = { + isa = PBXGroup; + children = ( + C6A448E32AC76E22005A01CC /* Preview Assets.xcassets */, + ); + path = "Preview Content"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + C6A448D82AC76E1F005A01CC /* SPMTest */ = { + isa = PBXNativeTarget; + buildConfigurationList = C6A448E72AC76E22005A01CC /* Build configuration list for PBXNativeTarget "SPMTest" */; + buildPhases = ( + C6A448D52AC76E1F005A01CC /* Sources */, + C6A448D62AC76E1F005A01CC /* Frameworks */, + C6A448D72AC76E1F005A01CC /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SPMTest; + packageProductDependencies = ( + C623E7182ADDB67200511176 /* PayPalMessages */, + ); + productName = SPMTest; + productReference = C6A448D92AC76E1F005A01CC /* SPMTest.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + C6A448D12AC76E1F005A01CC /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1500; + LastUpgradeCheck = 1500; + TargetAttributes = { + C6A448D82AC76E1F005A01CC = { + CreatedOnToolsVersion = 15.0; + }; + }; + }; + buildConfigurationList = C6A448D42AC76E1F005A01CC /* Build configuration list for PBXProject "SPMTest" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = C6A448D02AC76E1F005A01CC; + packageReferences = ( + C623E7172ADDB67200511176 /* XCRemoteSwiftPackageReference "paypal-messages-ios" */, + ); + productRefGroup = C6A448DA2AC76E1F005A01CC /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + C6A448D82AC76E1F005A01CC /* SPMTest */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + C6A448D72AC76E1F005A01CC /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C6A448E42AC76E22005A01CC /* Preview Assets.xcassets in Resources */, + C6A448E12AC76E22005A01CC /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + C6A448D52AC76E1F005A01CC /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C6A448DF2AC76E1F005A01CC /* ContentView.swift in Sources */, + C6A448DD2AC76E1F005A01CC /* SPMTestApp.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + C6A448E52AC76E22005A01CC /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + C6A448E62AC76E22005A01CC /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + C6A448E82AC76E22005A01CC /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"SPMTest/Preview Content\""; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 14.1; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.paypal.PayPalMessages.SPMTest; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + C6A448E92AC76E22005A01CC /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"SPMTest/Preview Content\""; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 14.1; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.paypal.PayPalMessages.SPMTest; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + C6A448D42AC76E1F005A01CC /* Build configuration list for PBXProject "SPMTest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C6A448E52AC76E22005A01CC /* Debug */, + C6A448E62AC76E22005A01CC /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C6A448E72AC76E22005A01CC /* Build configuration list for PBXNativeTarget "SPMTest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C6A448E82AC76E22005A01CC /* Debug */, + C6A448E92AC76E22005A01CC /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + C623E7172ADDB67200511176 /* XCRemoteSwiftPackageReference "paypal-messages-ios" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/paypal/paypal-messages-ios"; + requirement = { + branch = main; + kind = branch; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + C623E7182ADDB67200511176 /* PayPalMessages */ = { + isa = XCSwiftPackageProductDependency; + package = C623E7172ADDB67200511176 /* XCRemoteSwiftPackageReference "paypal-messages-ios" */; + productName = PayPalMessages; + }; +/* End XCSwiftPackageProductDependency section */ + }; + rootObject = C6A448D12AC76E1F005A01CC /* Project object */; +} diff --git a/TestApps/SPMTest/SPMTest.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/TestApps/SPMTest/SPMTest.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/TestApps/SPMTest/SPMTest.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/TestApps/SPMTest/SPMTest.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/TestApps/SPMTest/SPMTest.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/TestApps/SPMTest/SPMTest.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/TestApps/SPMTest/SPMTest.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/TestApps/SPMTest/SPMTest.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000..833ea61 --- /dev/null +++ b/TestApps/SPMTest/SPMTest.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,14 @@ +{ + "pins" : [ + { + "identity" : "paypal-messages-ios", + "kind" : "remoteSourceControl", + "location" : "https://github.com/paypal/paypal-messages-ios", + "state" : { + "branch" : "main", + "revision" : "7e32fd4230045bfd5be6c2a8124c02d127b89a69" + } + } + ], + "version" : 2 +} diff --git a/TestApps/SPMTest/SPMTest/Assets.xcassets/AccentColor.colorset/Contents.json b/TestApps/SPMTest/SPMTest/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/TestApps/SPMTest/SPMTest/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/TestApps/SPMTest/SPMTest/Assets.xcassets/AppIcon.appiconset/Contents.json b/TestApps/SPMTest/SPMTest/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..13613e3 --- /dev/null +++ b/TestApps/SPMTest/SPMTest/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,13 @@ +{ + "images" : [ + { + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/TestApps/SPMTest/SPMTest/Assets.xcassets/Contents.json b/TestApps/SPMTest/SPMTest/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/TestApps/SPMTest/SPMTest/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/TestApps/SPMTest/SPMTest/ContentView.swift b/TestApps/SPMTest/SPMTest/ContentView.swift new file mode 100644 index 0000000..1af5552 --- /dev/null +++ b/TestApps/SPMTest/SPMTest/ContentView.swift @@ -0,0 +1,28 @@ +import SwiftUI +import PayPalMessages + +struct ContentView: View { + var message = PayPalMessageView( + config: .init( + data: .init( + clientID: "test_app", + environment: .sandbox + ) + ) + ) + + var body: some View { + VStack { + Image(systemName: "globe") + .imageScale(.large) + Text("Hello, world!") + } + .padding() + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/TestApps/SPMTest/SPMTest/Preview Content/Preview Assets.xcassets/Contents.json b/TestApps/SPMTest/SPMTest/Preview Content/Preview Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/TestApps/SPMTest/SPMTest/Preview Content/Preview Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/TestApps/SPMTest/SPMTest/SPMTestApp.swift b/TestApps/SPMTest/SPMTest/SPMTestApp.swift new file mode 100644 index 0000000..f2d1e28 --- /dev/null +++ b/TestApps/SPMTest/SPMTest/SPMTestApp.swift @@ -0,0 +1,10 @@ +import SwiftUI + +@main +struct SPMTestApp: App { + var body: some Scene { + WindowGroup { + ContentView() + } + } +} diff --git a/Tests/PayPalMessagesTests/AnyCodableTests.swift b/Tests/PayPalMessagesTests/AnyCodableTests.swift new file mode 100644 index 0000000..355380e --- /dev/null +++ b/Tests/PayPalMessagesTests/AnyCodableTests.swift @@ -0,0 +1,62 @@ +import Foundation +import XCTest +@testable import PayPalMessages + +final class AnyCodableTests: XCTestCase { + + func testInitialization() { + // Test various initializations + let intValue: AnyCodable = 42 + let stringValue: AnyCodable = "Hello, World!" + let boolValue: AnyCodable = true + + XCTAssertEqual(intValue.value as? Int, 42) + XCTAssertEqual(stringValue.value as? String, "Hello, World!") + XCTAssertEqual(boolValue.value as? Bool, true) + } + + func testEncodeInt() throws { + // Test encoding int + let intValue: AnyCodable = 42 + + let encoder = JSONEncoder() + let data = try encoder.encode(intValue) + + let jsonString = String(data: data, encoding: .utf8) + XCTAssertEqual(jsonString, "42") + } + + + func testEncodeString() throws { + // Test encoding string + let stringValue: AnyCodable = "Hello, World!" + + let encoder = JSONEncoder() + let data = try encoder.encode(stringValue) + + let jsonString = String(data: data, encoding: .utf8) + XCTAssertEqual(jsonString, "\"Hello, World!\"") + } + + func testEncodeBool() throws { + // Test encoding bool + let boolValue: AnyCodable = true + + let encoder = JSONEncoder() + let data = try encoder.encode(boolValue) + + let jsonString = String(data: data, encoding: .utf8) + XCTAssertEqual(jsonString, "true") + } + + func testEncodeNil() throws { + // Test encoding nil + let nilValue: AnyCodable = nil + + let encoder = JSONEncoder() + let data = try encoder.encode(nilValue) + + let jsonString = String(data: data, encoding: .utf8) + XCTAssertEqual(jsonString, "null") + } +} diff --git a/Tests/PayPalMessagesTests/AnyStringKeyTests.swift b/Tests/PayPalMessagesTests/AnyStringKeyTests.swift new file mode 100644 index 0000000..37c0755 --- /dev/null +++ b/Tests/PayPalMessagesTests/AnyStringKeyTests.swift @@ -0,0 +1,36 @@ +import Foundation +import XCTest +@testable import PayPalMessages + +final class AnyStringKeyTests: XCTestCase { + + func testStringKey() { + // Create an AnyStringKey instance with a string value + let key = AnyStringKey(stringValue: "testKey") + + // Verify that the stringValue matches the provided value + XCTAssertEqual(key.stringValue, "testKey") + + // Verify that intValue is nil + XCTAssertNil(key.intValue) + } + + func testStringLiteralInitialization() { + // Create an AnyStringKey instance using string literal initialization + let key: AnyStringKey = "literalKey" + + // Verify that the stringValue matches the provided string literal + XCTAssertEqual(key.stringValue, "literalKey") + + // Verify that intValue is nil + XCTAssertNil(key.intValue) + } + + func testIntValue() { + // Attempt to create an AnyStringKey instance with an intValue (should return nil) + let key = AnyStringKey(intValue: 42) + + // Verify that the instance is nil + XCTAssertNil(key) + } +} diff --git a/Tests/PayPalMessagesTests/CloseButtonTests.swift b/Tests/PayPalMessagesTests/CloseButtonTests.swift new file mode 100644 index 0000000..380ef55 --- /dev/null +++ b/Tests/PayPalMessagesTests/CloseButtonTests.swift @@ -0,0 +1,95 @@ +@testable import PayPalMessages +import XCTest + +final class CloseButtonTests: XCTestCase { + + var closeButton: CloseButton? + var onTapCalled = false + + override func setUp() { + super.setUp() + + // Initialize a CloseButton with a tap closure + closeButton = CloseButton { + self.onTapCalled = true + } + } + + override func tearDown() { + closeButton = nil + super.tearDown() + } + + func testButtonInitialization() { + guard let button = closeButton else { return } + XCTAssertNotNil(button) + XCTAssertEqual(button.alpha, 1.0) + XCTAssertEqual(button.accessibilityLabel, "Cancel") + XCTAssertEqual(button.imageView?.contentMode, .scaleAspectFit) + } + + func testButtonHighlightAnimation() { + guard let button = closeButton else { return } + // Initially, the button should not be highlighted + XCTAssertFalse(button.isHighlighted) + XCTAssertEqual(button.alpha, 1.0) + + // Simulate the button being highlighted + button.isHighlighted = true + + // Use XCTAssertEqual with a tolerance parameter + XCTAssertEqual(button.alpha, CloseButton.Constants.fadeOutAlpha, accuracy: 0.001) + + // Simulate the button being unhighlighted + button.isHighlighted = false + + // Use XCTAssertEqual with a tolerance parameter + XCTAssertEqual(button.alpha, 1.0, accuracy: 0.001) + } + + func testIntrinsicContentSize() { + guard let button = closeButton else { return } + // Calculate the expected intrinsic content size based on your constants + let expectedWidth = CloseButton.Constants.buttonSize.width + + (CloseButton.Constants.contenInset.left + CloseButton.Constants.contenInset.right) + let expectedHeight = CloseButton.Constants.buttonSize.height + + (CloseButton.Constants.contenInset.top + CloseButton.Constants.contenInset.bottom) + + // Get the actual intrinsic content size from the button + let intrinsicSize = button.intrinsicContentSize + + // Assert that the actual intrinsic content size matches the expected size + XCTAssertEqual(intrinsicSize.width, expectedWidth) + XCTAssertEqual(intrinsicSize.height, expectedHeight) + } + + func testInitWithoutClosure() { + guard let button = closeButton else { return } + // Initialize a CloseButton using the init() method + closeButton = CloseButton() + + // Assert that the button is not nil + XCTAssertNotNil(closeButton) + + // Assert that the button is properly configured + XCTAssertEqual(button.alpha, 1.0) + XCTAssertEqual(button.accessibilityLabel, "Cancel") + XCTAssertEqual(button.imageView?.contentMode, .scaleAspectFit) + } + + func testTappedCloseButtonCallsOnTap() { + // Create a CloseButton instance + let closeButton = CloseButton() + + // Assign an onTap closure to the CloseButton + closeButton.onTap = { + self.onTapCalled = true + } + + // Simulate tapping the CloseButton + closeButton.tappedCloseButton(closeButton) + + // Verify that onTap was called + XCTAssertTrue(onTapCalled) + } +} diff --git a/Tests/PayPalMessagesTests/EnvironmentTests.swift b/Tests/PayPalMessagesTests/EnvironmentTests.swift new file mode 100644 index 0000000..8307d2b --- /dev/null +++ b/Tests/PayPalMessagesTests/EnvironmentTests.swift @@ -0,0 +1,32 @@ +import Foundation +import XCTest +@testable import PayPalMessages + +final class EnvironmentTests: XCTestCase { + + // Test rawValue correctness + func testRawValues() { + XCTAssertEqual(Environment.develop(host: "testhost").rawValue, "develop") + XCTAssertEqual(Environment.sandbox.rawValue, "sandbox") + XCTAssertEqual(Environment.live.rawValue, "production") + } + + // Test environment setting + func testEnvironmentSetting() { + XCTAssertTrue(Environment.live.isProduction) + XCTAssertTrue(Environment.sandbox.isProduction) + XCTAssertFalse(Environment.develop(host: "testhost").isProduction) + } + + // Test URL construction + func testURLConstruction() { + let stageURL = Environment.develop(host: "testhost").url(.modal, ["param": "value"]) + XCTAssertEqual(stageURL?.absoluteString, "https://www.testhost/credit-presentment/lander/modal?param=value") + + let sandboxURL = Environment.sandbox.url(.merchantProfile) + XCTAssertEqual(sandboxURL?.absoluteString, "https://www.sandbox.paypal.com/credit-presentment/merchant-profile") + + let liveURL = Environment.live.url(.log) + XCTAssertEqual(liveURL?.absoluteString, "https://api.paypal.com/v1/credit/upstream-messaging-events") + } +} diff --git a/Tests/PayPalMessagesTests/MerchantProfileProviderTests.swift b/Tests/PayPalMessagesTests/MerchantProfileProviderTests.swift index a48f002..e30a61a 100644 --- a/Tests/PayPalMessagesTests/MerchantProfileProviderTests.swift +++ b/Tests/PayPalMessagesTests/MerchantProfileProviderTests.swift @@ -4,12 +4,19 @@ import XCTest final class MerchantProfileProviderTests: XCTestCase { + let clientID = "testclientid" + let clientID2 = "testclientid2" + let merchantID = "testmerchantid" + let merchantID2 = "testmerchantid2" + override func setUp() { super.setUp() - UserDefaults.standard.removeObject( - forKey: UserDefaults.Key.merchantProfileData.rawValue - ) + // Clear out merchant profile cache + let dictionary = UserDefaults.standard.dictionaryRepresentation() + for key in dictionary.keys { + UserDefaults.standard.removeObject(forKey: key) + } } // MARK: - Tests @@ -23,7 +30,7 @@ final class MerchantProfileProviderTests: XCTestCase { XCTAssertEqual(requestMock.requestsPerformed, 0) // retrieve hash and check requests performed - provider.getMerchantProfileHash(environment: .live, clientID: "testclientid") { hash in + provider.getMerchantProfileHash(environment: .live, clientID: clientID, merchantID: merchantID) { hash in XCTAssertNotNil(hash) XCTAssertEqual(requestMock.requestsPerformed, 1) } @@ -35,32 +42,64 @@ final class MerchantProfileProviderTests: XCTestCase { let provider = MerchantProfileProvider(merchantProfileRequest: requestMock) // retrieve hash and check requests performed - provider.getMerchantProfileHash(environment: .live, clientID: "testclientid") { hash in + provider.getMerchantProfileHash(environment: .live, clientID: clientID, merchantID: merchantID) { hash in let firstHash = hash XCTAssertNotNil(hash) XCTAssertEqual(requestMock.requestsPerformed, 1) // after retrieving it again, the hash should not be empty -- and no new request performed - provider.getMerchantProfileHash(environment: .live, clientID: "testclientid") { secondHash in + provider.getMerchantProfileHash(environment: .live, clientID: self.clientID, merchantID: self.merchantID) { secondHash in XCTAssertEqual(firstHash, secondHash) XCTAssertEqual(requestMock.requestsPerformed, 1) } } } + func testCacheMissWhenDifferentMerchant() { + let requestMock = MerchantProfileRequestMock(scenario: .success) + let provider = MerchantProfileProvider(merchantProfileRequest: requestMock) + + + provider.getMerchantProfileHash(environment: .live, clientID: clientID, merchantID: nil) { hash in + let firstHash = hash + XCTAssertNotNil(hash) + XCTAssertEqual(requestMock.requestsPerformed, 1) + + provider.getMerchantProfileHash(environment: .live, clientID: self.clientID2, merchantID: nil) { secondHash in + XCTAssertNotEqual(firstHash, secondHash) + XCTAssertEqual(requestMock.requestsPerformed, 2) + + provider.getMerchantProfileHash(environment: .live, clientID: self.clientID, merchantID: self.merchantID) { hash in + let firstHash = hash + XCTAssertNotNil(hash) + XCTAssertEqual(requestMock.requestsPerformed, 3) + + provider.getMerchantProfileHash( + environment: .live, + clientID: self.clientID, + merchantID: self.merchantID2 + ) { secondHash in + XCTAssertNotEqual(firstHash, secondHash) + XCTAssertEqual(requestMock.requestsPerformed, 4) + } + } + } + } + } + // simulates a request with soft ttl expired, returns value but performs additional request func testTtlSoftExpired() { let requestMock = MerchantProfileRequestMock(scenario: .ttlSoftExpired) let provider = MerchantProfileProvider(merchantProfileRequest: requestMock) // perform first request - provider.getMerchantProfileHash(environment: .live, clientID: "testclientid") { hash in + provider.getMerchantProfileHash(environment: .live, clientID: clientID, merchantID: merchantID) { hash in let firstHash = hash XCTAssertNotNil(hash) XCTAssertEqual(requestMock.requestsPerformed, 1) // perform another request, cached value will be returned but another request perfoms on background - provider.getMerchantProfileHash(environment: .live, clientID: "testclientid") { secondHash in + provider.getMerchantProfileHash(environment: .live, clientID: self.clientID, merchantID: self.merchantID) { secondHash in XCTAssertEqual(firstHash, secondHash) XCTAssertEqual(requestMock.requestsPerformed, 2) } @@ -73,13 +112,13 @@ final class MerchantProfileProviderTests: XCTestCase { let provider = MerchantProfileProvider(merchantProfileRequest: requestMock) // perform first request - provider.getMerchantProfileHash(environment: .live, clientID: "testclientid") { hash in + provider.getMerchantProfileHash(environment: .live, clientID: clientID, merchantID: merchantID) { hash in let firstHash = hash XCTAssertNotNil(hash) XCTAssertEqual(requestMock.requestsPerformed, 1) // perform another request, new request performed - provider.getMerchantProfileHash(environment: .live, clientID: "testclientid") { secondHash in + provider.getMerchantProfileHash(environment: .live, clientID: self.clientID, merchantID: self.merchantID) { secondHash in XCTAssertNotEqual(firstHash, secondHash) XCTAssertEqual(requestMock.requestsPerformed, 2) } @@ -93,11 +132,11 @@ final class MerchantProfileProviderTests: XCTestCase { let provider = MerchantProfileProvider(merchantProfileRequest: requestMock) // perform first request -- null expected - provider.getMerchantProfileHash(environment: .live, clientID: "testclientid") { hash in + provider.getMerchantProfileHash(environment: .live, clientID: clientID, merchantID: merchantID) { hash in XCTAssertNil(hash) // perform another request, null expected and used cached result - provider.getMerchantProfileHash(environment: .live, clientID: "testclientid") { hash in + provider.getMerchantProfileHash(environment: .live, clientID: self.clientID, merchantID: self.merchantID) { hash in XCTAssertNil(hash) XCTAssertEqual(requestMock.requestsPerformed, 1) } @@ -110,11 +149,11 @@ final class MerchantProfileProviderTests: XCTestCase { let provider = MerchantProfileProvider(merchantProfileRequest: requestMock) // perform first request -- null expected - provider.getMerchantProfileHash(environment: .live, clientID: "testclientid") { hash in + provider.getMerchantProfileHash(environment: .live, clientID: clientID, merchantID: merchantID) { hash in XCTAssertNil(hash) // perform another request, null expected and new request performed - provider.getMerchantProfileHash(environment: .live, clientID: "testclientid") { hash in + provider.getMerchantProfileHash(environment: .live, clientID: self.clientID, merchantID: self.merchantID) { hash in XCTAssertNil(hash) XCTAssertEqual(requestMock.requestsPerformed, 2) } diff --git a/Tests/PayPalMessagesTests/Mocks/MerchantProfileRequestMock.swift b/Tests/PayPalMessagesTests/Mocks/MerchantProfileRequestMock.swift index f9eb736..66c38c2 100644 --- a/Tests/PayPalMessagesTests/Mocks/MerchantProfileRequestMock.swift +++ b/Tests/PayPalMessagesTests/Mocks/MerchantProfileRequestMock.swift @@ -34,6 +34,7 @@ class MerchantProfileRequestMock: MerchantProfileRequestable { func fetchMerchantProfile( environment: Environment, clientID: String, + merchantID: String?, onCompletion: @escaping (Result) -> Void ) { requestsPerformed += 1 diff --git a/Tests/PayPalMessagesTests/Mocks/PayPalMessageLogSenderMock.swift b/Tests/PayPalMessagesTests/Mocks/PayPalMessageLogSenderMock.swift index cf30978..efda147 100644 --- a/Tests/PayPalMessagesTests/Mocks/PayPalMessageLogSenderMock.swift +++ b/Tests/PayPalMessagesTests/Mocks/PayPalMessageLogSenderMock.swift @@ -3,9 +3,13 @@ import Foundation class LogSenderMock: LogSendable { - var data: Data? + var calls: [Data] = [] func send(_ data: Data, to environement: Environment) { - self.data = data + self.calls.append(data) + } + + func reset() { + self.calls = [] } } diff --git a/Tests/PayPalMessagesTests/Mocks/PayPalMessageMerchantProviderMock.swift b/Tests/PayPalMessagesTests/Mocks/PayPalMessageMerchantProviderMock.swift index 96f077e..0bf4bb4 100644 --- a/Tests/PayPalMessagesTests/Mocks/PayPalMessageMerchantProviderMock.swift +++ b/Tests/PayPalMessagesTests/Mocks/PayPalMessageMerchantProviderMock.swift @@ -10,13 +10,14 @@ class MerchantProfileProviderMock: MerchantProfileHashGetable { var scenario: Scenarios - init(_ scenario: Scenarios) { + init(scenario: Scenarios) { self.scenario = scenario } func getMerchantProfileHash( environment: Environment, clientID: String, + merchantID: String?, onCompletion: @escaping (String?) -> Void ) { switch scenario { diff --git a/Tests/PayPalMessagesTests/Mocks/PayPalMessageModalMocks.swift b/Tests/PayPalMessagesTests/Mocks/PayPalMessageModalMocks.swift index dae8983..9bdef65 100644 --- a/Tests/PayPalMessagesTests/Mocks/PayPalMessageModalMocks.swift +++ b/Tests/PayPalMessagesTests/Mocks/PayPalMessageModalMocks.swift @@ -5,7 +5,7 @@ class PayPalMessageModalStateDelegateMock: PayPalMessageModalStateDelegate { var onErrorCalled = false var onLoadingCalled = false - var onSuccussCalled = false + var onSuccessCalled = false func onError(_ modal: PayPalMessageModal, error: PayPalMessageError) { onErrorCalled = true @@ -16,7 +16,7 @@ class PayPalMessageModalStateDelegateMock: PayPalMessageModalStateDelegate { } func onSuccess(_ modal: PayPalMessageModal) { - onSuccussCalled = true + onSuccessCalled = true } } @@ -40,11 +40,11 @@ class PayPalMessageModalEventDelegateMock: PayPalMessageModalEventDelegate { } func onShow(_ modal: PayPalMessageModal) { - onShowCalled = false + onShowCalled = true } func onClose(_ modal: PayPalMessageModal) { - onCloseCalled = false + onCloseCalled = true } } diff --git a/Tests/PayPalMessagesTests/Mocks/PayPalMessageRequestMock.swift b/Tests/PayPalMessagesTests/Mocks/PayPalMessageRequestMock.swift index 07d1085..51de7a8 100644 --- a/Tests/PayPalMessagesTests/Mocks/PayPalMessageRequestMock.swift +++ b/Tests/PayPalMessagesTests/Mocks/PayPalMessageRequestMock.swift @@ -4,7 +4,7 @@ import Foundation class PayPalMessageRequestMock: MessageRequestable { enum Scenarios { - case success + case success(messageResponse: MessageResponse? = nil) case neverComplete case error(paypalDebugID: String?) } @@ -47,12 +47,18 @@ class PayPalMessageRequestMock: MessageRequestable { return nil } + if case .success(messageResponse: let messageResponse) = scenario, let messageResponse { + return messageResponse + } + return MessageResponse( offerType: makeOfferResponseType(fromParams: lastParamsReceived), productGroup: makeProductGroup(fromParams: lastParamsReceived), defaultMainContent: "", + defaultMainAlternative: nil, defaultDisclaimer: "", genericMainContent: "", + genericMainAlternative: nil, genericDisclaimer: "", logoPlaceholder: "", modalCloseButtonWidth: 25, @@ -60,7 +66,8 @@ class PayPalMessageRequestMock: MessageRequestable { modalCloseButtonAvailWidth: 60, modalCloseButtonAvailHeight: 60, modalCloseButtonColor: "#2d2d2d", - modalCloseButtonColorType: "DARK" + modalCloseButtonColorType: "DARK", + modalCloseButtonAlternativeText: "" ) } diff --git a/Tests/PayPalMessagesTests/Mocks/PayPalMessageViewMock.swift b/Tests/PayPalMessagesTests/Mocks/PayPalMessageViewMock.swift index 18e56d5..11dff36 100644 --- a/Tests/PayPalMessagesTests/Mocks/PayPalMessageViewMock.swift +++ b/Tests/PayPalMessagesTests/Mocks/PayPalMessageViewMock.swift @@ -6,7 +6,7 @@ class PayPalMessageViewMock: PayPalMessageViewModelDelegate { weak var viewModel: PayPalMessageViewModel? var refreshContentCalled = false - func refreshContent() { + func refreshContent(messageParameters: PayPalMessageViewParameters?) { refreshContentCalled = true } } diff --git a/Tests/PayPalMessagesTests/PayPalMessageAttributedStringTests.swift b/Tests/PayPalMessagesTests/PayPalMessageAttributedStringTests.swift index d67267f..1863c1b 100644 --- a/Tests/PayPalMessagesTests/PayPalMessageAttributedStringTests.swift +++ b/Tests/PayPalMessagesTests/PayPalMessageAttributedStringTests.swift @@ -31,7 +31,10 @@ final class PayPalMessageAttributedStringTests: XCTestCase { linkDescription: testLinkDescription, linkColor: .blue, linkUnderlineColor: .blue, - textAlignment: .left + textAlign: .left, + accessibilityLabel: "Pay in several installments with PayPal. Learn More", + accessibilityTraits: .button, + isAccessibilityElement: true ) } diff --git a/Tests/PayPalMessagesTests/PayPalMessageConfigTests.swift b/Tests/PayPalMessagesTests/PayPalMessageConfigTests.swift new file mode 100644 index 0000000..3fe28ab --- /dev/null +++ b/Tests/PayPalMessagesTests/PayPalMessageConfigTests.swift @@ -0,0 +1,83 @@ +import Foundation +import XCTest +@testable import PayPalMessages + +final class PayPalMessageConfigTests: XCTestCase { + + func testSetGlobalAnalytics() { + let integrationName = "MyIntegration" + let integrationVersion = "1.0" + + PayPalMessageModalConfig.setGlobalAnalytics( + integrationName: integrationName, + integrationVersion: integrationVersion + ) + + XCTAssertEqual(AnalyticsLogger.integrationName, integrationName) + XCTAssertEqual(AnalyticsLogger.integrationVersion, integrationVersion) + } + + func testStandardIntegrationInitialization() { + let clientID = "Client123" + let amount = 100.0 + let pageType = PayPalMessagePageType.home + let offerType = PayPalMessageOfferType.payLaterShortTerm + let environment = Environment.sandbox + + let data = PayPalMessageData( + clientID: clientID, + environment: environment, + amount: amount, + pageType: pageType, + offerType: offerType + ) + + let style = PayPalMessageStyle(logoType: .inline, color: .black, textAlign: .right) + let config = PayPalMessageConfig(data: data, style: style) + + XCTAssertEqual(config.data.clientID, clientID) + XCTAssertEqual(config.data.amount, amount) + XCTAssertEqual(config.data.pageType, pageType) + XCTAssertEqual(config.data.offerType, offerType) + XCTAssertEqual(config.data.environment, environment) + + XCTAssertEqual(config.style.logoType, .inline) + XCTAssertEqual(config.style.color, .black) + XCTAssertEqual(config.style.textAlign, .right) + } + + func testPartnerIntegrationInitialization() { + let clientID = "Client123" + let merchantID = "Merchant456" + let partnerAttributionID = "Partner789" + let amount = 100.0 + let pageType = PayPalMessagePageType.home + let offerType = PayPalMessageOfferType.payLaterShortTerm + let environment = Environment.sandbox + + let data = PayPalMessageData( + clientID: clientID, + merchantID: merchantID, + environment: environment, + partnerAttributionID: partnerAttributionID, + amount: amount, + pageType: pageType, + offerType: offerType + ) + + let style = PayPalMessageStyle(logoType: .inline, color: .black, textAlign: .right) + let config = PayPalMessageConfig(data: data, style: style) + + XCTAssertEqual(config.data.clientID, clientID) + XCTAssertEqual(config.data.merchantID, merchantID) + XCTAssertEqual(config.data.partnerAttributionID, partnerAttributionID) + XCTAssertEqual(config.data.amount, amount) + XCTAssertEqual(config.data.pageType, pageType) + XCTAssertEqual(config.data.offerType, offerType) + XCTAssertEqual(config.data.environment, environment) + + XCTAssertEqual(config.style.logoType, .inline) + XCTAssertEqual(config.style.color, .black) + XCTAssertEqual(config.style.textAlign, .right) + } +} diff --git a/Tests/PayPalMessagesTests/PayPalMessageLoggerTests.swift b/Tests/PayPalMessagesTests/PayPalMessageLoggerTests.swift index 0e92f6f..38d1c71 100644 --- a/Tests/PayPalMessagesTests/PayPalMessageLoggerTests.swift +++ b/Tests/PayPalMessagesTests/PayPalMessageLoggerTests.swift @@ -6,31 +6,54 @@ import XCTest final class PayPalMessageLoggerTests: XCTestCase { let mockSender = LogSenderMock() - let logger = Logger.get(for: "testclientid", in: .live) + let message = PayPalMessageView( + config: .init( + data: .init( + clientID: "testloggerclientid", + environment: .live, + amount: 50.0, + pageType: .productDetails, + offerType: .payLaterLongTerm + ), + style: .init( + logoType: .inline, + color: .black, + textAlign: .left + ) + ), + requester: PayPalMessageRequestMock(scenario: .success()), + merchantProfileProvider: MerchantProfileProviderMock(scenario: .success) + ) + let modal = PayPalMessageModal( + config: .init( + data: .init( + clientID: "testloggerclientid", + environment: .live, + amount: 50.0, + pageType: .productDetails, + offerType: .payLaterLongTerm + ) + ) + ) override func setUp() { super.setUp() - Logger.integrationName = "Test_SDK" - Logger.integrationVersion = "0.1.0" - Logger.deviceID = "987654321" - Logger.sessionID = "123456789" + BuildInfo.version = "1.0.0" + + PayPalMessageConfig.setGlobalAnalytics( + integrationName: "Test_SDK", + integrationVersion: "0.1.0" + ) // Inject mock sender to intercept log requests - logger.sender = mockSender + AnalyticsService.shared.sender = mockSender + AnalyticsService.shared.loggers = [] } + // swiftlint:disable:next function_body_length func testMessageLoggerEvents() { - let messageLogger = Logger.createMessageLogger( - environment: .live, - clientID: "testclientid", - offerType: .payLaterLongTerm, - amount: 50.0, - placement: .product, - styleColor: .black, - styleLogoType: .inline, - styleTextAlign: .left - ) + let messageLogger = AnalyticsLogger(.message(Weak(message))) messageLogger.dynamicData = [ "string_key": "hello", @@ -40,42 +63,60 @@ final class PayPalMessageLoggerTests: XCTestCase { messageLogger.addEvent(.messageRender(renderDuration: 10, requestDuration: 15)) messageLogger.addEvent(.messageClick(linkName: "linkName", linkSrc: "linkSrc")) + messageLogger.addEvent(.messageError(errorName: "errorName", errorDescription: "errorDescription")) - logger.flushEvents() + AnalyticsService.shared.flushEvents() - guard let data = mockSender.data, + guard let data = mockSender.calls.last, let data = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { return XCTFail("invalid JSON data") } let expectedPayload: [String: Any] = [ - "integration_type": "NATIVE_IOS", - "client_id": "testclientid", - "integration_version": "0.1.0", - "device_id": "987654321", - "session_id": "123456789", - "components": [ - [ - "amount": 50, - "offer_type": "PAY_LATER_LONG_TERM", - "placement": "product", - "type": "message", - "number_key": 50.5, - "string_key": "hello", - "boolean_key": true, - "style_logo_type": "inline", - "style_color": "black", - "style_text_align": "left", - "events": [ - [ - "event_type": "message_rendered", - "render_duration": 10, - "request_duration": 15 - ], - [ - "event_type": "message_clicked", - "link_name": "linkName", - "link_src": "linkSrc" + "specversion": "1.0", + "id": "123456789", + "type": "com.paypal.credit.upstream-presentment.v1", + "source": "urn:paypal:event-src:v1:ios:messages", + "datacontenttype": "application/json", + // swiftlint:disable:next line_length + "dataschema": "ppaas:events.credit.FinancingPresentmentAsyncAPISpecification/v1/schema/json/credit_upstream_presentment_event.json", + "time": "2023-11-01T11:12:05.791-0400", + "data": [ + "lib_version": "1.0.0", + "integration_name": "Test_SDK", + "integration_type": "NATIVE_IOS", + "client_id": "testloggerclientid", + "merchant_profile_hash": "TEST_HASH", + "integration_version": "0.1.0", + "components": [ + [ + "amount": "50.0", + "offer_type": "PAY_LATER_LONG_TERM", + "presentment_channel": "UPSTREAM", + "page_type": "product-details", + "type": "message", + "number_key": 50.5, + "string_key": "hello", + "boolean_key": true, + "style_logo_type": "inline", + "style_color": "black", + "style_text_align": "left", + "component_events": [ + [ + "event_type": "message_rendered", + "render_duration": "10", + "request_duration": "15" + ], + [ + "event_type": "message_clicked", + "page_view_link_name": "linkName", + "page_view_link_source": "linkSrc" + ], + [ + "event_type": "message_error", + "error_name": "errorName", + "error_description": "errorDescription" + ] ] ] ] @@ -86,13 +127,7 @@ final class PayPalMessageLoggerTests: XCTestCase { } func testModalLoggerEvents() { - let modalLogger = Logger.createModalLogger( - environment: .live, - clientID: "testclientid", - offerType: .payLaterLongTerm, - amount: 50.0, - placement: .product - ) + let modalLogger = AnalyticsLogger(.modal(Weak(modal))) modalLogger.dynamicData = [ "string_key": "hello", @@ -109,36 +144,47 @@ final class PayPalMessageLoggerTests: XCTestCase { "other_key": 100 ])) - logger.flushEvents() + AnalyticsService.shared.flushEvents() - guard let data = mockSender.data, + guard let data = mockSender.calls.last, let data = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { return XCTFail("invalid JSON data") } let expectedPayload: [String: Any] = [ - "integration_type": "NATIVE_IOS", - "client_id": "testclientid", - "integration_version": "0.1.0", - "device_id": "987654321", - "session_id": "123456789", - "components": [ - [ - "amount": 50, - "offer_type": "PAY_LATER_LONG_TERM", - "placement": "product", - "type": "modal", - "number_key": 50.5, - "string_key": "hello", - "boolean_key": true, - "events": [ - [ - "event_type": "modal_click", - "some_key": "test" - ], - [ - "event_type": "modal_open", - "other_key": 100 + "specversion": "1.0", + "id": "123456789", + "type": "com.paypal.credit.upstream-presentment.v1", + "source": "urn:paypal:event-src:v1:ios:messages", + "datacontenttype": "application/json", + // swiftlint:disable:next line_length + "dataschema": "ppaas:events.credit.FinancingPresentmentAsyncAPISpecification/v1/schema/json/credit_upstream_presentment_event.json", + "time": "2023-11-01T11:12:05.791-0400", + "data": [ + "lib_version": "1.0.0", + "integration_name": "Test_SDK", + "integration_type": "NATIVE_IOS", + "client_id": "testloggerclientid", + "integration_version": "0.1.0", + "components": [ + [ + "amount": "50.0", + "offer_type": "PAY_LATER_LONG_TERM", + "presentment_channel": "UPSTREAM", + "page_type": "product-details", + "type": "modal", + "number_key": 50.5, + "string_key": "hello", + "boolean_key": true, + "component_events": [ + [ + "event_type": "modal_click", + "some_key": "test" + ], + [ + "event_type": "modal_open", + "other_key": 100 + ] ] ] ] @@ -150,23 +196,8 @@ final class PayPalMessageLoggerTests: XCTestCase { // swiftlint:disable:next function_body_length func testMultipleComponentEvents() { - let messageLogger = Logger.createMessageLogger( - environment: .live, - clientID: "testclientid", - offerType: .payLaterLongTerm, - amount: 50.0, - placement: .product, - styleColor: .black, - styleLogoType: .inline, - styleTextAlign: .left - ) - let modalLogger = Logger.createModalLogger( - environment: .live, - clientID: "testclientid", - offerType: .payLaterLongTerm, - amount: 50.0, - placement: .product - ) + let messageLogger = AnalyticsLogger(.message(Weak(message))) + let modalLogger = AnalyticsLogger(.modal(Weak(modal))) messageLogger.dynamicData = [ "string_key": "hello" @@ -181,47 +212,60 @@ final class PayPalMessageLoggerTests: XCTestCase { "some_key": "test" ])) - logger.flushEvents() + AnalyticsService.shared.flushEvents() - guard let data = mockSender.data, + guard let data = mockSender.calls.last, let data = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { return XCTFail("invalid JSON data") } let expectedPayload: [String: Any] = [ - "integration_type": "NATIVE_IOS", - "client_id": "testclientid", - "integration_version": "0.1.0", - "device_id": "987654321", - "session_id": "123456789", - "components": [ - [ - "amount": 50, - "offer_type": "PAY_LATER_LONG_TERM", - "placement": "product", - "type": "message", - "string_key": "hello", - "style_logo_type": "inline", - "style_color": "black", - "style_text_align": "left", - "events": [ - [ - "event_type": "message_rendered", - "render_duration": 10, - "request_duration": 15 + "specversion": "1.0", + "id": "123456789", + "type": "com.paypal.credit.upstream-presentment.v1", + "source": "urn:paypal:event-src:v1:ios:messages", + "datacontenttype": "application/json", + // swiftlint:disable:next line_length + "dataschema": "ppaas:events.credit.FinancingPresentmentAsyncAPISpecification/v1/schema/json/credit_upstream_presentment_event.json", + "time": "2023-11-01T11:12:05.791-0400", + "data": [ + "lib_version": "1.0.0", + "integration_name": "Test_SDK", + "integration_type": "NATIVE_IOS", + "client_id": "testloggerclientid", + "merchant_profile_hash": "TEST_HASH", + "integration_version": "0.1.0", + "components": [ + [ + "amount": "50.0", + "offer_type": "PAY_LATER_LONG_TERM", + "presentment_channel": "UPSTREAM", + "page_type": "product-details", + "type": "message", + "string_key": "hello", + "style_logo_type": "inline", + "style_color": "black", + "style_text_align": "left", + "component_events": [ + [ + "event_type": "message_rendered", + "render_duration": "10", + "request_duration": "15" + ] ] - ] - ], - [ - "amount": 50, - "offer_type": "PAY_LATER_LONG_TERM", - "placement": "product", - "type": "modal", - "string_key": "world", - "events": [ - [ - "event_type": "modal_click", - "some_key": "test" + ], + [ + "amount": "50.0", + "offer_type": "PAY_LATER_LONG_TERM", + "presentment_channel": "UPSTREAM", + "page_type": "product-details", + "type": "modal", + "string_key": "world", + "component_events": [ + [ + "event_type": "modal_click", + "some_key": "test" + ] ] ] ] @@ -232,53 +276,50 @@ final class PayPalMessageLoggerTests: XCTestCase { } func testFiltersComponentsWithNoEvents() { - let messageLogger = Logger.createMessageLogger( - environment: .live, - clientID: "testclientid", - offerType: .payLaterLongTerm, - amount: 50.0, - placement: .product, - styleColor: .black, - styleLogoType: .inline, - styleTextAlign: .left - ) - _ = Logger.createModalLogger( - environment: .live, - clientID: "testclientid", - offerType: .payLaterLongTerm, - amount: 50.0, - placement: .product - ) + let messageLogger = AnalyticsLogger(.message(Weak(message))) + _ = AnalyticsLogger(.modal(Weak(modal))) messageLogger.addEvent(.messageRender(renderDuration: 10, requestDuration: 15)) - logger.flushEvents() + AnalyticsService.shared.flushEvents() - guard let data = mockSender.data, + guard let data = mockSender.calls.last, let data = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { return XCTFail("invalid JSON data") } let expectedPayload: [String: Any] = [ - "integration_type": "NATIVE_IOS", - "client_id": "testclientid", - "integration_version": "0.1.0", - "device_id": "987654321", - "session_id": "123456789", - "components": [ - [ - "amount": 50, - "offer_type": "PAY_LATER_LONG_TERM", - "placement": "product", - "type": "message", - "style_logo_type": "inline", - "style_color": "black", - "style_text_align": "left", - "events": [ - [ - "event_type": "message_rendered", - "render_duration": 10, - "request_duration": 15 + "specversion": "1.0", + "id": "123456789", + "type": "com.paypal.credit.upstream-presentment.v1", + "source": "urn:paypal:event-src:v1:ios:messages", + "datacontenttype": "application/json", + // swiftlint:disable:next line_length + "dataschema": "ppaas:events.credit.FinancingPresentmentAsyncAPISpecification/v1/schema/json/credit_upstream_presentment_event.json", + "time": "2023-11-01T11:12:05.791-0400", + "data": [ + "lib_version": "1.0.0", + "integration_name": "Test_SDK", + "integration_type": "NATIVE_IOS", + "client_id": "testloggerclientid", + "merchant_profile_hash": "TEST_HASH", + "integration_version": "0.1.0", + "components": [ + [ + "amount": "50.0", + "offer_type": "PAY_LATER_LONG_TERM", + "presentment_channel": "UPSTREAM", + "page_type": "product-details", + "type": "message", + "style_logo_type": "inline", + "style_color": "black", + "style_text_align": "left", + "component_events": [ + [ + "event_type": "message_rendered", + "render_duration": "10", + "request_duration": "15" + ] ] ] ] @@ -289,50 +330,119 @@ final class PayPalMessageLoggerTests: XCTestCase { } func testClearsEventsAfterFlush() { - let messageLogger = Logger.createMessageLogger( - environment: .live, - clientID: "testclientid", - offerType: .payLaterLongTerm, - amount: 50.0, - placement: .product, - styleColor: .black, - styleLogoType: .inline, - styleTextAlign: .left - ) + let messageLogger = AnalyticsLogger(.message(Weak(message))) messageLogger.addEvent(.messageRender(renderDuration: 10, requestDuration: 15)) - logger.flushEvents() + AnalyticsService.shared.flushEvents() messageLogger.addEvent(.messageClick(linkName: "linkName", linkSrc: "linkSrc")) - logger.flushEvents() + AnalyticsService.shared.flushEvents() + + guard let data = mockSender.calls.last, + let data = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { + return XCTFail("invalid JSON data") + } + + let expectedPayload: [String: Any] = [ + "specversion": "1.0", + "id": "123456789", + "type": "com.paypal.credit.upstream-presentment.v1", + "source": "urn:paypal:event-src:v1:ios:messages", + "datacontenttype": "application/json", + // swiftlint:disable:next line_length + "dataschema": "ppaas:events.credit.FinancingPresentmentAsyncAPISpecification/v1/schema/json/credit_upstream_presentment_event.json", + "time": "2023-11-01T11:12:05.791-0400", + "data": [ + "lib_version": "1.0.0", + "integration_name": "Test_SDK", + "integration_type": "NATIVE_IOS", + "client_id": "testloggerclientid", + "merchant_profile_hash": "TEST_HASH", + "integration_version": "0.1.0", + "components": [ + [ + "amount": "50.0", + "offer_type": "PAY_LATER_LONG_TERM", + "presentment_channel": "UPSTREAM", + "page_type": "product-details", + "type": "message", + "style_logo_type": "inline", + "style_color": "black", + "style_text_align": "left", + "component_events": [ + [ + "event_type": "message_clicked", + "page_view_link_name": "linkName", + "page_view_link_source": "linkSrc" + ] + ] + ] + ] + ] + ] + + assert(payload: data, equals: expectedPayload) + + mockSender.reset() + + AnalyticsService.shared.flushEvents() + + XCTAssertNil(mockSender.calls.last) + } + + func testUpdatesWhenMessagePropertiesChange() { + let messageLogger = AnalyticsLogger(.message(Weak(message))) + + messageLogger.addEvent(.messageRender(renderDuration: 10, requestDuration: 15)) + + AnalyticsService.shared.flushEvents() + + message.amount = 100.0 + message.clientID = "testloggerclientid2" + + messageLogger.addEvent(.messageRender(renderDuration: 10, requestDuration: 15)) + + AnalyticsService.shared.flushEvents() - guard let data = mockSender.data, + guard let data = mockSender.calls.last, let data = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { return XCTFail("invalid JSON data") } let expectedPayload: [String: Any] = [ - "integration_type": "NATIVE_IOS", - "client_id": "testclientid", - "integration_version": "0.1.0", - "device_id": "987654321", - "session_id": "123456789", - "components": [ - [ - "amount": 50, - "offer_type": "PAY_LATER_LONG_TERM", - "placement": "product", - "type": "message", - "style_logo_type": "inline", - "style_color": "black", - "style_text_align": "left", - "events": [ - [ - "event_type": "message_clicked", - "link_name": "linkName", - "link_src": "linkSrc" + "specversion": "1.0", + "id": "123456789", + "type": "com.paypal.credit.upstream-presentment.v1", + "source": "urn:paypal:event-src:v1:ios:messages", + "datacontenttype": "application/json", + // swiftlint:disable:next line_length + "dataschema": "ppaas:events.credit.FinancingPresentmentAsyncAPISpecification/v1/schema/json/credit_upstream_presentment_event.json", + "time": "2023-11-01T11:12:05.791-0400", + "data": [ + "lib_version": "1.0.0", + "integration_name": "Test_SDK", + "integration_type": "NATIVE_IOS", + "client_id": "testloggerclientid2", + "merchant_profile_hash": "TEST_HASH", + "integration_version": "0.1.0", + "components": [ + [ + "amount": "100.0", + "offer_type": "PAY_LATER_LONG_TERM", + "presentment_channel": "UPSTREAM", + "page_type": "product-details", + "type": "message", + "style_logo_type": "inline", + "style_color": "black", + "style_text_align": "left", + "component_events": [ + [ + "event_type": "message_rendered", + "render_duration": "10", + "request_duration": "15" + ] ] ] ] @@ -340,20 +450,54 @@ final class PayPalMessageLoggerTests: XCTestCase { ] assert(payload: data, equals: expectedPayload) + } + + func testSendsSeparatePayloadsForDifferentClientIDs() { + let messageLogger = AnalyticsLogger(.message(Weak(message))) + let modalLogger = AnalyticsLogger(.modal(Weak(modal))) - mockSender.data = nil + messageLogger.addEvent(.messageRender(renderDuration: 10, requestDuration: 15)) + modalLogger.addEvent(.dynamic(data: [ + "event_type": "modal_click", + "some_key": "test" + ])) - logger.flushEvents() + message.clientID = "testloggerclientid2" + modal.clientID = "testloggerclientid3" - XCTAssertNil(mockSender.data) + AnalyticsService.shared.flushEvents() + + XCTAssert(mockSender.calls.count == 2) + + let data1 = mockSender.calls[0] + let data2 = mockSender.calls[1] + + guard let data1 = try? JSONSerialization.jsonObject(with: data1) as? [String: Any], + let data2 = try? JSONSerialization.jsonObject(with: data2) as? [String: Any] else { + return XCTFail("invalid JSON data") + } + + let clientID1 = (data1["data"] as? [String: Any])?["client_id"] as? String + let clientID2 = (data2["data"] as? [String: Any])?["client_id"] as? String + + XCTAssert(clientID1 != clientID2) + XCTAssert(clientID1 == "testloggerclientid2" || clientID2 == "testloggerclientid2") + XCTAssert(clientID1 == "testloggerclientid3" || clientID2 == "testloggerclientid3") } // MARK: - Helper assert functions private func assert(payload: [String: Any], equals expectedPayload: [String: Any]) { var data = payload + var expected = expectedPayload - guard var components = data["components"] as? [[String: Any]] else { + // Extract logger data from CloudEvent + guard var loggerData = data["data"] as? [String: Any] else { + return XCTFail("missing logger data within CloudEvent") + } + + // Extract components from logger data + guard var components = loggerData["components"] as? [[String: Any]] else { return XCTFail("missing components") } @@ -367,9 +511,27 @@ final class PayPalMessageLoggerTests: XCTestCase { components[index] = value } - data["components"] = components + // Update the modified components back into loggerData + loggerData["components"] = components + + // Update the modified loggerData back into the CloudEvent data + data["data"] = loggerData + + // Ensure that the id exists and then remove it since it generates a unique value for each test run + guard data["id"] is String else { + return XCTFail("invalid id") + } + data.removeValue(forKey: "id") + expected.removeValue(forKey: "id") + + // Ensure that the time exists and then remove it since it generates a unique value for each test run + guard data["time"] is String else { + return XCTFail("invalid time") + } + data.removeValue(forKey: "time") + expected.removeValue(forKey: "time") - let isEqual = NSDictionary(dictionary: data).isEqual(to: expectedPayload) + let isEqual = NSDictionary(dictionary: data).isEqual(to: expected) if !isEqual, let payloadData = try? JSONSerialization.data( @@ -377,7 +539,7 @@ final class PayPalMessageLoggerTests: XCTestCase { options: .prettyPrinted ), let expectedData = try? JSONSerialization.data( - withJSONObject: expectedPayload, + withJSONObject: expected, options: .prettyPrinted ) { let payloadString = String(decoding: payloadData, as: UTF8.self) @@ -389,3 +551,4 @@ final class PayPalMessageLoggerTests: XCTestCase { XCTAssertTrue(isEqual) } } +// swiftlint:disable:this file_length diff --git a/Tests/PayPalMessagesTests/PayPalMessageLogoTests.swift b/Tests/PayPalMessagesTests/PayPalMessageLogoTests.swift index 61a1a14..cd5c878 100644 --- a/Tests/PayPalMessagesTests/PayPalMessageLogoTests.swift +++ b/Tests/PayPalMessagesTests/PayPalMessageLogoTests.swift @@ -14,10 +14,12 @@ final class PayPalMessageLogoTests: XCTestCase { ) { let resultParameter = paramsBuilder.makeParameters( message: "", + messageAlternative: nil, + offerType: PayPalMessageResponseOfferType.payLaterShortTerm, linkDescription: "", logoPlaceholder: "", logoType: logoType, - payPalAlignment: .left, + payPalAlign: .left, payPalColor: color, productGroup: productGroup ) @@ -261,10 +263,12 @@ final class PayPalMessageLogoTests: XCTestCase { for productGroup in allProductGroups { let resultParameter = paramsBuilder.makeParameters( message: "", + messageAlternative: nil, + offerType: PayPalMessageResponseOfferType.payLaterShortTerm, linkDescription: "", logoPlaceholder: "", logoType: .none, - payPalAlignment: .left, + payPalAlign: .left, payPalColor: color, productGroup: productGroup ) @@ -273,4 +277,15 @@ final class PayPalMessageLogoTests: XCTestCase { } } } + + func testImageAssetLoading() { + // Test loading an image without specifying a size + let loadingCircleImage = ImageAsset.image(.loadingCircle) + XCTAssertNotNil(loadingCircleImage) + + // Test loading an image with a specified size + let closeIconImage = ImageAsset.image(.closeIcon, CGSize(width: 20, height: 20)) + XCTAssertNotNil(closeIconImage) + XCTAssertEqual(closeIconImage.size, CGSize(width: 20, height: 20)) + } } diff --git a/Tests/PayPalMessagesTests/PayPalMessageModalTests.swift b/Tests/PayPalMessagesTests/PayPalMessageModalTests.swift new file mode 100644 index 0000000..77412a1 --- /dev/null +++ b/Tests/PayPalMessagesTests/PayPalMessageModalTests.swift @@ -0,0 +1,141 @@ +import Foundation +import XCTest +@testable import PayPalMessages + +final class PayPalMessageModalTests: XCTestCase { + + let config = PayPalMessageModalConfig( + data: .init( + clientID: "Test123", + environment: .sandbox, + amount: 100.0, + offerType: .payLaterLongTerm + ) + ) + + var modalViewController: PayPalMessageModal? + + override func setUp() { + super.setUp() + modalViewController = PayPalMessageModal(config: config) + modalViewController?.loadViewIfNeeded() + } + + override func tearDown() { + modalViewController = nil + super.tearDown() + } + + func testInitialPropertyValues() { + let modalViewController = PayPalMessageModal(config: config) + + let supportedOrientations = modalViewController.supportedInterfaceOrientations + let preferredOrientation = modalViewController.preferredInterfaceOrientationForPresentation + let shouldAutoRotate = modalViewController.shouldAutorotate + + XCTAssertEqual(supportedOrientations, .portrait) + XCTAssertEqual(preferredOrientation, .portrait) + XCTAssertFalse(shouldAutoRotate) + } + + func testViewOnLoadingDelegate() { + if let viewController = modalViewController { + let stateDelegateMock = PayPalMessageModalStateDelegateMock() + viewController.stateDelegate = stateDelegateMock + + viewController.viewDidLoad() + + XCTAssertTrue(stateDelegateMock.onLoadingCalled) + } + } + + func testViewWillAppearCallsOnShowDelegate() { + if let viewController = modalViewController { + let eventDelegateMock = PayPalMessageModalEventDelegateMock() + viewController.eventDelegate = eventDelegateMock + + viewController.viewWillAppear(false) + + XCTAssertTrue(eventDelegateMock.onShowCalled) + } + } + + func testModalDismissalCallsOnCloseDelegate() { + if let viewController = modalViewController { + let eventDelegateMock = PayPalMessageModalEventDelegateMock() + viewController.eventDelegate = eventDelegateMock + + viewController.viewDidDisappear(false) + + XCTAssertTrue(eventDelegateMock.onCloseCalled) + } + } + + func testModalPresentationAndDismissal() { + if let viewController = modalViewController { + let eventDelegateMock = PayPalMessageModalEventDelegateMock() + viewController.eventDelegate = eventDelegateMock + + viewController.show() + viewController.viewWillAppear(false) + + XCTAssertTrue(eventDelegateMock.onShowCalled) + + viewController.hide() + viewController.viewDidDisappear(false) + + XCTAssertTrue(eventDelegateMock.onCloseCalled) + } + } + + func testIntegrationInitializer() { + let clientID = "Client123" + let merchantID = "Merchant456" + let partnerAttributionID = "Partner789" + let amount = 100.0 + let pageType = PayPalMessagePageType.home + let offerType = PayPalMessageOfferType.payLaterShortTerm + let closeButtonWidth = 30 + let closeButtonHeight = 30 + let closeButtonAvailableWidth = 70 + let closeButtonAvailableHeight = 70 + let closeButtonColor = UIColor(hexString: "#001435") + let closeButtonColorType = "light" + let closeButtonAlternativeText = "PayPal learn more modal close" + let environment = Environment.sandbox + + let modalDataConfig = PayPalMessageModalDataConfig( + clientID: clientID, + merchantID: merchantID, + environment: environment, + partnerAttributionID: partnerAttributionID, + amount: amount, + pageType: pageType, + offerType: offerType, + modalCloseButton: ModalCloseButtonConfig( + width: closeButtonWidth, + height: closeButtonHeight, + availableWidth: closeButtonAvailableWidth, + availableHeight: closeButtonAvailableHeight, + color: closeButtonColor, + colorType: closeButtonColorType, + alternativeText: closeButtonAlternativeText + ) + ) + + XCTAssertEqual(modalDataConfig.clientID, clientID) + XCTAssertEqual(modalDataConfig.merchantID, merchantID) + XCTAssertEqual(modalDataConfig.partnerAttributionID, partnerAttributionID) + XCTAssertEqual(modalDataConfig.amount, amount) + XCTAssertEqual(modalDataConfig.pageType, pageType) + XCTAssertEqual(modalDataConfig.offerType, offerType) + XCTAssertEqual(modalDataConfig.modalCloseButton.width, closeButtonWidth) + XCTAssertEqual(modalDataConfig.modalCloseButton.height, closeButtonHeight) + XCTAssertEqual(modalDataConfig.modalCloseButton.availableWidth, closeButtonAvailableWidth) + XCTAssertEqual(modalDataConfig.modalCloseButton.availableHeight, closeButtonAvailableHeight) + XCTAssertEqual(modalDataConfig.modalCloseButton.color, closeButtonColor) + XCTAssertEqual(modalDataConfig.modalCloseButton.colorType, closeButtonColorType) + XCTAssertEqual(modalDataConfig.modalCloseButton.alternativeText, closeButtonAlternativeText) + XCTAssertEqual(modalDataConfig.environment, environment) + } +} diff --git a/Tests/PayPalMessagesTests/PayPalMessageModalViewModelTests.swift b/Tests/PayPalMessagesTests/PayPalMessageModalViewModelTests.swift index a56bff4..fcf9880 100644 --- a/Tests/PayPalMessagesTests/PayPalMessageModalViewModelTests.swift +++ b/Tests/PayPalMessagesTests/PayPalMessageModalViewModelTests.swift @@ -2,34 +2,54 @@ import WebKit import XCTest +// swiftlint:disable:next type_body_length final class PayPalMessageModalViewModelTests: XCTestCase { let navigation = WKNavigation() let mockSender = LogSenderMock() + var modal: PayPalMessageModal? + override func setUp() { super.setUp() // Inject mock sender to intercept log requests - let logger = Logger.get(for: "test", in: .live) - logger.sender = mockSender + AnalyticsService.shared.sender = mockSender + } + + // Helper function to convert JSON string to dictionary + func convertToDictionary(from jsonString: String) -> [String: Any]? { + // Extract JSON data from the string + guard let startIndex = jsonString.firstIndex(of: "{"), + let endIndex = jsonString.lastIndex(of: "}"), + endIndex > startIndex else { + print("Failed to extract JSON data from the string. JSON String: \(jsonString)") + return nil + } + + let jsonDataString = jsonString[startIndex...endIndex] + + guard let data = jsonDataString.data(using: .utf8), + let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else { + print("Failed to convert JSON string to dictionary. JSON String: \(jsonString)") + return nil + } + return json } func testInitialSetup() { let config = PayPalMessageModalConfig( data: .init( clientID: "testclientid", + environment: .live, amount: 100.0, - currency: "USD", - placement: .home, + pageType: .home, offerType: .payLaterLongTerm ) ) config.data.buyerCountry = "US" config.data.channel = "TEST" - config.data.devTouchpoint = true config.data.ignoreCache = true - config.data.stageTag = "test" let (viewModel, webView, stateDelegate, eventDelegate) = makePayPalMessageModalViewModel( config: config @@ -37,13 +57,10 @@ final class PayPalMessageModalViewModelTests: XCTestCase { XCTAssertEqual(viewModel.clientID, "testclientid") XCTAssertEqual(viewModel.amount, 100.0) - XCTAssertEqual(viewModel.currency, "USD") - XCTAssertEqual(viewModel.placement, .home) + XCTAssertEqual(viewModel.pageType, .home) XCTAssertEqual(viewModel.offerType, .payLaterLongTerm) XCTAssertEqual(viewModel.buyerCountry, "US") XCTAssertEqual(viewModel.channel, "TEST") - XCTAssertEqual(viewModel.stageTag, "test") - XCTAssertTrue(viewModel.devTouchpoint ?? false) XCTAssertTrue(viewModel.ignoreCache ?? false) XCTAssertEqual(viewModel.environment, .live) @@ -54,9 +71,7 @@ final class PayPalMessageModalViewModelTests: XCTestCase { } func testUpdateConfig() { - let expectation = expectation(description: "Evaluate JavaScript Callback") let (viewModel, webView, _, _) = makePayPalMessageModalViewModel() - webView.evaluateJavaScriptCallback = { _ in expectation.fulfill() } XCTAssertNil(viewModel.amount) XCTAssertNil(viewModel.offerType) @@ -64,6 +79,7 @@ final class PayPalMessageModalViewModelTests: XCTestCase { viewModel.setConfig(.init( data: .init( clientID: "testclientid", + environment: .live, amount: 200.0, offerType: .payLaterShortTerm ) @@ -74,19 +90,44 @@ final class PayPalMessageModalViewModelTests: XCTestCase { XCTAssertFalse(webView.evaluateJavaScriptCalled) - waitForExpectations(timeout: 0.5) + viewModel.flushUpdates() XCTAssertTrue(webView.evaluateJavaScriptCalled) - XCTAssertEqual( - webView.evaluateJavaScriptString, - "window.actions.updateProps({\"client_id\":\"testclientid\",\"amount\":200,\"offer\":\"PAY_LATER_SHORT_TERM\"})" - ) + + let expectedJSONString = """ + { + "client_id": "testclientid", + "amount": 200, + "offer": "PAY_LATER_SHORT_TERM", + "channel": "UPSTREAM" + } + """ + + guard let actualJSONString = webView.evaluateJavaScriptString else { + XCTFail("Failed to get JavaScript string") + return + } + + guard let expectedDictionary = convertToDictionary(from: expectedJSONString), + let actualDictionary = convertToDictionary(from: actualJSONString) else { + XCTFail("Failed to convert JSON strings to dictionaries") + return + } + + // Check if the actualJSONString matches the desired pattern + let pattern = "^window\\.actions\\.updateProps\\(.+\\)$" + guard let regex = try? NSRegularExpression(pattern: pattern, options: []) else { + XCTFail("Failed to create NSRegularExpression") + return + } + let matches = regex.matches(in: actualJSONString, options: [], range: NSRange(location: 0, length: actualJSONString.count)) + + XCTAssertTrue(!matches.isEmpty) + XCTAssertEqual(expectedDictionary as NSDictionary, actualDictionary as NSDictionary) } func testUpdateIndividualProperties() { - let expectation = expectation(description: "Evaluate JavaScript Callback") let (viewModel, webView, _, _) = makePayPalMessageModalViewModel() - webView.evaluateJavaScriptCallback = { _ in expectation.fulfill() } XCTAssertNil(viewModel.amount) XCTAssertNil(viewModel.offerType) @@ -99,19 +140,48 @@ final class PayPalMessageModalViewModelTests: XCTestCase { XCTAssertFalse(webView.evaluateJavaScriptCalled) - waitForExpectations(timeout: 0.5) + viewModel.flushUpdates() - XCTAssertTrue(webView.evaluateJavaScriptCalled) - XCTAssertEqual( - webView.evaluateJavaScriptString, - "window.actions.updateProps({\"client_id\":\"testclientid\",\"amount\":300,\"offer\":\"PAYPAL_CREDIT_NO_INTEREST\"})" - ) + let expectedJSONString = """ + { + "client_id": "testclientid", + "amount": 300, + "offer": "PAYPAL_CREDIT_NO_INTEREST", + "channel": "UPSTREAM" + } + """ + + guard let actualJSONString = webView.evaluateJavaScriptString else { + XCTFail("Failed to get JavaScript string") + return + } + + guard let expectedDictionary = convertToDictionary(from: expectedJSONString), + let actualDictionary = convertToDictionary(from: actualJSONString) else { + XCTFail("Failed to convert JSON strings to dictionaries") + return + } + + // Check if the actualJSONString matches the desired pattern + let pattern = "^window\\.actions\\.updateProps\\(.+\\)$" + guard let regex = try? NSRegularExpression(pattern: pattern, options: []) else { + XCTFail("Failed to create NSRegularExpression") + return + } + let matches = regex.matches(in: actualJSONString, options: [], range: NSRange(location: 0, length: actualJSONString.count)) + + XCTAssertTrue(!matches.isEmpty) + XCTAssertEqual(expectedDictionary as NSDictionary, actualDictionary as NSDictionary) } func testModalLoadSuccess() { let (viewModel, webView, _, _) = makePayPalMessageModalViewModel( config: .init( - data: .init(clientID: "testclientid", amount: 500.0) + data: .init( + clientID: "testclientid", + environment: .live, + amount: 500.0 + ) ) ) var loadResult: Result? @@ -234,8 +304,8 @@ final class PayPalMessageModalViewModelTests: XCTestCase { "name": "onClick", "args": [ { - "link_name": "Apply Now Link", - "link_src": "Apply Now Src" + "page_view_link_name": "Apply Now Link", + "page_view_link_source": "Apply Now Src" } ] } @@ -249,7 +319,7 @@ final class PayPalMessageModalViewModelTests: XCTestCase { } private func makePayPalMessageModalViewModel( - config: PayPalMessageModalConfig = PayPalMessageModalConfig(data: .init(clientID: "testclientid")) + config: PayPalMessageModalConfig = PayPalMessageModalConfig(data: .init(clientID: "testclientid", environment: .live)) ) -> ( // swiftlint:disable:this large_tuple PayPalMessageModalViewModel, PayPalMessageModalWebViewMock, @@ -268,9 +338,12 @@ final class PayPalMessageModalViewModelTests: XCTestCase { config: config, webView: webView, stateDelegate: stateDelegate, - eventDelegate: eventDelegate + eventDelegate: eventDelegate, + modal: modal ) - viewModel.modal = modal + + // Create a strong reference so the modal does not get cleaned up immediatedly after getting passed into the view model + self.modal = modal return ( viewModel, diff --git a/Tests/PayPalMessagesTests/PayPalMessageResponseTests.swift b/Tests/PayPalMessagesTests/PayPalMessageResponseTests.swift new file mode 100644 index 0000000..ad3b886 --- /dev/null +++ b/Tests/PayPalMessagesTests/PayPalMessageResponseTests.swift @@ -0,0 +1,70 @@ +import Foundation +import XCTest +@testable import PayPalMessages + +final class MessageResponseTests: XCTestCase { + + func testDecodeMessageResponse() throws { + let json = """ + { + "meta": { + "credit_product_group": "PAY_LATER", + "offer_country_code": "US", + "offer_type": "PAY_LATER_LONG_TERM", + "message_type": "PLLT_MQ_GZ", + "modal_close_button": { + "width": 26, + "height": 26, + "available_width": 60, + "available_height": 60, + "color": "#001435", + "color_type": "dark", + "alternative_text": "PayPal learn more modal close" + }, + "variables": { + "inline_logo_placeholder": "%paypal_logo%" + }, + "merchant_country_code": "US", + "credit_product_identifiers": [ + "PAY_LATER_LONG_TERM_US" + ], + "debug_id": "5eea97bb38fa9", + "fdata": "ABC123", + "originating_instance_id": "abc123", + "tracking_keys": [ + "merchant_country_code", + "credit_product_identifiers", + "offer_country_code", + "message_type", + "debug_id", + "fdata", + "originating_instance_id" + ] + }, + "content": { + "default": { + "main": "As low as $187.17/mo with %paypal_logo%.", + "main_alternative": "As low as $187.17 per month with PayPal.", + "disclaimer": "Learn more" + }, + "generic": { + "main": "Buy now, pay later with %paypal_logo%.", + "disclaimer": "Learn more" + } + } + } + """ + // swiftlint:disable force_unwrapping + .data(using: .utf8)! + + let decoder = JSONDecoder() + let messageResponse = try decoder.decode(MessageResponse.self, from: json) + + XCTAssertEqual(messageResponse.offerType, .payLaterLongTerm) + XCTAssertEqual(messageResponse.productGroup, .payLater) + XCTAssertEqual(messageResponse.defaultMainContent, "As low as $187.17/mo with %paypal_logo%.") + XCTAssertEqual(messageResponse.defaultDisclaimer, "Learn more") + XCTAssertEqual(messageResponse.defaultMainAlternative, "As low as $187.17 per month with PayPal.") + XCTAssertEqual(messageResponse.modalCloseButtonAlternativeText, "PayPal learn more modal close") + } +} diff --git a/Tests/PayPalMessagesTests/PayPalMessageViewModelTests.swift b/Tests/PayPalMessagesTests/PayPalMessageViewModelTests.swift index c63c435..b398d78 100644 --- a/Tests/PayPalMessagesTests/PayPalMessageViewModelTests.swift +++ b/Tests/PayPalMessagesTests/PayPalMessageViewModelTests.swift @@ -4,17 +4,13 @@ import XCTest // swiftlint:disable:next type_body_length final class PayPalMessageViewModelTests: XCTestCase { - // Message view passed into the view controller that gets passed back - // as a refernce in the delegate functions - let messageView = PayPalMessageView(config: .init(data: .init(clientID: "testclientid"))) let mockSender = LogSenderMock() override func setUp() { super.setUp() // Inject mock sender to intercept log requests - let logger = Logger.get(for: "testclientid", in: .live) - logger.sender = mockSender + AnalyticsService.shared.sender = mockSender } // MARK: - Test Initial Config Values @@ -77,7 +73,7 @@ final class PayPalMessageViewModelTests: XCTestCase { XCTAssertTrue(mockedDelegate.onErrorCalled) XCTAssertNil(viewModel.messageParameters) - guard case .invalidResponse(let paypalDebugID) = mockedDelegate.error else { + guard case .invalidResponse(let paypalDebugID, _, _) = mockedDelegate.error else { XCTFail("Expected error invalidResponse") return } @@ -88,7 +84,7 @@ final class PayPalMessageViewModelTests: XCTestCase { // MARK: - Single Parameter Testing func testSimpleAmountUpdate() { - let mockedRequest = PayPalMessageRequestMock(scenario: .success) + let mockedRequest = PayPalMessageRequestMock(scenario: .success()) // init ViewModel with mocked delegate in error scenario let viewModel = makePayPalMessageViewModel( @@ -103,32 +99,34 @@ final class PayPalMessageViewModelTests: XCTestCase { viewModel.amount = newAmount XCTAssertEqual(viewModel.amount, newAmount) - // verify a request has been performed - assert(mockedRequest, calledTimes: 2) + viewModel.flushUpdates() + + XCTAssertEqual(mockedRequest.requestsPerformed, 2) } - func testSimplePlacementUpdate() { - let mockedRequest = PayPalMessageRequestMock(scenario: .success) + func testSimplePageTypeUpdate() { + let mockedRequest = PayPalMessageRequestMock(scenario: .success()) // init ViewModel with mocked delegate in error scenario let viewModel = makePayPalMessageViewModel( mockedRequest: mockedRequest ) - XCTAssertNil(viewModel.placement) + XCTAssertNil(viewModel.pageType) XCTAssertEqual(mockedRequest.requestsPerformed, 1) // test the new parameter is being correctly sent - let newValue: PayPalMessagePlacement = .payment - viewModel.placement = newValue - XCTAssertEqual(viewModel.placement, newValue) + let newValue: PayPalMessagePageType = .checkout + viewModel.pageType = newValue + XCTAssertEqual(viewModel.pageType, newValue) + + viewModel.flushUpdates() - // verify a request has been performed - assert(mockedRequest, calledTimes: 2) + XCTAssertEqual(mockedRequest.requestsPerformed, 2) } func testSimpleOfferTypeUpdate() { - let mockedRequest = PayPalMessageRequestMock(scenario: .success) + let mockedRequest = PayPalMessageRequestMock(scenario: .success()) // init ViewModel with mocked delegate in error scenario let viewModel = makePayPalMessageViewModel( @@ -143,12 +141,13 @@ final class PayPalMessageViewModelTests: XCTestCase { viewModel.offerType = newValue XCTAssertEqual(viewModel.offerType, newValue) - // verify a request has been performed - assert(mockedRequest, calledTimes: 2) + viewModel.flushUpdates() + + XCTAssertEqual(mockedRequest.requestsPerformed, 2) } func testBuyerCountryTypeUpdate() { - let mockedRequest = PayPalMessageRequestMock(scenario: .success) + let mockedRequest = PayPalMessageRequestMock(scenario: .success()) // init ViewModel with mocked delegate in error scenario let viewModel = makePayPalMessageViewModel( @@ -163,13 +162,14 @@ final class PayPalMessageViewModelTests: XCTestCase { viewModel.buyerCountry = newValue XCTAssertEqual(viewModel.buyerCountry, newValue) - // verify a request has been performed - assert(mockedRequest, calledTimes: 2) + viewModel.flushUpdates() + + XCTAssertEqual(mockedRequest.requestsPerformed, 2) } func testSimpleLogoTypeUpdate() { - let mockedRequest = PayPalMessageRequestMock(scenario: .success) - let mockedConfig = PayPalMessageConfig(data: .init(clientID: "test")) + let mockedRequest = PayPalMessageRequestMock(scenario: .success()) + let mockedConfig = PayPalMessageConfig(data: .init(clientID: "testclientid", environment: .live)) // init ViewModel with mocked delegate in error scenario let viewModel = makePayPalMessageViewModel( @@ -185,13 +185,14 @@ final class PayPalMessageViewModelTests: XCTestCase { viewModel.logoType = newValue XCTAssertEqual(viewModel.logoType, newValue) - // verify a request has been performed - assert(mockedRequest, calledTimes: 2) + viewModel.flushUpdates() + + XCTAssertEqual(mockedRequest.requestsPerformed, 2) } func testSimpleColorUpdate() { - let mockedRequest = PayPalMessageRequestMock(scenario: .success) - let mockedConfig = PayPalMessageConfig(data: .init(clientID: "test")) + let mockedRequest = PayPalMessageRequestMock(scenario: .success()) + let mockedConfig = PayPalMessageConfig(data: .init(clientID: "testclientid", environment: .live)) // init ViewModel with mocked delegate in error scenario let viewModel = makePayPalMessageViewModel( @@ -207,13 +208,15 @@ final class PayPalMessageViewModelTests: XCTestCase { viewModel.color = newValue XCTAssertEqual(viewModel.color, newValue) + viewModel.flushUpdates() + // verify a request has NOT been performed as color changes shouldn't trigger them - assert(mockedRequest, calledTimes: 1) + XCTAssertEqual(mockedRequest.requestsPerformed, 1) } func testSimpleAlignmentUpdate() { - let mockedRequest = PayPalMessageRequestMock(scenario: .success) - let mockedConfig = PayPalMessageConfig(data: .init(clientID: "testclientid")) + let mockedRequest = PayPalMessageRequestMock(scenario: .success()) + let mockedConfig = PayPalMessageConfig(data: .init(clientID: "testclientid", environment: .live)) // init ViewModel with mocked delegate in error scenario let viewModel = makePayPalMessageViewModel( @@ -221,22 +224,24 @@ final class PayPalMessageViewModelTests: XCTestCase { mockedConfig: mockedConfig ) - XCTAssertEqual(viewModel.alignment, mockedConfig.style.textAlignment) + XCTAssertEqual(viewModel.textAlign, mockedConfig.style.textAlign) XCTAssertEqual(mockedRequest.requestsPerformed, 1) // test the new AND different parameter is being correctly sent - let newValue: PayPalMessageTextAlignment = .center - viewModel.alignment = newValue - XCTAssertEqual(viewModel.alignment, newValue) + let newValue: PayPalMessageTextAlign = .center + viewModel.textAlign = newValue + XCTAssertEqual(viewModel.textAlign, newValue) + + viewModel.flushUpdates() // verify a request has NOT been performed as alignment changes shouldn't trigger them - assert(mockedRequest, calledTimes: 1) + XCTAssertEqual(mockedRequest.requestsPerformed, 1) } // MARK: - Test Duplicated Value Updates func testDuplicatedAmountUpdate() { - let mockedRequest = PayPalMessageRequestMock(scenario: .success) + let mockedRequest = PayPalMessageRequestMock(scenario: .success()) // init ViewModel with mocked delegate in error scenario let viewModel = makePayPalMessageViewModel( @@ -250,12 +255,16 @@ final class PayPalMessageViewModelTests: XCTestCase { let newAmount = Double.random(in: 0...1000) viewModel.amount = newAmount - assert(mockedRequest, calledTimes: 2) + viewModel.flushUpdates() + + XCTAssertEqual(mockedRequest.requestsPerformed, 2) // set the same amount again, verify another redundant request hasn't been performed viewModel.amount = newAmount - assert(mockedRequest, calledTimes: 2) + viewModel.flushUpdates() + + XCTAssertEqual(mockedRequest.requestsPerformed, 2) } // MARK: - Test Update In Progress Cases @@ -290,7 +299,7 @@ final class PayPalMessageViewModelTests: XCTestCase { func testUpdateInProgressFromParams() { let mockedDelegate = PayPalMessageViewDelegateMock() - let mockedRequest = PayPalMessageRequestMock(scenario: .success) + let mockedRequest = PayPalMessageRequestMock(scenario: .success()) // init ViewModel with mocked delegate in error scenario let viewModel = makePayPalMessageViewModel( @@ -313,12 +322,14 @@ final class PayPalMessageViewModelTests: XCTestCase { let newerAmount = newAmount - 1 viewModel.amount = newerAmount - assert(mockedRequest, calledTimes: 2) + viewModel.flushUpdates() + + XCTAssertEqual(mockedRequest.requestsPerformed, 2) } func testUpdateInProgressFromConfig() { let mockedDelegate = PayPalMessageViewDelegateMock() - let mockedRequest = PayPalMessageRequestMock(scenario: .success) + let mockedRequest = PayPalMessageRequestMock(scenario: .success()) // init ViewModel with mocked delegate in error scenario let viewModel = makePayPalMessageViewModel( @@ -337,13 +348,17 @@ final class PayPalMessageViewModelTests: XCTestCase { let newAmount = Double.random(in: 1...1000) viewModel.amount = newAmount - assert(mockedRequest, calledTimes: 2) + viewModel.flushUpdates() + + XCTAssertEqual(mockedRequest.requestsPerformed, 2) // test a new config being set overrides the update in progress flag and triggers and update - let newConfig = PayPalMessageConfig(data: .init(clientID: "testclientid")) + let newConfig = PayPalMessageConfig(data: .init(clientID: "testclientid", environment: .live)) viewModel.config = newConfig - assert(mockedRequest, calledTimes: 3) + viewModel.flushUpdates() + + XCTAssertEqual(mockedRequest.requestsPerformed, 3) } // MARK: - Test Merchant Provider @@ -351,7 +366,7 @@ final class PayPalMessageViewModelTests: XCTestCase { func testMerchantProviderFailure() { let mockedView = PayPalMessageViewMock() let mockedDelegate = PayPalMessageViewDelegateMock() - let mockedMerchantProfileProvider = MerchantProfileProviderMock(.error) + let mockedMerchantProfileProvider = MerchantProfileProviderMock(scenario: .error) // init ViewModel with mocked delegate let viewModel = makePayPalMessageViewModel( @@ -368,37 +383,31 @@ final class PayPalMessageViewModelTests: XCTestCase { XCTAssertNotNil(viewModel.messageParameters) } - // MARK: - Helpers - - private func assert(_ mockRequest: PayPalMessageRequestMock, calledTimes count: Int) { - let predicate = NSPredicate { _, _ in - print(mockRequest.requestsPerformed, count) - return mockRequest.requestsPerformed == count - } - let expectation = XCTNSPredicateExpectation(predicate: predicate, object: mockRequest) - wait(for: [expectation], timeout: 2) - } - private func makePayPalMessageViewModel( mockedView: PayPalMessageViewMock = PayPalMessageViewMock(), mockedDelegate: PayPalMessageViewDelegateMock = PayPalMessageViewDelegateMock(), - mockedRequest: PayPalMessageRequestMock = PayPalMessageRequestMock(scenario: .success), - mockedMerchantProfile: MerchantProfileProviderMock - = MerchantProfileProviderMock(.success), - mockedConfig: PayPalMessageConfig = PayPalMessageConfig(data: .init(clientID: "testclientid")) + mockedRequest: PayPalMessageRequestMock = PayPalMessageRequestMock(scenario: .success()), + mockedMerchantProfile: MerchantProfileProviderMock = MerchantProfileProviderMock(scenario: .success), + mockedConfig: PayPalMessageConfig = PayPalMessageConfig(data: .init(clientID: "testclientid", environment: .sandbox)) ) -> PayPalMessageViewModel { + // Intentionally use different `requester` and `merchantProfileProvider` values from the view model to prevent interferring + // with mock request counts specifically fired from the view model itself + let messageView = PayPalMessageView( + config: mockedConfig, + requester: PayPalMessageRequestMock(scenario: .success()), + merchantProfileProvider: MerchantProfileProviderMock(scenario: .success) + ) + let viewModel = PayPalMessageViewModel( config: mockedConfig, requester: mockedRequest, merchantProfileProvider: mockedMerchantProfile, - delegate: mockedView, - eventDelegate: mockedDelegate, stateDelegate: mockedDelegate, + eventDelegate: mockedDelegate, + delegate: mockedView, messageView: messageView ) - viewModel.queueMessageContentUpdate(requiresFetch: true, fireImmediately: true) - return viewModel } } diff --git a/Tests/PayPalMessagesTests/PayPalMessageViewTests.swift b/Tests/PayPalMessagesTests/PayPalMessageViewTests.swift new file mode 100644 index 0000000..1275a25 --- /dev/null +++ b/Tests/PayPalMessagesTests/PayPalMessageViewTests.swift @@ -0,0 +1,156 @@ +import Foundation +import XCTest +import SwiftUI +@testable import PayPalMessages + +let config = PayPalMessageConfig( + data: .init( + clientID: "Test123", + environment: .sandbox + ), + style: .init( + color: .black + ) +) + +@available(iOS 13.0, *) +final class PayPalMessageViewTests: XCTestCase { + + var strongMessageView: PayPalMessageView? + weak var weakMessageView: PayPalMessageView? + + // MARK: - Test Initialization and Configuration + + func testInitialization() { + let config = config + + // TODO: This should mock the network requests our other tests, but that drops code coverage of files that do the fetching + let messageView = PayPalMessageView( + config: config + ) + + // Assert that properties are correctly set + XCTAssertEqual(messageView.clientID, config.data.clientID) + XCTAssertEqual(messageView.color, config.style.color) + } + + func testMessageViewNotStronglyReferencedInternally() { + let config = config + + var messageView: PayPalMessageView? = PayPalMessageView( + config: config, + requester: PayPalMessageRequestMock(scenario: .success()), + merchantProfileProvider: MerchantProfileProviderMock(scenario: .success) + ) + + strongMessageView = messageView + weakMessageView = messageView + + messageView = nil + + XCTAssertNotNil(strongMessageView) + XCTAssertNotNil(weakMessageView) + + strongMessageView = nil + + XCTAssertNil(weakMessageView) + } + + // swiftlint:disable:next function_body_length + func testMessageAccessibilityLabel() { + let config = config + + // Inline Pay Monthly message + + let messageResponse = MessageResponse( + offerType: .payLaterLongTerm, + productGroup: .payLater, + defaultMainContent: "As low as $187.17/mo with %paypal_logo%.", + defaultMainAlternative: "As low as $187.17 per month with PayPal.", + defaultDisclaimer: "Learn more.", + genericMainContent: "", + genericMainAlternative: nil, + genericDisclaimer: "", + logoPlaceholder: "%paypal_logo%", + modalCloseButtonWidth: 25, + modalCloseButtonHeight: 25, + modalCloseButtonAvailWidth: 60, + modalCloseButtonAvailHeight: 60, + modalCloseButtonColor: "#2d2d2d", + modalCloseButtonColorType: "DARK", + modalCloseButtonAlternativeText: "PayPal learn more modal close" + ) + + let messageView = PayPalMessageView( + config: config, + requester: PayPalMessageRequestMock(scenario: .success(messageResponse: messageResponse)), + merchantProfileProvider: MerchantProfileProviderMock(scenario: .success) + ) + + XCTAssertEqual(messageView.accessibilityTraits, .button) + XCTAssertEqual(messageView.isAccessibilityElement, true) + XCTAssertEqual(messageView.accessibilityLabel, "As low as $187.17 per month with PayPal. Learn more.") + + // Standard Pay Monthly message + + let messageResponse2 = MessageResponse( + offerType: .payLaterLongTerm, + productGroup: .payLater, + defaultMainContent: "As low as $187.17/mo.", + defaultMainAlternative: "As low as $187.17 per month.", + defaultDisclaimer: "Learn more.", + genericMainContent: "", + genericMainAlternative: nil, + genericDisclaimer: "", + logoPlaceholder: "%paypal_logo%", + modalCloseButtonWidth: 25, + modalCloseButtonHeight: 25, + modalCloseButtonAvailWidth: 60, + modalCloseButtonAvailHeight: 60, + modalCloseButtonColor: "#2d2d2d", + modalCloseButtonColorType: "DARK", + modalCloseButtonAlternativeText: "PayPal learn more modal close" + ) + + let messageView2 = PayPalMessageView( + config: config, + requester: PayPalMessageRequestMock(scenario: .success(messageResponse: messageResponse2)), + merchantProfileProvider: MerchantProfileProviderMock(scenario: .success) + ) + + XCTAssertEqual(messageView2.accessibilityTraits, .button) + XCTAssertEqual(messageView2.isAccessibilityElement, true) + XCTAssertEqual(messageView2.accessibilityLabel, "PayPal - As low as $187.17 per month. Learn more.") + + // PayPal Credit message + + let messageResponse3 = MessageResponse( + offerType: .payPalCreditNoInterest, + productGroup: .paypalCredit, + defaultMainContent: "No Interest if paid in full in 6 months.", + defaultMainAlternative: nil, + defaultDisclaimer: "Learn more.", + genericMainContent: "", + genericMainAlternative: nil, + genericDisclaimer: "", + logoPlaceholder: "%paypal_logo%", + modalCloseButtonWidth: 25, + modalCloseButtonHeight: 25, + modalCloseButtonAvailWidth: 60, + modalCloseButtonAvailHeight: 60, + modalCloseButtonColor: "#2d2d2d", + modalCloseButtonColorType: "DARK", + modalCloseButtonAlternativeText: "PayPal learn more modal close" + ) + + let messageView3 = PayPalMessageView( + config: config, + requester: PayPalMessageRequestMock(scenario: .success(messageResponse: messageResponse3)), + merchantProfileProvider: MerchantProfileProviderMock(scenario: .success) + ) + + XCTAssertEqual(messageView3.accessibilityTraits, .button) + XCTAssertEqual(messageView3.isAccessibilityElement, true) + XCTAssertEqual(messageView3.accessibilityLabel, "PayPal Credit - No Interest if paid in full in 6 months. Learn more.") + } +} diff --git a/Tests/PayPalMessagesTests/ResponseErrorTests.swift b/Tests/PayPalMessagesTests/ResponseErrorTests.swift new file mode 100644 index 0000000..e8c1189 --- /dev/null +++ b/Tests/PayPalMessagesTests/ResponseErrorTests.swift @@ -0,0 +1,58 @@ +import Foundation +@testable import PayPalMessages +import XCTest + +final class ResponseErrorTests: XCTestCase { + + func testInitialize() throws { + let responseError = ResponseError(paypalDebugID: "12345", issue: "SOME_ISSUE", description: "some description") + + XCTAssertEqual(responseError.paypalDebugID, "12345") + XCTAssertEqual(responseError.issue, "SOME_ISSUE") + XCTAssertEqual(responseError.description, "some description") + } + + func testErrorWithoutDetails() throws { + let json = """ + { + "name": "UNPROCESSABLE_ENTITY", + "message": "The requested action could not be performed, semantically incorrect, or failed business validation.", + "debug_id": "12345" + } + """ + // swiftlint:disable force_unwrapping + .data(using: .utf8)! + + let decoder = JSONDecoder() + let responseError = try decoder.decode(ResponseError.self, from: json) + + XCTAssertEqual(responseError.paypalDebugID, "12345") + XCTAssertNil(responseError.issue) + XCTAssertNil(responseError.description) + } + + func testErrorWithDetails() throws { + let json = """ + { + "name": "UNPROCESSABLE_ENTITY", + "message": "The requested action could not be performed, semantically incorrect, or failed business validation.", + "debug_id": "12345", + "details": [ + { + "issue": "TEST_ISSUE", + "description": "A helpful description." + } + ] + } + """ + // swiftlint:disable force_unwrapping + .data(using: .utf8)! + + let decoder = JSONDecoder() + let responseError = try decoder.decode(ResponseError.self, from: json) + + XCTAssertEqual(responseError.paypalDebugID, "12345") + XCTAssertEqual(responseError.issue, "TEST_ISSUE") + XCTAssertEqual(responseError.description, "A helpful description.") + } +} diff --git a/Tests/PayPalMessagesTests/UIViewTests.swift b/Tests/PayPalMessagesTests/UIViewTests.swift new file mode 100644 index 0000000..154f7bb --- /dev/null +++ b/Tests/PayPalMessagesTests/UIViewTests.swift @@ -0,0 +1,40 @@ +import Foundation +import XCTest +@testable import PayPalMessages + +final class UIViewExtensionTests: XCTestCase { + + var testView: UIView? + + override func setUp() { + super.setUp() + testView = UIView() + } + + override func tearDown() { + testView = nil + super.tearDown() + } + + + func testRotateIndefinitely() { + if let view = testView { + // Ensure that the view is not already rotating + XCTAssertNil(view.layer.animation(forKey: "rotation_animation")) + + // Apply the rotation animation using your extension method + view.rotateIndefinitely() + + + // Check properties of the animation + if let rotationAnimation = view.layer.animation(forKey: "rotation_animation") as? CABasicAnimation { + XCTAssertEqual(rotationAnimation.keyPath, "transform.rotation.z") + XCTAssertEqual(rotationAnimation.toValue as? Double, Double.pi * 2) + XCTAssertEqual(rotationAnimation.duration, 1) + XCTAssertEqual(rotationAnimation.isCumulative, true) + XCTAssertEqual(rotationAnimation.repeatCount, .infinity) + XCTAssertEqual(rotationAnimation.isRemovedOnCompletion, false) + } + } + } +} diff --git a/fastlane/Fastfile b/fastlane/Fastfile index fba8c16..61a4b76 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -1,74 +1,304 @@ +require 'json' + skip_docs default_platform(:ios) -ensure_xcode_version(version: "14.2") + +def setup_xcode + sh "which xcodes > /dev/null || brew install xcodes" + xcodes( + version: "14.3.1", + select_for_current_build_only: true + ) +end + +# Updates the Carthage JSON file with the specified version +def version_bump_carthage(path:, version_number:) + Dir.chdir("..") do + framework_url = "https://github.com/paypal/paypal-messages-ios/releases/download/#{version_number}/PayPalMessages.framework.zip" + xcframework_url = "https://github.com/paypal/paypal-messages-ios/releases/download/#{version_number}/PayPalMessages.xcframework.zip" + + parsed_data = JSON.parse(File.read(path)) + parsed_data[version_number] = "#{framework_url}?alt=#{xcframework_url}" + json_string = JSON.pretty_generate(parsed_data) + + File.open(path, 'w') { |file| file.puts(json_string) } + end +end + +def version_bump_spm(checksum_file:, version_number:) + Dir.chdir("..") do + sh "sed -i '' -E 's/version(.*) = \"[0-9a-zA-Z.-]+\"/version\\1 = \"#{version_number}\"/' Package.swift" + checksum = sh("shasum -a 256 #{checksum_file} | cut -d ' ' -f 1").strip! + sh "sed -i '' -E 's/checksum: *\"[0-9a-z]+\"/checksum: \"#{checksum}\"/' Package.swift" + end +end platform :ios do - desc "Runs tests & code coverage check" - lane :tests do - scan( - workspace: "PayPalMessages.xcworkspace", - scheme: "PayPalMessagesTests", - devices: ["iPhone 14"], - derived_data_path: "~/Library/Developer/Xcode/DerivedData", - skip_build: true, - result_bundle: true, - code_coverage: true - ) - - # Ensure the code coverage directory is empty before creating new coverage - sh "rm -rf coverage" - - xcov( - workspace: "PayPalMessages.xcworkspace", - scheme: "PayPalMessagesTests", - derived_data_path: "~/Library/Developer/Xcode/DerivedData", - output_directory: "fastlane/coverage", - markdown_report: true, - minimum_coverage_percentage: 80.0 - ) + desc "Runs tests & code coverage check" + lane :tests do |options| + setup_xcode + + scan( + workspace: "PayPalMessages.xcworkspace", + scheme: "PayPalMessagesTests", + devices: ["iPhone 14 (16.4)"], # default iOS 17 simulator runs much slower on GitHub Actions + derived_data_path: "~/Library/Developer/Xcode/DerivedData", + skip_build: true, + result_bundle: true, + code_coverage: true, + xcodebuild_formatter: "xcbeautify --renderer github-actions" + ) + + # Ensure the code coverage directory is empty before creating new coverage + sh "rm -rf coverage" + + begin + xcov( + workspace: "PayPalMessages.xcworkspace", + scheme: "PayPalMessagesTests", + derived_data_path: "~/Library/Developer/Xcode/DerivedData", + output_directory: "fastlane/coverage", + markdown_report: true, + minimum_coverage_percentage: 80.0 + ) + rescue => e + error = e # Store the exception + ensure + if options[:summary] + # Add coverage report to GitHub Actions summary page + sh "cat ./coverage/report.md > #{options[:summary]}" + end + raise error if error # Re-raise the exception if it exists end + end + + desc "Runs SwiftLint and returns any unmet warnings or errors" + lane :lint do |options| + setup_xcode - desc "Runs SwiftLint and returns any unmet warnings or errors" - lane :lint do - swiftlint( - mode: :lint, - raise_if_swiftlint_error: true, - strict: true, - reporter: "github-actions-logging", - quiet: true - ) + # Ensure directory exists since swiftlint command won't create it if missing + sh "mkdir -p swiftlint" + + begin + swiftlint( + mode: :lint, + raise_if_swiftlint_error: true, + strict: true, + reporter: "markdown", + output_file: "fastlane/swiftlint/report.md" + ) + rescue => e # only need the summary if there are lint issues + if options[:summary] + # Add SwiftLint report to GitHub Actions summary page + sh "cat ./swiftlint/report.md > #{options[:summary]}" + end + raise e # Re-raise the exception end + end + + desc "Build for Cocoapods" + lane :build_pod do + setup_xcode - lane :build do - pod_lib_lint + pod_lib_lint + end + + desc "Build for Swift Package Manager" + lane :build_spm do + setup_xcode + + Dir.chdir("..") do + current_commit = sh("git rev-parse HEAD").strip + # Point to current commit instead of `main` branch + sh "sed -i '' -E 's/kind = branch/kind = revision/' TestApps/SPMTest/SPMTest.xcodeproj/project.pbxproj" + sh "sed -i '' -E 's/branch = .*/revision = #{current_commit};/' TestApps/SPMTest/SPMTest.xcodeproj/project.pbxproj" end - desc "Update version number in various files" - lane :release do |options| - if options[:version] - # Update the hardcoded version string in the Swift code - sh "BUILD_INFO_PATH=$(find .. -name 'BuildInfo.swift')" - sh "sed -i.bak -E 's/version(.*) = \"[0-9a-zA-Z.-]+\"/version\1 = \"#{options[:version]}\"/' $BUILD_INFO_PATH" - sh "rm $BUILD_INFO_PATH.bak" - - # Update the version in the podspec file - version_bump_podspec( - path: "../PayPalMessages.podspec", - version_number: options[:version] - ) - end + gym( + project: "TestApps/SPMTest/SPMTest.xcodeproj", + scheme: "SPMTest", + clean: true, + skip_codesigning: true, + skip_archive: false, + skip_package_ipa: true, + skip_package_dependencies_resolution: false + ) + end + + desc "Build for Carthage" + lane :build_carthage do + setup_xcode + + Dir.chdir("..") do + # Point the Cartfile dependency to use from the latest commit + current_dir = sh("pwd").strip + current_commit = sh("git rev-parse HEAD").strip + sh "echo 'git \"file://#{current_dir}\" \"#{current_commit}\"' > TestApps/CarthageTest/Cartfile" end - desc "Sync develop with main branch" - lane :sync do - push_to_git_remote( - local_branch: "main", - remote_branch: "develop" - ) + # Add built dependencies to /Carthage/Build + carthage( + command: "update", + use_xcframeworks: true, + project_directory: "TestApps/CarthageTest" + ) + + # Build the test app + gym( + project: "TestApps/CarthageTest/CarthageTest.xcodeproj", + scheme: "CarthageTest", + clean: true, + skip_codesigning: true, + skip_archive: false, + skip_package_ipa: true, + skip_package_dependencies_resolution: true + ) + end + + desc "Update version number in various files" + lane :release do |options| + return unless options[:version] + + # Update the hardcoded version string in the Swift code + build_info_path = sh "find .. -name 'BuildInfo.swift'" + sh "sed -i '' -E 's/version(.*) = \"[0-9a-zA-Z.-]+\"/version\\1 = \"#{options[:version]}\"/' #{build_info_path}" + + # Update the version in the podspec file + version_bump_podspec( + path: "PayPalMessages.podspec", + version_number: options[:version] + ) + + version_bump_carthage( + path: "Carthage/PayPalMessages.json", + version_number: options[:version] + ) + + sh "rm -rf ../build" + + # Manual codesigning below + ENV["CODE_SIGN_IDENTITY"] = "" + ENV["CODE_SIGNING_REQUIRED"] = "NO" + ENV["CODE_SIGN_ENTITLEMENTS"] = "" + ENV["CODE_SIGNING_ALLOWED"] = "NO" + + xcodebuild( + archive: true, + clean: true, + project: "PayPalMessages.xcodeproj", + scheme: "PayPalMessages", + configuration: "Release", + sdk: "iphoneos", + archive_path: "./build/Archives/Device.xcarchive" + ) + + xcodebuild( + archive: true, + clean: true, + project: "PayPalMessages.xcodeproj", + scheme: "PayPalMessages", + configuration: "Release", + sdk: "iphonesimulator", + archive_path: "./build/Archives/Simulator.xcarchive" + ) + + # Set global env that will be used in the next xcodebuild command + ENV["EXCLUDED_ARCHS"] = "arm64" + + # For the older universal framework asset the device and simulator must be built separately due to conflicting architectures. + # Both the device and simulator include amd64 architecture which is incompatible with `lipo`, so arm64 is excluded from the + # simulator so that the binaries can be combined + xcodebuild( + archive: true, + clean: true, + project: "PayPalMessages.xcodeproj", + scheme: "PayPalMessages", + configuration: "Release", + sdk: "iphonesimulator", + archive_path: "./build/Archives/Simulator-NoArm64.xcarchive" + ) + + create_xcframework( + frameworks: [ + "build/Archives/Device.xcarchive/Products/Library/Frameworks/PayPalMessages.framework", + "build/Archives/Simulator.xcarchive/Products/Library/Frameworks/PayPalMessages.framework" + ], + output: "build/PayPalMessages.xcframework" + ) + + + temp_dir = ENV["RUNNER_TEMP"] || ENV["TMPDIR"] + ENV["CERTIFICATE_PATH"] = "#{temp_dir}/distribution_certificate.p12" + ENV["KEYCHAIN_PATH"] = "#{temp_dir}/distribution.keychain-db" + + # Import base64 certificate to file + sh "echo $DISTRIBUTION_CERTIFICATE_BASE64 | base64 --decode -o $CERTIFICATE_PATH" + + # Create new keychain to import distribution certificate + create_keychain( + path: ENV["KEYCHAIN_PATH"], + password: ENV["KEYCHAIN_PASSWORD"], + default_keychain: true, + unlock: true, + timeout: 21600, + lock_when_sleeps: true + ) + + # Import certificate to keychain + import_certificate( + certificate_path: ENV["CERTIFICATE_PATH"], + certificate_password: ENV["DISTRIBUTION_CERTIFICATE_PASSWORD"], + keychain_path: ENV["KEYCHAIN_PATH"], + keychain_password: ENV["KEYCHAIN_PASSWORD"], + ) + + begin + # Combine device and simulator builds into single universal framework + Dir.chdir("../build") do + # Base framework + sh "cp -R Archives/Device.xcarchive/Products/Library/Frameworks/PayPalMessages.framework ." + # Copy Simulator into base framework + sh "cp -R Archives/Simulator-NoArm64.xcarchive/Products/Library/Frameworks/PayPalMessages.framework/Modules/PayPalMessages.swiftmodule/ PayPalMessages.framework/Modules/PayPalMessages.swiftmodule" + # Combine binaries + sh "lipo Archives/Device.xcarchive/Products/Library/Frameworks/PayPalMessages.framework/PayPalMessages Archives/Simulator-NoArm64.xcarchive/Products/Library/Frameworks/PayPalMessages.framework/PayPalMessages -create -output PayPalMessages.framework/PayPalMessages" + # Zip up framework + sh "zip -r PayPalMessages.framework.zip PayPalMessages.framework" + # Sign xcframework with certificate + sh "codesign --timestamp -v --sign \"Braintree Payment Solutions, LLC (43253H4X22)\" PayPalMessages.xcframework" + # Zip up xcframework + sh "zip -r PayPalMessages.xcframework.zip PayPalMessages.xcframework" + end + rescue => e + error = e # Store the exception + ensure + # Cleanup keychain from machine + delete_keychain( + keychain_path: ENV["KEYCHAIN_PATH"] + ) + raise error if error # Re-raise the exception if it exists end - lane :publish do - pod_push(path: "PayPalMessages.podspec") + version_bump_spm( + version_number: options[:version], + checksum_file: "build/PayPalMessages.xcframework.zip" + ) + end + + desc "Sync develop with main branch" + lane :sync do |options| + # channel will be 'develop' when doing a prerelease which doesn't + # need to sync main back to develop then + if options[:channel].nil? || options[:channel].empty? + push_to_git_remote( + local_branch: "main", + remote_branch: "develop" + ) end + end + + desc "Publish podspec to Trunk" + lane :publish do + pod_push(path: "PayPalMessages.podspec") + end end diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..c531741 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,12309 @@ +{ + "name": "paypal-messages-ios", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "devDependencies": { + "@semantic-release/changelog": "^6.0.3", + "@semantic-release/exec": "^6.0.3", + "@semantic-release/git": "^10.0.1", + "conventional-changelog-conventionalcommits": "^6.1.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.4.tgz", + "integrity": "sha512-r1IONyb6Ia+jYR2vvIDhdWdlTGhqbBoFqLTQidzZ4kepUFH15ejXvFHxCVbtl7BOXIudsIubf4E81xeA3h3IXA==", + "dev": true, + "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", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "dev": true, + "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", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "peer": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "peer": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@octokit/auth-token": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz", + "integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/core": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.0.2.tgz", + "integrity": "sha512-cZUy1gUvd4vttMic7C0lwPed8IYXWYp8kHIMatyhY8t8n3Cpw2ILczkV5pGMPqef7v0bLo0pOHrEHarsau2Ydg==", + "dev": true, + "peer": true, + "dependencies": { + "@octokit/auth-token": "^4.0.0", + "@octokit/graphql": "^7.0.0", + "@octokit/request": "^8.0.2", + "@octokit/request-error": "^5.0.0", + "@octokit/types": "^12.0.0", + "before-after-hook": "^2.2.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/endpoint": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.2.tgz", + "integrity": "sha512-qhKW8YLIi+Kmc92FQUFGr++DYtkx/1fBv+Thua6baqnjnOsgBYJDCvWZR1YcINuHGOEQt416WOfE+A/oG60NBQ==", + "dev": true, + "peer": true, + "dependencies": { + "@octokit/types": "^12.0.0", + "is-plain-object": "^5.0.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/graphql": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.0.2.tgz", + "integrity": "sha512-OJ2iGMtj5Tg3s6RaXH22cJcxXRi7Y3EBqbHTBRq+PQAqfaS8f/236fUrWhfSn8P4jovyzqucxme7/vWSSZBX2Q==", + "dev": true, + "peer": true, + "dependencies": { + "@octokit/request": "^8.0.1", + "@octokit/types": "^12.0.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "19.0.2", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-19.0.2.tgz", + "integrity": "sha512-8li32fUDUeml/ACRp/njCWTsk5t17cfTM1jp9n08pBrqs5cDFJubtjsSnuz56r5Tad6jdEPJld7LxNp9dNcyjQ==", + "dev": true, + "peer": true + }, + "node_modules/@octokit/plugin-paginate-rest": { + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.1.4.tgz", + "integrity": "sha512-MvZx4WvfhBnt7PtH5XE7HORsO7bBk4er1FgRIUr1qJ89NR2I6bWjGyKsxk8z42FPQ34hFQm0Baanh4gzdZR4gQ==", + "dev": true, + "peer": true, + "dependencies": { + "@octokit/types": "^12.3.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": ">=5" + } + }, + "node_modules/@octokit/plugin-retry": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-6.0.1.tgz", + "integrity": "sha512-SKs+Tz9oj0g4p28qkZwl/topGcb0k0qPNX/i7vBKmDsjoeqnVfFUquqrE/O9oJY7+oLzdCtkiWSXLpLjvl6uog==", + "dev": true, + "peer": true, + "dependencies": { + "@octokit/request-error": "^5.0.0", + "@octokit/types": "^12.0.0", + "bottleneck": "^2.15.3" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": ">=5" + } + }, + "node_modules/@octokit/plugin-throttling": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-8.1.3.tgz", + "integrity": "sha512-pfyqaqpc0EXh5Cn4HX9lWYsZ4gGbjnSmUILeu4u2gnuM50K/wIk9s1Pxt3lVeVwekmITgN/nJdoh43Ka+vye8A==", + "dev": true, + "peer": true, + "dependencies": { + "@octokit/types": "^12.2.0", + "bottleneck": "^2.15.3" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": "^5.0.0" + } + }, + "node_modules/@octokit/request": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.1.6.tgz", + "integrity": "sha512-YhPaGml3ncZC1NfXpP3WZ7iliL1ap6tLkAp6MvbK2fTTPytzVUyUesBBogcdMm86uRYO5rHaM1xIWxigWZ17MQ==", + "dev": true, + "peer": true, + "dependencies": { + "@octokit/endpoint": "^9.0.0", + "@octokit/request-error": "^5.0.0", + "@octokit/types": "^12.0.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/request-error": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.0.1.tgz", + "integrity": "sha512-X7pnyTMV7MgtGmiXBwmO6M5kIPrntOXdyKZLigNfQWSEQzVxR4a4vo49vJjTWX70mPndj8KhfT4Dx+2Ng3vnBQ==", + "dev": true, + "peer": true, + "dependencies": { + "@octokit/types": "^12.0.0", + "deprecation": "^2.0.0", + "once": "^1.4.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/types": { + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.3.0.tgz", + "integrity": "sha512-nJ8X2HRr234q3w/FcovDlA+ttUU4m1eJAourvfUUtwAWeqL8AsyRqfnLvVnYn3NFbUnsmzQCzLNdFerPwdmcDQ==", + "dev": true, + "peer": true, + "dependencies": { + "@octokit/openapi-types": "^19.0.2" + } + }, + "node_modules/@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "dev": true, + "peer": true, + "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", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true, + "peer": true + }, + "node_modules/@pnpm/npm-conf": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.2.2.tgz", + "integrity": "sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==", + "dev": true, + "peer": true, + "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/@semantic-release/changelog": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@semantic-release/changelog/-/changelog-6.0.3.tgz", + "integrity": "sha512-dZuR5qByyfe3Y03TpmCvAxCyTnp7r5XwtHRf/8vD9EAn4ZWbavUX8adMtXYzE86EVh0gyLA7lm5yW4IV30XUag==", + "dev": true, + "dependencies": { + "@semantic-release/error": "^3.0.0", + "aggregate-error": "^3.0.0", + "fs-extra": "^11.0.0", + "lodash": "^4.17.4" + }, + "engines": { + "node": ">=14.17" + }, + "peerDependencies": { + "semantic-release": ">=18.0.0" + } + }, + "node_modules/@semantic-release/commit-analyzer": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-11.1.0.tgz", + "integrity": "sha512-cXNTbv3nXR2hlzHjAMgbuiQVtvWHTlwwISt60B+4NZv01y/QRY7p2HcJm8Eh2StzcTJoNnflvKjHH/cjFS7d5g==", + "dev": true, + "peer": true, + "dependencies": { + "conventional-changelog-angular": "^7.0.0", + "conventional-commits-filter": "^4.0.0", + "conventional-commits-parser": "^5.0.0", + "debug": "^4.0.0", + "import-from-esm": "^1.0.3", + "lodash-es": "^4.17.21", + "micromatch": "^4.0.2" + }, + "engines": { + "node": "^18.17 || >=20.6.1" + }, + "peerDependencies": { + "semantic-release": ">=20.1.0" + } + }, + "node_modules/@semantic-release/error": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-3.0.0.tgz", + "integrity": "sha512-5hiM4Un+tpl4cKw3lV4UgzJj+SmfNIDCLLw0TepzQxz9ZGV5ixnqkzIVF+3tp0ZHgcMKE+VNGHJjEeyFG2dcSw==", + "dev": true, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/@semantic-release/exec": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@semantic-release/exec/-/exec-6.0.3.tgz", + "integrity": "sha512-bxAq8vLOw76aV89vxxICecEa8jfaWwYITw6X74zzlO0mc/Bgieqx9kBRz9z96pHectiTAtsCwsQcUyLYWnp3VQ==", + "dev": true, + "dependencies": { + "@semantic-release/error": "^3.0.0", + "aggregate-error": "^3.0.0", + "debug": "^4.0.0", + "execa": "^5.0.0", + "lodash": "^4.17.4", + "parse-json": "^5.0.0" + }, + "engines": { + "node": ">=14.17" + }, + "peerDependencies": { + "semantic-release": ">=18.0.0" + } + }, + "node_modules/@semantic-release/git": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@semantic-release/git/-/git-10.0.1.tgz", + "integrity": "sha512-eWrx5KguUcU2wUPaO6sfvZI0wPafUKAMNC18aXY4EnNcrZL86dEmpNVnC9uMpGZkmZJ9EfCVJBQx4pV4EMGT1w==", + "dev": true, + "dependencies": { + "@semantic-release/error": "^3.0.0", + "aggregate-error": "^3.0.0", + "debug": "^4.0.0", + "dir-glob": "^3.0.0", + "execa": "^5.0.0", + "lodash": "^4.17.4", + "micromatch": "^4.0.0", + "p-reduce": "^2.0.0" + }, + "engines": { + "node": ">=14.17" + }, + "peerDependencies": { + "semantic-release": ">=18.0.0" + } + }, + "node_modules/@semantic-release/github": { + "version": "9.2.3", + "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-9.2.3.tgz", + "integrity": "sha512-FAjXb1F84CVI6IG8fWi+XS9ErYD+s3MHkP03zBa3+GyUrV4kqwYu/WPppIciHxujGFR51SAWPkOY5rnH6ZlrxA==", + "dev": true, + "peer": true, + "dependencies": { + "@octokit/core": "^5.0.0", + "@octokit/plugin-paginate-rest": "^9.0.0", + "@octokit/plugin-retry": "^6.0.0", + "@octokit/plugin-throttling": "^8.0.0", + "@semantic-release/error": "^4.0.0", + "aggregate-error": "^5.0.0", + "debug": "^4.3.4", + "dir-glob": "^3.0.1", + "globby": "^14.0.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "issue-parser": "^6.0.0", + "lodash-es": "^4.17.21", + "mime": "^3.0.0", + "p-filter": "^3.0.0", + "url-join": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "semantic-release": ">=20.1.0" + } + }, + "node_modules/@semantic-release/github/node_modules/@semantic-release/error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-4.0.0.tgz", + "integrity": "sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@semantic-release/github/node_modules/aggregate-error": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-5.0.0.tgz", + "integrity": "sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==", + "dev": true, + "peer": true, + "dependencies": { + "clean-stack": "^5.2.0", + "indent-string": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/github/node_modules/clean-stack": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-5.2.0.tgz", + "integrity": "sha512-TyUIUJgdFnCISzG5zu3291TAsE77ddchd0bepon1VVQrKLGKFED4iXFEDQ24mIPdPBbyE16PK3F8MYE1CmcBEQ==", + "dev": true, + "peer": true, + "dependencies": { + "escape-string-regexp": "5.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/github/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/github/node_modules/indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-11.0.1.tgz", + "integrity": "sha512-nFcT0pgVwpXsPkzjqP3ObH+pILeN1AbYscCDuYwgZEPZukL+RsGhrtdT4HA1Gjb/y1bVbE90JNtMIcgRi5z/Fg==", + "dev": true, + "peer": true, + "dependencies": { + "@semantic-release/error": "^4.0.0", + "aggregate-error": "^5.0.0", + "execa": "^8.0.0", + "fs-extra": "^11.0.0", + "lodash-es": "^4.17.21", + "nerf-dart": "^1.0.0", + "normalize-url": "^8.0.0", + "npm": "^10.0.0", + "rc": "^1.2.8", + "read-pkg": "^9.0.0", + "registry-auth-token": "^5.0.0", + "semver": "^7.1.2", + "tempy": "^3.0.0" + }, + "engines": { + "node": "^18.17 || >=20" + }, + "peerDependencies": { + "semantic-release": ">=20.1.0" + } + }, + "node_modules/@semantic-release/npm/node_modules/@semantic-release/error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-4.0.0.tgz", + "integrity": "sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@semantic-release/npm/node_modules/aggregate-error": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-5.0.0.tgz", + "integrity": "sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==", + "dev": true, + "peer": true, + "dependencies": { + "clean-stack": "^5.2.0", + "indent-string": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/clean-stack": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-5.2.0.tgz", + "integrity": "sha512-TyUIUJgdFnCISzG5zu3291TAsE77ddchd0bepon1VVQrKLGKFED4iXFEDQ24mIPdPBbyE16PK3F8MYE1CmcBEQ==", + "dev": true, + "peer": true, + "dependencies": { + "escape-string-regexp": "5.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "peer": true, + "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/@semantic-release/npm/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/@semantic-release/npm/node_modules/indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "peer": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, + "peer": true, + "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/@semantic-release/npm/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "peer": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@semantic-release/npm/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/release-notes-generator": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-12.1.0.tgz", + "integrity": "sha512-g6M9AjUKAZUZnxaJZnouNBeDNTCUrJ5Ltj+VJ60gJeDaRRahcHsry9HW8yKrnKkKNkx5lbWiEP1FPMqVNQz8Kg==", + "dev": true, + "peer": true, + "dependencies": { + "conventional-changelog-angular": "^7.0.0", + "conventional-changelog-writer": "^7.0.0", + "conventional-commits-filter": "^4.0.0", + "conventional-commits-parser": "^5.0.0", + "debug": "^4.0.0", + "get-stream": "^7.0.0", + "import-from-esm": "^1.0.3", + "into-stream": "^7.0.0", + "lodash-es": "^4.17.21", + "read-pkg-up": "^11.0.0" + }, + "engines": { + "node": "^18.17 || >=20.6.1" + }, + "peerDependencies": { + "semantic-release": ">=20.1.0" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/get-stream": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-7.0.1.tgz", + "integrity": "sha512-3M8C1EOFN6r8AMUhwUAACIoXZJEOufDU5+0gFFN5uNs6XYOralD2Pqkl7m046va6x77FwposWXbAhPPIOus7mQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-1.0.0.tgz", + "integrity": "sha512-rUV5WyJrJLoloD4NDN1V1+LDMDWOa4OTsT4yYJwQNpTU6FWxkxHpL7eu4w+DmiH8x/EAM1otkPE1+LaspIbplw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true, + "peer": true + }, + "node_modules/agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dev": true, + "peer": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-escapes": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.0.tgz", + "integrity": "sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==", + "dev": true, + "peer": true, + "dependencies": { + "type-fest": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ansicolors": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", + "integrity": "sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==", + "dev": true, + "peer": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "peer": true + }, + "node_modules/argv-formatter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/argv-formatter/-/argv-formatter-1.0.0.tgz", + "integrity": "sha512-F2+Hkm9xFaRg+GkaNnbwXNDV5O6pnCFEmqyhvfC/Ic5LbgOWjJh3L+mN/s91rxVL3znE7DYVpW0GJFT+4YBgWw==", + "dev": true, + "peer": true + }, + "node_modules/array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", + "dev": true + }, + "node_modules/before-after-hook": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", + "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==", + "dev": true, + "peer": true + }, + "node_modules/bottleneck": { + "version": "2.19.5", + "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", + "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==", + "dev": true, + "peer": true + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cardinal": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz", + "integrity": "sha512-JSr5eOgoEymtYHBjNWyjrMqet9Am2miJhlfKNdqLp6zoeAh0KN5dRAcxlecj5mAJrmQomgiOBj35xHLrFjqBpw==", + "dev": true, + "peer": true, + "dependencies": { + "ansicolors": "~0.3.2", + "redeyed": "~2.1.0" + }, + "bin": { + "cdl": "bin/cdl.js" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-table3": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", + "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", + "dev": true, + "peer": true, + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "peer": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "dev": true, + "dependencies": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "peer": true, + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/conventional-changelog-angular": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz", + "integrity": "sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==", + "dev": true, + "peer": true, + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/conventional-changelog-conventionalcommits": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-6.1.0.tgz", + "integrity": "sha512-3cS3GEtR78zTfMzk0AizXKKIdN4OvSh7ibNz6/DPbhWWQu7LqE/8+/GqSodV+sywUR2gpJAdP/1JFf4XtN7Zpw==", + "dev": true, + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/conventional-changelog-writer": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-7.0.1.tgz", + "integrity": "sha512-Uo+R9neH3r/foIvQ0MKcsXkX642hdm9odUp7TqgFS7BsalTcjzRlIfWZrZR1gbxOozKucaKt5KAbjW8J8xRSmA==", + "dev": true, + "peer": true, + "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-commits-filter": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-4.0.0.tgz", + "integrity": "sha512-rnpnibcSOdFcdclpFwWa+pPlZJhXE7l+XK04zxhbWrhgpR96h33QLz8hITTXbcYICxVr3HZFtbtUAQ+4LdBo9A==", + "dev": true, + "peer": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/conventional-commits-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz", + "integrity": "sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA==", + "dev": true, + "peer": true, + "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/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "peer": true + }, + "node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dev": true, + "peer": true, + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-random-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", + "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", + "dev": true, + "peer": true, + "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", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", + "dev": true, + "peer": true + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "dev": true, + "peer": true, + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "peer": true + }, + "node_modules/emojilib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/emojilib/-/emojilib-2.4.0.tgz", + "integrity": "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==", + "dev": true, + "peer": true + }, + "node_modules/env-ci": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-10.0.0.tgz", + "integrity": "sha512-U4xcd/utDYFgMh0yWj07R1H6L5fwhVbmxBCpnL0DbVSDZVnsC82HONw0wxtxNkIAcua3KtbomQvIk5xFZGAQJw==", + "dev": true, + "peer": true, + "dependencies": { + "execa": "^8.0.0", + "java-properties": "^1.0.2" + }, + "engines": { + "node": "^18.17 || >=20.6.1" + } + }, + "node_modules/env-ci/node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "peer": true, + "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/env-ci/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/env-ci/node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/env-ci/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "peer": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/env-ci/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/env-ci/node_modules/npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, + "peer": true, + "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/env-ci/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "peer": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/env-ci/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/env-ci/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/env-ci/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "peer": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "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/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "peer": true, + "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/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "peer": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/figures": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/figures/-/figures-6.0.1.tgz", + "integrity": "sha512-0oY/olScYD4IhQ8u//gCPA4F3mlTn2dacYmiDm/mbDQvpmLjV4uH+zhsQ5IyXRyvqkvtUkXkNdGvg5OFJTCsuQ==", + "dev": true, + "peer": true, + "dependencies": { + "is-unicode-supported": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "peer": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/find-up-simple": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.0.tgz", + "integrity": "sha512-q7Us7kcjj2VMePAa02hDAF6d+MzsdsAWEwYyOpwUtlerRBkOEPBCRZrAV4XfcSN8fHAgaD0hP7miwoay6DCprw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-versions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-5.1.0.tgz", + "integrity": "sha512-+iwzCJ7C5v5KgcBuueqVoNiHVoQpwiUK5XFLjf0affFTep+Wcw93tPvmb8tqujDNmzhBDPddnWV/qgWSXgq+Hg==", + "dev": true, + "peer": true, + "dependencies": { + "semver-regex": "^4.0.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", + "dev": true, + "peer": true, + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "node_modules/fs-extra": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", + "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "peer": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "peer": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/git-log-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/git-log-parser/-/git-log-parser-1.2.0.tgz", + "integrity": "sha512-rnCVNfkTL8tdNryFuaY0fYiBWEBcgF748O6ZI61rslBvr2o7U65c2/6npCRqH40vuAhtgtDiqLTJjBVdrejCzA==", + "dev": true, + "peer": true, + "dependencies": { + "argv-formatter": "~1.0.0", + "spawn-error-forwarder": "~1.0.0", + "split2": "~1.0.0", + "stream-combiner2": "~1.1.1", + "through2": "~2.0.0", + "traverse": "~0.6.6" + } + }, + "node_modules/git-log-parser/node_modules/split2": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-1.0.0.tgz", + "integrity": "sha512-NKywug4u4pX/AZBB1FCPzZ6/7O+Xhz1qMVbzTvvKvikjO99oPN87SkK08mEY9P63/5lWjK+wgOOgApnTg5r6qg==", + "dev": true, + "peer": true, + "dependencies": { + "through2": "~2.0.0" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "peer": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globby": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.0.tgz", + "integrity": "sha512-/1WM/LNHRAOH9lZta77uGbq0dAEQM+XjNesWwhlERDVenqothRbnzTrL3/LrIoEPPjeUHC3vrS6TwoyxeHs7MQ==", + "dev": true, + "peer": true, + "dependencies": { + "@sindresorhus/merge-streams": "^1.0.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", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", + "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dev": true, + "peer": true, + "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-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dev": true, + "peer": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hook-std": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hook-std/-/hook-std-3.0.0.tgz", + "integrity": "sha512-jHRQzjSDzMtFy34AGj1DN+vq54WVuhSvKgrHf0OMiFQTwDD4L/qqofVEWjLOBMTn5+lCD3fPg32W9yOfnEJTTw==", + "dev": true, + "peer": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hosted-git-info": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.1.tgz", + "integrity": "sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==", + "dev": true, + "peer": true, + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", + "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", + "dev": true, + "peer": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", + "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", + "dev": true, + "peer": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/ignore": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "peer": true, + "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", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/import-from-esm": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/import-from-esm/-/import-from-esm-1.3.3.tgz", + "integrity": "sha512-U3Qt/CyfFpTUv6LOP2jRTLYjphH6zg3okMfHbyqRa/W2w6hr8OsJWVggNlR4jxuojQy81TgTJTxgSkyoteRGMQ==", + "dev": true, + "peer": true, + "dependencies": { + "debug": "^4.3.4", + "import-meta-resolve": "^4.0.0" + }, + "engines": { + "node": ">=16.20" + } + }, + "node_modules/import-meta-resolve": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.0.0.tgz", + "integrity": "sha512-okYUR7ZQPH+efeuMJGlq4f8ubUgO50kByRPyt/Cy1Io4PSRsPjxME+YlVaCOx+NIToW7hCsZNFJyTPFFKepRSA==", + "dev": true, + "peer": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/index-to-position": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-0.1.2.tgz", + "integrity": "sha512-MWDKS3AS1bGCHLBA2VLImJz42f7bJh8wQsTGCzI3j519/CASStoDONUBVz2I/VID0MpiX3SGSnbOD2xUalbE5g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "peer": true + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "peer": true + }, + "node_modules/into-stream": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-7.0.0.tgz", + "integrity": "sha512-2dYz766i9HprMBasCMvHMuazJ7u4WzhJwo5kb3iPSiW/iRYV6uPari3zHoqZlnuaR7V1bEiNMxikhp37rdBXbw==", + "dev": true, + "peer": true, + "dependencies": { + "from2": "^2.3.0", + "p-is-promise": "^3.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "peer": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "peer": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-text-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-2.0.0.tgz", + "integrity": "sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==", + "dev": true, + "peer": true, + "dependencies": { + "text-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-unicode-supported": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.0.0.tgz", + "integrity": "sha512-FRdAyx5lusK1iHG0TWpVtk9+1i+GjrzRffhDg4ovQ7mcidMQ6mj+MhKPmvh7Xwyv5gIS06ns49CA7Sqg7lC22Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "peer": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/issue-parser": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-6.0.0.tgz", + "integrity": "sha512-zKa/Dxq2lGsBIXQ7CUZWTHfvxPC2ej0KfO7fIPqLlHB9J2hJ7rGhZ5rilhuufylr4RXYPzJUeFjKxz305OsNlA==", + "dev": true, + "peer": true, + "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": ">=10.13" + } + }, + "node_modules/java-properties": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/java-properties/-/java-properties-1.0.2.tgz", + "integrity": "sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "peer": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true, + "peer": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true, + "peer": true + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ], + "peer": true + }, + "node_modules/JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "peer": true, + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", + "dev": true, + "peer": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/load-json-file/node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "dev": true, + "peer": true, + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "peer": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "dev": true, + "peer": true + }, + "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, + "peer": true + }, + "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, + "peer": true + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true, + "peer": true + }, + "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, + "peer": true + }, + "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, + "peer": true + }, + "node_modules/lru-cache": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.3.tgz", + "integrity": "sha512-B7gr+F6MkqB3uzINHXNctGieGsRTMwIBgxkp0yq/5BwcuDzD4A8wQpHQW6vDAm1uKSLQghmRdD9sKqf2vJ1cEg==", + "dev": true, + "peer": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/marked": { + "version": "9.1.6", + "resolved": "https://registry.npmjs.org/marked/-/marked-9.1.6.tgz", + "integrity": "sha512-jcByLnIFkd5gSXZmjNvS1TlmRhCXZjIzHYlaGkPlLIekG55JDR2Z4va9tZwCiP+/RDERiNhMOFu01xd6O5ct1Q==", + "dev": true, + "peer": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 16" + } + }, + "node_modules/marked-terminal": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-6.1.0.tgz", + "integrity": "sha512-QaCSF6NV82oo6K0szEnmc65ooDeW0T/Adcyf0fcW+Hto2GT1VADFg8dn1zaeHqzj65fqDH1hMNChGNRaC/lbkA==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-escapes": "^6.2.0", + "cardinal": "^2.1.1", + "chalk": "^5.3.0", + "cli-table3": "^0.6.3", + "node-emoji": "^2.1.0", + "supports-hyperlinks": "^3.0.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "marked": ">=1 <11" + } + }, + "node_modules/marked-terminal/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "peer": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/meow": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz", + "integrity": "sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=16.10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "dev": true, + "peer": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "peer": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "peer": true + }, + "node_modules/nerf-dart": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/nerf-dart/-/nerf-dart-1.0.0.tgz", + "integrity": "sha512-EZSPZB70jiVsivaBLYDCyntd5eH8NTSMOn3rB+HxwdmKThGELLdYv8qVIMWvZEFy9w8ZZpW9h9OB32l1rGtj7g==", + "dev": true, + "peer": true + }, + "node_modules/node-emoji": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.1.3.tgz", + "integrity": "sha512-E2WEOVsgs7O16zsURJ/eH8BqhF029wGpEOnv7Urwdo2wmQanOACwJQh0devF9D9RhoZru0+9JXIS0dBXIAz+lA==", + "dev": true, + "peer": true, + "dependencies": { + "@sindresorhus/is": "^4.6.0", + "char-regex": "^1.0.2", + "emojilib": "^2.4.0", + "skin-tone": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/normalize-package-data": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.0.tgz", + "integrity": "sha512-UL7ELRVxYBHBgYEtZCXjxuD5vPxnmvMGq0jp/dGPKKrN7tfsBh2IY7TlJ15WWwdjRWD3RJbnsygUurTK3xkPkg==", + "dev": true, + "peer": true, + "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/normalize-url": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz", + "integrity": "sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/npm/-/npm-10.2.4.tgz", + "integrity": "sha512-umEuYneVEYO9KoEEI8n2sSGmNQeqco/3BSeacRlqIkCzw4E7XGtYSWMeJobxzr6hZ2n9cM+u5TsMTcC5bAgoWA==", + "bundleDependencies": [ + "@isaacs/string-locale-compare", + "@npmcli/arborist", + "@npmcli/config", + "@npmcli/fs", + "@npmcli/map-workspaces", + "@npmcli/package-json", + "@npmcli/promise-spawn", + "@npmcli/run-script", + "@sigstore/tuf", + "abbrev", + "archy", + "cacache", + "chalk", + "ci-info", + "cli-columns", + "cli-table3", + "columnify", + "fastest-levenshtein", + "fs-minipass", + "glob", + "graceful-fs", + "hosted-git-info", + "ini", + "init-package-json", + "is-cidr", + "json-parse-even-better-errors", + "libnpmaccess", + "libnpmdiff", + "libnpmexec", + "libnpmfund", + "libnpmhook", + "libnpmorg", + "libnpmpack", + "libnpmpublish", + "libnpmsearch", + "libnpmteam", + "libnpmversion", + "make-fetch-happen", + "minimatch", + "minipass", + "minipass-pipeline", + "ms", + "node-gyp", + "nopt", + "normalize-package-data", + "npm-audit-report", + "npm-install-checks", + "npm-package-arg", + "npm-pick-manifest", + "npm-profile", + "npm-registry-fetch", + "npm-user-validate", + "npmlog", + "p-map", + "pacote", + "parse-conflict-json", + "proc-log", + "qrcode-terminal", + "read", + "semver", + "spdx-expression-parse", + "ssri", + "strip-ansi", + "supports-color", + "tar", + "text-table", + "tiny-relative-date", + "treeverse", + "validate-npm-package-name", + "which", + "write-file-atomic" + ], + "dev": true, + "peer": true, + "dependencies": { + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/arborist": "^7.2.1", + "@npmcli/config": "^8.0.2", + "@npmcli/fs": "^3.1.0", + "@npmcli/map-workspaces": "^3.0.4", + "@npmcli/package-json": "^5.0.0", + "@npmcli/promise-spawn": "^7.0.0", + "@npmcli/run-script": "^7.0.2", + "@sigstore/tuf": "^2.2.0", + "abbrev": "^2.0.0", + "archy": "~1.0.0", + "cacache": "^18.0.0", + "chalk": "^5.3.0", + "ci-info": "^4.0.0", + "cli-columns": "^4.0.0", + "cli-table3": "^0.6.3", + "columnify": "^1.6.0", + "fastest-levenshtein": "^1.0.16", + "fs-minipass": "^3.0.3", + "glob": "^10.3.10", + "graceful-fs": "^4.2.11", + "hosted-git-info": "^7.0.1", + "ini": "^4.1.1", + "init-package-json": "^6.0.0", + "is-cidr": "^5.0.3", + "json-parse-even-better-errors": "^3.0.0", + "libnpmaccess": "^8.0.1", + "libnpmdiff": "^6.0.3", + "libnpmexec": "^7.0.4", + "libnpmfund": "^5.0.1", + "libnpmhook": "^10.0.0", + "libnpmorg": "^6.0.1", + "libnpmpack": "^6.0.3", + "libnpmpublish": "^9.0.2", + "libnpmsearch": "^7.0.0", + "libnpmteam": "^6.0.0", + "libnpmversion": "^5.0.1", + "make-fetch-happen": "^13.0.0", + "minimatch": "^9.0.3", + "minipass": "^7.0.4", + "minipass-pipeline": "^1.2.4", + "ms": "^2.1.2", + "node-gyp": "^10.0.1", + "nopt": "^7.2.0", + "normalize-package-data": "^6.0.0", + "npm-audit-report": "^5.0.0", + "npm-install-checks": "^6.3.0", + "npm-package-arg": "^11.0.1", + "npm-pick-manifest": "^9.0.0", + "npm-profile": "^9.0.0", + "npm-registry-fetch": "^16.1.0", + "npm-user-validate": "^2.0.0", + "npmlog": "^7.0.1", + "p-map": "^4.0.0", + "pacote": "^17.0.4", + "parse-conflict-json": "^3.0.1", + "proc-log": "^3.0.0", + "qrcode-terminal": "^0.12.0", + "read": "^2.1.0", + "semver": "^7.5.4", + "spdx-expression-parse": "^3.0.1", + "ssri": "^10.0.5", + "strip-ansi": "^7.1.0", + "supports-color": "^9.4.0", + "tar": "^6.2.0", + "text-table": "~0.2.0", + "tiny-relative-date": "^1.3.0", + "treeverse": "^3.0.0", + "validate-npm-package-name": "^5.0.0", + "which": "^4.0.0", + "write-file-atomic": "^5.0.1" + }, + "bin": { + "npm": "bin/npm-cli.js", + "npx": "bin/npx-cli.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/@colors/colors": { + "version": "1.5.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/npm/node_modules/@isaacs/cliui": { + "version": "8.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "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/npm/node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/npm/node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "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/npm/node_modules/@isaacs/string-locale-compare": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true + }, + "node_modules/npm/node_modules/@npmcli/agent": { + "version": "2.2.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/arborist": { + "version": "7.2.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/fs": "^3.1.0", + "@npmcli/installed-package-contents": "^2.0.2", + "@npmcli/map-workspaces": "^3.0.2", + "@npmcli/metavuln-calculator": "^7.0.0", + "@npmcli/name-from-folder": "^2.0.0", + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/package-json": "^5.0.0", + "@npmcli/query": "^3.0.1", + "@npmcli/run-script": "^7.0.2", + "bin-links": "^4.0.1", + "cacache": "^18.0.0", + "common-ancestor-path": "^1.0.1", + "hosted-git-info": "^7.0.1", + "json-parse-even-better-errors": "^3.0.0", + "json-stringify-nice": "^1.1.4", + "minimatch": "^9.0.0", + "nopt": "^7.0.0", + "npm-install-checks": "^6.2.0", + "npm-package-arg": "^11.0.1", + "npm-pick-manifest": "^9.0.0", + "npm-registry-fetch": "^16.0.0", + "npmlog": "^7.0.1", + "pacote": "^17.0.4", + "parse-conflict-json": "^3.0.0", + "proc-log": "^3.0.0", + "promise-all-reject-late": "^1.0.0", + "promise-call-limit": "^1.0.2", + "read-package-json-fast": "^3.0.2", + "semver": "^7.3.7", + "ssri": "^10.0.5", + "treeverse": "^3.0.0", + "walk-up-path": "^3.0.1" + }, + "bin": { + "arborist": "bin/index.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/config": { + "version": "8.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@npmcli/map-workspaces": "^3.0.2", + "ci-info": "^4.0.0", + "ini": "^4.1.0", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", + "read-package-json-fast": "^3.0.2", + "semver": "^7.3.5", + "walk-up-path": "^3.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/disparity-colors": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "ansi-styles": "^4.3.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/disparity-colors/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/npm/node_modules/@npmcli/fs": { + "version": "3.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/git": { + "version": "5.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@npmcli/promise-spawn": "^7.0.0", + "lru-cache": "^10.0.1", + "npm-pick-manifest": "^9.0.0", + "proc-log": "^3.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/installed-package-contents": { + "version": "2.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "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/npm/node_modules/@npmcli/map-workspaces": { + "version": "3.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@npmcli/name-from-folder": "^2.0.0", + "glob": "^10.2.2", + "minimatch": "^9.0.0", + "read-package-json-fast": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/metavuln-calculator": { + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "cacache": "^18.0.0", + "json-parse-even-better-errors": "^3.0.0", + "pacote": "^17.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/name-from-folder": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/node-gyp": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/package-json": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@npmcli/git": "^5.0.0", + "glob": "^10.2.2", + "hosted-git-info": "^7.0.0", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "proc-log": "^3.0.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/promise-spawn": { + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/query": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/run-script": { + "version": "7.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/promise-spawn": "^7.0.0", + "node-gyp": "^10.0.0", + "read-package-json-fast": "^3.0.0", + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/npm/node_modules/@sigstore/bundle": { + "version": "2.1.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.2.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@sigstore/protobuf-specs": { + "version": "0.2.1", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@sigstore/sign": { + "version": "2.2.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@sigstore/bundle": "^2.1.0", + "@sigstore/protobuf-specs": "^0.2.1", + "make-fetch-happen": "^13.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@sigstore/tuf": { + "version": "2.2.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.2.1", + "tuf-js": "^2.1.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@tufjs/canonical-json": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@tufjs/models": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^9.0.3" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/abbrev": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/abort-controller": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/npm/node_modules/agent-base": { + "version": "7.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/aggregate-error": { + "version": "3.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/ansi-regex": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/npm/node_modules/ansi-styles": { + "version": "6.2.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/npm/node_modules/aproba": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true + }, + "node_modules/npm/node_modules/archy": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/npm/node_modules/are-we-there-yet": { + "version": "4.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^4.1.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/npm/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" + } + ], + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/npm/node_modules/bin-links": { + "version": "4.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "cmd-shim": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "read-cmd-shim": "^4.0.0", + "write-file-atomic": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/binary-extensions": { + "version": "2.2.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/brace-expansion": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/npm/node_modules/buffer": { + "version": "6.0.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" + } + ], + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/npm/node_modules/builtins": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "semver": "^7.0.0" + } + }, + "node_modules/npm/node_modules/cacache": { + "version": "18.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.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": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/chalk": { + "version": "5.3.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/npm/node_modules/chownr": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/ci-info": { + "version": "4.0.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/cidr-regex": { + "version": "4.0.3", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "ip-regex": "^5.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/npm/node_modules/clean-stack": { + "version": "2.2.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/cli-columns": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/npm/node_modules/cli-columns/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/cli-columns/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/cli-table3": { + "version": "0.6.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/npm/node_modules/clone": { + "version": "1.0.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/npm/node_modules/cmd-shim": { + "version": "6.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/npm/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/npm/node_modules/color-support": { + "version": "1.1.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/npm/node_modules/columnify": { + "version": "1.6.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "strip-ansi": "^6.0.1", + "wcwidth": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/npm/node_modules/columnify/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/columnify/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/common-ancestor-path": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true + }, + "node_modules/npm/node_modules/console-control-strings": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true + }, + "node_modules/npm/node_modules/cross-spawn": { + "version": "7.0.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/cssesc": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/debug": { + "version": "4.3.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/npm/node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/npm/node_modules/defaults": { + "version": "1.0.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/delegates": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/npm/node_modules/diff": { + "version": "5.1.0", + "dev": true, + "inBundle": true, + "license": "BSD-3-Clause", + "peer": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/npm/node_modules/eastasianwidth": { + "version": "0.2.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/npm/node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/npm/node_modules/encoding": { + "version": "0.1.13", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/npm/node_modules/env-paths": { + "version": "2.2.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/err-code": { + "version": "2.0.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/npm/node_modules/event-target-shim": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/events": { + "version": "3.3.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/npm/node_modules/exponential-backoff": { + "version": "3.1.1", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "peer": true + }, + "node_modules/npm/node_modules/fastest-levenshtein": { + "version": "1.0.16", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/npm/node_modules/foreground-child": { + "version": "3.1.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/fs-minipass": { + "version": "3.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/function-bind": { + "version": "1.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/npm/node_modules/gauge": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "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": "^4.0.1", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/gauge/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/gauge/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/glob": { + "version": "10.3.10", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "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/npm/node_modules/graceful-fs": { + "version": "4.2.11", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true + }, + "node_modules/npm/node_modules/has-unicode": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true + }, + "node_modules/npm/node_modules/hasown": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/npm/node_modules/hosted-git-info": { + "version": "7.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/http-cache-semantics": { + "version": "4.1.1", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "peer": true + }, + "node_modules/npm/node_modules/http-proxy-agent": { + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/https-proxy-agent": { + "version": "7.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/iconv-lite": { + "version": "0.6.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/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" + } + ], + "inBundle": true, + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/npm/node_modules/ignore-walk": { + "version": "6.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "minimatch": "^9.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/imurmurhash": { + "version": "0.1.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/npm/node_modules/indent-string": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/ini": { + "version": "4.1.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/init-package-json": { + "version": "6.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "npm-package-arg": "^11.0.0", + "promzard": "^1.0.0", + "read": "^2.0.0", + "read-package-json": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/ip": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/npm/node_modules/ip-regex": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/is-cidr": { + "version": "5.0.3", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "cidr-regex": "4.0.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/npm/node_modules/is-core-module": { + "version": "2.13.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/npm/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/is-lambda": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/npm/node_modules/isexe": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true + }, + "node_modules/npm/node_modules/jackspeak": { + "version": "2.3.6", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "peer": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/npm/node_modules/json-parse-even-better-errors": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/json-stringify-nice": { + "version": "1.1.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/jsonparse": { + "version": "1.3.1", + "dev": true, + "engines": [ + "node >= 0.2.0" + ], + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/npm/node_modules/just-diff": { + "version": "6.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/npm/node_modules/just-diff-apply": { + "version": "5.5.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/npm/node_modules/libnpmaccess": { + "version": "8.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "npm-package-arg": "^11.0.1", + "npm-registry-fetch": "^16.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmdiff": { + "version": "6.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@npmcli/arborist": "^7.2.1", + "@npmcli/disparity-colors": "^3.0.0", + "@npmcli/installed-package-contents": "^2.0.2", + "binary-extensions": "^2.2.0", + "diff": "^5.1.0", + "minimatch": "^9.0.0", + "npm-package-arg": "^11.0.1", + "pacote": "^17.0.4", + "tar": "^6.2.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmexec": { + "version": "7.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@npmcli/arborist": "^7.2.1", + "@npmcli/run-script": "^7.0.2", + "ci-info": "^4.0.0", + "npm-package-arg": "^11.0.1", + "npmlog": "^7.0.1", + "pacote": "^17.0.4", + "proc-log": "^3.0.0", + "read": "^2.0.0", + "read-package-json-fast": "^3.0.2", + "semver": "^7.3.7", + "walk-up-path": "^3.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmfund": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@npmcli/arborist": "^7.2.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmhook": { + "version": "10.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^16.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmorg": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^16.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmpack": { + "version": "6.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@npmcli/arborist": "^7.2.1", + "@npmcli/run-script": "^7.0.2", + "npm-package-arg": "^11.0.1", + "pacote": "^17.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmpublish": { + "version": "9.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "ci-info": "^4.0.0", + "normalize-package-data": "^6.0.0", + "npm-package-arg": "^11.0.1", + "npm-registry-fetch": "^16.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.7", + "sigstore": "^2.1.0", + "ssri": "^10.0.5" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmsearch": { + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "npm-registry-fetch": "^16.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmteam": { + "version": "6.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^16.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmversion": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@npmcli/git": "^5.0.3", + "@npmcli/run-script": "^7.0.2", + "json-parse-even-better-errors": "^3.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/lru-cache": { + "version": "10.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/npm/node_modules/make-fetch-happen": { + "version": "13.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@npmcli/agent": "^2.0.0", + "cacache": "^18.0.0", + "http-cache-semantics": "^4.1.1", + "is-lambda": "^1.0.1", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/minimatch": { + "version": "9.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/minipass": { + "version": "7.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/npm/node_modules/minipass-collect": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/minipass-collect/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-fetch": { + "version": "3.0.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "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/npm/node_modules/minipass-flush": { + "version": "1.0.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-json-stream": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "node_modules/npm/node_modules/minipass-json-stream/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-pipeline": { + "version": "1.2.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-sized": { + "version": "1.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minizlib": { + "version": "2.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/mkdirp": { + "version": "1.0.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/ms": { + "version": "2.1.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/npm/node_modules/mute-stream": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/negotiator": { + "version": "0.6.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/npm/node_modules/node-gyp": { + "version": "10.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^10.3.10", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^13.0.0", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^4.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/nopt": { + "version": "7.2.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/normalize-package-data": { + "version": "6.0.0", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "peer": true, + "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/npm/node_modules/npm-audit-report": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-bundled": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-install-checks": { + "version": "6.3.0", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-normalize-package-bin": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-package-arg": { + "version": "11.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "hosted-git-info": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-packlist": { + "version": "8.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "ignore-walk": "^6.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-pick-manifest": { + "version": "9.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^11.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-profile": { + "version": "9.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "npm-registry-fetch": "^16.0.0", + "proc-log": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-registry-fetch": { + "version": "16.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "make-fetch-happen": "^13.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^11.0.0", + "proc-log": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-user-validate": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "peer": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npmlog": { + "version": "7.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "are-we-there-yet": "^4.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^5.0.0", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/p-map": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/pacote": { + "version": "17.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@npmcli/git": "^5.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/promise-spawn": "^7.0.0", + "@npmcli/run-script": "^7.0.0", + "cacache": "^18.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^11.0.0", + "npm-packlist": "^8.0.0", + "npm-pick-manifest": "^9.0.0", + "npm-registry-fetch": "^16.0.0", + "proc-log": "^3.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^7.0.0", + "read-package-json-fast": "^3.0.0", + "sigstore": "^2.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "lib/bin.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/parse-conflict-json": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "json-parse-even-better-errors": "^3.0.0", + "just-diff": "^6.0.0", + "just-diff-apply": "^5.2.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/path-key": { + "version": "3.1.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/path-scurry": { + "version": "1.10.1", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "peer": true, + "dependencies": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/postcss-selector-parser": { + "version": "6.0.13", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/proc-log": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/process": { + "version": "0.11.10", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/npm/node_modules/promise-all-reject-late": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/promise-call-limit": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/promise-inflight": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true + }, + "node_modules/npm/node_modules/promise-retry": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/promzard": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "read": "^2.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/qrcode-terminal": { + "version": "0.12.0", + "dev": true, + "inBundle": true, + "peer": true, + "bin": { + "qrcode-terminal": "bin/qrcode-terminal.js" + } + }, + "node_modules/npm/node_modules/read": { + "version": "2.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "mute-stream": "~1.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/read-cmd-shim": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/read-package-json": { + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "glob": "^10.2.2", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/read-package-json-fast": { + "version": "3.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "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/npm/node_modules/readable-stream": { + "version": "4.4.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/npm/node_modules/retry": { + "version": "0.12.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/npm/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" + } + ], + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/npm/node_modules/safer-buffer": { + "version": "2.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/npm/node_modules/semver": { + "version": "7.5.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/set-blocking": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true + }, + "node_modules/npm/node_modules/shebang-command": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/shebang-regex": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/signal-exit": { + "version": "4.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/sigstore": { + "version": "2.1.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@sigstore/bundle": "^2.1.0", + "@sigstore/protobuf-specs": "^0.2.1", + "@sigstore/sign": "^2.1.0", + "@sigstore/tuf": "^2.1.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/smart-buffer": { + "version": "4.2.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/npm/node_modules/socks": { + "version": "2.7.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/npm/node_modules/socks-proxy-agent": { + "version": "8.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "socks": "^2.7.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/spdx-correct": { + "version": "3.2.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/npm/node_modules/spdx-exceptions": { + "version": "2.3.0", + "dev": true, + "inBundle": true, + "license": "CC-BY-3.0", + "peer": true + }, + "node_modules/npm/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/npm/node_modules/spdx-license-ids": { + "version": "3.0.16", + "dev": true, + "inBundle": true, + "license": "CC0-1.0", + "peer": true + }, + "node_modules/npm/node_modules/ssri": { + "version": "10.0.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/string_decoder": { + "version": "1.3.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/npm/node_modules/string-width": { + "version": "4.2.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/string-width/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/string-width/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/strip-ansi": { + "version": "7.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/npm/node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/supports-color": { + "version": "9.4.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/npm/node_modules/tar": { + "version": "6.2.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "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/npm/node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/text-table": { + "version": "0.2.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/npm/node_modules/tiny-relative-date": { + "version": "1.3.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/npm/node_modules/treeverse": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/tuf-js": { + "version": "2.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@tufjs/models": "2.0.0", + "debug": "^4.3.4", + "make-fetch-happen": "^13.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/unique-filename": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/unique-slug": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/util-deprecate": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/npm/node_modules/validate-npm-package-license": { + "version": "3.0.4", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/npm/node_modules/validate-npm-package-name": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "builtins": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/walk-up-path": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true + }, + "node_modules/npm/node_modules/wcwidth": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/npm/node_modules/which": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/which/node_modules/isexe": { + "version": "3.1.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/npm/node_modules/wide-align": { + "version": "1.1.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/npm/node_modules/wrap-ansi": { + "version": "8.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "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/npm/node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "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/npm/node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/npm/node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "9.2.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/npm/node_modules/wrap-ansi/node_modules/string-width": { + "version": "5.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "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/npm/node_modules/write-file-atomic": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "peer": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-each-series": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-3.0.0.tgz", + "integrity": "sha512-lastgtAdoH9YaLyDa5i5z64q+kzOcQHsQ5SsZJD3q0VEyI8mq872S3geuNbRUQLVAE9siMfgKrpj7MloKFHruw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-filter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-3.0.0.tgz", + "integrity": "sha512-QtoWLjXAW++uTX67HZQz1dbTpqBfiidsB6VtQUC9iR85S120+s0T5sO6s+B5MLzFcZkrEd/DGMmCjR+f2Qpxwg==", + "dev": true, + "peer": true, + "dependencies": { + "p-map": "^5.1.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-is-promise": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz", + "integrity": "sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "peer": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dev": true, + "peer": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-map": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-5.5.0.tgz", + "integrity": "sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg==", + "dev": true, + "peer": true, + "dependencies": { + "aggregate-error": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map/node_modules/aggregate-error": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-4.0.1.tgz", + "integrity": "sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==", + "dev": true, + "peer": true, + "dependencies": { + "clean-stack": "^4.0.0", + "indent-string": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map/node_modules/clean-stack": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-4.2.0.tgz", + "integrity": "sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==", + "dev": true, + "peer": true, + "dependencies": { + "escape-string-regexp": "5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map/node_modules/indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-reduce": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-2.1.0.tgz", + "integrity": "sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "peer": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "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/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-conf": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz", + "integrity": "sha512-C+VUP+8jis7EsQZIhDYmS5qlNtjv2yP4SNtjXK9AP1ZcTRlnSfuumaTnRfYZnYgUUYVIKqL0fRvmUGDV2fmp6g==", + "dev": true, + "peer": true, + "dependencies": { + "find-up": "^2.0.0", + "load-json-file": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "peer": true + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true, + "peer": true + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "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" + } + ], + "peer": true + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "peer": true, + "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/read-pkg": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-9.0.1.tgz", + "integrity": "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==", + "dev": true, + "peer": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.3", + "normalize-package-data": "^6.0.0", + "parse-json": "^8.0.0", + "type-fest": "^4.6.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-11.0.0.tgz", + "integrity": "sha512-LOVbvF1Q0SZdjClSefZ0Nz5z8u+tIE7mV5NibzmE9VYmDe9CaBbAVtz1veOSZbofrdsilxuDAYnFenukZVp8/Q==", + "deprecated": "Renamed to read-package-up", + "dev": true, + "peer": true, + "dependencies": { + "find-up-simple": "^1.0.0", + "read-pkg": "^9.0.0", + "type-fest": "^4.6.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/type-fest": { + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.8.2.tgz", + "integrity": "sha512-mcvrCjixA5166hSrUoJgGb9gBQN4loMYyj9zxuMs/66ibHNEFd5JXMw37YVDx58L4/QID9jIzdTBB4mDwDJ6KQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg/node_modules/json-parse-even-better-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", + "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", + "dev": true, + "peer": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-pkg/node_modules/parse-json": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.0.1.tgz", + "integrity": "sha512-soKUg/q/8bcfuF3+plsbYldE74cVEVEPSC1BUPIGTaX1byXdz6Fo+CVYBdH0jj/5xWsFrNRksl11QkBgHqPQeQ==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.22.13", + "index-to-position": "^0.1.1", + "json-parse-even-better-errors": "^3.0.0", + "type-fest": "^4.7.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg/node_modules/type-fest": { + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.8.2.tgz", + "integrity": "sha512-mcvrCjixA5166hSrUoJgGb9gBQN4loMYyj9zxuMs/66ibHNEFd5JXMw37YVDx58L4/QID9jIzdTBB4mDwDJ6KQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "peer": true, + "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/redeyed": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/redeyed/-/redeyed-2.1.1.tgz", + "integrity": "sha512-FNpGGo1DycYAdnrKFxCMmKYgo/mILAqtRYbkdQD8Ep/Hk2PQ5+aEAEx+IU713RTDmuBaH0c8P5ZozurNu5ObRQ==", + "dev": true, + "peer": true, + "dependencies": { + "esprima": "~4.0.0" + } + }, + "node_modules/registry-auth-token": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz", + "integrity": "sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==", + "dev": true, + "peer": true, + "dependencies": { + "@pnpm/npm-conf": "^2.1.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "peer": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "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" + } + ], + "peer": true, + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "peer": true + }, + "node_modules/semantic-release": { + "version": "22.0.8", + "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-22.0.8.tgz", + "integrity": "sha512-55rb31jygqIYsGU/rY+gXXm2fnxBIWo9azOjxbqKsPnq7p70zwZ5v+xnD7TxJC+zvS3sy1eHLGXYWCaX3WI76A==", + "dev": true, + "peer": true, + "dependencies": { + "@semantic-release/commit-analyzer": "^11.0.0", + "@semantic-release/error": "^4.0.0", + "@semantic-release/github": "^9.0.0", + "@semantic-release/npm": "^11.0.0", + "@semantic-release/release-notes-generator": "^12.0.0", + "aggregate-error": "^5.0.0", + "cosmiconfig": "^8.0.0", + "debug": "^4.0.0", + "env-ci": "^10.0.0", + "execa": "^8.0.0", + "figures": "^6.0.0", + "find-versions": "^5.1.0", + "get-stream": "^6.0.0", + "git-log-parser": "^1.2.0", + "hook-std": "^3.0.0", + "hosted-git-info": "^7.0.0", + "import-from-esm": "^1.3.1", + "lodash-es": "^4.17.21", + "marked": "^9.0.0", + "marked-terminal": "^6.0.0", + "micromatch": "^4.0.2", + "p-each-series": "^3.0.0", + "p-reduce": "^3.0.0", + "read-pkg-up": "^11.0.0", + "resolve-from": "^5.0.0", + "semver": "^7.3.2", + "semver-diff": "^4.0.0", + "signale": "^1.2.1", + "yargs": "^17.5.1" + }, + "bin": { + "semantic-release": "bin/semantic-release.js" + }, + "engines": { + "node": "^18.17 || >=20.6.1" + } + }, + "node_modules/semantic-release/node_modules/@semantic-release/error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-4.0.0.tgz", + "integrity": "sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/semantic-release/node_modules/aggregate-error": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-5.0.0.tgz", + "integrity": "sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==", + "dev": true, + "peer": true, + "dependencies": { + "clean-stack": "^5.2.0", + "indent-string": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/clean-stack": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-5.2.0.tgz", + "integrity": "sha512-TyUIUJgdFnCISzG5zu3291TAsE77ddchd0bepon1VVQrKLGKFED4iXFEDQ24mIPdPBbyE16PK3F8MYE1CmcBEQ==", + "dev": true, + "peer": true, + "dependencies": { + "escape-string-regexp": "5.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "peer": true, + "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/semantic-release/node_modules/execa/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/semantic-release/node_modules/indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "peer": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, + "peer": true, + "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/semantic-release/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "peer": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/p-reduce": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-3.0.0.tgz", + "integrity": "sha512-xsrIUgI0Kn6iyDYm9StOpOeK29XM1aboGji26+QEortiFST1hGZaUQOLhtEbqHErPpGW/aSz6allwK2qcptp0Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/semantic-release/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "peer": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-4.0.0.tgz", + "integrity": "sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==", + "dev": true, + "peer": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semver-regex": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-4.0.5.tgz", + "integrity": "sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "peer": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/signale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/signale/-/signale-1.4.0.tgz", + "integrity": "sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w==", + "dev": true, + "peer": true, + "dependencies": { + "chalk": "^2.3.2", + "figures": "^2.0.0", + "pkg-conf": "^2.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/signale/node_modules/figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==", + "dev": true, + "peer": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/skin-tone": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/skin-tone/-/skin-tone-2.0.0.tgz", + "integrity": "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==", + "dev": true, + "peer": true, + "dependencies": { + "unicode-emoji-modifier-base": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spawn-error-forwarder": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/spawn-error-forwarder/-/spawn-error-forwarder-1.0.0.tgz", + "integrity": "sha512-gRjMgK5uFjbCvdibeGJuy3I5OYz6VLoVdsOJdA6wV0WlfQVLFueoqMxwwYD9RODdgb6oUIvlRlsyFSiQkMKu0g==", + "dev": true, + "peer": true + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "peer": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true, + "peer": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "peer": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", + "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", + "dev": true, + "peer": true + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/stream-combiner2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", + "integrity": "sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw==", + "dev": true, + "peer": true, + "dependencies": { + "duplexer2": "~0.1.0", + "readable-stream": "^2.0.2" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "peer": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "peer": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-hyperlinks": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.0.0.tgz", + "integrity": "sha512-QBDPHyPQDRTy9ku4URNGY5Lah8PAaXs6tAAwp55sL5WCsSW7GIfdf6W5ixfziW+t7wh3GVvHyHHyQ1ESsoRvaA==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=14.18" + } + }, + "node_modules/supports-hyperlinks/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, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks/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, + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/temp-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-3.0.0.tgz", + "integrity": "sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/tempy": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-3.1.0.tgz", + "integrity": "sha512-7jDLIdD2Zp0bDe5r3D2qtkd1QOCacylBuL7oa4udvN6v2pqr4+LcCr67C8DR1zkpaZ8XosF5m1yQSabKAW6f2g==", + "dev": true, + "peer": true, + "dependencies": { + "is-stream": "^3.0.0", + "temp-dir": "^3.0.0", + "type-fest": "^2.12.2", + "unique-string": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tempy/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "peer": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tempy/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/text-extensions": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-2.4.0.tgz", + "integrity": "sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true, + "peer": true + }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "peer": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/traverse": { + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.7.tgz", + "integrity": "sha512-/y956gpUo9ZNCb99YjxG7OaslxZWHfCHAUUfshwqOXmxUIvqLjVO581BT+gM59+QV9tFe6/CGG53tsA1Y7RSdg==", + "dev": true, + "peer": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/type-fest": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", + "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/uglify-js": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "dev": true, + "optional": true, + "peer": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/unicode-emoji-modifier-base": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz", + "integrity": "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unique-string": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", + "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", + "dev": true, + "peer": true, + "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", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz", + "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==", + "dev": true, + "peer": true + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/url-join": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-5.0.0.tgz", + "integrity": "sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==", + "dev": true, + "peer": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "peer": true + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "peer": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "peer": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "peer": true, + "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/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, + "peer": true, + "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", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/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, + "peer": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "peer": true + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "peer": true + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "peer": true, + "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", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + } + } + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.4.tgz", + "integrity": "sha512-r1IONyb6Ia+jYR2vvIDhdWdlTGhqbBoFqLTQidzZ4kepUFH15ejXvFHxCVbtl7BOXIudsIubf4E81xeA3h3IXA==", + "dev": true, + "requires": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true + }, + "@babel/highlight": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + } + }, + "@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "optional": true, + "peer": true + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "peer": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "peer": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "peer": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@octokit/auth-token": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz", + "integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==", + "dev": true, + "peer": true + }, + "@octokit/core": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.0.2.tgz", + "integrity": "sha512-cZUy1gUvd4vttMic7C0lwPed8IYXWYp8kHIMatyhY8t8n3Cpw2ILczkV5pGMPqef7v0bLo0pOHrEHarsau2Ydg==", + "dev": true, + "peer": true, + "requires": { + "@octokit/auth-token": "^4.0.0", + "@octokit/graphql": "^7.0.0", + "@octokit/request": "^8.0.2", + "@octokit/request-error": "^5.0.0", + "@octokit/types": "^12.0.0", + "before-after-hook": "^2.2.0", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/endpoint": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.2.tgz", + "integrity": "sha512-qhKW8YLIi+Kmc92FQUFGr++DYtkx/1fBv+Thua6baqnjnOsgBYJDCvWZR1YcINuHGOEQt416WOfE+A/oG60NBQ==", + "dev": true, + "peer": true, + "requires": { + "@octokit/types": "^12.0.0", + "is-plain-object": "^5.0.0", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/graphql": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.0.2.tgz", + "integrity": "sha512-OJ2iGMtj5Tg3s6RaXH22cJcxXRi7Y3EBqbHTBRq+PQAqfaS8f/236fUrWhfSn8P4jovyzqucxme7/vWSSZBX2Q==", + "dev": true, + "peer": true, + "requires": { + "@octokit/request": "^8.0.1", + "@octokit/types": "^12.0.0", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/openapi-types": { + "version": "19.0.2", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-19.0.2.tgz", + "integrity": "sha512-8li32fUDUeml/ACRp/njCWTsk5t17cfTM1jp9n08pBrqs5cDFJubtjsSnuz56r5Tad6jdEPJld7LxNp9dNcyjQ==", + "dev": true, + "peer": true + }, + "@octokit/plugin-paginate-rest": { + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.1.4.tgz", + "integrity": "sha512-MvZx4WvfhBnt7PtH5XE7HORsO7bBk4er1FgRIUr1qJ89NR2I6bWjGyKsxk8z42FPQ34hFQm0Baanh4gzdZR4gQ==", + "dev": true, + "peer": true, + "requires": { + "@octokit/types": "^12.3.0" + } + }, + "@octokit/plugin-retry": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-6.0.1.tgz", + "integrity": "sha512-SKs+Tz9oj0g4p28qkZwl/topGcb0k0qPNX/i7vBKmDsjoeqnVfFUquqrE/O9oJY7+oLzdCtkiWSXLpLjvl6uog==", + "dev": true, + "peer": true, + "requires": { + "@octokit/request-error": "^5.0.0", + "@octokit/types": "^12.0.0", + "bottleneck": "^2.15.3" + } + }, + "@octokit/plugin-throttling": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-8.1.3.tgz", + "integrity": "sha512-pfyqaqpc0EXh5Cn4HX9lWYsZ4gGbjnSmUILeu4u2gnuM50K/wIk9s1Pxt3lVeVwekmITgN/nJdoh43Ka+vye8A==", + "dev": true, + "peer": true, + "requires": { + "@octokit/types": "^12.2.0", + "bottleneck": "^2.15.3" + } + }, + "@octokit/request": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.1.6.tgz", + "integrity": "sha512-YhPaGml3ncZC1NfXpP3WZ7iliL1ap6tLkAp6MvbK2fTTPytzVUyUesBBogcdMm86uRYO5rHaM1xIWxigWZ17MQ==", + "dev": true, + "peer": true, + "requires": { + "@octokit/endpoint": "^9.0.0", + "@octokit/request-error": "^5.0.0", + "@octokit/types": "^12.0.0", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/request-error": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.0.1.tgz", + "integrity": "sha512-X7pnyTMV7MgtGmiXBwmO6M5kIPrntOXdyKZLigNfQWSEQzVxR4a4vo49vJjTWX70mPndj8KhfT4Dx+2Ng3vnBQ==", + "dev": true, + "peer": true, + "requires": { + "@octokit/types": "^12.0.0", + "deprecation": "^2.0.0", + "once": "^1.4.0" + } + }, + "@octokit/types": { + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.3.0.tgz", + "integrity": "sha512-nJ8X2HRr234q3w/FcovDlA+ttUU4m1eJAourvfUUtwAWeqL8AsyRqfnLvVnYn3NFbUnsmzQCzLNdFerPwdmcDQ==", + "dev": true, + "peer": true, + "requires": { + "@octokit/openapi-types": "^19.0.2" + } + }, + "@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "dev": true, + "peer": true + }, + "@pnpm/network.ca-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "dev": true, + "peer": true, + "requires": { + "graceful-fs": "4.2.10" + }, + "dependencies": { + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true, + "peer": true + } + } + }, + "@pnpm/npm-conf": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.2.2.tgz", + "integrity": "sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==", + "dev": true, + "peer": true, + "requires": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + } + }, + "@semantic-release/changelog": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@semantic-release/changelog/-/changelog-6.0.3.tgz", + "integrity": "sha512-dZuR5qByyfe3Y03TpmCvAxCyTnp7r5XwtHRf/8vD9EAn4ZWbavUX8adMtXYzE86EVh0gyLA7lm5yW4IV30XUag==", + "dev": true, + "requires": { + "@semantic-release/error": "^3.0.0", + "aggregate-error": "^3.0.0", + "fs-extra": "^11.0.0", + "lodash": "^4.17.4" + } + }, + "@semantic-release/commit-analyzer": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-11.1.0.tgz", + "integrity": "sha512-cXNTbv3nXR2hlzHjAMgbuiQVtvWHTlwwISt60B+4NZv01y/QRY7p2HcJm8Eh2StzcTJoNnflvKjHH/cjFS7d5g==", + "dev": true, + "peer": true, + "requires": { + "conventional-changelog-angular": "^7.0.0", + "conventional-commits-filter": "^4.0.0", + "conventional-commits-parser": "^5.0.0", + "debug": "^4.0.0", + "import-from-esm": "^1.0.3", + "lodash-es": "^4.17.21", + "micromatch": "^4.0.2" + } + }, + "@semantic-release/error": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-3.0.0.tgz", + "integrity": "sha512-5hiM4Un+tpl4cKw3lV4UgzJj+SmfNIDCLLw0TepzQxz9ZGV5ixnqkzIVF+3tp0ZHgcMKE+VNGHJjEeyFG2dcSw==", + "dev": true + }, + "@semantic-release/exec": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@semantic-release/exec/-/exec-6.0.3.tgz", + "integrity": "sha512-bxAq8vLOw76aV89vxxICecEa8jfaWwYITw6X74zzlO0mc/Bgieqx9kBRz9z96pHectiTAtsCwsQcUyLYWnp3VQ==", + "dev": true, + "requires": { + "@semantic-release/error": "^3.0.0", + "aggregate-error": "^3.0.0", + "debug": "^4.0.0", + "execa": "^5.0.0", + "lodash": "^4.17.4", + "parse-json": "^5.0.0" + } + }, + "@semantic-release/git": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@semantic-release/git/-/git-10.0.1.tgz", + "integrity": "sha512-eWrx5KguUcU2wUPaO6sfvZI0wPafUKAMNC18aXY4EnNcrZL86dEmpNVnC9uMpGZkmZJ9EfCVJBQx4pV4EMGT1w==", + "dev": true, + "requires": { + "@semantic-release/error": "^3.0.0", + "aggregate-error": "^3.0.0", + "debug": "^4.0.0", + "dir-glob": "^3.0.0", + "execa": "^5.0.0", + "lodash": "^4.17.4", + "micromatch": "^4.0.0", + "p-reduce": "^2.0.0" + } + }, + "@semantic-release/github": { + "version": "9.2.3", + "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-9.2.3.tgz", + "integrity": "sha512-FAjXb1F84CVI6IG8fWi+XS9ErYD+s3MHkP03zBa3+GyUrV4kqwYu/WPppIciHxujGFR51SAWPkOY5rnH6ZlrxA==", + "dev": true, + "peer": true, + "requires": { + "@octokit/core": "^5.0.0", + "@octokit/plugin-paginate-rest": "^9.0.0", + "@octokit/plugin-retry": "^6.0.0", + "@octokit/plugin-throttling": "^8.0.0", + "@semantic-release/error": "^4.0.0", + "aggregate-error": "^5.0.0", + "debug": "^4.3.4", + "dir-glob": "^3.0.1", + "globby": "^14.0.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "issue-parser": "^6.0.0", + "lodash-es": "^4.17.21", + "mime": "^3.0.0", + "p-filter": "^3.0.0", + "url-join": "^5.0.0" + }, + "dependencies": { + "@semantic-release/error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-4.0.0.tgz", + "integrity": "sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ==", + "dev": true, + "peer": true + }, + "aggregate-error": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-5.0.0.tgz", + "integrity": "sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==", + "dev": true, + "peer": true, + "requires": { + "clean-stack": "^5.2.0", + "indent-string": "^5.0.0" + } + }, + "clean-stack": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-5.2.0.tgz", + "integrity": "sha512-TyUIUJgdFnCISzG5zu3291TAsE77ddchd0bepon1VVQrKLGKFED4iXFEDQ24mIPdPBbyE16PK3F8MYE1CmcBEQ==", + "dev": true, + "peer": true, + "requires": { + "escape-string-regexp": "5.0.0" + } + }, + "escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "peer": true + }, + "indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true, + "peer": true + } + } + }, + "@semantic-release/npm": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-11.0.1.tgz", + "integrity": "sha512-nFcT0pgVwpXsPkzjqP3ObH+pILeN1AbYscCDuYwgZEPZukL+RsGhrtdT4HA1Gjb/y1bVbE90JNtMIcgRi5z/Fg==", + "dev": true, + "peer": true, + "requires": { + "@semantic-release/error": "^4.0.0", + "aggregate-error": "^5.0.0", + "execa": "^8.0.0", + "fs-extra": "^11.0.0", + "lodash-es": "^4.17.21", + "nerf-dart": "^1.0.0", + "normalize-url": "^8.0.0", + "npm": "^10.0.0", + "rc": "^1.2.8", + "read-pkg": "^9.0.0", + "registry-auth-token": "^5.0.0", + "semver": "^7.1.2", + "tempy": "^3.0.0" + }, + "dependencies": { + "@semantic-release/error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-4.0.0.tgz", + "integrity": "sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ==", + "dev": true, + "peer": true + }, + "aggregate-error": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-5.0.0.tgz", + "integrity": "sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==", + "dev": true, + "peer": true, + "requires": { + "clean-stack": "^5.2.0", + "indent-string": "^5.0.0" + } + }, + "clean-stack": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-5.2.0.tgz", + "integrity": "sha512-TyUIUJgdFnCISzG5zu3291TAsE77ddchd0bepon1VVQrKLGKFED4iXFEDQ24mIPdPBbyE16PK3F8MYE1CmcBEQ==", + "dev": true, + "peer": true, + "requires": { + "escape-string-regexp": "5.0.0" + } + }, + "escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "peer": true + }, + "execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "peer": true, + "requires": { + "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" + } + }, + "get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "peer": true + }, + "human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "peer": true + }, + "indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true, + "peer": true + }, + "is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "peer": true + }, + "mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "peer": true + }, + "npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, + "peer": true, + "requires": { + "path-key": "^4.0.0" + } + }, + "onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "peer": true, + "requires": { + "mimic-fn": "^4.0.0" + } + }, + "path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "peer": true + }, + "signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "peer": true + }, + "strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "peer": true + } + } + }, + "@semantic-release/release-notes-generator": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-12.1.0.tgz", + "integrity": "sha512-g6M9AjUKAZUZnxaJZnouNBeDNTCUrJ5Ltj+VJ60gJeDaRRahcHsry9HW8yKrnKkKNkx5lbWiEP1FPMqVNQz8Kg==", + "dev": true, + "peer": true, + "requires": { + "conventional-changelog-angular": "^7.0.0", + "conventional-changelog-writer": "^7.0.0", + "conventional-commits-filter": "^4.0.0", + "conventional-commits-parser": "^5.0.0", + "debug": "^4.0.0", + "get-stream": "^7.0.0", + "import-from-esm": "^1.0.3", + "into-stream": "^7.0.0", + "lodash-es": "^4.17.21", + "read-pkg-up": "^11.0.0" + }, + "dependencies": { + "get-stream": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-7.0.1.tgz", + "integrity": "sha512-3M8C1EOFN6r8AMUhwUAACIoXZJEOufDU5+0gFFN5uNs6XYOralD2Pqkl7m046va6x77FwposWXbAhPPIOus7mQ==", + "dev": true, + "peer": true + } + } + }, + "@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true, + "peer": true + }, + "@sindresorhus/merge-streams": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-1.0.0.tgz", + "integrity": "sha512-rUV5WyJrJLoloD4NDN1V1+LDMDWOa4OTsT4yYJwQNpTU6FWxkxHpL7eu4w+DmiH8x/EAM1otkPE1+LaspIbplw==", + "dev": true, + "peer": true + }, + "@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true, + "peer": true + }, + "agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dev": true, + "peer": true, + "requires": { + "debug": "^4.3.4" + } + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ansi-escapes": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.0.tgz", + "integrity": "sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==", + "dev": true, + "peer": true, + "requires": { + "type-fest": "^3.0.0" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "peer": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "ansicolors": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", + "integrity": "sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==", + "dev": true, + "peer": true + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "peer": true + }, + "argv-formatter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/argv-formatter/-/argv-formatter-1.0.0.tgz", + "integrity": "sha512-F2+Hkm9xFaRg+GkaNnbwXNDV5O6pnCFEmqyhvfC/Ic5LbgOWjJh3L+mN/s91rxVL3znE7DYVpW0GJFT+4YBgWw==", + "dev": true, + "peer": true + }, + "array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", + "dev": true + }, + "before-after-hook": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", + "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==", + "dev": true, + "peer": true + }, + "bottleneck": { + "version": "2.19.5", + "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", + "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==", + "dev": true, + "peer": true + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "peer": true + }, + "cardinal": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz", + "integrity": "sha512-JSr5eOgoEymtYHBjNWyjrMqet9Am2miJhlfKNdqLp6zoeAh0KN5dRAcxlecj5mAJrmQomgiOBj35xHLrFjqBpw==", + "dev": true, + "peer": true, + "requires": { + "ansicolors": "~0.3.2", + "redeyed": "~2.1.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "peer": true + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, + "cli-table3": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", + "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", + "dev": true, + "peer": true, + "requires": { + "@colors/colors": "1.5.0", + "string-width": "^4.2.0" + } + }, + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "peer": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "dev": true, + "requires": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + }, + "config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "peer": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "conventional-changelog-angular": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz", + "integrity": "sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==", + "dev": true, + "peer": true, + "requires": { + "compare-func": "^2.0.0" + } + }, + "conventional-changelog-conventionalcommits": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-6.1.0.tgz", + "integrity": "sha512-3cS3GEtR78zTfMzk0AizXKKIdN4OvSh7ibNz6/DPbhWWQu7LqE/8+/GqSodV+sywUR2gpJAdP/1JFf4XtN7Zpw==", + "dev": true, + "requires": { + "compare-func": "^2.0.0" + } + }, + "conventional-changelog-writer": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-7.0.1.tgz", + "integrity": "sha512-Uo+R9neH3r/foIvQ0MKcsXkX642hdm9odUp7TqgFS7BsalTcjzRlIfWZrZR1gbxOozKucaKt5KAbjW8J8xRSmA==", + "dev": true, + "peer": true, + "requires": { + "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" + } + }, + "conventional-commits-filter": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-4.0.0.tgz", + "integrity": "sha512-rnpnibcSOdFcdclpFwWa+pPlZJhXE7l+XK04zxhbWrhgpR96h33QLz8hITTXbcYICxVr3HZFtbtUAQ+4LdBo9A==", + "dev": true, + "peer": true + }, + "conventional-commits-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz", + "integrity": "sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA==", + "dev": true, + "peer": true, + "requires": { + "is-text-path": "^2.0.0", + "JSONStream": "^1.3.5", + "meow": "^12.0.1", + "split2": "^4.0.0" + } + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "peer": true + }, + "cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dev": true, + "peer": true, + "requires": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "crypto-random-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", + "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", + "dev": true, + "peer": true, + "requires": { + "type-fest": "^1.0.1" + }, + "dependencies": { + "type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true, + "peer": true + } + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "peer": true + }, + "deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", + "dev": true, + "peer": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "requires": { + "is-obj": "^2.0.0" + } + }, + "duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "dev": true, + "peer": true, + "requires": { + "readable-stream": "^2.0.2" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "peer": true + }, + "emojilib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/emojilib/-/emojilib-2.4.0.tgz", + "integrity": "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==", + "dev": true, + "peer": true + }, + "env-ci": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-10.0.0.tgz", + "integrity": "sha512-U4xcd/utDYFgMh0yWj07R1H6L5fwhVbmxBCpnL0DbVSDZVnsC82HONw0wxtxNkIAcua3KtbomQvIk5xFZGAQJw==", + "dev": true, + "peer": true, + "requires": { + "execa": "^8.0.0", + "java-properties": "^1.0.2" + }, + "dependencies": { + "execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "peer": true, + "requires": { + "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" + } + }, + "get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "peer": true + }, + "human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "peer": true + }, + "is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "peer": true + }, + "mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "peer": true + }, + "npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, + "peer": true, + "requires": { + "path-key": "^4.0.0" + } + }, + "onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "peer": true, + "requires": { + "mimic-fn": "^4.0.0" + } + }, + "path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "peer": true + }, + "signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "peer": true + }, + "strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "peer": true + } + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "peer": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "peer": true + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "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" + } + }, + "fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "peer": true, + "requires": { + "@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" + } + }, + "fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "peer": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "figures": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/figures/-/figures-6.0.1.tgz", + "integrity": "sha512-0oY/olScYD4IhQ8u//gCPA4F3mlTn2dacYmiDm/mbDQvpmLjV4uH+zhsQ5IyXRyvqkvtUkXkNdGvg5OFJTCsuQ==", + "dev": true, + "peer": true, + "requires": { + "is-unicode-supported": "^2.0.0" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "peer": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "find-up-simple": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.0.tgz", + "integrity": "sha512-q7Us7kcjj2VMePAa02hDAF6d+MzsdsAWEwYyOpwUtlerRBkOEPBCRZrAV4XfcSN8fHAgaD0hP7miwoay6DCprw==", + "dev": true, + "peer": true + }, + "find-versions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-5.1.0.tgz", + "integrity": "sha512-+iwzCJ7C5v5KgcBuueqVoNiHVoQpwiUK5XFLjf0affFTep+Wcw93tPvmb8tqujDNmzhBDPddnWV/qgWSXgq+Hg==", + "dev": true, + "peer": true, + "requires": { + "semver-regex": "^4.0.5" + } + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", + "dev": true, + "peer": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs-extra": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", + "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "peer": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "peer": true + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "git-log-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/git-log-parser/-/git-log-parser-1.2.0.tgz", + "integrity": "sha512-rnCVNfkTL8tdNryFuaY0fYiBWEBcgF748O6ZI61rslBvr2o7U65c2/6npCRqH40vuAhtgtDiqLTJjBVdrejCzA==", + "dev": true, + "peer": true, + "requires": { + "argv-formatter": "~1.0.0", + "spawn-error-forwarder": "~1.0.0", + "split2": "~1.0.0", + "stream-combiner2": "~1.1.1", + "through2": "~2.0.0", + "traverse": "~0.6.6" + }, + "dependencies": { + "split2": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-1.0.0.tgz", + "integrity": "sha512-NKywug4u4pX/AZBB1FCPzZ6/7O+Xhz1qMVbzTvvKvikjO99oPN87SkK08mEY9P63/5lWjK+wgOOgApnTg5r6qg==", + "dev": true, + "peer": true, + "requires": { + "through2": "~2.0.0" + } + } + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "peer": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globby": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.0.tgz", + "integrity": "sha512-/1WM/LNHRAOH9lZta77uGbq0dAEQM+XjNesWwhlERDVenqothRbnzTrL3/LrIoEPPjeUHC3vrS6TwoyxeHs7MQ==", + "dev": true, + "peer": true, + "requires": { + "@sindresorhus/merge-streams": "^1.0.0", + "fast-glob": "^3.3.2", + "ignore": "^5.2.4", + "path-type": "^5.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.1.0" + }, + "dependencies": { + "path-type": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", + "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", + "dev": true, + "peer": true + } + } + }, + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dev": true, + "peer": true, + "requires": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dev": true, + "peer": true, + "requires": { + "function-bind": "^1.1.2" + } + }, + "hook-std": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hook-std/-/hook-std-3.0.0.tgz", + "integrity": "sha512-jHRQzjSDzMtFy34AGj1DN+vq54WVuhSvKgrHf0OMiFQTwDD4L/qqofVEWjLOBMTn5+lCD3fPg32W9yOfnEJTTw==", + "dev": true, + "peer": true + }, + "hosted-git-info": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.1.tgz", + "integrity": "sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==", + "dev": true, + "peer": true, + "requires": { + "lru-cache": "^10.0.1" + } + }, + "http-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", + "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", + "dev": true, + "peer": true, + "requires": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + } + }, + "https-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", + "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", + "dev": true, + "peer": true, + "requires": { + "agent-base": "^7.0.2", + "debug": "4" + } + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + }, + "ignore": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "dev": true, + "peer": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "peer": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "peer": true + } + } + }, + "import-from-esm": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/import-from-esm/-/import-from-esm-1.3.3.tgz", + "integrity": "sha512-U3Qt/CyfFpTUv6LOP2jRTLYjphH6zg3okMfHbyqRa/W2w6hr8OsJWVggNlR4jxuojQy81TgTJTxgSkyoteRGMQ==", + "dev": true, + "peer": true, + "requires": { + "debug": "^4.3.4", + "import-meta-resolve": "^4.0.0" + } + }, + "import-meta-resolve": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.0.0.tgz", + "integrity": "sha512-okYUR7ZQPH+efeuMJGlq4f8ubUgO50kByRPyt/Cy1Io4PSRsPjxME+YlVaCOx+NIToW7hCsZNFJyTPFFKepRSA==", + "dev": true, + "peer": true + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, + "index-to-position": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-0.1.2.tgz", + "integrity": "sha512-MWDKS3AS1bGCHLBA2VLImJz42f7bJh8wQsTGCzI3j519/CASStoDONUBVz2I/VID0MpiX3SGSnbOD2xUalbE5g==", + "dev": true, + "peer": true + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "peer": true + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "peer": true + }, + "into-stream": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-7.0.0.tgz", + "integrity": "sha512-2dYz766i9HprMBasCMvHMuazJ7u4WzhJwo5kb3iPSiW/iRYV6uPari3zHoqZlnuaR7V1bEiNMxikhp37rdBXbw==", + "dev": true, + "peer": true, + "requires": { + "from2": "^2.3.0", + "p-is-promise": "^3.0.0" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "peer": true, + "requires": { + "hasown": "^2.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "peer": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "peer": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "peer": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true + }, + "is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "peer": true + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, + "is-text-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-2.0.0.tgz", + "integrity": "sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==", + "dev": true, + "peer": true, + "requires": { + "text-extensions": "^2.0.0" + } + }, + "is-unicode-supported": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.0.0.tgz", + "integrity": "sha512-FRdAyx5lusK1iHG0TWpVtk9+1i+GjrzRffhDg4ovQ7mcidMQ6mj+MhKPmvh7Xwyv5gIS06ns49CA7Sqg7lC22Q==", + "dev": true, + "peer": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "peer": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "issue-parser": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-6.0.0.tgz", + "integrity": "sha512-zKa/Dxq2lGsBIXQ7CUZWTHfvxPC2ej0KfO7fIPqLlHB9J2hJ7rGhZ5rilhuufylr4RXYPzJUeFjKxz305OsNlA==", + "dev": true, + "peer": true, + "requires": { + "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" + } + }, + "java-properties": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/java-properties/-/java-properties-1.0.2.tgz", + "integrity": "sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==", + "dev": true, + "peer": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "peer": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true, + "peer": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true, + "peer": true + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "peer": true + }, + "JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "peer": true, + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", + "dev": true, + "peer": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "dev": true, + "peer": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + } + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "peer": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "dev": true, + "peer": true + }, + "lodash.capitalize": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz", + "integrity": "sha512-kZzYOKspf8XVX5AvmQF94gQW0lejFVgb80G85bU4ZWzoJ6C03PQg3coYAUpSTpQWelrZELd3XWgHzw4Ck5kaIw==", + "dev": true, + "peer": true + }, + "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, + "peer": true + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true, + "peer": true + }, + "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, + "peer": true + }, + "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, + "peer": true + }, + "lru-cache": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.3.tgz", + "integrity": "sha512-B7gr+F6MkqB3uzINHXNctGieGsRTMwIBgxkp0yq/5BwcuDzD4A8wQpHQW6vDAm1uKSLQghmRdD9sKqf2vJ1cEg==", + "dev": true, + "peer": true + }, + "marked": { + "version": "9.1.6", + "resolved": "https://registry.npmjs.org/marked/-/marked-9.1.6.tgz", + "integrity": "sha512-jcByLnIFkd5gSXZmjNvS1TlmRhCXZjIzHYlaGkPlLIekG55JDR2Z4va9tZwCiP+/RDERiNhMOFu01xd6O5ct1Q==", + "dev": true, + "peer": true + }, + "marked-terminal": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-6.1.0.tgz", + "integrity": "sha512-QaCSF6NV82oo6K0szEnmc65ooDeW0T/Adcyf0fcW+Hto2GT1VADFg8dn1zaeHqzj65fqDH1hMNChGNRaC/lbkA==", + "dev": true, + "peer": true, + "requires": { + "ansi-escapes": "^6.2.0", + "cardinal": "^2.1.1", + "chalk": "^5.3.0", + "cli-table3": "^0.6.3", + "node-emoji": "^2.1.0", + "supports-hyperlinks": "^3.0.0" + }, + "dependencies": { + "chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "peer": true + } + } + }, + "meow": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz", + "integrity": "sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==", + "dev": true, + "peer": true + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "peer": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "dev": true, + "peer": true + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "peer": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "peer": true + }, + "nerf-dart": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/nerf-dart/-/nerf-dart-1.0.0.tgz", + "integrity": "sha512-EZSPZB70jiVsivaBLYDCyntd5eH8NTSMOn3rB+HxwdmKThGELLdYv8qVIMWvZEFy9w8ZZpW9h9OB32l1rGtj7g==", + "dev": true, + "peer": true + }, + "node-emoji": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.1.3.tgz", + "integrity": "sha512-E2WEOVsgs7O16zsURJ/eH8BqhF029wGpEOnv7Urwdo2wmQanOACwJQh0devF9D9RhoZru0+9JXIS0dBXIAz+lA==", + "dev": true, + "peer": true, + "requires": { + "@sindresorhus/is": "^4.6.0", + "char-regex": "^1.0.2", + "emojilib": "^2.4.0", + "skin-tone": "^2.0.0" + } + }, + "normalize-package-data": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.0.tgz", + "integrity": "sha512-UL7ELRVxYBHBgYEtZCXjxuD5vPxnmvMGq0jp/dGPKKrN7tfsBh2IY7TlJ15WWwdjRWD3RJbnsygUurTK3xkPkg==", + "dev": true, + "peer": true, + "requires": { + "hosted-git-info": "^7.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + } + }, + "normalize-url": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz", + "integrity": "sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==", + "dev": true, + "peer": true + }, + "npm": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/npm/-/npm-10.2.4.tgz", + "integrity": "sha512-umEuYneVEYO9KoEEI8n2sSGmNQeqco/3BSeacRlqIkCzw4E7XGtYSWMeJobxzr6hZ2n9cM+u5TsMTcC5bAgoWA==", + "dev": true, + "peer": true, + "requires": { + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/arborist": "^7.2.1", + "@npmcli/config": "^8.0.2", + "@npmcli/fs": "^3.1.0", + "@npmcli/map-workspaces": "^3.0.4", + "@npmcli/package-json": "^5.0.0", + "@npmcli/promise-spawn": "^7.0.0", + "@npmcli/run-script": "^7.0.2", + "@sigstore/tuf": "^2.2.0", + "abbrev": "^2.0.0", + "archy": "~1.0.0", + "cacache": "^18.0.0", + "chalk": "^5.3.0", + "ci-info": "^4.0.0", + "cli-columns": "^4.0.0", + "cli-table3": "^0.6.3", + "columnify": "^1.6.0", + "fastest-levenshtein": "^1.0.16", + "fs-minipass": "^3.0.3", + "glob": "^10.3.10", + "graceful-fs": "^4.2.11", + "hosted-git-info": "^7.0.1", + "ini": "^4.1.1", + "init-package-json": "^6.0.0", + "is-cidr": "^5.0.3", + "json-parse-even-better-errors": "^3.0.0", + "libnpmaccess": "^8.0.1", + "libnpmdiff": "^6.0.3", + "libnpmexec": "^7.0.4", + "libnpmfund": "^5.0.1", + "libnpmhook": "^10.0.0", + "libnpmorg": "^6.0.1", + "libnpmpack": "^6.0.3", + "libnpmpublish": "^9.0.2", + "libnpmsearch": "^7.0.0", + "libnpmteam": "^6.0.0", + "libnpmversion": "^5.0.1", + "make-fetch-happen": "^13.0.0", + "minimatch": "^9.0.3", + "minipass": "^7.0.4", + "minipass-pipeline": "^1.2.4", + "ms": "^2.1.2", + "node-gyp": "^10.0.1", + "nopt": "^7.2.0", + "normalize-package-data": "^6.0.0", + "npm-audit-report": "^5.0.0", + "npm-install-checks": "^6.3.0", + "npm-package-arg": "^11.0.1", + "npm-pick-manifest": "^9.0.0", + "npm-profile": "^9.0.0", + "npm-registry-fetch": "^16.1.0", + "npm-user-validate": "^2.0.0", + "npmlog": "^7.0.1", + "p-map": "^4.0.0", + "pacote": "^17.0.4", + "parse-conflict-json": "^3.0.1", + "proc-log": "^3.0.0", + "qrcode-terminal": "^0.12.0", + "read": "^2.1.0", + "semver": "^7.5.4", + "spdx-expression-parse": "^3.0.1", + "ssri": "^10.0.5", + "strip-ansi": "^7.1.0", + "supports-color": "^9.4.0", + "tar": "^6.2.0", + "text-table": "~0.2.0", + "tiny-relative-date": "^1.3.0", + "treeverse": "^3.0.0", + "validate-npm-package-name": "^5.0.0", + "which": "^4.0.0", + "write-file-atomic": "^5.0.1" + }, + "dependencies": { + "@colors/colors": { + "version": "1.5.0", + "bundled": true, + "dev": true, + "optional": true, + "peer": true + }, + "@isaacs/cliui": { + "version": "8.0.2", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "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" + }, + "dependencies": { + "emoji-regex": { + "version": "9.2.2", + "bundled": true, + "dev": true, + "peer": true + }, + "string-width": { + "version": "5.1.2", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + } + } + }, + "@isaacs/string-locale-compare": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "peer": true + }, + "@npmcli/agent": { + "version": "2.2.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.1" + } + }, + "@npmcli/arborist": { + "version": "7.2.1", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/fs": "^3.1.0", + "@npmcli/installed-package-contents": "^2.0.2", + "@npmcli/map-workspaces": "^3.0.2", + "@npmcli/metavuln-calculator": "^7.0.0", + "@npmcli/name-from-folder": "^2.0.0", + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/package-json": "^5.0.0", + "@npmcli/query": "^3.0.1", + "@npmcli/run-script": "^7.0.2", + "bin-links": "^4.0.1", + "cacache": "^18.0.0", + "common-ancestor-path": "^1.0.1", + "hosted-git-info": "^7.0.1", + "json-parse-even-better-errors": "^3.0.0", + "json-stringify-nice": "^1.1.4", + "minimatch": "^9.0.0", + "nopt": "^7.0.0", + "npm-install-checks": "^6.2.0", + "npm-package-arg": "^11.0.1", + "npm-pick-manifest": "^9.0.0", + "npm-registry-fetch": "^16.0.0", + "npmlog": "^7.0.1", + "pacote": "^17.0.4", + "parse-conflict-json": "^3.0.0", + "proc-log": "^3.0.0", + "promise-all-reject-late": "^1.0.0", + "promise-call-limit": "^1.0.2", + "read-package-json-fast": "^3.0.2", + "semver": "^7.3.7", + "ssri": "^10.0.5", + "treeverse": "^3.0.0", + "walk-up-path": "^3.0.1" + } + }, + "@npmcli/config": { + "version": "8.0.2", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "@npmcli/map-workspaces": "^3.0.2", + "ci-info": "^4.0.0", + "ini": "^4.1.0", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", + "read-package-json-fast": "^3.0.2", + "semver": "^7.3.5", + "walk-up-path": "^3.0.1" + } + }, + "@npmcli/disparity-colors": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "ansi-styles": "^4.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "color-convert": "^2.0.1" + } + } + } + }, + "@npmcli/fs": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "semver": "^7.3.5" + } + }, + "@npmcli/git": { + "version": "5.0.3", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "@npmcli/promise-spawn": "^7.0.0", + "lru-cache": "^10.0.1", + "npm-pick-manifest": "^9.0.0", + "proc-log": "^3.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^4.0.0" + } + }, + "@npmcli/installed-package-contents": { + "version": "2.0.2", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + } + }, + "@npmcli/map-workspaces": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "@npmcli/name-from-folder": "^2.0.0", + "glob": "^10.2.2", + "minimatch": "^9.0.0", + "read-package-json-fast": "^3.0.0" + } + }, + "@npmcli/metavuln-calculator": { + "version": "7.0.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "cacache": "^18.0.0", + "json-parse-even-better-errors": "^3.0.0", + "pacote": "^17.0.0", + "semver": "^7.3.5" + } + }, + "@npmcli/name-from-folder": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "peer": true + }, + "@npmcli/node-gyp": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "peer": true + }, + "@npmcli/package-json": { + "version": "5.0.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "@npmcli/git": "^5.0.0", + "glob": "^10.2.2", + "hosted-git-info": "^7.0.0", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "proc-log": "^3.0.0", + "semver": "^7.5.3" + } + }, + "@npmcli/promise-spawn": { + "version": "7.0.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "which": "^4.0.0" + } + }, + "@npmcli/query": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "postcss-selector-parser": "^6.0.10" + } + }, + "@npmcli/run-script": { + "version": "7.0.2", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/promise-spawn": "^7.0.0", + "node-gyp": "^10.0.0", + "read-package-json-fast": "^3.0.0", + "which": "^4.0.0" + } + }, + "@pkgjs/parseargs": { + "version": "0.11.0", + "bundled": true, + "dev": true, + "optional": true, + "peer": true + }, + "@sigstore/bundle": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "@sigstore/protobuf-specs": "^0.2.1" + } + }, + "@sigstore/protobuf-specs": { + "version": "0.2.1", + "bundled": true, + "dev": true, + "peer": true + }, + "@sigstore/sign": { + "version": "2.2.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "@sigstore/bundle": "^2.1.0", + "@sigstore/protobuf-specs": "^0.2.1", + "make-fetch-happen": "^13.0.0" + } + }, + "@sigstore/tuf": { + "version": "2.2.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "@sigstore/protobuf-specs": "^0.2.1", + "tuf-js": "^2.1.0" + } + }, + "@tufjs/canonical-json": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "peer": true + }, + "@tufjs/models": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^9.0.3" + } + }, + "abbrev": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "peer": true + }, + "abort-controller": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "event-target-shim": "^5.0.0" + } + }, + "agent-base": { + "version": "7.1.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "debug": "^4.3.4" + } + }, + "aggregate-error": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ansi-regex": { + "version": "6.0.1", + "bundled": true, + "dev": true, + "peer": true + }, + "ansi-styles": { + "version": "6.2.1", + "bundled": true, + "dev": true, + "peer": true + }, + "aproba": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "peer": true + }, + "archy": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "peer": true + }, + "are-we-there-yet": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^4.1.0" + } + }, + "balanced-match": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "peer": true + }, + "base64-js": { + "version": "1.5.1", + "bundled": true, + "dev": true, + "peer": true + }, + "bin-links": { + "version": "4.0.3", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "cmd-shim": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "read-cmd-shim": "^4.0.0", + "write-file-atomic": "^5.0.0" + } + }, + "binary-extensions": { + "version": "2.2.0", + "bundled": true, + "dev": true, + "peer": true + }, + "brace-expansion": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "buffer": { + "version": "6.0.3", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "builtins": { + "version": "5.0.1", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "semver": "^7.0.0" + } + }, + "cacache": { + "version": "18.0.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.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" + } + }, + "chalk": { + "version": "5.3.0", + "bundled": true, + "dev": true, + "peer": true + }, + "chownr": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "peer": true + }, + "ci-info": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "peer": true + }, + "cidr-regex": { + "version": "4.0.3", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "ip-regex": "^5.0.0" + } + }, + "clean-stack": { + "version": "2.2.0", + "bundled": true, + "dev": true, + "peer": true + }, + "cli-columns": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "bundled": true, + "dev": true, + "peer": true + }, + "strip-ansi": { + "version": "6.0.1", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "ansi-regex": "^5.0.1" + } + } + } + }, + "cli-table3": { + "version": "0.6.3", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "@colors/colors": "1.5.0", + "string-width": "^4.2.0" + } + }, + "clone": { + "version": "1.0.4", + "bundled": true, + "dev": true, + "peer": true + }, + "cmd-shim": { + "version": "6.0.2", + "bundled": true, + "dev": true, + "peer": true + }, + "color-convert": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "bundled": true, + "dev": true, + "peer": true + }, + "color-support": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "peer": true + }, + "columnify": { + "version": "1.6.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "strip-ansi": "^6.0.1", + "wcwidth": "^1.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "bundled": true, + "dev": true, + "peer": true + }, + "strip-ansi": { + "version": "6.0.1", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "ansi-regex": "^5.0.1" + } + } + } + }, + "common-ancestor-path": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "peer": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "peer": true + }, + "cross-spawn": { + "version": "7.0.3", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "cssesc": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "peer": true + }, + "debug": { + "version": "4.3.4", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "ms": "2.1.2" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "peer": true + } + } + }, + "defaults": { + "version": "1.0.4", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "clone": "^1.0.2" + } + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "peer": true + }, + "diff": { + "version": "5.1.0", + "bundled": true, + "dev": true, + "peer": true + }, + "eastasianwidth": { + "version": "0.2.0", + "bundled": true, + "dev": true, + "peer": true + }, + "emoji-regex": { + "version": "8.0.0", + "bundled": true, + "dev": true, + "peer": true + }, + "encoding": { + "version": "0.1.13", + "bundled": true, + "dev": true, + "optional": true, + "peer": true, + "requires": { + "iconv-lite": "^0.6.2" + } + }, + "env-paths": { + "version": "2.2.1", + "bundled": true, + "dev": true, + "peer": true + }, + "err-code": { + "version": "2.0.3", + "bundled": true, + "dev": true, + "peer": true + }, + "event-target-shim": { + "version": "5.0.1", + "bundled": true, + "dev": true, + "peer": true + }, + "events": { + "version": "3.3.0", + "bundled": true, + "dev": true, + "peer": true + }, + "exponential-backoff": { + "version": "3.1.1", + "bundled": true, + "dev": true, + "peer": true + }, + "fastest-levenshtein": { + "version": "1.0.16", + "bundled": true, + "dev": true, + "peer": true + }, + "foreground-child": { + "version": "3.1.1", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + } + }, + "fs-minipass": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "minipass": "^7.0.3" + } + }, + "function-bind": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "peer": true + }, + "gauge": { + "version": "5.0.1", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "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": "^4.0.1", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "bundled": true, + "dev": true, + "peer": true + }, + "strip-ansi": { + "version": "6.0.1", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "ansi-regex": "^5.0.1" + } + } + } + }, + "glob": { + "version": "10.3.10", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "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" + } + }, + "graceful-fs": { + "version": "4.2.11", + "bundled": true, + "dev": true, + "peer": true + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "peer": true + }, + "hasown": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "function-bind": "^1.1.2" + } + }, + "hosted-git-info": { + "version": "7.0.1", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "lru-cache": "^10.0.1" + } + }, + "http-cache-semantics": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "peer": true + }, + "http-proxy-agent": { + "version": "7.0.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + } + }, + "https-proxy-agent": { + "version": "7.0.2", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "agent-base": "^7.0.2", + "debug": "4" + } + }, + "iconv-lite": { + "version": "0.6.3", + "bundled": true, + "dev": true, + "optional": true, + "peer": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, + "ieee754": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "peer": true + }, + "ignore-walk": { + "version": "6.0.3", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "minimatch": "^9.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "bundled": true, + "dev": true, + "peer": true + }, + "indent-string": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "peer": true + }, + "ini": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "peer": true + }, + "init-package-json": { + "version": "6.0.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "npm-package-arg": "^11.0.0", + "promzard": "^1.0.0", + "read": "^2.0.0", + "read-package-json": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "^5.0.0" + } + }, + "ip": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "peer": true + }, + "ip-regex": { + "version": "5.0.0", + "bundled": true, + "dev": true, + "peer": true + }, + "is-cidr": { + "version": "5.0.3", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "cidr-regex": "4.0.3" + } + }, + "is-core-module": { + "version": "2.13.1", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "hasown": "^2.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "peer": true + }, + "is-lambda": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "peer": true + }, + "isexe": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "peer": true + }, + "jackspeak": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "@isaacs/cliui": "^8.0.2", + "@pkgjs/parseargs": "^0.11.0" + } + }, + "json-parse-even-better-errors": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "peer": true + }, + "json-stringify-nice": { + "version": "1.1.4", + "bundled": true, + "dev": true, + "peer": true + }, + "jsonparse": { + "version": "1.3.1", + "bundled": true, + "dev": true, + "peer": true + }, + "just-diff": { + "version": "6.0.2", + "bundled": true, + "dev": true, + "peer": true + }, + "just-diff-apply": { + "version": "5.5.0", + "bundled": true, + "dev": true, + "peer": true + }, + "libnpmaccess": { + "version": "8.0.1", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "npm-package-arg": "^11.0.1", + "npm-registry-fetch": "^16.0.0" + } + }, + "libnpmdiff": { + "version": "6.0.3", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "@npmcli/arborist": "^7.2.1", + "@npmcli/disparity-colors": "^3.0.0", + "@npmcli/installed-package-contents": "^2.0.2", + "binary-extensions": "^2.2.0", + "diff": "^5.1.0", + "minimatch": "^9.0.0", + "npm-package-arg": "^11.0.1", + "pacote": "^17.0.4", + "tar": "^6.2.0" + } + }, + "libnpmexec": { + "version": "7.0.4", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "@npmcli/arborist": "^7.2.1", + "@npmcli/run-script": "^7.0.2", + "ci-info": "^4.0.0", + "npm-package-arg": "^11.0.1", + "npmlog": "^7.0.1", + "pacote": "^17.0.4", + "proc-log": "^3.0.0", + "read": "^2.0.0", + "read-package-json-fast": "^3.0.2", + "semver": "^7.3.7", + "walk-up-path": "^3.0.1" + } + }, + "libnpmfund": { + "version": "5.0.1", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "@npmcli/arborist": "^7.2.1" + } + }, + "libnpmhook": { + "version": "10.0.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^16.0.0" + } + }, + "libnpmorg": { + "version": "6.0.1", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^16.0.0" + } + }, + "libnpmpack": { + "version": "6.0.3", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "@npmcli/arborist": "^7.2.1", + "@npmcli/run-script": "^7.0.2", + "npm-package-arg": "^11.0.1", + "pacote": "^17.0.4" + } + }, + "libnpmpublish": { + "version": "9.0.2", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "ci-info": "^4.0.0", + "normalize-package-data": "^6.0.0", + "npm-package-arg": "^11.0.1", + "npm-registry-fetch": "^16.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.7", + "sigstore": "^2.1.0", + "ssri": "^10.0.5" + } + }, + "libnpmsearch": { + "version": "7.0.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "npm-registry-fetch": "^16.0.0" + } + }, + "libnpmteam": { + "version": "6.0.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^16.0.0" + } + }, + "libnpmversion": { + "version": "5.0.1", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "@npmcli/git": "^5.0.3", + "@npmcli/run-script": "^7.0.2", + "json-parse-even-better-errors": "^3.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.7" + } + }, + "lru-cache": { + "version": "10.0.2", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "semver": "^7.3.5" + } + }, + "make-fetch-happen": { + "version": "13.0.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "@npmcli/agent": "^2.0.0", + "cacache": "^18.0.0", + "http-cache-semantics": "^4.1.1", + "is-lambda": "^1.0.1", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "ssri": "^10.0.0" + } + }, + "minimatch": { + "version": "9.0.3", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "minipass": { + "version": "7.0.4", + "bundled": true, + "dev": true, + "peer": true + }, + "minipass-collect": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass-fetch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "encoding": "^0.1.13", + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + } + }, + "minipass-flush": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass-json-stream": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass-pipeline": { + "version": "1.2.4", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass-sized": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minizlib": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "mkdirp": { + "version": "1.0.4", + "bundled": true, + "dev": true, + "peer": true + }, + "ms": { + "version": "2.1.3", + "bundled": true, + "dev": true, + "peer": true + }, + "mute-stream": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "peer": true + }, + "negotiator": { + "version": "0.6.3", + "bundled": true, + "dev": true, + "peer": true + }, + "node-gyp": { + "version": "10.0.1", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^10.3.10", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^13.0.0", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^4.0.0" + } + }, + "nopt": { + "version": "7.2.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "abbrev": "^2.0.0" + } + }, + "normalize-package-data": { + "version": "6.0.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "hosted-git-info": "^7.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + } + }, + "npm-audit-report": { + "version": "5.0.0", + "bundled": true, + "dev": true, + "peer": true + }, + "npm-bundled": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "npm-normalize-package-bin": "^3.0.0" + } + }, + "npm-install-checks": { + "version": "6.3.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "semver": "^7.1.1" + } + }, + "npm-normalize-package-bin": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "peer": true + }, + "npm-package-arg": { + "version": "11.0.1", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "hosted-git-info": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + } + }, + "npm-packlist": { + "version": "8.0.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "ignore-walk": "^6.0.0" + } + }, + "npm-pick-manifest": { + "version": "9.0.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^11.0.0", + "semver": "^7.3.5" + } + }, + "npm-profile": { + "version": "9.0.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "npm-registry-fetch": "^16.0.0", + "proc-log": "^3.0.0" + } + }, + "npm-registry-fetch": { + "version": "16.1.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "make-fetch-happen": "^13.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^11.0.0", + "proc-log": "^3.0.0" + } + }, + "npm-user-validate": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "peer": true + }, + "npmlog": { + "version": "7.0.1", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "are-we-there-yet": "^4.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^5.0.0", + "set-blocking": "^2.0.0" + } + }, + "p-map": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "pacote": { + "version": "17.0.4", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "@npmcli/git": "^5.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/promise-spawn": "^7.0.0", + "@npmcli/run-script": "^7.0.0", + "cacache": "^18.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^11.0.0", + "npm-packlist": "^8.0.0", + "npm-pick-manifest": "^9.0.0", + "npm-registry-fetch": "^16.0.0", + "proc-log": "^3.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^7.0.0", + "read-package-json-fast": "^3.0.0", + "sigstore": "^2.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + } + }, + "parse-conflict-json": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "json-parse-even-better-errors": "^3.0.0", + "just-diff": "^6.0.0", + "just-diff-apply": "^5.2.0" + } + }, + "path-key": { + "version": "3.1.1", + "bundled": true, + "dev": true, + "peer": true + }, + "path-scurry": { + "version": "1.10.1", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + } + }, + "postcss-selector-parser": { + "version": "6.0.13", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "proc-log": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "peer": true + }, + "process": { + "version": "0.11.10", + "bundled": true, + "dev": true, + "peer": true + }, + "promise-all-reject-late": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "peer": true + }, + "promise-call-limit": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "peer": true + }, + "promise-inflight": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "peer": true + }, + "promise-retry": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + } + }, + "promzard": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "read": "^2.0.0" + } + }, + "qrcode-terminal": { + "version": "0.12.0", + "bundled": true, + "dev": true, + "peer": true + }, + "read": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "mute-stream": "~1.0.0" + } + }, + "read-cmd-shim": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "peer": true + }, + "read-package-json": { + "version": "7.0.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "glob": "^10.2.2", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0" + } + }, + "read-package-json-fast": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + } + }, + "readable-stream": { + "version": "4.4.2", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + } + }, + "retry": { + "version": "0.12.0", + "bundled": true, + "dev": true, + "peer": true + }, + "safe-buffer": { + "version": "5.2.1", + "bundled": true, + "dev": true, + "peer": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true, + "peer": true + }, + "semver": { + "version": "7.5.4", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "lru-cache": "^6.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "peer": true + }, + "shebang-command": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "peer": true + }, + "signal-exit": { + "version": "4.1.0", + "bundled": true, + "dev": true, + "peer": true + }, + "sigstore": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "@sigstore/bundle": "^2.1.0", + "@sigstore/protobuf-specs": "^0.2.1", + "@sigstore/sign": "^2.1.0", + "@sigstore/tuf": "^2.1.0" + } + }, + "smart-buffer": { + "version": "4.2.0", + "bundled": true, + "dev": true, + "peer": true + }, + "socks": { + "version": "2.7.1", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + } + }, + "socks-proxy-agent": { + "version": "8.0.2", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "socks": "^2.7.1" + } + }, + "spdx-correct": { + "version": "3.2.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "bundled": true, + "dev": true, + "peer": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.16", + "bundled": true, + "dev": true, + "peer": true + }, + "ssri": { + "version": "10.0.5", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "minipass": "^7.0.3" + } + }, + "string_decoder": { + "version": "1.3.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "string-width": { + "version": "4.2.3", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "bundled": true, + "dev": true, + "peer": true + }, + "strip-ansi": { + "version": "6.0.1", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "ansi-regex": "^5.0.1" + } + } + } + }, + "string-width-cjs": { + "version": "npm:string-width@4.2.3", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "bundled": true, + "dev": true, + "peer": true + }, + "strip-ansi": { + "version": "6.0.1", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "ansi-regex": "^5.0.1" + } + } + } + }, + "strip-ansi": { + "version": "7.1.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "ansi-regex": "^6.0.1" + } + }, + "strip-ansi-cjs": { + "version": "npm:strip-ansi@6.0.1", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "ansi-regex": "^5.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "bundled": true, + "dev": true, + "peer": true + } + } + }, + "supports-color": { + "version": "9.4.0", + "bundled": true, + "dev": true, + "peer": true + }, + "tar": { + "version": "6.2.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "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" + }, + "dependencies": { + "fs-minipass": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass": { + "version": "5.0.0", + "bundled": true, + "dev": true, + "peer": true + } + } + }, + "text-table": { + "version": "0.2.0", + "bundled": true, + "dev": true, + "peer": true + }, + "tiny-relative-date": { + "version": "1.3.0", + "bundled": true, + "dev": true, + "peer": true + }, + "treeverse": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "peer": true + }, + "tuf-js": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "@tufjs/models": "2.0.0", + "debug": "^4.3.4", + "make-fetch-happen": "^13.0.0" + } + }, + "unique-filename": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "unique-slug": "^4.0.0" + } + }, + "unique-slug": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "peer": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "validate-npm-package-name": { + "version": "5.0.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "builtins": "^5.0.0" + } + }, + "walk-up-path": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "peer": true + }, + "wcwidth": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "defaults": "^1.0.3" + } + }, + "which": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "isexe": "^3.1.1" + }, + "dependencies": { + "isexe": { + "version": "3.1.1", + "bundled": true, + "dev": true, + "peer": true + } + } + }, + "wide-align": { + "version": "1.1.5", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "wrap-ansi": { + "version": "8.1.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "dependencies": { + "emoji-regex": { + "version": "9.2.2", + "bundled": true, + "dev": true, + "peer": true + }, + "string-width": { + "version": "5.1.2", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + } + } + }, + "wrap-ansi-cjs": { + "version": "npm:wrap-ansi@7.0.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "bundled": true, + "dev": true, + "peer": true + }, + "ansi-styles": { + "version": "4.3.0", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "ansi-regex": "^5.0.1" + } + } + } + }, + "write-file-atomic": { + "version": "5.0.1", + "bundled": true, + "dev": true, + "peer": true, + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + } + }, + "yallist": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "peer": true + } + } + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "peer": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "p-each-series": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-3.0.0.tgz", + "integrity": "sha512-lastgtAdoH9YaLyDa5i5z64q+kzOcQHsQ5SsZJD3q0VEyI8mq872S3geuNbRUQLVAE9siMfgKrpj7MloKFHruw==", + "dev": true, + "peer": true + }, + "p-filter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-3.0.0.tgz", + "integrity": "sha512-QtoWLjXAW++uTX67HZQz1dbTpqBfiidsB6VtQUC9iR85S120+s0T5sO6s+B5MLzFcZkrEd/DGMmCjR+f2Qpxwg==", + "dev": true, + "peer": true, + "requires": { + "p-map": "^5.1.0" + } + }, + "p-is-promise": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz", + "integrity": "sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==", + "dev": true, + "peer": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "peer": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dev": true, + "peer": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-map": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-5.5.0.tgz", + "integrity": "sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg==", + "dev": true, + "peer": true, + "requires": { + "aggregate-error": "^4.0.0" + }, + "dependencies": { + "aggregate-error": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-4.0.1.tgz", + "integrity": "sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==", + "dev": true, + "peer": true, + "requires": { + "clean-stack": "^4.0.0", + "indent-string": "^5.0.0" + } + }, + "clean-stack": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-4.2.0.tgz", + "integrity": "sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==", + "dev": true, + "peer": true, + "requires": { + "escape-string-regexp": "5.0.0" + } + }, + "escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "peer": true + }, + "indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true, + "peer": true + } + } + }, + "p-reduce": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-2.1.0.tgz", + "integrity": "sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==", + "dev": true + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true, + "peer": true + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "peer": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@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" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "peer": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "peer": true + }, + "pkg-conf": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz", + "integrity": "sha512-C+VUP+8jis7EsQZIhDYmS5qlNtjv2yP4SNtjXK9AP1ZcTRlnSfuumaTnRfYZnYgUUYVIKqL0fRvmUGDV2fmp6g==", + "dev": true, + "peer": true, + "requires": { + "find-up": "^2.0.0", + "load-json-file": "^4.0.0" + } + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "peer": true + }, + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true, + "peer": true + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "peer": true + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "peer": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, + "read-pkg": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-9.0.1.tgz", + "integrity": "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==", + "dev": true, + "peer": true, + "requires": { + "@types/normalize-package-data": "^2.4.3", + "normalize-package-data": "^6.0.0", + "parse-json": "^8.0.0", + "type-fest": "^4.6.0", + "unicorn-magic": "^0.1.0" + }, + "dependencies": { + "json-parse-even-better-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", + "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", + "dev": true, + "peer": true + }, + "parse-json": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.0.1.tgz", + "integrity": "sha512-soKUg/q/8bcfuF3+plsbYldE74cVEVEPSC1BUPIGTaX1byXdz6Fo+CVYBdH0jj/5xWsFrNRksl11QkBgHqPQeQ==", + "dev": true, + "peer": true, + "requires": { + "@babel/code-frame": "^7.22.13", + "index-to-position": "^0.1.1", + "json-parse-even-better-errors": "^3.0.0", + "type-fest": "^4.7.1" + } + }, + "type-fest": { + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.8.2.tgz", + "integrity": "sha512-mcvrCjixA5166hSrUoJgGb9gBQN4loMYyj9zxuMs/66ibHNEFd5JXMw37YVDx58L4/QID9jIzdTBB4mDwDJ6KQ==", + "dev": true, + "peer": true + } + } + }, + "read-pkg-up": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-11.0.0.tgz", + "integrity": "sha512-LOVbvF1Q0SZdjClSefZ0Nz5z8u+tIE7mV5NibzmE9VYmDe9CaBbAVtz1veOSZbofrdsilxuDAYnFenukZVp8/Q==", + "dev": true, + "peer": true, + "requires": { + "find-up-simple": "^1.0.0", + "read-pkg": "^9.0.0", + "type-fest": "^4.6.0" + }, + "dependencies": { + "type-fest": { + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.8.2.tgz", + "integrity": "sha512-mcvrCjixA5166hSrUoJgGb9gBQN4loMYyj9zxuMs/66ibHNEFd5JXMw37YVDx58L4/QID9jIzdTBB4mDwDJ6KQ==", + "dev": true, + "peer": true + } + } + }, + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "peer": true, + "requires": { + "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" + } + }, + "redeyed": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/redeyed/-/redeyed-2.1.1.tgz", + "integrity": "sha512-FNpGGo1DycYAdnrKFxCMmKYgo/mILAqtRYbkdQD8Ep/Hk2PQ5+aEAEx+IU713RTDmuBaH0c8P5ZozurNu5ObRQ==", + "dev": true, + "peer": true, + "requires": { + "esprima": "~4.0.0" + } + }, + "registry-auth-token": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz", + "integrity": "sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==", + "dev": true, + "peer": true, + "requires": { + "@pnpm/npm-conf": "^2.1.0" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "peer": true + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "peer": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "peer": true + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "peer": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "peer": true + }, + "semantic-release": { + "version": "22.0.8", + "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-22.0.8.tgz", + "integrity": "sha512-55rb31jygqIYsGU/rY+gXXm2fnxBIWo9azOjxbqKsPnq7p70zwZ5v+xnD7TxJC+zvS3sy1eHLGXYWCaX3WI76A==", + "dev": true, + "peer": true, + "requires": { + "@semantic-release/commit-analyzer": "^11.0.0", + "@semantic-release/error": "^4.0.0", + "@semantic-release/github": "^9.0.0", + "@semantic-release/npm": "^11.0.0", + "@semantic-release/release-notes-generator": "^12.0.0", + "aggregate-error": "^5.0.0", + "cosmiconfig": "^8.0.0", + "debug": "^4.0.0", + "env-ci": "^10.0.0", + "execa": "^8.0.0", + "figures": "^6.0.0", + "find-versions": "^5.1.0", + "get-stream": "^6.0.0", + "git-log-parser": "^1.2.0", + "hook-std": "^3.0.0", + "hosted-git-info": "^7.0.0", + "import-from-esm": "^1.3.1", + "lodash-es": "^4.17.21", + "marked": "^9.0.0", + "marked-terminal": "^6.0.0", + "micromatch": "^4.0.2", + "p-each-series": "^3.0.0", + "p-reduce": "^3.0.0", + "read-pkg-up": "^11.0.0", + "resolve-from": "^5.0.0", + "semver": "^7.3.2", + "semver-diff": "^4.0.0", + "signale": "^1.2.1", + "yargs": "^17.5.1" + }, + "dependencies": { + "@semantic-release/error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-4.0.0.tgz", + "integrity": "sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ==", + "dev": true, + "peer": true + }, + "aggregate-error": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-5.0.0.tgz", + "integrity": "sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==", + "dev": true, + "peer": true, + "requires": { + "clean-stack": "^5.2.0", + "indent-string": "^5.0.0" + } + }, + "clean-stack": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-5.2.0.tgz", + "integrity": "sha512-TyUIUJgdFnCISzG5zu3291TAsE77ddchd0bepon1VVQrKLGKFED4iXFEDQ24mIPdPBbyE16PK3F8MYE1CmcBEQ==", + "dev": true, + "peer": true, + "requires": { + "escape-string-regexp": "5.0.0" + } + }, + "escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "peer": true + }, + "execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "peer": true, + "requires": { + "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" + }, + "dependencies": { + "get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "peer": true + } + } + }, + "human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "peer": true + }, + "indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true, + "peer": true + }, + "is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "peer": true + }, + "mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "peer": true + }, + "npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, + "peer": true, + "requires": { + "path-key": "^4.0.0" + } + }, + "onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "peer": true, + "requires": { + "mimic-fn": "^4.0.0" + } + }, + "p-reduce": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-3.0.0.tgz", + "integrity": "sha512-xsrIUgI0Kn6iyDYm9StOpOeK29XM1aboGji26+QEortiFST1hGZaUQOLhtEbqHErPpGW/aSz6allwK2qcptp0Q==", + "dev": true, + "peer": true + }, + "path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "peer": true + }, + "signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "peer": true + }, + "strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "peer": true + } + } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "peer": true, + "requires": { + "lru-cache": "^6.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "peer": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "semver-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-4.0.0.tgz", + "integrity": "sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==", + "dev": true, + "peer": true, + "requires": { + "semver": "^7.3.5" + } + }, + "semver-regex": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-4.0.5.tgz", + "integrity": "sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==", + "dev": true, + "peer": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "signale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/signale/-/signale-1.4.0.tgz", + "integrity": "sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w==", + "dev": true, + "peer": true, + "requires": { + "chalk": "^2.3.2", + "figures": "^2.0.0", + "pkg-conf": "^2.1.0" + }, + "dependencies": { + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==", + "dev": true, + "peer": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + } + } + }, + "skin-tone": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/skin-tone/-/skin-tone-2.0.0.tgz", + "integrity": "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==", + "dev": true, + "peer": true, + "requires": { + "unicode-emoji-modifier-base": "^1.0.0" + } + }, + "slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "peer": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "peer": true + }, + "spawn-error-forwarder": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/spawn-error-forwarder/-/spawn-error-forwarder-1.0.0.tgz", + "integrity": "sha512-gRjMgK5uFjbCvdibeGJuy3I5OYz6VLoVdsOJdA6wV0WlfQVLFueoqMxwwYD9RODdgb6oUIvlRlsyFSiQkMKu0g==", + "dev": true, + "peer": true + }, + "spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "peer": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true, + "peer": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "peer": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", + "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", + "dev": true, + "peer": true + }, + "split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "dev": true, + "peer": true + }, + "stream-combiner2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", + "integrity": "sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw==", + "dev": true, + "peer": true, + "requires": { + "duplexer2": "~0.1.0", + "readable-stream": "^2.0.2" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "peer": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "peer": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "peer": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "peer": true + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "peer": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "supports-hyperlinks": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.0.0.tgz", + "integrity": "sha512-QBDPHyPQDRTy9ku4URNGY5Lah8PAaXs6tAAwp55sL5WCsSW7GIfdf6W5ixfziW+t7wh3GVvHyHHyQ1ESsoRvaA==", + "dev": true, + "peer": true, + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "dependencies": { + "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, + "peer": true + }, + "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, + "peer": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "temp-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-3.0.0.tgz", + "integrity": "sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==", + "dev": true, + "peer": true + }, + "tempy": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-3.1.0.tgz", + "integrity": "sha512-7jDLIdD2Zp0bDe5r3D2qtkd1QOCacylBuL7oa4udvN6v2pqr4+LcCr67C8DR1zkpaZ8XosF5m1yQSabKAW6f2g==", + "dev": true, + "peer": true, + "requires": { + "is-stream": "^3.0.0", + "temp-dir": "^3.0.0", + "type-fest": "^2.12.2", + "unique-string": "^3.0.0" + }, + "dependencies": { + "is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "peer": true + }, + "type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true, + "peer": true + } + } + }, + "text-extensions": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-2.4.0.tgz", + "integrity": "sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==", + "dev": true, + "peer": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true, + "peer": true + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "peer": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "traverse": { + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.7.tgz", + "integrity": "sha512-/y956gpUo9ZNCb99YjxG7OaslxZWHfCHAUUfshwqOXmxUIvqLjVO581BT+gM59+QV9tFe6/CGG53tsA1Y7RSdg==", + "dev": true, + "peer": true + }, + "type-fest": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", + "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", + "dev": true, + "peer": true + }, + "uglify-js": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "dev": true, + "optional": true, + "peer": true + }, + "unicode-emoji-modifier-base": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz", + "integrity": "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==", + "dev": true, + "peer": true + }, + "unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true, + "peer": true + }, + "unique-string": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", + "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", + "dev": true, + "peer": true, + "requires": { + "crypto-random-string": "^4.0.0" + } + }, + "universal-user-agent": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz", + "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==", + "dev": true, + "peer": true + }, + "universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true + }, + "url-join": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-5.0.0.tgz", + "integrity": "sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==", + "dev": true, + "peer": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "peer": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "peer": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "peer": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "peer": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "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, + "peer": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "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, + "peer": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "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, + "peer": true + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "peer": true + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "peer": true + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "peer": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "peer": true + }, + "yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "peer": true, + "requires": { + "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" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "peer": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..73e2ad1 --- /dev/null +++ b/package.json @@ -0,0 +1,8 @@ +{ + "devDependencies": { + "@semantic-release/changelog": "^6.0.3", + "@semantic-release/exec": "^6.0.3", + "@semantic-release/git": "^10.0.1", + "conventional-changelog-conventionalcommits": "^6.1.0" + } +}