diff --git a/.github/actions/authorize-dev-hub/action.yml b/.github/actions/authorize-dev-hub/action.yml new file mode 100644 index 000000000..791ecb24f --- /dev/null +++ b/.github/actions/authorize-dev-hub/action.yml @@ -0,0 +1,39 @@ +# Composite action that authorizes the Salesforce Dev Hub via JWT and sets +# it as the default. All inputs are required. +name: 'Authorize Dev Hub' +description: 'Authorize the Salesforce Dev Hub via JWT and set it as the default' + +inputs: + auth-url: + description: 'Dev Hub login URL' + required: true + bot-username: + description: 'Dev Hub bot username' + required: true + consumer-key: + description: 'Dev Hub connected app consumer key' + required: true + jwt-server-key: + description: 'Dev Hub JWT private key (PEM)' + required: true + +runs: + using: 'composite' + steps: + # The key file must remain on disk for the rest of the job. The SF CLI records the + # key's path (not its contents) in ~/.sfdx/ and re-reads it whenever it has to refresh + # the JWT - including the implicit re-auth that `sf org create scratch` performs when + # authenticating into the new scratch org. Deleting the file mid-job causes ENOENT on + # the next refresh. Cleanup is unnecessary anyway: GitHub-hosted runners are single-use + # ephemeral VMs that get wiped after the job ends. + - name: 'Authorize Dev Hub' + shell: bash + env: + DEV_HUB_AUTH_URL: ${{ inputs.auth-url }} + DEV_HUB_BOT_USERNAME: ${{ inputs.bot-username }} + DEV_HUB_CONSUMER_KEY: ${{ inputs.consumer-key }} + DEV_HUB_JWT_SERVER_KEY: ${{ inputs.jwt-server-key }} + run: | + npx sf version + echo "$DEV_HUB_JWT_SERVER_KEY" > ./jwt-server.key + npx sf org login jwt --instance-url "$DEV_HUB_AUTH_URL" --client-id "$DEV_HUB_CONSUMER_KEY" --username "$DEV_HUB_BOT_USERNAME" --jwt-key-file ./jwt-server.key --set-default-dev-hub diff --git a/.github/actions/setup-npm/action.yml b/.github/actions/setup-npm/action.yml new file mode 100644 index 000000000..bdfb20b64 --- /dev/null +++ b/.github/actions/setup-npm/action.yml @@ -0,0 +1,28 @@ +# Composite action that restores the node_modules cache and installs +# npm dependencies on a cache miss. Used by every job in build.yml. +name: 'Setup npm' +description: 'Restore the node_modules cache and run npm ci on a cache miss' + +runs: + using: 'composite' + steps: + - name: 'Restore node_modules cache' + id: cache-npm + uses: actions/cache@v5 + with: + path: node_modules + key: npm-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + npm-${{ env.cache-name }}- + npm- + + - name: 'Install npm dependencies' + if: steps.cache-npm.outputs.cache-hit != 'true' + shell: bash + run: npm ci + + - name: 'Link sf CLI plugins from node_modules' + shell: bash + run: | + npm run sf:plugins:link:bummer + npm run sf:plugins:link:dotenv diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index aaaba715c..fce7058fb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,6 +12,7 @@ on: - main paths: - .github/workflows/** + - .github/actions/** - config/scratch-orgs/** - nebula-logger/** - sfdx-project.json @@ -19,6 +20,7 @@ on: types: [opened, synchronize, reopened] paths: - .github/workflows/** + - .github/actions/** - config/scratch-orgs/** - nebula-logger/** - sfdx-project.json @@ -29,42 +31,27 @@ jobs: runs-on: ubuntu-22.04 steps: - name: 'Checkout source code' - uses: actions/checkout@v4 - - - name: 'Restore node_modules cache' - id: cache-npm - uses: actions/cache@v4 - with: - path: node_modules - key: npm-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - npm-${{ env.cache-name }}- - npm- - - - name: 'Install npm dependencies' - if: steps.cache-npm.outputs.cache-hit != 'true' - run: npm ci + uses: actions/checkout@v6 - name: 'Check for changes in core directory' - uses: dorny/paths-filter@v3 + uses: dorny/paths-filter@v4 id: changes with: filters: | core: - './nebula-logger/core/**' + - name: 'Setup npm' + uses: ./.github/actions/setup-npm + - name: 'Authorize Dev Hub' if: ${{ (github.event_name == 'pull_request') && (github.event.pull_request.draft == false) && (steps.changes.outputs.core == 'true') }} - shell: bash - run: | - npx sf version - echo "${{ env.DEV_HUB_JWT_SERVER_KEY }}" > ./jwt-server.key - npx sf org login jwt --instance-url ${{ env.DEV_HUB_AUTH_URL }} --client-id ${{ env.DEV_HUB_CONSUMER_KEY }} --username ${{ env.DEV_HUB_BOT_USERNAME }} --jwt-key-file ./jwt-server.key --set-default-dev-hub - env: - DEV_HUB_AUTH_URL: ${{ secrets.DEV_HUB_AUTH_URL }} - DEV_HUB_BOT_USERNAME: ${{ secrets.DEV_HUB_BOT_USERNAME }} - DEV_HUB_CONSUMER_KEY: ${{ secrets.DEV_HUB_CONSUMER_KEY }} - DEV_HUB_JWT_SERVER_KEY: ${{ secrets.DEV_HUB_JWT_SERVER_KEY }} + uses: ./.github/actions/authorize-dev-hub + with: + auth-url: ${{ secrets.DEV_HUB_AUTH_URL }} + bot-username: ${{ secrets.DEV_HUB_BOT_USERNAME }} + consumer-key: ${{ secrets.DEV_HUB_CONSUMER_KEY }} + jwt-server-key: ${{ secrets.DEV_HUB_JWT_SERVER_KEY }} - name: 'Verify package version number is updated' if: ${{ (github.event_name == 'pull_request') && (github.event.pull_request.draft == false) && (steps.changes.outputs.core == 'true') }} @@ -74,8 +61,7 @@ jobs: run: npm run scan:lwc - name: 'Verify Apex with Code Analyzer' - run: | - npm run scan:apex + run: npm run scan:apex # TODO - uncomment - temporarily commented-out due to an issue with apexdocs in the pipeline # - name: 'Verify docs are updated' @@ -86,517 +72,103 @@ jobs: lwc-jest-tests: name: 'Run LWC Jest Tests' - needs: [code-quality-tests] runs-on: ubuntu-22.04 steps: - name: 'Checkout source code' - uses: actions/checkout@v4 + uses: actions/checkout@v6 - - name: 'Restore node_modules cache' - id: cache-npm - uses: actions/cache@v4 - with: - path: node_modules - key: npm-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - npm-${{ env.cache-name }}- - npm- - - - name: 'Install npm dependencies' - if: steps.cache-npm.outputs.cache-hit != 'true' - run: npm ci + - name: 'Setup npm' + uses: ./.github/actions/setup-npm - name: 'Run LWC Tests' run: npm run test:lwc - name: 'Upload LWC code coverage to Codecov.io' - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@v6 with: fail_ci_if_error: true flags: LWC token: ${{ secrets.CODECOV_TOKEN }} - advanced-scratch-org-tests: - environment: 'Advanced Scratch Org' - name: 'Run Advanced Scratch Org Tests' - needs: [code-quality-tests] - runs-on: ubuntu-22.04 - steps: - - name: 'Checkout source code' - uses: actions/checkout@v4 - - - name: 'Restore node_modules cache' - id: cache-npm - uses: actions/cache@v4 - with: - path: node_modules - key: npm-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - npm-${{ env.cache-name }}- - npm- - - - name: 'Install npm dependencies' - if: steps.cache-npm.outputs.cache-hit != 'true' - run: npm ci - - - name: 'Authorize Dev Hub' - shell: bash - run: | - npx sf version - echo "${{ env.DEV_HUB_JWT_SERVER_KEY }}" > ./jwt-server.key - npx sf org login jwt --instance-url ${{ env.DEV_HUB_AUTH_URL }} --client-id ${{ env.DEV_HUB_CONSUMER_KEY }} --username ${{ env.DEV_HUB_BOT_USERNAME }} --jwt-key-file ./jwt-server.key --set-default-dev-hub - env: - DEV_HUB_AUTH_URL: ${{ secrets.DEV_HUB_AUTH_URL }} - DEV_HUB_BOT_USERNAME: ${{ secrets.DEV_HUB_BOT_USERNAME }} - DEV_HUB_CONSUMER_KEY: ${{ secrets.DEV_HUB_CONSUMER_KEY }} - DEV_HUB_JWT_SERVER_KEY: ${{ secrets.DEV_HUB_JWT_SERVER_KEY }} - - - name: 'Create Scratch Org' - run: npx sf org create scratch --no-namespace --no-track-source --duration-days 1 --definition-file ./config/scratch-orgs/advanced-scratch-def.json --wait 20 --set-default --json - - # https://help.salesforce.com/s/articleView?id=000394906&type=1 - - name: "Install OmniStudio managed package v258.6 (Winter '26 release)" - run: npx sf package install --package 04tKb000000tAtyIAE --security-type AdminsOnly --wait 30 --no-prompt - - # To ensure that all of the Apex classes in the core directory have 75+ code coverage, - # deploy only the core directory & run all of its tests as part of the deployment, using `--test-level RunLocalTests` - - name: 'Validate Core Source in Scratch Org' - run: npx sf project deploy validate --concise --source-dir ./nebula-logger/core/ --test-level RunLocalTests - - # Now that the core directory has been deployed & tests have passed, deploy all of the metadata - - name: 'Deploy All Source to Scratch Org' - run: npx sf project deploy start --source-dir ./nebula-logger/ - - - name: 'Deploy Test Metadata' - run: npx sf project deploy start --source-dir ./config/scratch-orgs/ - - - name: 'Assign Logger Admin Permission Set' - run: npm run permset:assign:admin - - # Nebula Logger has functionality that queries the AuthSession object when the current user has an active session. - # The code should work with or without an active session, so the pipeline runs the tests twice - asynchronously and synchronously. - # This is done because, based on how you execute Apex tests, the running user may have an active session (synchrously) or not (asynchronously). - # This data is also mocked during tests, but running the Apex tests sync & async serves within the pipeline acts as an extra level of - # integration testing to ensure that everything works with or without an active session. - - name: 'Run Apex Tests Asynchronously' - run: npm run test:apex:nocoverage - - - name: 'Run Apex Tests Synchronously' - run: npm run test:apex:nocoverage -- --synchronous - - - name: 'Delete Scratch Org' - run: npx sf org delete scratch --no-prompt - if: ${{ always() }} - - base-scratch-org-tests: - environment: 'Base Scratch Org' - name: 'Run Base Scratch Org Tests' - needs: [code-quality-tests] - runs-on: ubuntu-22.04 - steps: - - name: 'Checkout source code' - uses: actions/checkout@v4 - - - name: 'Restore node_modules cache' - id: cache-npm - uses: actions/cache@v4 - with: - path: node_modules - key: npm-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - npm-${{ env.cache-name }}- - npm- - - - name: 'Install npm dependencies' - if: steps.cache-npm.outputs.cache-hit != 'true' - run: npm ci - - - name: 'Authorize Dev Hub' - shell: bash - run: | - npx sf version - echo "${{ env.DEV_HUB_JWT_SERVER_KEY }}" > ./jwt-server.key - npx sf org login jwt --instance-url ${{ env.DEV_HUB_AUTH_URL }} --client-id ${{ env.DEV_HUB_CONSUMER_KEY }} --username ${{ env.DEV_HUB_BOT_USERNAME }} --jwt-key-file ./jwt-server.key --set-default-dev-hub - env: - DEV_HUB_AUTH_URL: ${{ secrets.DEV_HUB_AUTH_URL }} - DEV_HUB_BOT_USERNAME: ${{ secrets.DEV_HUB_BOT_USERNAME }} - DEV_HUB_CONSUMER_KEY: ${{ secrets.DEV_HUB_CONSUMER_KEY }} - DEV_HUB_JWT_SERVER_KEY: ${{ secrets.DEV_HUB_JWT_SERVER_KEY }} - - - name: 'Create Scratch Org' - run: npx sf org create scratch --no-namespace --no-track-source --duration-days 1 --definition-file ./config/scratch-orgs/base-scratch-def.json --wait 20 --set-default --json - - # To ensure that all of the Apex classes in the core directory have 75+ code coverage, - # deploy only the core directory & run all of its tests as part of the deployment, using `--test-level RunLocalTests` - - name: 'Validate Core Source in Scratch Org' - run: npx sf project deploy validate --concise --source-dir ./nebula-logger/core/ --test-level RunLocalTests - - # Now that the core directory has been deployed & tests have passed, deploy all of the metadata - - name: 'Deploy All Source to Scratch Org' - run: npx sf project deploy start --source-dir ./nebula-logger/ - - - name: 'Assign Logger Admin Permission Set' - run: npm run permset:assign:admin - - # Nebula Logger has functionality that queries the AuthSession object when the current user has an active session. - # The code should work with or without an active session, so the pipeline runs the tests twice - asynchronously and synchronously. - # This is done because, based on how you execute Apex tests, the running user may have an active session (synchrously) or not (asynchronously). - # This data is also mocked during tests, but running the Apex tests sync & async serves within the pipeline acts as an extra level of - # integration testing to ensure that everything works with or without an active session. - - name: 'Run Apex Tests Asynchronously' - run: npm run test:apex:nocoverage - - - name: 'Run Apex Tests Synchronously' - run: npm run test:apex:nocoverage -- --synchronous - - # This is the only place in Nebula Logger's pipeline where the `LoggerCore` test suite runs & the results are sent to Codecov.io. - # This is specifically done in the base scratch org, using only the `LoggerCore test` suite, in order to help validate that the core metadata - # provides sufficient code coverage for teams that deploy Nebula Logger's metadata directly to their org, instead of installing one of Nebula Logger's 2GP packages. - # 1. Many teams cannot use one of the 2GP packages for various reasons, including company policies, security concerns, etc., - # and being able to deploy the core metadata is something that should be supported. - # 2. And even though the pipeline runs the `extra-tests` directory to validate logging works correctly in various types of scratch orgs, - # for teams that are trying to deploy Nebula Logger's metadata, it's critical that the core tests have sufficient code coverage to be deployed to a prod org. - # - In the past, this has not always been the case, resulting in some teams having deployment issues & project delays due to the low code coverage - # that was (formerly) provided by some of the core tests classes. - # - In orgs that do not have some optional Salesforce features enabled/available (e.g., orgs without Experience Cloud, OmniStudio, Platform Cache, etc.), - # the code coverage can be especially low, so using the base scratch org acts - # - - # So now only the core test suite's results, from a base scratch org, are used for reporting code coverage, even though the project's overall code coverage - # is much higher when using the `extra-tests` directory. - - name: 'Get Core Test Suite Code Coverage' - run: npm run test:apex:suite:core - - # This is the only scratch org that's used for uploading code coverage - - name: 'Upload Apex test code coverage to Codecov.io' - uses: codecov/codecov-action@v4 - with: - fail_ci_if_error: true - flags: Apex - token: ${{ secrets.CODECOV_TOKEN }} - - - name: 'Delete Scratch Org' - run: npx sf org delete scratch --no-prompt - if: ${{ always() }} - - event-monitoring-scratch-org-tests: - environment: 'Event Monitoring Scratch Org' - name: 'Run Event Monitoring Scratch Org Tests' - needs: [code-quality-tests] - runs-on: ubuntu-22.04 - steps: - - name: 'Checkout source code' - uses: actions/checkout@v4 - - - name: 'Restore node_modules cache' - id: cache-npm - uses: actions/cache@v4 - with: - path: node_modules - key: npm-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - npm-${{ env.cache-name }}- - npm- - - - name: 'Install npm dependencies' - if: steps.cache-npm.outputs.cache-hit != 'true' - run: npm ci - - - name: 'Authorize Dev Hub' - shell: bash - run: | - npx sf version - echo "${{ env.DEV_HUB_JWT_SERVER_KEY }}" > ./jwt-server.key - npx sf org login jwt --instance-url ${{ env.DEV_HUB_AUTH_URL }} --client-id ${{ env.DEV_HUB_CONSUMER_KEY }} --username ${{ env.DEV_HUB_BOT_USERNAME }} --jwt-key-file ./jwt-server.key --set-default-dev-hub - env: - DEV_HUB_AUTH_URL: ${{ secrets.DEV_HUB_AUTH_URL }} - DEV_HUB_BOT_USERNAME: ${{ secrets.DEV_HUB_BOT_USERNAME }} - DEV_HUB_CONSUMER_KEY: ${{ secrets.DEV_HUB_CONSUMER_KEY }} - DEV_HUB_JWT_SERVER_KEY: ${{ secrets.DEV_HUB_JWT_SERVER_KEY }} - - - name: 'Create Scratch Org' - run: npx sf org create scratch --no-namespace --no-track-source --duration-days 1 --definition-file ./config/scratch-orgs/event-monitoring-scratch-def.json --wait 20 --set-default --json - - # To ensure that all of the Apex classes in the core directory have 75+ code coverage, - # deploy only the core directory & run all of its tests as part of the deployment, using `--test-level RunLocalTests` - - name: 'Validate Core Source in Scratch Org' - run: npx sf project deploy validate --concise --source-dir ./nebula-logger/core/ --test-level RunLocalTests - - # Now that the core directory has been deployed & tests have passed, deploy all of the metadata - - name: 'Deploy All Source to Scratch Org' - run: npx sf project deploy start --source-dir ./nebula-logger/ - - - name: 'Assign Logger Admin Permission Set' - run: npm run permset:assign:admin - - # Nebula Logger has functionality that queries the AuthSession object when the current user has an active session. - # The code should work with or without an active session, so the pipeline runs the tests twice - asynchronously and synchronously. - # This is done because, based on how you execute Apex tests, the running user may have an active session (synchrously) or not (asynchronously). - # This data is also mocked during tests, but running the Apex tests sync & async serves within the pipeline acts as an extra level of - # integration testing to ensure that everything works with or without an active session. - - name: 'Run Apex Tests Asynchronously' - run: npm run test:apex:nocoverage - - - name: 'Run Apex Tests Synchronously' - run: npm run test:apex:nocoverage -- --synchronous - - - name: 'Delete Scratch Org' - run: npx sf org delete scratch --no-prompt - if: ${{ always() }} - - experience-cloud-scratch-org-tests: - environment: 'Experience Cloud Scratch Org' - name: 'Run Experience Cloud Scratch Org Tests' - needs: [code-quality-tests, advanced-scratch-org-tests] - runs-on: ubuntu-22.04 - steps: - - name: 'Checkout source code' - uses: actions/checkout@v4 - - - name: 'Restore node_modules cache' - id: cache-npm - uses: actions/cache@v4 - with: - path: node_modules - key: npm-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - npm-${{ env.cache-name }}- - npm- - - - name: 'Install npm dependencies' - if: steps.cache-npm.outputs.cache-hit != 'true' - run: npm ci - - - name: 'Authorize Dev Hub' - shell: bash - run: | - npx sf version - echo "${{ env.DEV_HUB_JWT_SERVER_KEY }}" > ./jwt-server.key - npx sf org login jwt --instance-url ${{ env.DEV_HUB_AUTH_URL }} --client-id ${{ env.DEV_HUB_CONSUMER_KEY }} --username ${{ env.DEV_HUB_BOT_USERNAME }} --jwt-key-file ./jwt-server.key --set-default-dev-hub - env: - DEV_HUB_AUTH_URL: ${{ secrets.DEV_HUB_AUTH_URL }} - DEV_HUB_BOT_USERNAME: ${{ secrets.DEV_HUB_BOT_USERNAME }} - DEV_HUB_CONSUMER_KEY: ${{ secrets.DEV_HUB_CONSUMER_KEY }} - DEV_HUB_JWT_SERVER_KEY: ${{ secrets.DEV_HUB_JWT_SERVER_KEY }} - - - name: 'Create Scratch Org' - run: npx sf org create scratch --no-namespace --no-track-source --duration-days 1 --definition-file ./config/scratch-orgs/experience-cloud-scratch-def.json --wait 20 --set-default --json - - # To ensure that all of the Apex classes in the core directory have 75+ code coverage, - # deploy only the core directory & run all of its tests as part of the deployment, using `--test-level RunLocalTests` - - name: 'Validate Core Source in Scratch Org' - run: npx sf project deploy validate --concise --source-dir ./nebula-logger/core/ --test-level RunLocalTests - - # Now that the core directory has been deployed & tests have passed, deploy all of the metadata - - name: 'Deploy All Source to Scratch Org' - run: npx sf project deploy start --source-dir ./nebula-logger/ - - - name: 'Deploy Test Experience Sites Metadata' - run: npx sf project deploy start --source-dir ./config/scratch-orgs/experience-cloud/ - - - name: 'Assign Logger Admin Permission Set' - run: npm run permset:assign:admin - - # Nebula Logger has functionality that queries the AuthSession object when the current user has an active session. - # The code should work with or without an active session, so the pipeline runs the tests twice - asynchronously and synchronously. - # This is done because, based on how you execute Apex tests, the running user may have an active session (synchrously) or not (asynchronously). - # This data is also mocked during tests, but running the Apex tests sync & async serves within the pipeline acts as an extra level of - # integration testing to ensure that everything works with or without an active session. - - name: 'Run Apex Tests Asynchronously' - run: npm run test:apex:nocoverage - - - name: 'Run Apex Tests Synchronously' - run: npm run test:apex:nocoverage -- --synchronous - - - name: 'Delete Scratch Org' - run: npx sf org delete scratch --no-prompt - if: ${{ always() }} - - omnistudio-scratch-org-tests: - environment: 'OmniStudio Scratch Org' - name: 'Run OmniStudio Scratch Org Tests' - needs: [code-quality-tests, base-scratch-org-tests] - runs-on: ubuntu-22.04 - steps: - - name: 'Checkout source code' - uses: actions/checkout@v4 - - - name: 'Restore node_modules cache' - id: cache-npm - uses: actions/cache@v4 - with: - path: node_modules - key: npm-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - npm-${{ env.cache-name }}- - npm- - - - name: 'Install npm dependencies' - if: steps.cache-npm.outputs.cache-hit != 'true' - run: npm ci - - - name: 'Authorize Dev Hub' - shell: bash - run: | - npx sf version - echo "${{ env.DEV_HUB_JWT_SERVER_KEY }}" > ./jwt-server.key - npx sf org login jwt --instance-url ${{ env.DEV_HUB_AUTH_URL }} --client-id ${{ env.DEV_HUB_CONSUMER_KEY }} --username ${{ env.DEV_HUB_BOT_USERNAME }} --jwt-key-file ./jwt-server.key --set-default-dev-hub - env: - DEV_HUB_AUTH_URL: ${{ secrets.DEV_HUB_AUTH_URL }} - DEV_HUB_BOT_USERNAME: ${{ secrets.DEV_HUB_BOT_USERNAME }} - DEV_HUB_CONSUMER_KEY: ${{ secrets.DEV_HUB_CONSUMER_KEY }} - DEV_HUB_JWT_SERVER_KEY: ${{ secrets.DEV_HUB_JWT_SERVER_KEY }} - - - name: 'Create Scratch Org' - run: npx sf org create scratch --no-namespace --no-track-source --duration-days 1 --definition-file ./config/scratch-orgs/omnistudio-scratch-def.json --wait 20 --set-default --json - - # https://help.salesforce.com/s/articleView?id=000394906&type=1 - - name: "Install OmniStudio managed package v258.6 (Winter '26 release)" - run: npx sf package install --package 04tKb000000tAtyIAE --security-type AdminsOnly --wait 30 --no-prompt - - # To ensure that all of the Apex classes in the core directory have 75+ code coverage, - # deploy only the core directory & run all of its tests as part of the deployment, using `--test-level RunLocalTests` - - name: 'Validate Core Source in Scratch Org' - run: npx sf project deploy validate --concise --source-dir ./nebula-logger/core/ --test-level RunLocalTests - - # Now that the core directory has been deployed & tests have passed, deploy all of the metadata - - name: 'Deploy All Source to Scratch Org' - run: npx sf project deploy start --source-dir ./nebula-logger/ - - - name: 'Deploy Test OmniStudio Metadata' - run: npx sf project deploy start --source-dir ./config/scratch-orgs/omnistudio/ - - - name: 'Assign Logger Admin Permission Set' - run: npm run permset:assign:admin - - # Nebula Logger has functionality that queries the AuthSession object when the current user has an active session. - # The code should work with or without an active session, so the pipeline runs the tests twice - asynchronously and synchronously. - # This is done because, based on how you execute Apex tests, the running user may have an active session (synchrously) or not (asynchronously). - # This data is also mocked during tests, but running the Apex tests sync & async serves within the pipeline acts as an extra level of - # integration testing to ensure that everything works with or without an active session. - - name: 'Run Apex Tests Asynchronously' - run: npm run test:apex:nocoverage - - - name: 'Run Apex Tests Synchronously' - run: npm run test:apex:nocoverage -- --synchronous - - - name: 'Delete Base Scratch Org' - run: npx sf org delete scratch --no-prompt - if: ${{ always() }} - - platform-cache-scratch-org-tests: - environment: 'Platform Cache Scratch Org' - name: 'Run Platform Cache Scratch Org Tests' - needs: [code-quality-tests, event-monitoring-scratch-org-tests] - runs-on: ubuntu-22.04 - steps: - - name: 'Checkout source code' - uses: actions/checkout@v4 - - - name: 'Restore node_modules cache' - id: cache-npm - uses: actions/cache@v4 - with: - path: node_modules - key: npm-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - npm-${{ env.cache-name }}- - npm- - - - name: 'Install npm dependencies' - if: steps.cache-npm.outputs.cache-hit != 'true' - run: npm ci - - - name: 'Authorize Dev Hub' - shell: bash - run: | - npx sf version - echo "${{ env.DEV_HUB_JWT_SERVER_KEY }}" > ./jwt-server.key - npx sf org login jwt --instance-url ${{ env.DEV_HUB_AUTH_URL }} --client-id ${{ env.DEV_HUB_CONSUMER_KEY }} --username ${{ env.DEV_HUB_BOT_USERNAME }} --jwt-key-file ./jwt-server.key --set-default-dev-hub - env: - DEV_HUB_AUTH_URL: ${{ secrets.DEV_HUB_AUTH_URL }} - DEV_HUB_BOT_USERNAME: ${{ secrets.DEV_HUB_BOT_USERNAME }} - DEV_HUB_CONSUMER_KEY: ${{ secrets.DEV_HUB_CONSUMER_KEY }} - DEV_HUB_JWT_SERVER_KEY: ${{ secrets.DEV_HUB_JWT_SERVER_KEY }} - - - name: 'Create Scratch Org' - run: npx sf org create scratch --no-namespace --no-track-source --duration-days 1 --definition-file ./config/scratch-orgs/platform-cache-scratch-def.json --wait 20 --set-default --json - - # To ensure that all of the Apex classes in the core directory have 75+ code coverage, - # deploy only the core directory & run all of its tests as part of the deployment, using `--test-level RunLocalTests` - - name: 'Validate Core Source in Scratch Org' - run: npx sf project deploy validate --concise --source-dir ./nebula-logger/core/ --test-level RunLocalTests - - # Now that the core directory has been deployed & tests have passed, deploy all of the metadata - - name: 'Deploy All Source to Scratch Org' - run: npx sf project deploy start --source-dir ./nebula-logger/ - - - name: 'Assign Logger Admin Permission Set' - run: npm run permset:assign:admin - - # Nebula Logger has functionality that queries the AuthSession object when the current user has an active session. - # The code should work with or without an active session, so the pipeline runs the tests twice - asynchronously and synchronously. - # This is done because, based on how you execute Apex tests, the running user may have an active session (synchrously) or not (asynchronously). - # This data is also mocked during tests, but running the Apex tests sync & async serves within the pipeline acts as an extra level of - # integration testing to ensure that everything works with or without an active session. - - name: 'Run Apex Tests Asynchronously' - run: npm run test:apex:nocoverage - - - name: 'Run Apex Tests Synchronously' - run: npm run test:apex:nocoverage -- --synchronous - - - name: 'Delete Scratch Org' - run: npx sf org delete scratch --no-prompt - if: ${{ always() }} + # Each matrix row spawns an independent run of the scratch-org-tests reusable workflow, + # all in parallel. To add a new scratch org, add a new row - no other edits needed. + # + # The Base row is the canonical environment for Codecov code coverage reporting: + # only the `LoggerCore` test suite's results are uploaded, which validates that the core + # metadata alone (what teams deploy when they cannot install one of Nebula Logger's 2GP + # packages) has sufficient coverage to deploy to a prod org. Orgs without optional + # Salesforce features (Experience Cloud, OmniStudio, Platform Cache, etc.) tend to report + # lower coverage, so the base scratch org acts as the most conservative baseline. + scratch-org-tests: + name: 'Run ${{ matrix.label }} Scratch Org Tests' + strategy: + fail-fast: false + matrix: + include: + - label: 'Advanced' + environment: 'Advanced Scratch Org' + definition-file: ./config/scratch-orgs/advanced-scratch-def.json + install-omnistudio: true + extra-metadata-directory: ./config/scratch-orgs/ + + - label: 'Base' + environment: 'Base Scratch Org' + definition-file: ./config/scratch-orgs/base-scratch-def.json + run-core-test-suite: true + upload-apex-coverage: true + + - label: 'Event Monitoring' + environment: 'Event Monitoring Scratch Org' + definition-file: ./config/scratch-orgs/event-monitoring-scratch-def.json + + - label: 'Experience Cloud' + environment: 'Experience Cloud Scratch Org' + definition-file: ./config/scratch-orgs/experience-cloud-scratch-def.json + extra-metadata-directory: ./config/scratch-orgs/experience-cloud/ + + - label: 'OmniStudio' + environment: 'OmniStudio Scratch Org' + definition-file: ./config/scratch-orgs/omnistudio-scratch-def.json + install-omnistudio: true + extra-metadata-directory: ./config/scratch-orgs/omnistudio/ + + - label: 'Platform Cache' + environment: 'Platform Cache Scratch Org' + definition-file: ./config/scratch-orgs/platform-cache-scratch-def.json + + uses: ./.github/workflows/test-scratch-org.yml + with: + environment: ${{ matrix.environment }} + definition-file: ${{ matrix.definition-file }} + install-omnistudio: ${{ matrix.install-omnistudio || false }} + extra-metadata-directory: ${{ matrix.extra-metadata-directory || '' }} + run-core-test-suite: ${{ matrix.run-core-test-suite || false }} + upload-apex-coverage: ${{ matrix.upload-apex-coverage || false }} + secrets: inherit create-managed-package-beta: if: ${{ github.ref != 'refs/heads/main' }} environment: 'Base Scratch Org' name: 'Create Managed Package Beta' - needs: - [ - code-quality-tests, - lwc-jest-tests, - advanced-scratch-org-tests, - base-scratch-org-tests, - event-monitoring-scratch-org-tests, - experience-cloud-scratch-org-tests, - omnistudio-scratch-org-tests, - platform-cache-scratch-org-tests - ] + needs: [code-quality-tests, lwc-jest-tests, scratch-org-tests] runs-on: ubuntu-22.04 steps: - name: 'Checkout source code' - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: ref: ${{ github.event.pull_request.head.ref }} - - name: 'Restore node_modules cache' - id: cache-npm - uses: actions/cache@v4 - with: - path: node_modules - key: npm-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - npm-${{ env.cache-name }}- - npm- - - - name: 'Install npm dependencies' - if: steps.cache-npm.outputs.cache-hit != 'true' - run: npm ci + - name: 'Setup npm' + uses: ./.github/actions/setup-npm - name: 'Authorize Dev Hub' - shell: bash - run: | - npx sf version - echo "${{ env.DEV_HUB_JWT_SERVER_KEY }}" > ./jwt-server.key - npx sf org login jwt --instance-url ${{ env.DEV_HUB_AUTH_URL }} --client-id ${{ env.DEV_HUB_CONSUMER_KEY }} --username ${{ env.DEV_HUB_BOT_USERNAME }} --jwt-key-file ./jwt-server.key --set-default-dev-hub - env: - DEV_HUB_AUTH_URL: ${{ secrets.DEV_HUB_AUTH_URL }} - DEV_HUB_BOT_USERNAME: ${{ secrets.DEV_HUB_BOT_USERNAME }} - DEV_HUB_CONSUMER_KEY: ${{ secrets.DEV_HUB_CONSUMER_KEY }} - DEV_HUB_JWT_SERVER_KEY: ${{ secrets.DEV_HUB_JWT_SERVER_KEY }} + uses: ./.github/actions/authorize-dev-hub + with: + auth-url: ${{ secrets.DEV_HUB_AUTH_URL }} + bot-username: ${{ secrets.DEV_HUB_BOT_USERNAME }} + consumer-key: ${{ secrets.DEV_HUB_CONSUMER_KEY }} + jwt-server-key: ${{ secrets.DEV_HUB_JWT_SERVER_KEY }} - name: 'Create Beta Managed Package Version' run: npm run package:version:create:managed @@ -610,39 +182,27 @@ jobs: runs-on: ubuntu-22.04 steps: - name: 'Checkout source code' - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: ref: ${{ github.event.pull_request.head.ref }} - - name: 'Restore node_modules cache' - id: cache-npm - uses: actions/cache@v4 - with: - path: node_modules - key: npm-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - npm-${{ env.cache-name }}- - npm- - - - name: 'Install npm dependencies' - if: steps.cache-npm.outputs.cache-hit != 'true' - run: npm ci + - name: 'Setup npm' + uses: ./.github/actions/setup-npm - name: 'Authorize Dev Hub' - shell: bash - run: | - npx sf version - echo "${{ env.DEV_HUB_JWT_SERVER_KEY }}" > ./jwt-server.key - npx sf org login jwt --instance-url ${{ env.DEV_HUB_AUTH_URL }} --client-id ${{ env.DEV_HUB_CONSUMER_KEY }} --username ${{ env.DEV_HUB_BOT_USERNAME }} --jwt-key-file ./jwt-server.key --set-default-dev-hub - env: - DEV_HUB_AUTH_URL: ${{ secrets.DEV_HUB_AUTH_URL }} - DEV_HUB_BOT_USERNAME: ${{ secrets.DEV_HUB_BOT_USERNAME }} - DEV_HUB_CONSUMER_KEY: ${{ secrets.DEV_HUB_CONSUMER_KEY }} - DEV_HUB_JWT_SERVER_KEY: ${{ secrets.DEV_HUB_JWT_SERVER_KEY }} + uses: ./.github/actions/authorize-dev-hub + with: + auth-url: ${{ secrets.DEV_HUB_AUTH_URL }} + bot-username: ${{ secrets.DEV_HUB_BOT_USERNAME }} + consumer-key: ${{ secrets.DEV_HUB_CONSUMER_KEY }} + jwt-server-key: ${{ secrets.DEV_HUB_JWT_SERVER_KEY }} - name: 'Create Scratch Org' run: npx sf org create scratch --no-namespace --no-track-source --alias base_package_subscriber_scratch_org --duration-days 1 --definition-file ./config/scratch-orgs/base-scratch-def.json --wait 20 --set-default --json + - name: 'Set EMAIL_SERVICE_RUN_AS_USER for the scratch org' + run: npm run env:set:email-service-run-as-user + - name: 'Create & Install Package Version' run: npx pwsh ./scripts/build/create-and-install-package-version.ps1 -targetpackagealias '"Nebula Logger - Core"' -targetreadme ./README.md -targetusername base_package_subscriber_scratch_org @@ -716,8 +276,6 @@ jobs: - name: 'Commit new package version' if: ${{ github.event_name == 'pull_request' }} run: | - # npm run sf:plugins:link:bummer - echo y | npx sf plugins install @jongpie/sfdx-bummer-plugin --force npx sf bummer:package:aliases:sort npx prettier --write ./sfdx-project.json git add ./sfdx-project.json @@ -740,47 +298,22 @@ jobs: if: ${{ github.ref == 'refs/heads/main' }} name: 'Promote Package Versions' - needs: - [ - code-quality-tests, - lwc-jest-tests, - advanced-scratch-org-tests, - base-scratch-org-tests, - event-monitoring-scratch-org-tests, - experience-cloud-scratch-org-tests, - omnistudio-scratch-org-tests, - platform-cache-scratch-org-tests - ] + needs: [code-quality-tests, lwc-jest-tests, scratch-org-tests] runs-on: ubuntu-22.04 steps: - name: 'Checkout source code' - uses: actions/checkout@v4 + uses: actions/checkout@v6 - - name: 'Restore node_modules cache' - id: cache-npm - uses: actions/cache@v4 - with: - path: node_modules - key: npm-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - npm-${{ env.cache-name }}- - npm- - - - name: 'Install npm dependencies' - if: steps.cache-npm.outputs.cache-hit != 'true' - run: npm ci + - name: 'Setup npm' + uses: ./.github/actions/setup-npm - name: 'Authorize Dev Hub' - shell: bash - run: | - npx sf version - echo "${{ env.DEV_HUB_JWT_SERVER_KEY }}" > ./jwt-server.key - npx sf org login jwt --instance-url ${{ env.DEV_HUB_AUTH_URL }} --client-id ${{ env.DEV_HUB_CONSUMER_KEY }} --username ${{ env.DEV_HUB_BOT_USERNAME }} --jwt-key-file ./jwt-server.key --set-default-dev-hub - env: - DEV_HUB_AUTH_URL: ${{ secrets.DEV_HUB_AUTH_URL }} - DEV_HUB_BOT_USERNAME: ${{ secrets.DEV_HUB_BOT_USERNAME }} - DEV_HUB_CONSUMER_KEY: ${{ secrets.DEV_HUB_CONSUMER_KEY }} - DEV_HUB_JWT_SERVER_KEY: ${{ secrets.DEV_HUB_JWT_SERVER_KEY }} + uses: ./.github/actions/authorize-dev-hub + with: + auth-url: ${{ secrets.DEV_HUB_AUTH_URL }} + bot-username: ${{ secrets.DEV_HUB_BOT_USERNAME }} + consumer-key: ${{ secrets.DEV_HUB_CONSUMER_KEY }} + jwt-server-key: ${{ secrets.DEV_HUB_JWT_SERVER_KEY }} - name: 'Promote package versions' run: npx pwsh ./scripts/build/promote-readme-packages.ps1 diff --git a/.github/workflows/delete-stale-scratch-orgs.yml b/.github/workflows/delete-stale-scratch-orgs.yml new file mode 100644 index 000000000..e51ed3fdb --- /dev/null +++ b/.github/workflows/delete-stale-scratch-orgs.yml @@ -0,0 +1,143 @@ +# Scheduled cleanup for orphaned pipeline scratch orgs. +# +# The build pipeline creates scratch orgs tagged with description +# "Nebula Logger pipeline run attempt " and tries to delete them +# in an `if: always()` step at the end of the test job. That cleanup is best-effort +# and cannot run when: +# 1. The runner VM dies (infra incidents, network partitions, hitting the 6h timeout). +# 2. A pull-request push auto-cancels a run, and the cancellation grace period expires +# while a slow step is still running, so the runner is killed before `if: always()` +# can fire. +# 3. The `sf org delete scratch` call itself errors transiently (rate-limit, API blip). +# +# This workflow is the safety net. It runs hourly, queries the Dev Hub for +# `ActiveScratchOrg` records tagged with the pipeline description marker that are +# older than 2 hours, parses the GitHub run ID out of each description, and asks the +# GitHub REST API for the run's status. Orgs whose owning run is still queued or +# in-progress are skipped so a slow but healthy build never has its scratch org +# yanked out from under it. Everything else is deleted directly via the Tooling API. +name: Delete Stale Scratch Orgs + +on: + schedule: + # Hourly. The 2h age filter + per-org in-progress check is what prevents this from + # killing healthy in-flight runs, not the cron interval. + - cron: '0 * * * *' + workflow_dispatch: + +env: + SF_DISABLE_AUTOUPDATE: true + SF_LOG_LEVEL: debug + SF_SKIP_NEW_VERSION_CHECK: true + +# Don't run more than one cleanup at a time. If a manual dispatch overlaps with the +# hourly cron, the second invocation queues until the first finishes. +concurrency: + group: delete-stale-scratch-orgs + cancel-in-progress: false + +# Need read access to other workflow runs so we can ask "is run still in-progress". +permissions: + actions: read + contents: read + +jobs: + delete-orphaned-scratch-orgs: + name: 'Delete Orphaned Pipeline Scratch Orgs' + environment: 'Base Scratch Org' + runs-on: ubuntu-22.04 + steps: + - name: 'Checkout source code' + uses: actions/checkout@v6 + + - name: 'Setup npm' + uses: ./.github/actions/setup-npm + + - name: 'Authorize Dev Hub' + uses: ./.github/actions/authorize-dev-hub + with: + auth-url: ${{ secrets.DEV_HUB_AUTH_URL }} + bot-username: ${{ secrets.DEV_HUB_BOT_USERNAME }} + consumer-key: ${{ secrets.DEV_HUB_CONSUMER_KEY }} + jwt-server-key: ${{ secrets.DEV_HUB_JWT_SERVER_KEY }} + + - name: 'Delete orphaned pipeline scratch orgs' + env: + DEV_HUB_BOT_USERNAME: ${{ secrets.DEV_HUB_BOT_USERNAME }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} + shell: bash + run: | + set -euo pipefail + + # ActiveScratchOrg holds the live scratch org records on the Dev Hub. Deleting an + # ActiveScratchOrg row releases the scratch org - same mechanism used by + # `sf org delete scratch`, but it doesn't require re-authenticating into the + # scratch org from this runner (we may not have the auth state any more). + QUERY="SELECT Id, SignupUsername, Description, CreatedDate FROM ActiveScratchOrg WHERE Description LIKE 'Nebula Logger pipeline run%' AND CreatedDate < LAST_N_HOURS:2" + + echo "Querying Dev Hub for pipeline scratch orgs older than 2h..." + query_result=$(npx sf data query --query "$QUERY" --target-org "$DEV_HUB_BOT_USERNAME" --json) + + total=$(echo "$query_result" | jq -r '.result.totalSize') + echo "Found $total candidate scratch org(s)." + + if [ "$total" = "0" ]; then + echo "Nothing to clean up." + exit 0 + fi + + echo "$query_result" | jq -r '.result.records[] | "\(.Id)\t\(.SignupUsername)\t\(.CreatedDate)\t\(.Description)"' + + deleted_count=0 + skipped_count=0 + failed_count=0 + + # Iterate as TSV so spaces in Description don't break the loop. + while IFS=$'\t' read -r record_id description; do + # Description format: "Nebula Logger pipeline run attempt " + run_id=$(echo "$description" | sed -nE 's/^Nebula Logger pipeline run ([0-9]+) attempt [0-9]+.*$/\1/p') + + if [ -z "$run_id" ]; then + echo "" + echo "ActiveScratchOrg $record_id has unparseable description: '$description'. Treating as orphaned." + run_status="unknown" + else + echo "" + echo "ActiveScratchOrg $record_id - checking GitHub run $run_id..." + # Pull just the status. If the run ID no longer exists (deleted, or wrong repo), + # gh exits non-zero and we treat that as "safe to delete". + if run_status=$(gh run view "$run_id" --repo "$GH_REPO" --json status --jq '.status' 2>/dev/null); then + echo " GitHub run $run_id status: $run_status" + else + echo " GitHub run $run_id not found (or inaccessible). Treating as orphaned." + run_status="not_found" + fi + fi + + # Statuses where the run is still alive: queued, in_progress, requested, waiting, pending. + # `completed` (with any conclusion) means the run is done and any leftover org is orphaned. + case "$run_status" in + queued|in_progress|requested|waiting|pending) + echo " Skipping ActiveScratchOrg $record_id - owning run is still active." + skipped_count=$((skipped_count + 1)) + ;; + *) + echo " Deleting ActiveScratchOrg $record_id..." + if npx sf data delete record --sobject ActiveScratchOrg --record-id "$record_id" --target-org "$DEV_HUB_BOT_USERNAME"; then + deleted_count=$((deleted_count + 1)) + else + echo " Failed to delete ActiveScratchOrg $record_id. Continuing with the rest." + failed_count=$((failed_count + 1)) + fi + ;; + esac + done < <(echo "$query_result" | jq -r '.result.records[] | "\(.Id)\t\(.Description)"') + + echo "" + echo "Cleanup summary: deleted=$deleted_count, skipped=$skipped_count, failed=$failed_count, total=$total" + + if [ "$failed_count" -gt 0 ]; then + echo "::warning::$failed_count orphaned scratch org(s) could not be deleted - investigate Dev Hub state." + exit 1 + fi diff --git a/.github/workflows/publish-docker-container.yml b/.github/workflows/publish-docker-container.yml index c8d8ddafd..e0b769cbb 100644 --- a/.github/workflows/publish-docker-container.yml +++ b/.github/workflows/publish-docker-container.yml @@ -11,17 +11,17 @@ jobs: permissions: packages: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - - uses: docker/setup-buildx-action@v3 + - uses: docker/setup-buildx-action@v4 - - uses: docker/login-action@v3 + - uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GH_TOKEN_PUBLISH_DOCKER_IMAGE }} - - uses: docker/build-push-action@v5 + - uses: docker/build-push-action@v7 with: context: . file: .devcontainer/Dockerfile diff --git a/.github/workflows/test-scratch-org.yml b/.github/workflows/test-scratch-org.yml new file mode 100644 index 000000000..6ab29fdfd --- /dev/null +++ b/.github/workflows/test-scratch-org.yml @@ -0,0 +1,146 @@ +# Reusable workflow that creates a scratch org, deploys Nebula Logger, runs the +# Apex tests sync + async, and tears the scratch org down. Variations across the +# different scratch org definitions are controlled via inputs. +name: Test Scratch Org + +on: + workflow_call: + inputs: + environment: + description: 'GitHub environment used for secret scoping (e.g. "Base Scratch Org").' + required: true + type: string + definition-file: + description: 'Path to the scratch org definition file passed to `sf org create scratch`.' + required: true + type: string + install-omnistudio: + description: 'When true, install the OmniStudio managed package after creating the scratch org.' + required: false + type: boolean + default: false + extra-metadata-directory: + description: 'Optional source directory to deploy after the main metadata deploy. Empty string skips this step.' + required: false + type: string + default: '' + run-core-test-suite: + description: 'When true, run the LoggerCore Apex test suite for code coverage reporting.' + required: false + type: boolean + default: false + upload-apex-coverage: + description: 'When true, upload Apex test coverage to Codecov.io. Requires `run-core-test-suite: true`.' + required: false + type: boolean + default: false + secrets: + DEV_HUB_AUTH_URL: + required: true + DEV_HUB_BOT_USERNAME: + required: true + DEV_HUB_CONSUMER_KEY: + required: true + DEV_HUB_JWT_SERVER_KEY: + required: true + CODECOV_TOKEN: + required: false + +env: + SF_DISABLE_AUTOUPDATE: true + SF_LOG_LEVEL: debug + SF_SKIP_NEW_VERSION_CHECK: true + +jobs: + scratch-org-tests: + environment: ${{ inputs.environment }} + runs-on: ubuntu-22.04 + steps: + - name: 'Checkout source code' + uses: actions/checkout@v6 + + - name: 'Setup npm' + uses: ./.github/actions/setup-npm + + - name: 'Authorize Dev Hub' + uses: ./.github/actions/authorize-dev-hub + with: + auth-url: ${{ secrets.DEV_HUB_AUTH_URL }} + bot-username: ${{ secrets.DEV_HUB_BOT_USERNAME }} + consumer-key: ${{ secrets.DEV_HUB_CONSUMER_KEY }} + jwt-server-key: ${{ secrets.DEV_HUB_JWT_SERVER_KEY }} + + # Pipeline scratch orgs are tagged with the alias `pipeline-scratch-org` and a description + # that includes the GitHub run ID. The alias makes the delete step targeted (so it cannot + # accidentally delete a different default org), and the description marker is what the + # scheduled cleanup workflow (.github/workflows/delete-stale-scratch-orgs.yml) uses to + # identify orphaned scratch orgs that escaped the in-job cleanup. + - name: 'Create Scratch Org' + env: + DEFINITION_FILE: ${{ inputs.definition-file }} + SCRATCH_ORG_DESCRIPTION: 'Nebula Logger pipeline run ${{ github.run_id }} attempt ${{ github.run_attempt }}' + run: npx sf org create scratch --no-namespace --no-track-source --duration-days 1 --definition-file "$DEFINITION_FILE" --description "$SCRATCH_ORG_DESCRIPTION" --alias pipeline-scratch-org --wait 20 --set-default --json + + # The replacements block in sfdx-project.json swaps {{EMAIL_SERVICE_RUN_AS_USER}} in + # ExampleInboundEmailService.xml-meta.xml with the value of this env var at deploy time. + - name: 'Set EMAIL_SERVICE_RUN_AS_USER for the scratch org' + run: npm run env:set:email-service-run-as-user + + # https://help.salesforce.com/s/articleView?id=000394906&type=1 + - name: "Install OmniStudio managed package v258.6 (Winter '26 release)" + if: ${{ inputs.install-omnistudio }} + run: npx sf package install --package 04tKb000000tAtyIAE --security-type AdminsOnly --wait 30 --no-prompt + + # To ensure that all of the Apex classes in the core directory have 75+ code coverage, + # deploy only the core directory & run all of its tests as part of the deployment, using `--test-level RunLocalTests` + - name: 'Validate Core Source in Scratch Org' + run: npx sf project deploy validate --concise --source-dir ./nebula-logger/core/ --test-level RunLocalTests + + # Now that the core directory has been deployed & tests have passed, deploy all of the metadata + - name: 'Deploy All Source to Scratch Org' + run: npx sf project deploy start --source-dir ./nebula-logger/ + + - name: 'Deploy Extra Metadata' + if: ${{ inputs.extra-metadata-directory != '' }} + env: + EXTRA_METADATA_DIRECTORY: ${{ inputs.extra-metadata-directory }} + run: npx sf project deploy start --source-dir "$EXTRA_METADATA_DIRECTORY" + + - name: 'Assign Logger Admin Permission Set' + run: npm run permset:assign:admin + + # Nebula Logger has functionality that queries the AuthSession object when the current user has an active session. + # The code should work with or without an active session, so the pipeline runs the tests twice - asynchronously and synchronously. + # This is done because, based on how you execute Apex tests, the running user may have an active session (synchrously) or not (asynchronously). + # This data is also mocked during tests, but running the Apex tests sync & async serves within the pipeline acts as an extra level of + # integration testing to ensure that everything works with or without an active session. + - name: 'Run Apex Tests Asynchronously' + run: npm run test:apex:nocoverage + + - name: 'Run Apex Tests Synchronously' + run: npm run test:apex:nocoverage -- --synchronous + + # This step only runs in the base scratch org. The `LoggerCore` test suite's results are sent to Codecov.io + # specifically from a base scratch org so the reported code coverage reflects the metadata that teams who + # cannot install the 2GP packages will deploy directly. See the long-form rationale in the prior history of build.yml. + - name: 'Get Core Test Suite Code Coverage' + if: ${{ inputs.run-core-test-suite }} + run: npm run test:apex:suite:core + + - name: 'Upload Apex test code coverage to Codecov.io' + if: ${{ inputs.upload-apex-coverage }} + uses: codecov/codecov-action@v6 + with: + fail_ci_if_error: true + flags: Apex + token: ${{ secrets.CODECOV_TOKEN }} + + # `if: always()` runs this on success, failure, and most cancellations. It cannot run if + # the runner VM dies or if the cancellation grace period expires mid-step - the scheduled + # cleanup workflow (delete-stale-scratch-orgs.yml) is the safety net for those cases. + # `continue-on-error: true` means a transient delete failure (rate-limit, API blip) does + # not mask a real test failure earlier in the job. The cleanup workflow will mop up if it happens. + - name: 'Delete Scratch Org' + if: ${{ always() }} + continue-on-error: true + run: npx sf org delete scratch --target-org pipeline-scratch-org --no-prompt diff --git a/.gitignore b/.gitignore index 1119bd874..c5ec6ed19 100644 --- a/.gitignore +++ b/.gitignore @@ -8,12 +8,14 @@ docs/apex/Miscellaneous/ temp/ test-coverage/ +.claude/ # NPM node_modules/ yarn.lock # Files to exclude +*.env *.log **/lwc/jsconfig.json .config diff --git a/README.md b/README.md index c4db31bfb..088daa695 100644 --- a/README.md +++ b/README.md @@ -5,13 +5,13 @@ The most robust observability solution for Salesforce experts. Built 100% natively on the platform, and designed to work seamlessly with Apex, Lightning Components, Flow, OmniStudio, and integrations. -## Unlocked Package - v4.18.3 +## Unlocked Package - v4.18.4 -[![Install Unlocked Package in a Sandbox](./images/btn-install-unlocked-package-sandbox.png)](https://test.salesforce.com/packaging/installPackage.apexp?p0=04tg70000009GaDAAU) -[![Install Unlocked Package in Production](./images/btn-install-unlocked-package-production.png)](https://login.salesforce.com/packaging/installPackage.apexp?p0=04tg70000009GaDAAU) +[![Install Unlocked Package in a Sandbox](./images/btn-install-unlocked-package-sandbox.png)](https://test.salesforce.com/packaging/installPackage.apexp?p0=04tg7000000Bb13AAC) +[![Install Unlocked Package in Production](./images/btn-install-unlocked-package-production.png)](https://login.salesforce.com/packaging/installPackage.apexp?p0=04tg7000000Bb13AAC) [![View Documentation](./images/btn-view-documentation.png)](https://github.com/jongpie/NebulaLogger/wiki) -`sf package install --wait 20 --security-type AdminsOnly --package 04tg70000009GaDAAU` +`sf package install --wait 20 --security-type AdminsOnly --package 04tg7000000Bb13AAC` --- diff --git a/config/scratch-orgs/experience-cloud/authproviders/ExampleGoogleAuth.authprovider-meta.xml b/config/scratch-orgs/experience-cloud/authproviders/ExampleGoogleAuth.authprovider-meta.xml new file mode 100644 index 000000000..83478ca15 --- /dev/null +++ b/config/scratch-orgs/experience-cloud/authproviders/ExampleGoogleAuth.authprovider-meta.xml @@ -0,0 +1,13 @@ + + + test-dzvrxqazkvaw@example.com + ExampleGoogleAuth + false + true + Google + ExampleRegistrationHandler + false + false + false + true + diff --git a/config/scratch-orgs/experience-cloud/classes/ExampleRegistrationHandler.cls b/config/scratch-orgs/experience-cloud/classes/ExampleRegistrationHandler.cls new file mode 100644 index 000000000..7f9888089 --- /dev/null +++ b/config/scratch-orgs/experience-cloud/classes/ExampleRegistrationHandler.cls @@ -0,0 +1,199 @@ +global class ExampleRegistrationHandler implements Auth.RegistrationHandler { + private static final String LOGGER_SCENARIO = 'Nebula Logger - Experience Cloud testing'; + + global Schema.User createUser(Id portalId, Auth.UserData userData) { + Logger.setScenario(LOGGER_SCENARIO); + Logger.info( + new LogMessage('Running custom auth registration handler for portalId {0} with user data:\n\n{1}', portalId, System.JSON.serializePretty(userData)) + ); + Logger.saveLog(); + + try { + Schema.User existingUser = findExistingUser(userData); + if (existingUser != null) { + return existingUser; + } + + Schema.Contact contact = getOrCreateContact(userData); + Schema.Profile communityProfile = getCommunityProfile(); + + String email = normalizeEmail(userData.email); + String localPart = email != null ? email.substringBefore('@') : 'social.user'; + String timeSuffix = String.valueOf(DateTime.now().getTime()); + + Schema.User newUser = new Schema.User( + Alias = makeAlias(localPart), + CommunityNickname = makeNickname(localPart, timeSuffix), + ContactId = contact.Id, + Email = (email != null ? email : localPart + '+' + timeSuffix + '@example.invalid'), + EmailEncodingKey = 'UTF-8', + FederationIdentifier = userData.identifier, + FirstName = String.isBlank(userData.firstName) ? 'Social' : userData.firstName, + LanguageLocaleKey = 'en_US', + LastName = String.isBlank(userData.lastName) ? 'User' : userData.lastName, + LocaleSidKey = 'en_US', + ProfileId = communityProfile.Id, + TimeZoneSidKey = 'America/Los_Angeles', + Username = (email != null ? email : localPart + '.' + timeSuffix + '@example.invalid') + ); + + insert newUser; + + Logger.info('Successfully created new user', newUser); + Logger.saveLog(); + + return newUser; + } catch (System.Exception ex) { + Logger.exception('Error trying to create user', ex); + // Logger.exception (above) will thrown an exception, + // but to keep the Apex compiler happy, we have to have return null below + return null; + } + } + + global void updateUser(Id userId, Id portalId, Auth.UserData userData) { + Schema.User userToUpdate = new Schema.User( + Id = userId, + FirstName = String.isBlank(userData.firstName) ? null : userData.firstName, + LastName = String.isBlank(userData.lastName) ? null : userData.lastName, + Email = normalizeEmail(userData.email), + FederationIdentifier = userData.identifier + ); + update userToUpdate; + } + + private static Schema.User findExistingUser(Auth.UserData userData) { + if (String.isNotBlank(userData.identifier)) { + List usersByFederationId = [ + SELECT Id, FederationIdentifier + FROM User + WHERE FederationIdentifier = :userData.identifier + LIMIT 1 + ]; + if (!usersByFederationId.isEmpty()) { + return usersByFederationId[0]; + } + } + + String email = normalizeEmail(userData.email); + if (email != null) { + List usersByEmail = [ + SELECT Id, Email + FROM User + WHERE Email = :email + LIMIT 1 + ]; + if (!usersByEmail.isEmpty()) { + return usersByEmail[0]; + } + } + + return null; + } + + private static Schema.Contact getOrCreateContact(Auth.UserData userData) { + String email = normalizeEmail(userData.email); + if (email != null) { + List existingContacts = [ + SELECT Id + FROM Contact + WHERE Email = :email + LIMIT 1 + ]; + if (!existingContacts.isEmpty()) { + return existingContacts[0]; + } + } + + Schema.Account account = new Schema.Account(Name = 'Experience Cloud Social Login Users'); + insert account; + + Schema.Contact contact = new Schema.Contact( + AccountId = account.Id, + FirstName = String.isBlank(userData.firstName) ? 'Social' : userData.firstName, + LastName = String.isBlank(userData.lastName) ? 'User' : userData.lastName, + Email = email + ); + insert contact; + return contact; + } + + private static Schema.Profile getCommunityProfile() { + Id siteId = Site.getSiteId(); + if (siteId != null) { + Site currentSite = [SELECT GuestUserId FROM Site WHERE Id = :siteId LIMIT 1]; + if (currentSite.GuestUserId != null) { + Schema.User guestUser = [ + SELECT Profile.Name + FROM User + WHERE Id = :currentSite.GuestUserId + LIMIT 1 + ]; + + String siteNamePrefix = getSiteNamePrefixFromGuestProfileName(guestUser.Profile.Name); + if (String.isNotBlank(siteNamePrefix)) { + List siteScopedProfiles = [ + SELECT Id, Name, UserType + FROM Profile + WHERE UserType IN ('CSPLitePortal', 'PowerCustomerSuccess', 'CustomerSuccess') AND Name LIKE :siteNamePrefix + '%' + ORDER BY Name + LIMIT 1 + ]; + if (!siteScopedProfiles.isEmpty()) { + return siteScopedProfiles[0]; + } + } + } + } + + List fallbackByNameProfiles = [ + SELECT Id, Name, UserType + FROM Profile + WHERE UserType IN ('CSPLitePortal', 'PowerCustomerSuccess', 'CustomerSuccess') AND Name = 'Logger Test Site User Profile' + LIMIT 1 + ]; + if (!fallbackByNameProfiles.isEmpty()) { + return fallbackByNameProfiles[0]; + } + + List genericFallbackProfiles = [ + SELECT Id, Name, UserType + FROM Profile + WHERE UserType IN ('CSPLitePortal', 'PowerCustomerSuccess', 'CustomerSuccess') + ORDER BY Name + LIMIT 1 + ]; + if (genericFallbackProfiles.isEmpty()) { + throw new System.IllegalArgumentException('No Experience Cloud user profile found. Create/enable a community user profile first.'); + } + return genericFallbackProfiles[0]; + } + + private static String getSiteNamePrefixFromGuestProfileName(String guestProfileName) { + if (String.isBlank(guestProfileName)) { + return null; + } + String suffix = ' Guest Profile'; + if (guestProfileName.endsWith(suffix)) { + return guestProfileName.substring(0, guestProfileName.length() - suffix.length()); + } + return guestProfileName; + } + + private static String normalizeEmail(String email) { + return String.isBlank(email) ? null : email.trim().toLowerCase(); + } + + private static String makeAlias(String value) { + String cleaned = String.isBlank(value) ? 'socialusr' : value.replaceAll('[^A-Za-z0-9]', ''); + if (cleaned.length() < 2) { + cleaned = cleaned + 'usr'; + } + return cleaned.left(8); + } + + private static String makeNickname(String value, String suffix) { + String cleaned = String.isBlank(value) ? 'social.user' : value.replaceAll('[^A-Za-z0-9]', '.'); + return (cleaned.left(Math.min(20, cleaned.length())) + '.' + suffix.right(6)).toLowerCase(); + } +} diff --git a/config/scratch-orgs/experience-cloud/classes/ExampleRegistrationHandler.cls-meta.xml b/config/scratch-orgs/experience-cloud/classes/ExampleRegistrationHandler.cls-meta.xml new file mode 100644 index 000000000..cad713d0a --- /dev/null +++ b/config/scratch-orgs/experience-cloud/classes/ExampleRegistrationHandler.cls-meta.xml @@ -0,0 +1,5 @@ + + + 66.0 + Active + diff --git a/config/scratch-orgs/experience-cloud/classes/ExampleRegistrationHandlerTest.cls b/config/scratch-orgs/experience-cloud/classes/ExampleRegistrationHandlerTest.cls new file mode 100644 index 000000000..f66550e8a --- /dev/null +++ b/config/scratch-orgs/experience-cloud/classes/ExampleRegistrationHandlerTest.cls @@ -0,0 +1,73 @@ +@IsTest +private class ExampleRegistrationHandlerTest { + @IsTest + static void createUser_returnsExistingUser_whenFederationIdentifierMatches() { + Schema.User existingUser = createInternalUser('fed-match@example.com', 'fed-match-1'); + Auth.UserData userData = makeUserData('fed-match-1', 'Someone', 'Else', 'FED-MATCH@EXAMPLE.COM'); + + System.Test.startTest(); + Schema.User result = new ExampleRegistrationHandler().createUser(null, userData); + System.Test.stopTest(); + + System.assertEquals(existingUser.Id, result.Id, 'Expected existing user to be returned by federation identifier.'); + } + + @IsTest + static void createUser_returnsExistingUser_whenEmailMatches() { + Schema.User existingUser = createInternalUser('email-match@example.com', null); + Auth.UserData userData = makeUserData(null, 'Another', 'Person', 'EMAIL-MATCH@EXAMPLE.COM'); + + System.Test.startTest(); + Schema.User result = new ExampleRegistrationHandler().createUser(null, userData); + System.Test.stopTest(); + + System.assertEquals(existingUser.Id, result.Id, 'Expected existing user to be returned by email fallback.'); + } + + @IsTest + static void updateUser_updatesMappedFields() { + Schema.User existingUser = createInternalUser('update-me@example.com', null); + Auth.UserData updatedData = makeUserData('updated-federation-id', 'UpdatedFirst', 'UpdatedLast', 'updated@example.com'); + + System.Test.startTest(); + new ExampleRegistrationHandler().updateUser(existingUser.Id, null, updatedData); + System.Test.stopTest(); + + Schema.User actualUser = [ + SELECT Email, FirstName, LastName, FederationIdentifier + FROM User + WHERE Id = :existingUser.Id + ]; + + System.assertEquals('updated@example.com', actualUser.Email); + System.assertEquals('UpdatedFirst', actualUser.FirstName); + System.assertEquals('UpdatedLast', actualUser.LastName); + System.assertEquals('updated-federation-id', actualUser.FederationIdentifier); + } + + private static Auth.UserData makeUserData(String identifier, String firstName, String lastName, String email) { + Map attributeMap = new Map(); + return new Auth.UserData(identifier, firstName, lastName, firstName + ' ' + lastName, email, null, email, 'en_US', 'Google', null, attributeMap); + } + + private static Schema.User createInternalUser(String email, String federationIdentifier) { + String timestamp = String.valueOf(DateTime.now().getTime()); + String username = 'example.handler.' + timestamp + '.' + Math.abs(Crypto.getRandomInteger()) + '@example.invalid'; + Id currentUserProfileId = [SELECT ProfileId FROM User WHERE Id = :System.UserInfo.getUserId()].ProfileId; + + Schema.User userToInsert = new Schema.User( + ProfileId = currentUserProfileId, + Username = username, + Email = email, + LastName = 'Test User', + Alias = 'tuser', + TimeZoneSidKey = 'America/Los_Angeles', + LocaleSidKey = 'en_US', + EmailEncodingKey = 'UTF-8', + LanguageLocaleKey = 'en_US', + FederationIdentifier = federationIdentifier + ); + insert userToInsert; + return userToInsert; + } +} diff --git a/config/scratch-orgs/experience-cloud/classes/ExampleRegistrationHandlerTest.cls-meta.xml b/config/scratch-orgs/experience-cloud/classes/ExampleRegistrationHandlerTest.cls-meta.xml new file mode 100644 index 000000000..cad713d0a --- /dev/null +++ b/config/scratch-orgs/experience-cloud/classes/ExampleRegistrationHandlerTest.cls-meta.xml @@ -0,0 +1,5 @@ + + + 66.0 + Active + diff --git a/config/scratch-orgs/experience-cloud/networks/Logger Test Aura Site.network-meta.xml b/config/scratch-orgs/experience-cloud/networks/Logger Test Aura Site.network-meta.xml index 9ce021b30..029e67596 100644 --- a/config/scratch-orgs/experience-cloud/networks/Logger Test Aura Site.network-meta.xml +++ b/config/scratch-orgs/experience-cloud/networks/Logger Test Aura Site.network-meta.xml @@ -3,10 +3,11 @@ false false unfiled$public/CommunityChangePasswordEmailTemplate - + true - salesforce.nebula.packages@jongpie.com + salesforce.nebula.packages@jongpie.com.invalid Logger Test Aura Site + false true false true @@ -33,18 +34,38 @@ false unfiled$public/CommunityHeadlessForgotPasswordTemplate unfiled$public/CommunityHeadlessRegistrationTemplate + + false + true + false + false + false + false + false + false + false + false + false + false + false + false + false + 5 + 0.0 + LoggerLogCreator admin - Logger Test Site User Profile + logger test site user profile Standard - Designer + Standard Designer - Designer + Standard Designer + salesforce.nebula.packages@jongpie.com Logger_Test_Aura_Site1 false true diff --git a/config/scratch-orgs/experience-cloud/sites/Logger_Test_Aura_Site.site-meta.xml b/config/scratch-orgs/experience-cloud/sites/Logger_Test_Aura_Site.site-meta.xml index 9c5ed929d..5ed7f61ee 100644 --- a/config/scratch-orgs/experience-cloud/sites/Logger_Test_Aura_Site.site-meta.xml +++ b/config/scratch-orgs/experience-cloud/sites/Logger_Test_Aura_Site.site-meta.xml @@ -23,8 +23,8 @@ false true CommunitiesSelfReg - test-poxlhhmpqbuq@example.com - test-poxlhhmpqbuq@example.com + test-dzvrxqazkvaw@example.com + test-dzvrxqazkvaw@example.com ChatterNetwork loggeraura diff --git a/config/scratch-orgs/state-and-country-picklists-scratch-def.json b/config/scratch-orgs/state-and-country-picklists-scratch-def.json new file mode 100644 index 000000000..6d2bbd8f0 --- /dev/null +++ b/config/scratch-orgs/state-and-country-picklists-scratch-def.json @@ -0,0 +1,34 @@ +{ + "orgName": "Nebula Logger - State & Country Picklists Scratch Org", + "edition": "Enterprise", + "features": ["Communities", "ContactsToMultipleAccounts", "PersonAccounts", "StateAndCountryPicklist"], + "settings": { + "communitiesSettings": { + "enableNetworksEnabled": true + }, + "enhancedNotesSettings": { + "enableEnhancedNotes": true + }, + "emailAdministrationSettings": { + "enableEnhancedEmailEnabled": true + }, + "experienceBundleSettings": { + "enableExperienceBundleMetadata": true + }, + "lightningExperienceSettings": { + "enableS1DesktopEnabled": true + }, + "nameSettings": { + "enableMiddleName": true, + "enableNameSuffix": true + }, + "securitySettings": { + "enableAuditFieldsInactiveOwner": "true", + "sessionSettings": { + "lockSessionsToDomain": "false", + "lockSessionsToIp": "false", + "sessionTimeout": "TwelveHours" + } + } + } +} diff --git a/nebula-logger/core/main/logger-engine/classes/Logger.cls b/nebula-logger/core/main/logger-engine/classes/Logger.cls index 661834039..c79bad487 100644 --- a/nebula-logger/core/main/logger-engine/classes/Logger.cls +++ b/nebula-logger/core/main/logger-engine/classes/Logger.cls @@ -15,12 +15,12 @@ global with sharing class Logger { // There's no reliable way to get the version number dynamically in Apex @TestVisible - private static final String CURRENT_VERSION_NUMBER = 'v4.18.3'; + private static final String CURRENT_VERSION_NUMBER = 'v4.18.4'; private static final System.LoggingLevel FALLBACK_LOGGING_LEVEL = System.LoggingLevel.DEBUG; private static final List LOG_ENTRIES_BUFFER = new List(); private static final String MISSING_SCENARIO_ERROR_MESSAGE = 'No logger scenario specified. A scenario is required for logging in this org.'; private static final String ORGANIZATION_DOMAIN_URL = System.URL.getOrgDomainUrl()?.toExternalForm(); - private static final String REQUEST_ID = System.Request.getCurrent().getRequestId(); + private static final String REQUEST_ID = System.Request.getCurrent()?.getRequestId(); private static final Map SAVE_METHOD_NAME_TO_SAVE_METHOD = new Map(); private static final Map TRANSACTION_FIELD_TO_VALUE = new Map(); private static final String TRANSACTION_ID = System.UUID.randomUUID().toString(); @@ -36,7 +36,7 @@ global with sharing class Logger { private static Integer saveLogCallCount = 0; private static Boolean suspendSaving = false; @TestVisible - private static System.Quiddity transactionQuiddity = loadTransactionQuiddity(); + private static System.Quiddity transactionQuiddity = System.Request.getCurrent()?.getQuiddity() ?? System.Quiddity.UNDEFINED; private static String transactionScenario; private static final List CLASSES_TO_IGNORE { @@ -86,26 +86,6 @@ global with sharing class Logger { set; } - @SuppressWarnings('PMD.AvoidUnauthorizedGetSessionIdInApex') - private static final String USER_SESSION_ID { - get { - if (USER_SESSION_ID == null) { - // TODO Spring '24 release - simplify this (and other lazy-loaded values) - // by switching to the fancy, new ?? null coalescing operator - try { - USER_SESSION_ID = System.UserInfo.getSessionId(); - } catch (Exception ex) { - USER_SESSION_ID = ''; - } - // If System.UserInfo.getSessionId() returns null, set to an empty string to - // avoid calling System.UserInfo.getSessionId() again - USER_SESSION_ID = USER_SESSION_ID ?? ''; - } - return USER_SESSION_ID; - } - set; - } - private static String transactionSaveMethodName { get { if (transactionSaveMethodName == null) { @@ -3755,13 +3735,7 @@ global with sharing class Logger { LoggerDataStore.getJobQueue().enqueueJob(new QueueableSaver(logEntryEvents)); } when REST { - // If the user doesn't have a session ID (e.g., site guest user), the REST API call will fail - // To avoid that, use the EventBus instead (even though REST was specified) - if (String.isBlank(USER_SESSION_ID)) { - saveLog(Logger.SaveMethod.EVENT_BUS); - } else { - new RestApiSaver().insertRecords(logEntryEvents); - } + new RestApiSaver(System.UserInfo.getSessionId()).insertRecords(logEntryEvents); } when SYNCHRONOUS_DML { LoggerTriggerableContext logEntryEventsAfterContext = new LoggerTriggerableContext( @@ -3932,18 +3906,6 @@ global with sharing class Logger { return isStartTimeValid && isEndTimeValid; } - private static System.Quiddity loadTransactionQuiddity() { - // An error can sometimes occur when calling System.Request.getCurrent(), such as when logging - // from an Auth Provider class (that implements Auth.RegistrationHandler). As a workaround, - // skip calling System.Request.getCurrent() if there is no user session. - // TODO: see if there is a better approach for this long term (or hopefully Salesforce fixes the gack error) - if (String.isNotBlank(USER_SESSION_ID)) { - return System.Request.getCurrent().getQuiddity(); - } else { - return null; - } - } - private static void setAsyncContext(AsyncContext asyncContext) { // Only set the async context the first time that a non-null value is provided // Previous versions of Nebula Logger would always set it, but that wasn't the @@ -3978,12 +3940,7 @@ global with sharing class Logger { String messageTemplate = 'Nebula Logger - Saving {0} log entries via {1}, save method is {2}. Logger.saveLog() has been called {3} in the current transaction.'; LogMessage savingLogMessage = new LogMessage( messageTemplate, - new List{ - LOG_ENTRIES_BUFFER.size(), - (getCurrentQuiddity() ?? System.Quiddity.UNDEFINED).name(), - saveMethodName, - saveLogCallCount + (saveLogCallCount == 1 ? ' time' : ' times') - } + new List{ LOG_ENTRIES_BUFFER.size(), getCurrentQuiddity(), saveMethodName, saveLogCallCount + (saveLogCallCount == 1 ? ' time' : ' times') } ); return savingLogMessage.getMessage(); @@ -4090,6 +4047,11 @@ global with sharing class Logger { private class RestApiSaver { private final String baseURL = ORGANIZATION_DOMAIN_URL + '/services/data/' + getOrganizationApiVersion(); private final String compositeEndpoint = '/composite/sobjects'; + private final String sessionId; + + public RestApiSaver(String sessionId) { + this.sessionId = sessionId; + } @SuppressWarnings('PMD.ApexSuggestUsingNamedCred') /** @@ -4099,7 +4061,7 @@ global with sharing class Logger { public void insertRecords(List records) { System.HttpRequest request = new System.HttpRequest(); request.setEndpoint(baseURL + compositeEndpoint); - request.setHeader('Authorization', 'Bearer ' + USER_SESSION_ID); + request.setHeader('Authorization', 'Bearer ' + this.sessionId); request.setHeader('Content-Type', 'application/json; charset=utf-8'); request.setMethod('POST'); diff --git a/nebula-logger/core/main/logger-engine/lwc/logger/loggerService.js b/nebula-logger/core/main/logger-engine/lwc/logger/loggerService.js index cb87dbb96..3b782083e 100644 --- a/nebula-logger/core/main/logger-engine/lwc/logger/loggerService.js +++ b/nebula-logger/core/main/logger-engine/lwc/logger/loggerService.js @@ -10,7 +10,7 @@ import LoggerServiceTaskQueue from './loggerServiceTaskQueue'; import getSettings from '@salesforce/apex/ComponentLogger.getSettings'; import saveComponentLogEntries from '@salesforce/apex/ComponentLogger.saveComponentLogEntries'; -const CURRENT_VERSION_NUMBER = 'v4.18.3'; +const CURRENT_VERSION_NUMBER = 'v4.18.4'; const CONSOLE_OUTPUT_CONFIG = { messagePrefix: `%c Nebula Logger ${CURRENT_VERSION_NUMBER} `, diff --git a/nebula-logger/extra-tests/integration-tests/emailservices/ExampleInboundEmailService.xml-meta.xml b/nebula-logger/extra-tests/integration-tests/emailservices/ExampleInboundEmailService.xml-meta.xml new file mode 100644 index 000000000..90f791b75 --- /dev/null +++ b/nebula-logger/extra-tests/integration-tests/emailservices/ExampleInboundEmailService.xml-meta.xml @@ -0,0 +1,22 @@ + + + ExampleInboundEmailHandler + None + Discard + Discard + + salesforce.com, nebulalogger.com, jongpie.com + ExampleEmailAddress + true + exampleinboundemailservice + {{EMAIL_SERVICE_RUN_AS_USER}} + + Discard + ExampleInboundEmailService + true + false + false + false + false + Discard + diff --git a/package-lock.json b/package-lock.json index cc866b1da..9c9024892 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "nebula-logger", - "version": "4.18.3", + "version": "4.18.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "nebula-logger", - "version": "4.18.3", + "version": "4.18.4", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -14,6 +14,7 @@ }, "devDependencies": { "@cparra/apexdocs": "1.13.7", + "@jongpie/sf-dotenv-cli-plugin": "^1.0.0", "@jongpie/sfdx-bummer-plugin": "0.0.20", "@salesforce-ux/slds-linter": "1.2.0", "@salesforce/cli": "2.134.1", @@ -2676,6 +2677,118 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@jongpie/sf-dotenv-cli-plugin": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@jongpie/sf-dotenv-cli-plugin/-/sf-dotenv-cli-plugin-1.0.0.tgz", + "integrity": "sha512-V/MklEaCQJYa+sHzKtsyBbZMcwGX/zQleiw2Q4syLPolhiX3xFOzdpGy3bhFzrFoQjLG2vNNXMsrswg9ofG0fA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oclif/core": "4.10.2", + "dotenv": "17.3.1", + "fs-extra": "11.3.4" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@jongpie/sf-dotenv-cli-plugin/node_modules/@oclif/core": { + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/@oclif/core/-/core-4.10.2.tgz", + "integrity": "sha512-3GvDh5nqpIE8566qUF5cBHKog9DFV9XgBeuR0nUrz0OMuz2FPYHat1AZHOwyQbvH9OKL4gJNQZHcsDOqDM/FRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^4.3.2", + "ansis": "^3.17.0", + "clean-stack": "^3.0.1", + "cli-spinners": "^2.9.2", + "debug": "^4.4.3", + "ejs": "^3.1.10", + "get-package-type": "^0.1.0", + "indent-string": "^4.0.0", + "is-wsl": "^2.2.0", + "lilconfig": "^3.1.3", + "minimatch": "^10.2.4", + "semver": "^7.7.3", + "string-width": "^4.2.3", + "supports-color": "^8", + "tinyglobby": "^0.2.14", + "widest-line": "^3.1.0", + "wordwrap": "^1.0.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@jongpie/sf-dotenv-cli-plugin/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@jongpie/sf-dotenv-cli-plugin/node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@jongpie/sf-dotenv-cli-plugin/node_modules/fs-extra": { + "version": "11.3.4", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.4.tgz", + "integrity": "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@jongpie/sf-dotenv-cli-plugin/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@jongpie/sf-dotenv-cli-plugin/node_modules/semver": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.2.tgz", + "integrity": "sha512-c8jsqUZm3omBOI66G90z1Dyw5z622G8oLG+omfsHBJf3CWQTlOcwOjvOG6wtiNfW6anKm/eA39LMwMtMez2TiQ==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@jongpie/sfdx-bummer-plugin": { "version": "0.0.20", "resolved": "https://registry.npmjs.org/@jongpie/sfdx-bummer-plugin/-/sfdx-bummer-plugin-0.0.20.tgz", @@ -5867,16 +5980,6 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@salesforce/cli/node_modules/@gar/promise-retry": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@gar/promise-retry/-/promise-retry-1.0.3.tgz", - "integrity": "sha512-GmzA9ckNokPypTg10pgpeHNQe7ph+iIKKmhKu3Ob9ANkswreCx7R3cKmY781K8QK3AqVL3xVh9A42JvIAbkkSA==", - "extraneous": true, - "license": "MIT", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/@salesforce/cli/node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -6868,13 +6971,6 @@ "node": ">=18.0.0" } }, - "node_modules/@salesforce/cli/node_modules/@isaacs/string-locale-compare": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@isaacs/string-locale-compare/-/string-locale-compare-1.1.0.tgz", - "integrity": "sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ==", - "extraneous": true, - "license": "ISC" - }, "node_modules/@salesforce/cli/node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -7213,287 +7309,6 @@ "node": ">= 8" } }, - "node_modules/@salesforce/cli/node_modules/@npmcli/agent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-4.0.0.tgz", - "integrity": "sha512-kAQTcEN9E8ERLVg5AsGwLNoFb+oEG6engbqAU2P43gD4JEIkNGMHdVQ096FsOAAYpZPB0RSt0zgInKIAS1l5QA==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "agent-base": "^7.1.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.1", - "lru-cache": "^11.2.1", - "socks-proxy-agent": "^8.0.3" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/@npmcli/arborist": { - "version": "9.4.3", - "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-9.4.3.tgz", - "integrity": "sha512-YhkR7XFdO7OBr8U1qs7DA7PmhSJXg59rLqd53jmeJ4pYe8WTCAsUZsKqxX7KKPEgAO5K7D/SjbyPUrBes9aP6Q==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "@gar/promise-retry": "^1.0.0", - "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/fs": "^5.0.0", - "@npmcli/installed-package-contents": "^4.0.0", - "@npmcli/map-workspaces": "^5.0.0", - "@npmcli/metavuln-calculator": "^9.0.2", - "@npmcli/name-from-folder": "^4.0.0", - "@npmcli/node-gyp": "^5.0.0", - "@npmcli/package-json": "^7.0.0", - "@npmcli/query": "^5.0.0", - "@npmcli/redact": "^4.0.0", - "@npmcli/run-script": "^10.0.0", - "bin-links": "^6.0.0", - "cacache": "^20.0.1", - "common-ancestor-path": "^2.0.0", - "hosted-git-info": "^9.0.0", - "json-stringify-nice": "^1.1.4", - "lru-cache": "^11.2.1", - "minimatch": "^10.0.3", - "nopt": "^9.0.0", - "npm-install-checks": "^8.0.0", - "npm-package-arg": "^13.0.0", - "npm-pick-manifest": "^11.0.1", - "npm-registry-fetch": "^19.0.0", - "pacote": "^21.0.2", - "parse-conflict-json": "^5.0.1", - "proc-log": "^6.0.0", - "proggy": "^4.0.0", - "promise-all-reject-late": "^1.0.0", - "promise-call-limit": "^3.0.1", - "semver": "^7.3.7", - "ssri": "^13.0.0", - "treeverse": "^3.0.0", - "walk-up-path": "^4.0.0" - }, - "bin": { - "arborist": "bin/index.js" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/@npmcli/config": { - "version": "10.8.1", - "resolved": "https://registry.npmjs.org/@npmcli/config/-/config-10.8.1.tgz", - "integrity": "sha512-MAYk9IlIGiyC0c9fnjdBSQfIFPZT0g1MfeSiD1UXTq2zJOLX55jS9/sETJHqw/7LN18JjITrhYfgCfapbmZHiQ==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "@npmcli/map-workspaces": "^5.0.0", - "@npmcli/package-json": "^7.0.0", - "ci-info": "^4.0.0", - "ini": "^6.0.0", - "nopt": "^9.0.0", - "proc-log": "^6.0.0", - "semver": "^7.3.5", - "walk-up-path": "^4.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/@npmcli/config/node_modules/ini": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-6.0.0.tgz", - "integrity": "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==", - "extraneous": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/@npmcli/fs": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-5.0.0.tgz", - "integrity": "sha512-7OsC1gNORBEawOa5+j2pXN9vsicaIOH5cPXxoR6fJOmH6/EXpJB2CajXOu1fPRFun2m1lktEFX11+P89hqO/og==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/@npmcli/git": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-7.0.2.tgz", - "integrity": "sha512-oeolHDjExNAJAnlYP2qzNjMX/Xi9bmu78C9dIGr4xjobrSKbuMYCph8lTzn4vnW3NjIqVmw/f8BCfouqyJXlRg==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "@gar/promise-retry": "^1.0.0", - "@npmcli/promise-spawn": "^9.0.0", - "ini": "^6.0.0", - "lru-cache": "^11.2.1", - "npm-pick-manifest": "^11.0.1", - "proc-log": "^6.0.0", - "semver": "^7.3.5", - "which": "^6.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/@npmcli/git/node_modules/ini": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-6.0.0.tgz", - "integrity": "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==", - "extraneous": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/@npmcli/installed-package-contents": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-4.0.0.tgz", - "integrity": "sha512-yNyAdkBxB72gtZ4GrwXCM0ZUedo9nIbOMKfGjt6Cu6DXf0p8y1PViZAKDC8q8kv/fufx0WTjRBdSlyrvnP7hmA==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "npm-bundled": "^5.0.0", - "npm-normalize-package-bin": "^5.0.0" - }, - "bin": { - "installed-package-contents": "bin/index.js" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/@npmcli/map-workspaces": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@npmcli/map-workspaces/-/map-workspaces-5.0.3.tgz", - "integrity": "sha512-o2grssXo1e774E5OtEwwrgoszYRh0lqkJH+Pb9r78UcqdGJRDRfhpM8DvZPjzNLLNYeD/rNbjOKM3Ss5UABROw==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "@npmcli/name-from-folder": "^4.0.0", - "@npmcli/package-json": "^7.0.0", - "glob": "^13.0.0", - "minimatch": "^10.0.3" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/@npmcli/metavuln-calculator": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/@npmcli/metavuln-calculator/-/metavuln-calculator-9.0.3.tgz", - "integrity": "sha512-94GLSYhLXF2t2LAC7pDwLaM4uCARzxShyAQKsirmlNcpidH89VA4/+K1LbJmRMgz5gy65E/QBBWQdUvGLe2Frg==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "cacache": "^20.0.0", - "json-parse-even-better-errors": "^5.0.0", - "pacote": "^21.0.0", - "proc-log": "^6.0.0", - "semver": "^7.3.5" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/@npmcli/name-from-folder": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/name-from-folder/-/name-from-folder-4.0.0.tgz", - "integrity": "sha512-qfrhVlOSqmKM8i6rkNdZzABj8MKEITGFAY+4teqBziksCQAOLutiAxM1wY2BKEd8KjUSpWmWCYxvXr0y4VTlPg==", - "extraneous": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/@npmcli/node-gyp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-5.0.0.tgz", - "integrity": "sha512-uuG5HZFXLfyFKqg8QypsmgLQW7smiRjVc45bqD/ofZZcR/uxEjgQU8qDPv0s9TEeMUiAAU/GC5bR6++UdTirIQ==", - "extraneous": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/@npmcli/package-json": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-7.0.5.tgz", - "integrity": "sha512-iVuTlG3ORq2iaVa1IWUxAO/jIp77tUKBhoMjuzYW2kL4MLN1bi/ofqkZ7D7OOwh8coAx1/S2ge0rMdGv8sLSOQ==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "@npmcli/git": "^7.0.0", - "glob": "^13.0.0", - "hosted-git-info": "^9.0.0", - "json-parse-even-better-errors": "^5.0.0", - "proc-log": "^6.0.0", - "semver": "^7.5.3", - "spdx-expression-parse": "^4.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/@npmcli/promise-spawn": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-9.0.1.tgz", - "integrity": "sha512-OLUaoqBuyxeTqUvjA3FZFiXUfYC1alp3Sa99gW3EUDz3tZ3CbXDdcZ7qWKBzicrJleIgucoWamWH1saAmH/l2Q==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "which": "^6.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/@npmcli/query": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/query/-/query-5.0.0.tgz", - "integrity": "sha512-8TZWfTQOsODpLqo9SVhVjHovmKXNpevHU0gO9e+y4V4fRIOneiXy0u0sMP9LmS71XivrEWfZWg50ReH4WRT4aQ==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "postcss-selector-parser": "^7.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/@npmcli/redact": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-4.0.0.tgz", - "integrity": "sha512-gOBg5YHMfZy+TfHArfVogwgfBeQnKbbGo3pSUyK/gSI0AVu+pEiDVcKlQb0D8Mg1LNRZILZ6XG8I5dJ4KuAd9Q==", - "extraneous": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/@npmcli/run-script": { - "version": "10.0.4", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-10.0.4.tgz", - "integrity": "sha512-mGUWr1uMnf0le2TwfOZY4SFxZGXGfm4Jtay/nwAa2FLNAKXUoUwaGwBMNH36UHPtinWfTSJ3nqFQr0091CxVGg==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "@npmcli/node-gyp": "^5.0.0", - "@npmcli/package-json": "^7.0.0", - "@npmcli/promise-spawn": "^9.0.0", - "node-gyp": "^12.1.0", - "proc-log": "^6.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/@salesforce/cli/node_modules/@oclif/core": { "version": "4.11.0", "resolved": "https://registry.npmjs.org/@oclif/core/-/core-4.11.0.tgz", @@ -10964,86 +10779,6 @@ "extraneous": true, "license": "MIT" }, - "node_modules/@salesforce/cli/node_modules/@sigstore/bundle": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-4.0.0.tgz", - "integrity": "sha512-NwCl5Y0V6Di0NexvkTqdoVfmjTaQwoLM236r89KEojGmq/jMls8S+zb7yOwAPdXvbwfKDlP+lmXgAL4vKSQT+A==", - "extraneous": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/protobuf-specs": "^0.5.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/@sigstore/core": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-3.2.0.tgz", - "integrity": "sha512-kxHrDQ9YgfrWUSXU0cjsQGv8JykOFZQ9ErNKbFPWzk3Hgpwu8x2hHrQ9IdA8yl+j9RTLTC3sAF3Tdq1IQCP4oA==", - "extraneous": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/@sigstore/protobuf-specs": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.5.1.tgz", - "integrity": "sha512-/ScWUhhoFasJsSRGTVBwId1loQjjnjAfE4djL6ZhrXRpNCmPTnUKF5Jokd58ILseOMjzET3UrMOtJPS9sYeI0g==", - "extraneous": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/@salesforce/cli/node_modules/@sigstore/sign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-4.1.1.tgz", - "integrity": "sha512-Hf4xglukg0XXQ2RiD5vSoLjdPe8OBUPA8XeVjUObheuDcWdYWrnH/BNmxZCzkAy68MzmNCxXLeurJvs6hcP2OQ==", - "extraneous": true, - "license": "Apache-2.0", - "dependencies": { - "@gar/promise-retry": "^1.0.2", - "@sigstore/bundle": "^4.0.0", - "@sigstore/core": "^3.2.0", - "@sigstore/protobuf-specs": "^0.5.0", - "make-fetch-happen": "^15.0.4", - "proc-log": "^6.1.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/@sigstore/tuf": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-4.0.2.tgz", - "integrity": "sha512-TCAzTy0xzdP79EnxSjq9KQ3eaR7+FmudLC6eRKknVKZbV7ZNlGLClAAQb/HMNJ5n2OBNk2GT1tEmU0xuPr+SLQ==", - "extraneous": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/protobuf-specs": "^0.5.0", - "tuf-js": "^4.1.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/@sigstore/verify": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-3.1.0.tgz", - "integrity": "sha512-mNe0Iigql08YupSOGv197YdHpPPr+EzDZmfCgMc7RPNaZTw5aLN01nBl6CHJOh3BGtnMIj83EeN4butBchc8Ag==", - "extraneous": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/bundle": "^4.0.0", - "@sigstore/core": "^3.1.0", - "@sigstore/protobuf-specs": "^0.5.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/@salesforce/cli/node_modules/@sindresorhus/is": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", @@ -11946,30 +11681,6 @@ "extraneous": true, "license": "MIT" }, - "node_modules/@salesforce/cli/node_modules/@tufjs/canonical-json": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", - "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==", - "extraneous": true, - "license": "MIT", - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@salesforce/cli/node_modules/@tufjs/models": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-4.1.0.tgz", - "integrity": "sha512-Y8cK9aggNRsqJVaKUlEYs4s7CvQ1b1ta2DVPyAimb0I2qhzjNk+A+mxvll/klL0RlfuIUei8BF7YWiua4kQqww==", - "extraneous": true, - "license": "MIT", - "dependencies": { - "@tufjs/canonical-json": "2.0.0", - "minimatch": "^10.1.1" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/@salesforce/cli/node_modules/@types/cacheable-request": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", @@ -12428,16 +12139,6 @@ "extraneous": true, "license": "BSD-2-Clause" }, - "node_modules/@salesforce/cli/node_modules/abbrev": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-4.0.0.tgz", - "integrity": "sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA==", - "extraneous": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/@salesforce/cli/node_modules/abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -12515,8 +12216,10 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "extraneous": true, + "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" @@ -12529,8 +12232,10 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "extraneous": true, + "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">=6" } @@ -12690,19 +12395,14 @@ } } }, - "node_modules/@salesforce/cli/node_modules/aproba": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", - "extraneous": true, - "license": "ISC" - }, "node_modules/@salesforce/cli/node_modules/archy": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", - "extraneous": true, - "license": "MIT" + "dev": true, + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/@salesforce/cli/node_modules/are-docs-informative": { "version": "0.0.2", @@ -13114,62 +12814,6 @@ "extraneous": true, "license": "Apache-2.0" }, - "node_modules/@salesforce/cli/node_modules/bin-links": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-6.0.0.tgz", - "integrity": "sha512-X4CiKlcV2GjnCMwnKAfbVWpHa++65th9TuzAEYtZoATiOE2DQKhSp4CJlyLoTqdhBKlXjpXjCTYPNNFS33Fi6w==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "cmd-shim": "^8.0.0", - "npm-normalize-package-bin": "^5.0.0", - "proc-log": "^6.0.0", - "read-cmd-shim": "^6.0.0", - "write-file-atomic": "^7.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/bin-links/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==", - "extraneous": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@salesforce/cli/node_modules/bin-links/node_modules/write-file-atomic": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-7.0.1.tgz", - "integrity": "sha512-OTIk8iR8/aCRWBqvxrzxR0hgxWpnYBblY1S5hDWBQfk/VFmJwzmJgQFN3WsoUKHISv2eAwe+PpbUzyL1CKTLXg==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "signal-exit": "^4.0.1" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/binary-extensions": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-3.1.0.tgz", - "integrity": "sha512-Jvvd9hy1w+xUad8+ckQsWA/V1AoyubOvqn0aygjMOVM4BfIaRav1NFS3LsTSDaV4n4FtcCtQXvzep1E6MboqwQ==", - "extraneous": true, - "license": "MIT", - "engines": { - "node": ">=18.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@salesforce/cli/node_modules/bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", @@ -13339,41 +12983,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@salesforce/cli/node_modules/cacache": { - "version": "20.0.4", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-20.0.4.tgz", - "integrity": "sha512-M3Lab8NPYlZU2exsL3bMVvMrMqgwCnMWfdZbK28bn3pK6APT/Te/I8hjRPNu1uwORY9a1eEQoifXbKPQMfMTOA==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "@npmcli/fs": "^5.0.0", - "fs-minipass": "^3.0.0", - "glob": "^13.0.0", - "lru-cache": "^11.1.0", - "minipass": "^7.0.3", - "minipass-collect": "^2.0.1", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "p-map": "^7.0.2", - "ssri": "^13.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/cacache/node_modules/p-map": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", - "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", - "extraneous": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@salesforce/cli/node_modules/cacheable-lookup": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", @@ -13778,7 +13387,7 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", - "extraneous": true, + "dev": true, "funding": [ { "type": "github", @@ -13786,20 +13395,12 @@ } ], "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">=8" } }, - "node_modules/@salesforce/cli/node_modules/cidr-regex": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/cidr-regex/-/cidr-regex-5.0.5.tgz", - "integrity": "sha512-59tdLZcC+BJXa4C5rOmVSuJTy/UneqfJJtCraqwdx5BDHTkGrBtKCUl3u2uiCFvXu+wk0kVuX8axX7yHCZOI9w==", - "extraneous": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=20" - } - }, "node_modules/@salesforce/cli/node_modules/cjs-module-lexer": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", @@ -14129,16 +13730,6 @@ "semver": "bin/semver" } }, - "node_modules/@salesforce/cli/node_modules/cmd-shim": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-8.0.0.tgz", - "integrity": "sha512-Jk/BK6NCapZ58BKUxlSI+ouKRbjH1NLZCgJkYoab+vEHUY3f6OzpNBN9u7HFSv9J6TRDGs4PLOHezoKGaFRSCA==", - "extraneous": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/@salesforce/cli/node_modules/code-excerpt": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/code-excerpt/-/code-excerpt-4.0.0.tgz", @@ -14504,16 +14095,6 @@ "node": ">=12" } }, - "node_modules/@salesforce/cli/node_modules/common-ancestor-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-2.0.0.tgz", - "integrity": "sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng==", - "extraneous": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">= 18" - } - }, "node_modules/@salesforce/cli/node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -15119,19 +14700,6 @@ "node": ">=0.6.0" } }, - "node_modules/@salesforce/cli/node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "extraneous": true, - "license": "MIT", - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@salesforce/cli/node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -15526,8 +15094,10 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "extraneous": true, + "dev": true, "license": "BSD-3-Clause", + "optional": true, + "peer": true, "engines": { "node": ">=0.3.1" } @@ -15828,16 +15398,6 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/@salesforce/cli/node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "extraneous": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/@salesforce/cli/node_modules/environment": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", @@ -16631,13 +16191,6 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/@salesforce/cli/node_modules/exponential-backoff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", - "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", - "extraneous": true, - "license": "Apache-2.0" - }, "node_modules/@salesforce/cli/node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -17135,19 +16688,6 @@ "node": ">=14.14" } }, - "node_modules/@salesforce/cli/node_modules/fs-minipass": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", - "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/@salesforce/cli/node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -17552,24 +17092,6 @@ "extraneous": true, "license": "ISC" }, - "node_modules/@salesforce/cli/node_modules/glob": { - "version": "13.0.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", - "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", - "extraneous": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "minimatch": "^10.2.2", - "minipass": "^7.1.3", - "path-scurry": "^2.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@salesforce/cli/node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", @@ -18035,19 +17557,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@salesforce/cli/node_modules/hosted-git-info": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.2.tgz", - "integrity": "sha512-M422h7o/BR3rmCQ8UHi7cyyMqKltdP9Uo+J2fXK+RSAY+wTcKOIRyhTuKv4qn+DJf3g+PL890AzId5KZpX+CBg==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^11.1.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/@salesforce/cli/node_modules/hpagent": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/hpagent/-/hpagent-1.2.0.tgz", @@ -18254,19 +17763,6 @@ "node": ">= 4" } }, - "node_modules/@salesforce/cli/node_modules/ignore-walk": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-8.0.0.tgz", - "integrity": "sha512-FCeMZT4NiRQGh+YkeKMtWrOmBgWjHjMJ26WQWrRQyoyzqevdaGSakUaJW5xQYmjLlUVk2qUnCjYVBax9EKKg8A==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "minimatch": "^10.0.3" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/@salesforce/cli/node_modules/immediate": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", @@ -18318,8 +17814,10 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "extraneous": true, + "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">=0.8.19" } @@ -18359,34 +17857,6 @@ "dev": true, "license": "ISC" }, - "node_modules/@salesforce/cli/node_modules/init-package-json": { - "version": "8.2.5", - "resolved": "https://registry.npmjs.org/init-package-json/-/init-package-json-8.2.5.tgz", - "integrity": "sha512-IknQ+upLuJU6t3p0uo9wS3GjFD/1GtxIwcIGYOWR8zL2HxQeJwvxYTgZr9brJ8pyZ4kvpkebM8ZKcyqOeLOHSg==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "@npmcli/package-json": "^7.0.0", - "npm-package-arg": "^13.0.0", - "promzard": "^3.0.1", - "read": "^5.0.1", - "semver": "^7.7.2", - "validate-npm-package-name": "^7.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/init-package-json/node_modules/validate-npm-package-name": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-7.0.2.tgz", - "integrity": "sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A==", - "extraneous": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/@salesforce/cli/node_modules/ink": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ink/-/ink-5.0.1.tgz", @@ -18948,19 +18418,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@salesforce/cli/node_modules/is-cidr": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/is-cidr/-/is-cidr-6.0.4.tgz", - "integrity": "sha512-tOIBU3QiXy0W4LvHbcKWAWSuQfGwDiEILphFCAZtDqj7C57uv3ClO6K8aNEGV4VTA7bWJlpQ0suKQkUe6Rd6ag==", - "extraneous": true, - "license": "BSD-2-Clause", - "dependencies": { - "cidr-regex": "^5.0.4" - }, - "engines": { - "node": ">=20" - } - }, "node_modules/@salesforce/cli/node_modules/is-core-module": { "version": "2.13.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", @@ -19322,8 +18779,10 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "extraneous": true, - "license": "MIT" + "dev": true, + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/@salesforce/cli/node_modules/is-unicode-supported": { "version": "0.1.0", @@ -19381,16 +18840,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@salesforce/cli/node_modules/isexe": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz", - "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==", - "extraneous": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=20" - } - }, "node_modules/@salesforce/cli/node_modules/isomorphic-git": { "version": "1.34.2", "resolved": "https://registry.npmjs.org/isomorphic-git/-/isomorphic-git-1.34.2.tgz", @@ -19710,16 +19159,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@salesforce/cli/node_modules/json-parse-even-better-errors": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-5.0.0.tgz", - "integrity": "sha512-ZF1nxZ28VhQouRWhUcVlUIN3qwSgPuswK05s/HIaoetAoE/9tngVmCHjSxmSQPav1nd+lPtTL0YZ/2AFdR/iYQ==", - "extraneous": true, - "license": "MIT", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/@salesforce/cli/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -19744,16 +19183,6 @@ "node": ">=7.10.1" } }, - "node_modules/@salesforce/cli/node_modules/json-stringify-nice": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/json-stringify-nice/-/json-stringify-nice-1.1.4.tgz", - "integrity": "sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw==", - "extraneous": true, - "license": "ISC", - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@salesforce/cli/node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -19798,11 +19227,13 @@ "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" ], - "extraneous": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/@salesforce/cli/node_modules/JSONStream": { "version": "1.3.5", @@ -19894,15 +19325,10 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/just-diff/-/just-diff-5.2.0.tgz", "integrity": "sha512-6ufhP9SHjb7jibNFrNxyFZ6od3g+An6Ai9mhGRvcYe8UJlH0prseN64M+6ZBBUoKYHZsitDP42gAJ8+eVWr3lw==", - "extraneous": true, - "license": "MIT" - }, - "node_modules/@salesforce/cli/node_modules/just-diff-apply": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/just-diff-apply/-/just-diff-apply-5.5.0.tgz", - "integrity": "sha512-OYTthRfSh55WOItVqwpefPtNt2VdKsq5AnAK6apdtR6yCH8pr0CmSr710J0Mf+WdQy7K/OzMy7K2MgAfdQURDw==", - "extraneous": true, - "license": "MIT" + "dev": true, + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/@salesforce/cli/node_modules/just-extend": { "version": "4.2.1", @@ -19968,194 +19394,6 @@ "node": ">= 0.8.0" } }, - "node_modules/@salesforce/cli/node_modules/libnpmaccess": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/libnpmaccess/-/libnpmaccess-10.0.3.tgz", - "integrity": "sha512-JPHTfWJxIK+NVPdNMNGnkz4XGX56iijPbe0qFWbdt68HL+kIvSzh+euBL8npLZvl2fpaxo+1eZSdoG15f5YdIQ==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "npm-package-arg": "^13.0.0", - "npm-registry-fetch": "^19.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/libnpmdiff": { - "version": "8.1.6", - "resolved": "https://registry.npmjs.org/libnpmdiff/-/libnpmdiff-8.1.6.tgz", - "integrity": "sha512-nr6/MrxRnqMUoB9t0aHImBKArkJCU3YeaTyu817XYQXAQq9iWgX+ZVLgd+5wZVfoyemPdJj2LasXhFNyVk5GAA==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "@npmcli/arborist": "^9.4.3", - "@npmcli/installed-package-contents": "^4.0.0", - "binary-extensions": "^3.0.0", - "diff": "^8.0.2", - "minimatch": "^10.0.3", - "npm-package-arg": "^13.0.0", - "pacote": "^21.0.2", - "tar": "^7.5.1" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/libnpmdiff/node_modules/diff": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", - "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", - "extraneous": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/@salesforce/cli/node_modules/libnpmexec": { - "version": "10.2.6", - "resolved": "https://registry.npmjs.org/libnpmexec/-/libnpmexec-10.2.6.tgz", - "integrity": "sha512-aUHRHUhoi98CW9x+0+RzOVvKvl4rvGgr6o7wnWfdyuvZtU5WXGStfuArN1wBANxEP50bLTocMJrEsBktEuiVqw==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "@gar/promise-retry": "^1.0.0", - "@npmcli/arborist": "^9.4.3", - "@npmcli/package-json": "^7.0.0", - "@npmcli/run-script": "^10.0.0", - "ci-info": "^4.0.0", - "npm-package-arg": "^13.0.0", - "pacote": "^21.0.2", - "proc-log": "^6.0.0", - "read": "^5.0.1", - "semver": "^7.3.7", - "signal-exit": "^4.1.0", - "walk-up-path": "^4.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/libnpmexec/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==", - "extraneous": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@salesforce/cli/node_modules/libnpmfund": { - "version": "7.0.20", - "resolved": "https://registry.npmjs.org/libnpmfund/-/libnpmfund-7.0.20.tgz", - "integrity": "sha512-H1FvUdssvUlAfQJsNotf+DUetF2mS7d2sW8+MByLCMmgsZ+OkKbXgQit0PCjAwg8BD/Z/f8UO0FJT7bOYe73fQ==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "@npmcli/arborist": "^9.4.3" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/libnpmorg": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/libnpmorg/-/libnpmorg-8.0.1.tgz", - "integrity": "sha512-/QeyXXg4hqMw0ESM7pERjIT2wbR29qtFOWIOug/xO4fRjS3jJJhoAPQNsnHtdwnCqgBdFpGQ45aIdFFZx2YhTA==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "aproba": "^2.0.0", - "npm-registry-fetch": "^19.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/libnpmpack": { - "version": "9.1.6", - "resolved": "https://registry.npmjs.org/libnpmpack/-/libnpmpack-9.1.6.tgz", - "integrity": "sha512-Uov/MsMO+1MdJdT4PKdz6MiLNuZb73REKxbxKXKcNUaDkeBGNXxGB1GUxpdsvZlx1sos4MQDTYw34q4yw7hzHw==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "@npmcli/arborist": "^9.4.3", - "@npmcli/run-script": "^10.0.0", - "npm-package-arg": "^13.0.0", - "pacote": "^21.0.2" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/libnpmpublish": { - "version": "11.1.3", - "resolved": "https://registry.npmjs.org/libnpmpublish/-/libnpmpublish-11.1.3.tgz", - "integrity": "sha512-NVPTth/71cfbdYHqypcO9Lt5WFGTzFEcx81lWd7GDJIgZ95ERdYHGUfCtFejHCyqodKsQkNEx2JCkMpreDty/A==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "@npmcli/package-json": "^7.0.0", - "ci-info": "^4.0.0", - "npm-package-arg": "^13.0.0", - "npm-registry-fetch": "^19.0.0", - "proc-log": "^6.0.0", - "semver": "^7.3.7", - "sigstore": "^4.0.0", - "ssri": "^13.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/libnpmsearch": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/libnpmsearch/-/libnpmsearch-9.0.1.tgz", - "integrity": "sha512-oKw58X415ERY/BOGV3jQPVMcep8YeMRWMzuuqB0BAIM5VxicOU1tQt19ExCu4SV77SiTOEoziHxGEgJGw3FBYQ==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "npm-registry-fetch": "^19.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/libnpmteam": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/libnpmteam/-/libnpmteam-8.0.2.tgz", - "integrity": "sha512-ypLrDUQoi8EhG+gzx5ENMcYq23YjPV17Mfvx4nOnQiHOi8vp47+4GvZBrMsEM4yeHPwxguF/HZoXH4rJfHdH/w==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "aproba": "^2.0.0", - "npm-registry-fetch": "^19.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/libnpmversion": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/libnpmversion/-/libnpmversion-8.0.3.tgz", - "integrity": "sha512-Avj1GG3DT6MGzWOOk3yA7rORcMDUPizkIGbI8glHCO7WoYn3NYNmskLDwxg2NMY1Tyf2vrHAqTuSG58uqd1lJg==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "@npmcli/git": "^7.0.0", - "@npmcli/run-script": "^10.0.0", - "json-parse-even-better-errors": "^5.0.0", - "proc-log": "^6.0.0", - "semver": "^7.3.7" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/@salesforce/cli/node_modules/lie": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", @@ -20666,30 +19904,6 @@ "extraneous": true, "license": "ISC" }, - "node_modules/@salesforce/cli/node_modules/make-fetch-happen": { - "version": "15.0.5", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-15.0.5.tgz", - "integrity": "sha512-uCbIa8jWWmQZt4dSnEStkVC6gdakiinAm4PiGsywIkguF0eWMdcjDz0ECYhUolFU3pFLOev9VNPCEygydXnddg==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "@gar/promise-retry": "^1.0.0", - "@npmcli/agent": "^4.0.0", - "@npmcli/redact": "^4.0.0", - "cacache": "^20.0.1", - "http-cache-semantics": "^4.1.1", - "minipass": "^7.0.2", - "minipass-fetch": "^5.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^1.0.0", - "proc-log": "^6.0.0", - "ssri": "^13.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/@salesforce/cli/node_modules/map-obj": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", @@ -21169,102 +20383,6 @@ "node": ">=16 || 14 >=14.17" } }, - "node_modules/@salesforce/cli/node_modules/minipass-collect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", - "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/@salesforce/cli/node_modules/minipass-fetch": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-5.0.2.tgz", - "integrity": "sha512-2d0q2a8eCi2IRg/IGubCNRJoYbA1+YPXAzQVRFmB45gdGZafyivnZ5YSEfo3JikbjGxOdntGFvBQGqaSMXlAFQ==", - "extraneous": true, - "license": "MIT", - "dependencies": { - "minipass": "^7.0.3", - "minipass-sized": "^2.0.0", - "minizlib": "^3.0.1" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - }, - "optionalDependencies": { - "iconv-lite": "^0.7.2" - } - }, - "node_modules/@salesforce/cli/node_modules/minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@salesforce/cli/node_modules/minipass-flush/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@salesforce/cli/node_modules/minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@salesforce/cli/node_modules/minipass-pipeline/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@salesforce/cli/node_modules/minipass-sized": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-2.0.0.tgz", - "integrity": "sha512-zSsHhto5BcUVM2m1LurnXY6M//cGhVaegT71OfOXoprxT6o780GZd792ea6FfrQkuU4usHZIUczAQMRUE2plzA==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.1.2" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/@salesforce/cli/node_modules/minizlib": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", @@ -21537,16 +20655,6 @@ "node": ">=18" } }, - "node_modules/@salesforce/cli/node_modules/negotiator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", - "extraneous": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/@salesforce/cli/node_modules/neo-async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", @@ -21668,41 +20776,6 @@ } } }, - "node_modules/@salesforce/cli/node_modules/node-gyp": { - "version": "12.3.0", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-12.3.0.tgz", - "integrity": "sha512-QNcUWM+HgJplcPzBvFBZ9VXacyGZ4+VTOb80PwWR+TlVzoHbRKULNEzpRsnaoxG3Wzr7Qh7BYxGDU3CbKib2Yg==", - "extraneous": true, - "license": "MIT", - "dependencies": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "graceful-fs": "^4.2.6", - "nopt": "^9.0.0", - "proc-log": "^6.0.0", - "semver": "^7.3.5", - "tar": "^7.5.4", - "tinyglobby": "^0.2.12", - "undici": "^6.25.0", - "which": "^6.0.0" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/node-gyp/node_modules/undici": { - "version": "6.25.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.25.0.tgz", - "integrity": "sha512-ZgpWDC5gmNiuY9CnLVXEH8rl50xhRCuLNA97fAUnKi8RRuV4E6KG31pDTsLVUKnohJE0I3XDrTeEydAXRw47xg==", - "extraneous": true, - "license": "MIT", - "engines": { - "node": ">=18.17" - } - }, "node_modules/@salesforce/cli/node_modules/node-preload": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", @@ -21723,22 +20796,6 @@ "extraneous": true, "license": "MIT" }, - "node_modules/@salesforce/cli/node_modules/nopt": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-9.0.0.tgz", - "integrity": "sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "abbrev": "^4.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/@salesforce/cli/node_modules/normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -21947,142 +21004,6 @@ "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/@salesforce/cli/node_modules/npm-audit-report": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/npm-audit-report/-/npm-audit-report-7.0.0.tgz", - "integrity": "sha512-bluLL4xwGr/3PERYz50h2Upco0TJMDcLcymuFnfDWeGO99NqH724MNzhWi5sXXuXf2jbytFF0LyR8W+w1jTI6A==", - "extraneous": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/npm-bundled": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-5.0.0.tgz", - "integrity": "sha512-JLSpbzh6UUXIEoqPsYBvVNVmyrjVZ1fzEFbqxKkTJQkWBO3xFzFT+KDnSKQWwOQNbuWRwt5LSD6HOTLGIWzfrw==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "npm-normalize-package-bin": "^5.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/npm-install-checks": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-8.0.0.tgz", - "integrity": "sha512-ScAUdMpyzkbpxoNekQ3tNRdFI8SJ86wgKZSQZdUxT+bj0wVFpsEMWnkXP0twVe1gJyNF5apBWDJhhIbgrIViRA==", - "extraneous": true, - "license": "BSD-2-Clause", - "dependencies": { - "semver": "^7.1.1" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/npm-normalize-package-bin": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-5.0.0.tgz", - "integrity": "sha512-CJi3OS4JLsNMmr2u07OJlhcrPxCeOeP/4xq67aWNai6TNWWbTrlNDgl8NcFKVlcBKp18GPj+EzbNIgrBfZhsag==", - "extraneous": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/npm-package-arg": { - "version": "13.0.2", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-13.0.2.tgz", - "integrity": "sha512-IciCE3SY3uE84Ld8WZU23gAPPV9rIYod4F+rc+vJ7h7cwAJt9Vk6TVsK60ry7Uj3SRS3bqRRIGuTp9YVlk6WNA==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "hosted-git-info": "^9.0.0", - "proc-log": "^6.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^7.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/npm-package-arg/node_modules/validate-npm-package-name": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-7.0.2.tgz", - "integrity": "sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A==", - "extraneous": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/npm-packlist": { - "version": "10.0.4", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-10.0.4.tgz", - "integrity": "sha512-uMW73iajD8hiH4ZBxEV3HC+eTnppIqwakjOYuvgddnalIw2lJguKviK1pcUJDlIWm1wSJkchpDZDSVVsZEYRng==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "ignore-walk": "^8.0.0", - "proc-log": "^6.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/npm-pick-manifest": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-11.0.3.tgz", - "integrity": "sha512-buzyCfeoGY/PxKqmBqn1IUJrZnUi1VVJTdSSRPGI60tJdUhUoSQFhs0zycJokDdOznQentgrpf8LayEHyyYlqQ==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "npm-install-checks": "^8.0.0", - "npm-normalize-package-bin": "^5.0.0", - "npm-package-arg": "^13.0.0", - "semver": "^7.3.5" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/npm-profile": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/npm-profile/-/npm-profile-12.0.1.tgz", - "integrity": "sha512-Xs1mejJ1/9IKucCxdFMkiBJUre0xaxfCpbsO7DB7CadITuT4k68eI05HBlw4kj+Em1rsFMgeFNljFPYvPETbVQ==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "npm-registry-fetch": "^19.0.0", - "proc-log": "^6.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/npm-registry-fetch": { - "version": "19.1.1", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-19.1.1.tgz", - "integrity": "sha512-TakBap6OM1w0H73VZVDf44iFXsOS3h+L4wVMXmbWOQroZgFhMch0juN6XSzBNlD965yIKvWg2dfu7NSiaYLxtw==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "@npmcli/redact": "^4.0.0", - "jsonparse": "^1.3.1", - "make-fetch-happen": "^15.0.0", - "minipass": "^7.0.2", - "minipass-fetch": "^5.0.0", - "minizlib": "^3.0.1", - "npm-package-arg": "^13.0.0", - "proc-log": "^6.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/@salesforce/cli/node_modules/npm-run-path": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", @@ -22096,16 +21017,6 @@ "node": ">=8" } }, - "node_modules/@salesforce/cli/node_modules/npm-user-validate": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/npm-user-validate/-/npm-user-validate-4.0.0.tgz", - "integrity": "sha512-TP+Ziq/qPi/JRdhaEhnaiMkqfMGjhDLoh/oRfW+t5aCuIfJxIUxvwk6Sg/6ZJ069N/Be6gs00r+aZeJTfS9uHQ==", - "extraneous": true, - "license": "BSD-2-Clause", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/@salesforce/cli/node_modules/npm/node_modules/@gar/promise-retry": { "version": "1.0.3", "dev": true, @@ -24493,8 +23404,10 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", - "extraneous": true, + "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "aggregate-error": "^3.0.0" }, @@ -24569,38 +23482,6 @@ "dev": true, "license": "BlueOak-1.0.0" }, - "node_modules/@salesforce/cli/node_modules/pacote": { - "version": "21.5.0", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-21.5.0.tgz", - "integrity": "sha512-VtZ0SB8mb5Tzw3dXDfVAIjhyVKUHZkS/ZH9/5mpKenwC9sFOXNI0JI7kEF7IMkwOnsWMFrvAZHzx1T5fmrp9FQ==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "@gar/promise-retry": "^1.0.0", - "@npmcli/git": "^7.0.0", - "@npmcli/installed-package-contents": "^4.0.0", - "@npmcli/package-json": "^7.0.0", - "@npmcli/promise-spawn": "^9.0.0", - "@npmcli/run-script": "^10.0.0", - "cacache": "^20.0.0", - "fs-minipass": "^3.0.0", - "minipass": "^7.0.2", - "npm-package-arg": "^13.0.0", - "npm-packlist": "^10.0.1", - "npm-pick-manifest": "^11.0.1", - "npm-registry-fetch": "^19.0.0", - "proc-log": "^6.0.0", - "sigstore": "^4.0.0", - "ssri": "^13.0.0", - "tar": "^7.4.3" - }, - "bin": { - "pacote": "bin/index.js" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/@salesforce/cli/node_modules/pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", @@ -24632,28 +23513,6 @@ "node": ">=6" } }, - "node_modules/@salesforce/cli/node_modules/parse-conflict-json": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/parse-conflict-json/-/parse-conflict-json-5.0.1.tgz", - "integrity": "sha512-ZHEmNKMq1wyJXNwLxyHnluPfRAFSIliBvbK/UiOceROt4Xh9Pz0fq49NytIaeaCUf5VR86hwQ/34FCcNU5/LKQ==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "json-parse-even-better-errors": "^5.0.0", - "just-diff": "^6.0.0", - "just-diff-apply": "^5.2.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/parse-conflict-json/node_modules/just-diff": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/just-diff/-/just-diff-6.0.2.tgz", - "integrity": "sha512-S59eriX5u3/QhMNq3v/gm8Kd0w8OS6Tz2FS1NG4blv+z0MuQcBRJyFWjdovM0Rad4/P4aUPFtnkNjMjyMlMSYA==", - "extraneous": true, - "license": "MIT" - }, "node_modules/@salesforce/cli/node_modules/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -25005,20 +23864,6 @@ "node": ">= 0.4" } }, - "node_modules/@salesforce/cli/node_modules/postcss-selector-parser": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", - "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", - "extraneous": true, - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@salesforce/cli/node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -25133,16 +23978,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/@salesforce/cli/node_modules/proc-log": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz", - "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==", - "extraneous": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/@salesforce/cli/node_modules/process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -25190,49 +24025,6 @@ ], "license": "MIT" }, - "node_modules/@salesforce/cli/node_modules/proggy": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/proggy/-/proggy-4.0.0.tgz", - "integrity": "sha512-MbA4R+WQT76ZBm/5JUpV9yqcJt92175+Y0Bodg3HgiXzrmKu7Ggq+bpn6y6wHH+gN9NcyKn3yg1+d47VaKwNAQ==", - "extraneous": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/promise-all-reject-late": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz", - "integrity": "sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw==", - "extraneous": true, - "license": "ISC", - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@salesforce/cli/node_modules/promise-call-limit": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/promise-call-limit/-/promise-call-limit-3.0.1.tgz", - "integrity": "sha512-utl+0x8gIDasV5X+PI5qWEPqH6fJS0pFtQ/4gZ95xfEFb/89dmh+/b895TbFDBLiafBvxD/PGTKfvxl4kH/pQg==", - "extraneous": true, - "license": "ISC", - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@salesforce/cli/node_modules/promzard": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/promzard/-/promzard-3.0.1.tgz", - "integrity": "sha512-M5mHhWh+Adz0BIxgSrqcc6GTCSconR7zWQV9vnOSptNtr6cSFlApLc28GbQhuN6oOWBQeV2C0bNE47JCY/zu3Q==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "read": "^5.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/@salesforce/cli/node_modules/propagate": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz", @@ -25383,15 +24175,6 @@ "node": ">=6" } }, - "node_modules/@salesforce/cli/node_modules/qrcode-terminal": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz", - "integrity": "sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ==", - "extraneous": true, - "bin": { - "qrcode-terminal": "bin/qrcode-terminal.js" - } - }, "node_modules/@salesforce/cli/node_modules/querystring": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", @@ -25489,29 +24272,6 @@ "react": "^18.3.1" } }, - "node_modules/@salesforce/cli/node_modules/read": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/read/-/read-5.0.1.tgz", - "integrity": "sha512-+nsqpqYkkpet2UVPG8ZiuE8d113DK4vHYEoEhcrXBAlPiq6di7QRTuNiKQAbaRYegobuX2BpZ6QjanKOXnJdTA==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "mute-stream": "^3.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@salesforce/cli/node_modules/read-cmd-shim": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-6.0.0.tgz", - "integrity": "sha512-1zM5HuOfagXCBWMN83fuFI/x+T/UhZ7k+KIzhrHXcQoeX5+7gmaDYjELQHmmzIodumBHeByBJT4QYS7ufAgs7A==", - "extraneous": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/@salesforce/cli/node_modules/read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", @@ -25610,16 +24370,6 @@ "node": ">=4" } }, - "node_modules/@salesforce/cli/node_modules/read/node_modules/mute-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-3.0.0.tgz", - "integrity": "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==", - "extraneous": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/@salesforce/cli/node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -26376,24 +25126,6 @@ "dev": true, "license": "ISC" }, - "node_modules/@salesforce/cli/node_modules/sigstore": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-4.1.0.tgz", - "integrity": "sha512-/fUgUhYghuLzVT/gaJoeVehLCgZiUxPCPMcyVNY0lIf/cTCz58K/WTI7PefDarXxp9nUKpEwg1yyz3eSBMTtgA==", - "extraneous": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/bundle": "^4.0.0", - "@sigstore/core": "^3.1.0", - "@sigstore/protobuf-specs": "^0.5.0", - "@sigstore/sign": "^4.1.0", - "@sigstore/tuf": "^4.0.1", - "@sigstore/verify": "^3.1.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/@salesforce/cli/node_modules/simple-concat": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", @@ -26766,15 +25498,19 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", - "extraneous": true, - "license": "CC-BY-3.0" + "dev": true, + "license": "CC-BY-3.0", + "optional": true, + "peer": true }, "node_modules/@salesforce/cli/node_modules/spdx-expression-parse": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", - "extraneous": true, + "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" @@ -26784,8 +25520,10 @@ "version": "3.0.17", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz", "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==", - "extraneous": true, - "license": "CC0-1.0" + "dev": true, + "license": "CC0-1.0", + "optional": true, + "peer": true }, "node_modules/@salesforce/cli/node_modules/split": { "version": "1.0.1", @@ -26830,19 +25568,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@salesforce/cli/node_modules/ssri": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-13.0.1.tgz", - "integrity": "sha512-QUiRf1+u9wPTL/76GTYlKttDEBWV1ga9ZXW8BG6kfdeyyM8LGPix9gROyg9V2+P0xNyF3X2Go526xKFdMZrHSQ==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/@salesforce/cli/node_modules/stack-chain": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/stack-chain/-/stack-chain-1.3.7.tgz", @@ -27294,8 +26019,10 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "extraneous": true, - "license": "MIT" + "dev": true, + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/@salesforce/cli/node_modules/thingies": { "version": "2.5.0", @@ -27348,13 +26075,6 @@ "extraneous": true, "license": "MIT" }, - "node_modules/@salesforce/cli/node_modules/tiny-relative-date": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/tiny-relative-date/-/tiny-relative-date-2.0.2.tgz", - "integrity": "sha512-rGxAbeL9z3J4pI2GtBEoFaavHdO4RKAU54hEuOef5kfx5aPqiQtbhYktMOTL5OA33db8BjsDcLXuNp+/v19PHw==", - "extraneous": true, - "license": "MIT" - }, "node_modules/@salesforce/cli/node_modules/tinyglobby": { "version": "0.2.14", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", @@ -27485,16 +26205,6 @@ "tslib": "2" } }, - "node_modules/@salesforce/cli/node_modules/treeverse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/treeverse/-/treeverse-3.0.0.tgz", - "integrity": "sha512-gcANaAnd2QDZFmHFEOF4k7uc1J/6a6z3DJMd/QwEyxLoKGiptJRwid582r7QIsFlFMIZ3SnxfS52S4hm2DHkuQ==", - "extraneous": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/@salesforce/cli/node_modules/trim-lines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", @@ -27695,21 +26405,6 @@ "dev": true, "license": "0BSD" }, - "node_modules/@salesforce/cli/node_modules/tuf-js": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-4.1.0.tgz", - "integrity": "sha512-50QV99kCKH5P/Vs4E2Gzp7BopNV+KzTXqWeaxrfu5IQJBOULRsTIS9seSsOVT8ZnGXzCyx55nYWAi4qJzpZKEQ==", - "extraneous": true, - "license": "MIT", - "dependencies": { - "@tufjs/models": "4.1.0", - "debug": "^4.4.3", - "make-fetch-happen": "^15.0.1" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/@salesforce/cli/node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -27844,8 +26539,10 @@ "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "extraneous": true, + "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "is-typedarray": "^1.0.0" } @@ -28259,16 +26956,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/@salesforce/cli/node_modules/walk-up-path": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-4.0.0.tgz", - "integrity": "sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A==", - "extraneous": true, - "license": "ISC", - "engines": { - "node": "20 || >=22" - } - }, "node_modules/@salesforce/cli/node_modules/web-vitals": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.4.tgz", @@ -28319,22 +27006,6 @@ "webidl-conversions": "^3.0.0" } }, - "node_modules/@salesforce/cli/node_modules/which": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz", - "integrity": "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "isexe": "^4.0.0" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/@salesforce/cli/node_modules/which-boxed-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", @@ -28532,8 +27203,10 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "extraneous": true, + "dev": true, "license": "ISC", + "optional": true, + "peer": true, "dependencies": { "imurmurhash": "^0.1.4", "is-typedarray": "^1.0.0", @@ -28657,8 +27330,10 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "extraneous": true, - "license": "ISC" + "dev": true, + "license": "ISC", + "optional": true, + "peer": true }, "node_modules/@salesforce/cli/node_modules/yaml": { "version": "2.8.3", @@ -30158,6 +28833,16 @@ "dev": true, "license": "MIT" }, + "node_modules/ansis": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/ansis/-/ansis-3.17.0.tgz", + "integrity": "sha512-0qWUglt9JEqLFr3w1I1pbrChn1grhaiAR2ocX1PP/flRmxgtwTzPFFFnfIlD6aMOLQZgSuCRlidD70lvx8yhzg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + } + }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -32031,6 +30716,19 @@ "tslib": "^2.0.3" } }, + "node_modules/dotenv": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.3.1.tgz", + "integrity": "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/dtrace-provider": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.6.0.tgz", @@ -37005,6 +35703,19 @@ "immediate": "~3.0.5" } }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, "node_modules/line-column": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/line-column/-/line-column-1.0.2.tgz", diff --git a/package.json b/package.json index 7c119af9b..dfca9f625 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nebula-logger", - "version": "4.18.3", + "version": "4.18.4", "description": "The most robust logger for Salesforce. Works with Apex, Lightning Components, Flow, Process Builder & Integrations. Designed for Salesforce admins, developers & architects.", "author": "Jonathan Gillespie", "license": "MIT", @@ -40,6 +40,9 @@ "docs:verify": "pwsh ./scripts/build/verify-docs-up-to-date.ps1", "husky:pre-commit": "lint-staged", "lwc:preview:recipes": "sf lightning dev app --device-type desktop --name \"Logger Recipes\"", + "env:set:email-service-run-as-user": "node ./scripts/dev/set-email-service-run-as-user.js", + "scratch:assign:current-user-role": "node ./scripts/dev/assign-role-to-current-user.js", + "scratch:link:community:authprovider": "node ./scripts/dev/link-community-auth-provider.js --network \"Logger Test Aura Site\" --auth-provider ExampleGoogleAuth", "package:manifest:generate:core": "sf project generate manifest --source-dir ./nebula-logger/core/ --output-dir ./nebula-logger/ --name core.package", "package:version:create:managed": "pwsh ./scripts/build/create-managed-package-beta-version.ps1", "package:version:create:unlocked": "sf package version create --json --package \"Nebula Logger - Core\" --skip-ancestor-check --code-coverage --installation-key-bypass --wait 30", @@ -65,6 +68,7 @@ "scan:lwc:local": "npx sf code-analyzer run --rule-selector \"eslint:(1,2,3)\" --workspace ./nebula-logger/core/**/lwc/** --output-file ./code-analyzer-lwc-eslint-violations.json", "scan:lwc:slds:fix": "npx @salesforce-ux/slds-linter@latest lint ./nebula-logger/core/**/lwc/** --fix", "sf:plugins:link:bummer": "npx sf plugins link ./node_modules/@jongpie/sfdx-bummer-plugin", + "sf:plugins:link:dotenv": "npx sf plugins link ./node_modules/@jongpie/sf-dotenv-cli-plugin", "test": "npm run test:lwc && npm run test:apex", "test:apex": "npm run test:apex:nocoverage -- --code-coverage --detailed-coverage", "test:apex:nocoverage": "npx sf apex run test --concise --test-level RunLocalTests --wait 30 --result-format human --output-dir ./test-coverage/apex", @@ -81,6 +85,7 @@ }, "devDependencies": { "@cparra/apexdocs": "1.13.7", + "@jongpie/sf-dotenv-cli-plugin": "^1.0.0", "@jongpie/sfdx-bummer-plugin": "0.0.20", "@salesforce-ux/slds-linter": "1.2.0", "@salesforce/cli": "2.134.1", @@ -92,8 +97,8 @@ "jest-when": "3.7.0", "jsdoc-to-markdown": "9.1.3", "lint-staged": "16.2.7", - "prettier-plugin-apex": "2.2.6", "prettier": "3.8.1", + "prettier-plugin-apex": "2.2.6", "pwsh": "0.3.0" } } diff --git a/scripts/dev/assign-role-to-current-user.js b/scripts/dev/assign-role-to-current-user.js new file mode 100644 index 000000000..afc621e25 --- /dev/null +++ b/scripts/dev/assign-role-to-current-user.js @@ -0,0 +1,87 @@ +#!/usr/bin/env node + +const { spawnSync } = require('child_process'); +const { parseArgs } = require('util'); + +const { values } = parseArgs({ + options: { + role: { type: 'string' }, + 'target-org': { type: 'string' } + } +}); + +const roleName = values.role || 'Scratch Org User Role'; +const targetOrg = values['target-org']; + +const isWindows = process.platform === 'win32'; + +function quoteForShell(arg) { + if (isWindows) { + return `"${String(arg).replace(/"/g, '\\"')}"`; + } + return `'${String(arg).replace(/'/g, `'\\''`)}'`; +} + +function runSf(args) { + const fullArgs = [...args, '--json']; + if (targetOrg) { + fullArgs.push('--target-org', targetOrg); + } + const command = ['sf', ...fullArgs.map(quoteForShell)].join(' '); + const result = spawnSync(command, { encoding: 'utf8', shell: true }); + if (result.error) { + console.error(result.error.message); + process.exit(1); + } + if (result.status !== 0) { + console.error(result.stderr || result.stdout); + process.exit(result.status ?? 1); + } + return JSON.parse(result.stdout); +} + +function escapeSoql(value) { + return value.replace(/\\/g, '\\\\').replace(/'/g, "\\'"); +} + +function querySingle(soql) { + const response = runSf(['data', 'query', '--query', soql]); + return response.result.records?.[0]; +} + +const orgInfo = runSf(['org', 'display', '--verbose']); +const currentUsername = orgInfo.result.username; +if (!currentUsername) { + console.error('Could not resolve the current org username.'); + process.exit(1); +} + +const currentUser = querySingle(`SELECT Id, Username, UserRoleId FROM User WHERE Username = '${escapeSoql(currentUsername)}' LIMIT 1`); +if (!currentUser) { + console.error(`Could not find user with Username '${currentUsername}'.`); + process.exit(1); +} + +if (currentUser.UserRoleId) { + console.info('Current user already has a role.'); + console.info(`Username: ${currentUser.Username}`); + console.info(`UserRoleId: ${currentUser.UserRoleId}`); + process.exit(0); +} + +let role = querySingle(`SELECT Id, Name FROM UserRole WHERE Name = '${escapeSoql(roleName)}' LIMIT 1`); +let roleId; +if (role) { + roleId = role.Id; + console.info(`Using existing role: ${roleName} (${roleId})`); +} else { + const createResponse = runSf(['data', 'create', 'record', '--sobject', 'UserRole', '--values', `Name=${roleName}`]); + roleId = createResponse.result.id; + console.info(`Created role: ${roleName} (${roleId})`); +} + +runSf(['data', 'update', 'record', '--sobject', 'User', '--record-id', currentUser.Id, '--values', `UserRoleId=${roleId}`]); + +console.info('Assigned role to current user.'); +console.info(`Username: ${currentUser.Username}`); +console.info(`UserRoleId: ${roleId}`); diff --git a/scripts/dev/link-community-auth-provider.js b/scripts/dev/link-community-auth-provider.js new file mode 100644 index 000000000..20245b26a --- /dev/null +++ b/scripts/dev/link-community-auth-provider.js @@ -0,0 +1,101 @@ +#!/usr/bin/env node + +const { spawnSync } = require('child_process'); +const { parseArgs } = require('util'); + +const { values } = parseArgs({ + options: { + network: { type: 'string' }, + 'auth-provider': { type: 'string' }, + 'target-org': { type: 'string' } + } +}); + +if (!values.network || !values['auth-provider']) { + console.error('Usage: node ./scripts/dev/link-community-auth-provider.js --network --auth-provider [--target-org ]'); + process.exit(1); +} + +const networkName = values.network; +const authProviderDeveloperName = values['auth-provider']; +const targetOrg = values['target-org']; + +const isWindows = process.platform === 'win32'; + +// Quote each arg for a shell command line. On Windows, cmd.exe needs +// double-quoted args with internal `"` escaped; POSIX shells need single quotes +// with embedded `'` closed and re-quoted. +function quoteForShell(arg) { + if (isWindows) { + return `"${String(arg).replace(/"/g, '\\"')}"`; + } + return `'${String(arg).replace(/'/g, `'\\''`)}'`; +} + +function runSf(args) { + const fullArgs = [...args, '--json']; + if (targetOrg) { + fullArgs.push('--target-org', targetOrg); + } + // Use a single shell command string (instead of [cmd, args, {shell: true}]) + // to (a) let Windows resolve the `sf.cmd` shim and (b) avoid Node's DEP0190 + // deprecation warning that fires for the array+shell combination. + const command = ['sf', ...fullArgs.map(quoteForShell)].join(' '); + const result = spawnSync(command, { encoding: 'utf8', shell: true }); + if (result.error) { + console.error(result.error.message); + process.exit(1); + } + if (result.status !== 0) { + console.error(result.stderr || result.stdout); + process.exit(result.status ?? 1); + } + return JSON.parse(result.stdout); +} + +// SOQL string literals only need single quotes and backslashes escaped. +function escapeSoql(value) { + return value.replace(/\\/g, '\\\\').replace(/'/g, "\\'"); +} + +function querySingle(soql) { + const response = runSf(['data', 'query', '--query', soql]); + return response.result.records?.[0]; +} + +const network = querySingle(`SELECT Id, Name, UrlPathPrefix FROM Network WHERE Name = '${escapeSoql(networkName)}' LIMIT 1`); +if (!network || !network.UrlPathPrefix) { + console.error(`Could not find Network '${networkName}' or its UrlPathPrefix.`); + process.exit(1); +} + +const authProvider = querySingle(`SELECT Id, DeveloperName FROM AuthProvider WHERE DeveloperName = '${escapeSoql(authProviderDeveloperName)}' LIMIT 1`); +if (!authProvider) { + console.error(`Could not find AuthProvider with DeveloperName '${authProviderDeveloperName}'.`); + process.exit(1); +} + +const authConfig = querySingle( + `SELECT Id, DeveloperName, Url, AuthOptionsAuthProvider FROM AuthConfig WHERE Type = 'Community' AND Url LIKE '%/${escapeSoql(network.UrlPathPrefix)}' LIMIT 1` +); +if (!authConfig) { + console.error(`Could not find AuthConfig for Network '${networkName}' (urlPathPrefix '${network.UrlPathPrefix}').`); + process.exit(1); +} + +console.info(`Network: ${networkName} (${network.Id})`); +console.info(`AuthProvider: ${authProviderDeveloperName} (${authProvider.Id})`); +console.info(`AuthConfig: ${authConfig.Id}`); + +const existingLink = querySingle( + `SELECT Id FROM AuthConfigProviders WHERE AuthConfigId = '${authConfig.Id}' AND AuthProviderId = '${authProvider.Id}' LIMIT 1` +); + +if (existingLink) { + console.info(`Auth provider is already linked (AuthConfigProviders.Id=${existingLink.Id}).`); +} else { + runSf(['data', 'create', 'record', '--sobject', 'AuthConfigProviders', '--values', `AuthConfigId=${authConfig.Id} AuthProviderId=${authProvider.Id}`]); + console.info('Linked auth provider to community login configuration.'); +} + +console.info('Done.'); diff --git a/scripts/dev/set-email-service-run-as-user.js b/scripts/dev/set-email-service-run-as-user.js new file mode 100644 index 000000000..86ccb2dad --- /dev/null +++ b/scripts/dev/set-email-service-run-as-user.js @@ -0,0 +1,46 @@ +#!/usr/bin/env node + +const { spawnSync } = require('child_process'); +const fs = require('fs'); +const path = require('path'); + +const ENV_VAR_NAME = 'EMAIL_SERVICE_RUN_AS_USER'; +const envFilePath = path.resolve(process.cwd(), '.env'); + +const sfResult = spawnSync('sf', ['org', 'display', '--json'], { encoding: 'utf8', shell: true }); +if (sfResult.status !== 0) { + console.error(sfResult.stderr || sfResult.stdout); + process.exit(sfResult.status ?? 1); +} +const orgInfo = JSON.parse(sfResult.stdout); +const username = orgInfo.result?.username; +if (!username) { + console.error('Could not resolve the current org username from `sf org display --json`.'); + process.exit(1); +} + +const newLine = `${ENV_VAR_NAME}=${username}`; +const existingContents = fs.existsSync(envFilePath) ? fs.readFileSync(envFilePath, 'utf8') : ''; +const lines = existingContents.length > 0 ? existingContents.split(/\r?\n/) : []; + +const matcher = new RegExp(`^${ENV_VAR_NAME}=`); +const matchingIndex = lines.findIndex(line => matcher.test(line)); + +if (matchingIndex >= 0) { + lines[matchingIndex] = newLine; +} else { + if (lines.length > 0 && lines[lines.length - 1] === '') { + lines.splice(lines.length - 1, 0, newLine); + } else { + lines.push(newLine); + } +} + +let updatedContents = lines.join('\n'); +if (!updatedContents.endsWith('\n')) { + updatedContents += '\n'; +} +fs.writeFileSync(envFilePath, updatedContents); + +console.info(`${matchingIndex >= 0 ? 'Updated' : 'Added'} ${ENV_VAR_NAME} in ${envFilePath}`); +console.info(newLine); diff --git a/scripts/dev/setup-dev-scratch-org.sh b/scripts/dev/setup-dev-scratch-org.sh deleted file mode 100644 index a56af157c..000000000 --- a/scripts/dev/setup-dev-scratch-org.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -SCRATCH_ORG_ALIAS="$1" - -sf org create scratch --definition-file ./config/scratch-orgs/dev-scratch-def.json --alias $SCRATCH_ORG_ALIAS --duration-days 30 --set-default --json -wait - -sf project deploy start -c -wait - -npm run permset:assign:all -wait - -sf apex run --file ./scripts/data/create-sample-log-entries.apex -wait - -# These 2 commands require https://github.com/jamessimone/sf-trace-plugin -sf apex trace -sf lightning debug diff --git a/sfdx-project.json b/sfdx-project.json index 1ae67f066..bbe8075e6 100644 --- a/sfdx-project.json +++ b/sfdx-project.json @@ -9,9 +9,9 @@ "path": "./nebula-logger/core", "definitionFile": "./config/scratch-orgs/base-scratch-def.json", "scopeProfiles": true, - "versionNumber": "4.18.3.NEXT", - "versionName": "PrismJS Loading Improvements & Error Handling", - "versionDescription": "Fixed some issues with loading PrismJS from LoggerStaticResoures by switching to minified versions + added error handling with fallback display when PrismJS cannot be properly loaded", + "versionNumber": "4.18.4.NEXT", + "versionName": "Bugfix: Removed most of the usage of UserInfo.getSessionId()", + "versionDescription": "Fixed some issues related to trying to use UserInfo.getSessionId() by just.... not using it (for the most part)", "postInstallUrl": "https://github.com/jongpie/NebulaLogger/wiki", "releaseNotesUrl": "https://github.com/jongpie/NebulaLogger/releases", "unpackagedMetadata": { @@ -84,6 +84,13 @@ "default": false } ], + "replacements": [ + { + "filename": "nebula-logger/extra-tests/integration-tests/emailservices/ExampleInboundEmailService.xml-meta.xml", + "stringToReplace": "{{EMAIL_SERVICE_RUN_AS_USER}}", + "replaceWithEnv": "EMAIL_SERVICE_RUN_AS_USER" + } + ], "packageAliases": { "Nebula Logger - Core": "0Ho5Y000000TNKASA4", "Nebula Logger - Core@4.4.1-unlocked-package-release": "04t5Y0000027FGFQA2", @@ -231,6 +238,7 @@ "Nebula Logger - Core@4.18.1-new-declarative-configuration-for-ignoring-apex-classes-in-stack-traces": "04tg70000008GVpAAM", "Nebula Logger - Core@4.18.2-new-field-logentry__c.wasloggedbycurrentuser__c": "04tg70000008YZBAA2", "Nebula Logger - Core@4.18.3-prismjs-loading-improvements-&-error-handling": "04tg70000009GaDAAU", + "Nebula Logger - Core@4.18.4-bugfix:-removed-most-of-the-usage-of-userinfo.getsessionid()": "04tg7000000Bb13AAC", "Nebula Logger - Core Plugin - Async Failure Additions": "0Ho5Y000000blO4SAI", "Nebula Logger - Core Plugin - Async Failure Additions@1.0.0": "04t5Y0000015lhiQAA", "Nebula Logger - Core Plugin - Async Failure Additions@1.0.1": "04t5Y0000015lhsQAA",