diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 50a3d0334..c1f3ac630 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -7,3 +7,10 @@ updates: target-branch: "main" labels: - "dependencies" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + target-branch: "main" + labels: + - "dependencies" diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml index 65f737d98..3665d48af 100644 --- a/.github/workflows/build-pr.yml +++ b/.github/workflows/build-pr.yml @@ -4,6 +4,8 @@ on: pull_request: types: [opened, synchronize, closed, ready_for_review] +permissions: write-all + jobs: build: if: github.event.pull_request.draft == false && github.event.action != 'closed' @@ -17,6 +19,7 @@ jobs: uses: actions/setup-node@v3 with: node-version: '20' + cache: 'npm' - name: Install dependencies run: npm install @@ -40,7 +43,7 @@ jobs: echo "COMMIT_HASH=$(git rev-parse HEAD)" >> $GITHUB_ENV - name: Post comment on PR - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 68770a6dd..e57852184 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,7 +16,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: - node-version: 18 + node-version: 20 cache: 'npm' - name: Fetch files and checkout @@ -47,7 +47,7 @@ jobs: bash ./scripts/changelog.sh > ${{ github.workspace }}-CHANGELOG.txt - name: Create Release - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@v2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index d643a68bd..f53f9c869 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -31,7 +31,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -51,4 +51,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e2a73161b..a3ab925f5 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -27,7 +27,7 @@ jobs: uses: actions/setup-node@v1 with: node-version: 20.x - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: ~/.npm key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} @@ -49,7 +49,7 @@ jobs: uses: actions/setup-node@v1 with: node-version: 20.x - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: ~/.npm key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} @@ -61,7 +61,7 @@ jobs: npm run build - name: Cache docs output id: docs-output - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: docs key: docs-output-${{ github.run_id }} @@ -69,14 +69,14 @@ jobs: run: npx playwright install --with-deps - run: npm run playwright # - run: npm run playwright-e2e - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 if: always() with: name: playwright-report path: test-results retention-days: 5 - run: npm run test-int-x - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 if: always() with: name: playwright-report-pages @@ -100,12 +100,12 @@ jobs: node-version: 20.x - name: Cache build outputs id: docs-output - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: docs key: docs-output-${{ github.run_id }} - name: Setup Github Pages - uses: actions/configure-pages@v2 + uses: actions/configure-pages@v5 - name: Upload artifact uses: actions/upload-pages-artifact@v1 with: diff --git a/Sources/ContentScopeScripts/dist/contentScopeIsolated.js b/Sources/ContentScopeScripts/dist/contentScopeIsolated.js index ae4ed7ccd..ea1064d38 100644 --- a/Sources/ContentScopeScripts/dist/contentScopeIsolated.js +++ b/Sources/ContentScopeScripts/dist/contentScopeIsolated.js @@ -3356,9 +3356,7 @@ overlayInteracted: false, privatePlayerMode: { alwaysAsk: {} } }, - ui: { - overlayCopy: this.environment.getOverlayCopyOverride() || 'default' - } + ui: {} }) } return this.messaging.request(MSG_NAME_INITIAL_SETUP) @@ -3923,15 +3921,6 @@ } }; - /** - * Converts occurrences of {newline} in a string to
tags - * @param {string} text - */ - function nl2br (text) { - return html`${text.split('{newline}') - .map((line, i) => i === 0 ? line : html`
${line}`)}` - } - /** * @typedef {ReturnType} Template */ @@ -3946,29 +3935,15 @@ */ /** - * @type {Record} + * @type {Record<'default', OverlayCopyTranslation>} */ const overlayCopyVariants = { default: { - title: i18n.t('videoOverlayTitle'), - subtitle: html`${i18n.t('playText')} ${i18n.t('videoOverlaySubtitle')}`, - buttonOptOut: i18n.t('videoButtonOptOut'), - buttonOpen: i18n.t('videoButtonOpen'), - rememberLabel: i18n.t('rememberLabel') - }, - a1: { title: i18n.t('videoOverlayTitle2'), subtitle: i18n.t('videoOverlaySubtitle2'), buttonOptOut: i18n.t('videoButtonOptOut2'), buttonOpen: i18n.t('videoButtonOpen2'), rememberLabel: i18n.t('rememberLabel') - }, - b1: { - title: nl2br(i18n.t('videoOverlayTitle3')), - subtitle: i18n.t('videoOverlaySubtitle2'), - buttonOptOut: i18n.t('videoButtonOptOut2'), - buttonOpen: i18n.t('videoButtonOpen2'), - rememberLabel: i18n.t('rememberLabel') } }; @@ -4620,7 +4595,7 @@ * @returns {HTMLDivElement} */ createOverlay () { - const overlayCopy = overlayCopyVariants[this.ui?.overlayCopy || 'default']; + const overlayCopy = overlayCopyVariants.default; const overlayElement = document.createElement('div'); overlayElement.classList.add('ddg-video-player-overlay'); const svgIcon = trustedUnsafe(dax); @@ -5526,22 +5501,6 @@ return false } - /** - * @returns {import("../duck-player.js").UISettings['overlayCopy'] | null} - */ - getOverlayCopyOverride () { - if (this.isIntegrationMode()) { - const allowedOverlayCopyOverrides = ['default', 'a1', 'b1']; - - const url = new URLSearchParams(window.location.href); - const override = url.get('overlayCopy'); - if (override && allowedOverlayCopyOverrides.includes(override)) { - return /** @type {import("../duck-player.js").UISettings['overlayCopy']} */ (override) - } - } - return null - } - isIntegrationMode () { return this.debug === true && this.injectName === 'integration' } @@ -5624,7 +5583,6 @@ /** * @typedef UISettings - UI-specific settings - * @property {'default'|'a1'|'b1'} overlayCopy - Overlay copy experiment variant * @property {boolean} [allowFirstVideo] - should the first video be allowed to load/play? * @property {boolean} [playInDuckPlayer] - Forces next video to be played in Duck Player regardless of user setting */ diff --git a/build/android/contentScope.js b/build/android/contentScope.js index 0a5096884..522fd66f5 100644 --- a/build/android/contentScope.js +++ b/build/android/contentScope.js @@ -12192,9 +12192,7 @@ overlayInteracted: false, privatePlayerMode: { alwaysAsk: {} } }, - ui: { - overlayCopy: this.environment.getOverlayCopyOverride() || 'default' - } + ui: {} }) } return this.messaging.request(MSG_NAME_INITIAL_SETUP) @@ -12677,15 +12675,6 @@ } }; - /** - * Converts occurrences of {newline} in a string to
tags - * @param {string} text - */ - function nl2br (text) { - return html`${text.split('{newline}') - .map((line, i) => i === 0 ? line : html`
${line}`)}` - } - /** * @typedef {ReturnType} Template */ @@ -12700,29 +12689,15 @@ */ /** - * @type {Record} + * @type {Record<'default', OverlayCopyTranslation>} */ const overlayCopyVariants = { default: { - title: i18n.t('videoOverlayTitle'), - subtitle: html`${i18n.t('playText')} ${i18n.t('videoOverlaySubtitle')}`, - buttonOptOut: i18n.t('videoButtonOptOut'), - buttonOpen: i18n.t('videoButtonOpen'), - rememberLabel: i18n.t('rememberLabel') - }, - a1: { title: i18n.t('videoOverlayTitle2'), subtitle: i18n.t('videoOverlaySubtitle2'), buttonOptOut: i18n.t('videoButtonOptOut2'), buttonOpen: i18n.t('videoButtonOpen2'), rememberLabel: i18n.t('rememberLabel') - }, - b1: { - title: nl2br(i18n.t('videoOverlayTitle3')), - subtitle: i18n.t('videoOverlaySubtitle2'), - buttonOptOut: i18n.t('videoButtonOptOut2'), - buttonOpen: i18n.t('videoButtonOpen2'), - rememberLabel: i18n.t('rememberLabel') } }; @@ -13374,7 +13349,7 @@ * @returns {HTMLDivElement} */ createOverlay () { - const overlayCopy = overlayCopyVariants[this.ui?.overlayCopy || 'default']; + const overlayCopy = overlayCopyVariants.default; const overlayElement = document.createElement('div'); overlayElement.classList.add('ddg-video-player-overlay'); const svgIcon = trustedUnsafe(dax); @@ -14280,22 +14255,6 @@ return false } - /** - * @returns {import("../duck-player.js").UISettings['overlayCopy'] | null} - */ - getOverlayCopyOverride () { - if (this.isIntegrationMode()) { - const allowedOverlayCopyOverrides = ['default', 'a1', 'b1']; - - const url = new URLSearchParams(window.location.href); - const override = url.get('overlayCopy'); - if (override && allowedOverlayCopyOverrides.includes(override)) { - return /** @type {import("../duck-player.js").UISettings['overlayCopy']} */ (override) - } - } - return null - } - isIntegrationMode () { return this.debug === true && this.injectName === 'integration' } @@ -14378,7 +14337,6 @@ /** * @typedef UISettings - UI-specific settings - * @property {'default'|'a1'|'b1'} overlayCopy - Overlay copy experiment variant * @property {boolean} [allowFirstVideo] - should the first video be allowed to load/play? * @property {boolean} [playInDuckPlayer] - Forces next video to be played in Duck Player regardless of user setting */ diff --git a/build/contentScope.js b/build/contentScope.js index adc7a2635..ff893b395 100644 --- a/build/contentScope.js +++ b/build/contentScope.js @@ -11815,9 +11815,7 @@ overlayInteracted: false, privatePlayerMode: { alwaysAsk: {} } }, - ui: { - overlayCopy: this.environment.getOverlayCopyOverride() || 'default' - } + ui: {} }) } return this.messaging.request(MSG_NAME_INITIAL_SETUP) @@ -12300,15 +12298,6 @@ } }; - /** - * Converts occurrences of {newline} in a string to
tags - * @param {string} text - */ - function nl2br (text) { - return html`${text.split('{newline}') - .map((line, i) => i === 0 ? line : html`
${line}`)}` - } - /** * @typedef {ReturnType} Template */ @@ -12323,29 +12312,15 @@ */ /** - * @type {Record} + * @type {Record<'default', OverlayCopyTranslation>} */ const overlayCopyVariants = { default: { - title: i18n.t('videoOverlayTitle'), - subtitle: html`${i18n.t('playText')} ${i18n.t('videoOverlaySubtitle')}`, - buttonOptOut: i18n.t('videoButtonOptOut'), - buttonOpen: i18n.t('videoButtonOpen'), - rememberLabel: i18n.t('rememberLabel') - }, - a1: { title: i18n.t('videoOverlayTitle2'), subtitle: i18n.t('videoOverlaySubtitle2'), buttonOptOut: i18n.t('videoButtonOptOut2'), buttonOpen: i18n.t('videoButtonOpen2'), rememberLabel: i18n.t('rememberLabel') - }, - b1: { - title: nl2br(i18n.t('videoOverlayTitle3')), - subtitle: i18n.t('videoOverlaySubtitle2'), - buttonOptOut: i18n.t('videoButtonOptOut2'), - buttonOpen: i18n.t('videoButtonOpen2'), - rememberLabel: i18n.t('rememberLabel') } }; @@ -12997,7 +12972,7 @@ * @returns {HTMLDivElement} */ createOverlay () { - const overlayCopy = overlayCopyVariants[this.ui?.overlayCopy || 'default']; + const overlayCopy = overlayCopyVariants.default; const overlayElement = document.createElement('div'); overlayElement.classList.add('ddg-video-player-overlay'); const svgIcon = trustedUnsafe(dax); @@ -13903,22 +13878,6 @@ return false } - /** - * @returns {import("../duck-player.js").UISettings['overlayCopy'] | null} - */ - getOverlayCopyOverride () { - if (this.isIntegrationMode()) { - const allowedOverlayCopyOverrides = ['default', 'a1', 'b1']; - - const url = new URLSearchParams(window.location.href); - const override = url.get('overlayCopy'); - if (override && allowedOverlayCopyOverrides.includes(override)) { - return /** @type {import("../duck-player.js").UISettings['overlayCopy']} */ (override) - } - } - return null - } - isIntegrationMode () { return this.debug === true && this.injectName === 'integration' } @@ -14001,7 +13960,6 @@ /** * @typedef UISettings - UI-specific settings - * @property {'default'|'a1'|'b1'} overlayCopy - Overlay copy experiment variant * @property {boolean} [allowFirstVideo] - should the first video be allowed to load/play? * @property {boolean} [playInDuckPlayer] - Forces next video to be played in Duck Player regardless of user setting */ diff --git a/build/integration/contentScope.js b/build/integration/contentScope.js index adc7a2635..ff893b395 100644 --- a/build/integration/contentScope.js +++ b/build/integration/contentScope.js @@ -11815,9 +11815,7 @@ overlayInteracted: false, privatePlayerMode: { alwaysAsk: {} } }, - ui: { - overlayCopy: this.environment.getOverlayCopyOverride() || 'default' - } + ui: {} }) } return this.messaging.request(MSG_NAME_INITIAL_SETUP) @@ -12300,15 +12298,6 @@ } }; - /** - * Converts occurrences of {newline} in a string to
tags - * @param {string} text - */ - function nl2br (text) { - return html`${text.split('{newline}') - .map((line, i) => i === 0 ? line : html`
${line}`)}` - } - /** * @typedef {ReturnType} Template */ @@ -12323,29 +12312,15 @@ */ /** - * @type {Record} + * @type {Record<'default', OverlayCopyTranslation>} */ const overlayCopyVariants = { default: { - title: i18n.t('videoOverlayTitle'), - subtitle: html`${i18n.t('playText')} ${i18n.t('videoOverlaySubtitle')}`, - buttonOptOut: i18n.t('videoButtonOptOut'), - buttonOpen: i18n.t('videoButtonOpen'), - rememberLabel: i18n.t('rememberLabel') - }, - a1: { title: i18n.t('videoOverlayTitle2'), subtitle: i18n.t('videoOverlaySubtitle2'), buttonOptOut: i18n.t('videoButtonOptOut2'), buttonOpen: i18n.t('videoButtonOpen2'), rememberLabel: i18n.t('rememberLabel') - }, - b1: { - title: nl2br(i18n.t('videoOverlayTitle3')), - subtitle: i18n.t('videoOverlaySubtitle2'), - buttonOptOut: i18n.t('videoButtonOptOut2'), - buttonOpen: i18n.t('videoButtonOpen2'), - rememberLabel: i18n.t('rememberLabel') } }; @@ -12997,7 +12972,7 @@ * @returns {HTMLDivElement} */ createOverlay () { - const overlayCopy = overlayCopyVariants[this.ui?.overlayCopy || 'default']; + const overlayCopy = overlayCopyVariants.default; const overlayElement = document.createElement('div'); overlayElement.classList.add('ddg-video-player-overlay'); const svgIcon = trustedUnsafe(dax); @@ -13903,22 +13878,6 @@ return false } - /** - * @returns {import("../duck-player.js").UISettings['overlayCopy'] | null} - */ - getOverlayCopyOverride () { - if (this.isIntegrationMode()) { - const allowedOverlayCopyOverrides = ['default', 'a1', 'b1']; - - const url = new URLSearchParams(window.location.href); - const override = url.get('overlayCopy'); - if (override && allowedOverlayCopyOverrides.includes(override)) { - return /** @type {import("../duck-player.js").UISettings['overlayCopy']} */ (override) - } - } - return null - } - isIntegrationMode () { return this.debug === true && this.injectName === 'integration' } @@ -14001,7 +13960,6 @@ /** * @typedef UISettings - UI-specific settings - * @property {'default'|'a1'|'b1'} overlayCopy - Overlay copy experiment variant * @property {boolean} [allowFirstVideo] - should the first video be allowed to load/play? * @property {boolean} [playInDuckPlayer] - Forces next video to be played in Duck Player regardless of user setting */ diff --git a/build/windows/contentScope.js b/build/windows/contentScope.js index 369b2ffea..cc919d597 100644 --- a/build/windows/contentScope.js +++ b/build/windows/contentScope.js @@ -8597,9 +8597,7 @@ overlayInteracted: false, privatePlayerMode: { alwaysAsk: {} } }, - ui: { - overlayCopy: this.environment.getOverlayCopyOverride() || 'default' - } + ui: {} }) } return this.messaging.request(MSG_NAME_INITIAL_SETUP) @@ -9164,15 +9162,6 @@ } }; - /** - * Converts occurrences of {newline} in a string to
tags - * @param {string} text - */ - function nl2br (text) { - return html`${text.split('{newline}') - .map((line, i) => i === 0 ? line : html`
${line}`)}` - } - /** * @typedef {ReturnType} Template */ @@ -9187,29 +9176,15 @@ */ /** - * @type {Record} + * @type {Record<'default', OverlayCopyTranslation>} */ const overlayCopyVariants = { default: { - title: i18n.t('videoOverlayTitle'), - subtitle: html`${i18n.t('playText')} ${i18n.t('videoOverlaySubtitle')}`, - buttonOptOut: i18n.t('videoButtonOptOut'), - buttonOpen: i18n.t('videoButtonOpen'), - rememberLabel: i18n.t('rememberLabel') - }, - a1: { title: i18n.t('videoOverlayTitle2'), subtitle: i18n.t('videoOverlaySubtitle2'), buttonOptOut: i18n.t('videoButtonOptOut2'), buttonOpen: i18n.t('videoButtonOpen2'), rememberLabel: i18n.t('rememberLabel') - }, - b1: { - title: nl2br(i18n.t('videoOverlayTitle3')), - subtitle: i18n.t('videoOverlaySubtitle2'), - buttonOptOut: i18n.t('videoButtonOptOut2'), - buttonOpen: i18n.t('videoButtonOpen2'), - rememberLabel: i18n.t('rememberLabel') } }; @@ -9861,7 +9836,7 @@ * @returns {HTMLDivElement} */ createOverlay () { - const overlayCopy = overlayCopyVariants[this.ui?.overlayCopy || 'default']; + const overlayCopy = overlayCopyVariants.default; const overlayElement = document.createElement('div'); overlayElement.classList.add('ddg-video-player-overlay'); const svgIcon = trustedUnsafe(dax); @@ -10767,22 +10742,6 @@ return false } - /** - * @returns {import("../duck-player.js").UISettings['overlayCopy'] | null} - */ - getOverlayCopyOverride () { - if (this.isIntegrationMode()) { - const allowedOverlayCopyOverrides = ['default', 'a1', 'b1']; - - const url = new URLSearchParams(window.location.href); - const override = url.get('overlayCopy'); - if (override && allowedOverlayCopyOverrides.includes(override)) { - return /** @type {import("../duck-player.js").UISettings['overlayCopy']} */ (override) - } - } - return null - } - isIntegrationMode () { return this.debug === true && this.injectName === 'integration' } @@ -10865,7 +10824,6 @@ /** * @typedef UISettings - UI-specific settings - * @property {'default'|'a1'|'b1'} overlayCopy - Overlay copy experiment variant * @property {boolean} [allowFirstVideo] - should the first video be allowed to load/play? * @property {boolean} [playInDuckPlayer] - Forces next video to be played in Duck Player regardless of user setting */ diff --git a/integration-test/playwright/duckplayer.spec.js b/integration-test/playwright/duckplayer.spec.js index 5db4dea2d..af7aa14ac 100644 --- a/integration-test/playwright/duckplayer.spec.js +++ b/integration-test/playwright/duckplayer.spec.js @@ -232,7 +232,7 @@ test.describe('Video Player overlays', () => { // No video overlay await overlays.videoOverlayDoesntShow() }) - test('Selecting \'watch in duck player\'', async ({ page }, workerInfo) => { + test('Selecting \'Turn On Duck Player\'', async ({ page }, workerInfo) => { const overlays = DuckplayerOverlays.create(page, workerInfo) // Given overlays feature is enabled @@ -242,10 +242,10 @@ test.describe('Video Player overlays', () => { await overlays.userSettingIs('always ask') await overlays.gotoPlayerPage() - await overlays.watchInDuckPlayer() + await overlays.turnOnDuckPlayer() await overlays.userSettingWasUpdatedTo('always ask') // not updated }) - test('Selecting \'watch in duck player\' + remember', async ({ page }, workerInfo) => { + test('Selecting \'Turn On Duck Player\' + remember', async ({ page }, workerInfo) => { const overlays = DuckplayerOverlays.create(page, workerInfo) // Given overlays feature is enabled @@ -256,10 +256,10 @@ test.describe('Video Player overlays', () => { await overlays.gotoPlayerPage() await overlays.rememberMyChoice() - await overlays.watchInDuckPlayer() + await overlays.turnOnDuckPlayer() await overlays.userSettingWasUpdatedTo('enabled') // updated }) - test('Selecting \'watch here\'', async ({ page }, workerInfo) => { + test('Selecting \'No Thanks\'', async ({ page }, workerInfo) => { const overlays = DuckplayerOverlays.create(page, workerInfo) // Given overlays feature is enabled @@ -269,10 +269,10 @@ test.describe('Video Player overlays', () => { await overlays.userSettingIs('always ask') await overlays.gotoPlayerPage() - await overlays.watchHere() + await overlays.noThanks() await overlays.secondOverlayExistsOnVideo() }) - test('Selecting \'watch here\' + remember', async ({ page }, workerInfo) => { + test('Selecting \'No Thanks\' + remember', async ({ page }, workerInfo) => { const overlays = DuckplayerOverlays.create(page, workerInfo) // Given overlays feature is enabled @@ -283,11 +283,11 @@ test.describe('Video Player overlays', () => { await overlays.gotoPlayerPage() await overlays.rememberMyChoice() - await overlays.watchHere() + await overlays.noThanks() await overlays.userSettingWasUpdatedTo('always ask remembered') // updated }) test.describe('with remote config overrides', () => { - test('Selecting \'watch here\' + remember', async ({ page }, workerInfo) => { + test('Selecting \'No Thanks\' + remember', async ({ page }, workerInfo) => { const overlays = DuckplayerOverlays.create(page, workerInfo) // config with some CSS selectors overridden @@ -300,7 +300,7 @@ test.describe('Video Player overlays', () => { }) }) test.describe('with UI settings overrides', () => { - test('displays default overlay copy when no cohort is given', async ({ page }, workerInfo) => { + test('displays default overlay copy', async ({ page }, workerInfo) => { const overlays = DuckplayerOverlays.create(page, workerInfo) // Given overlays feature is enabled @@ -315,51 +315,6 @@ test.describe('Video Player overlays', () => { await overlays.overlayCopyIsDefault() }) - test('displays default overlay copy in control cohort', async ({ page }, workerInfo) => { - const overlays = DuckplayerOverlays.create(page, workerInfo) - - // Given overlays feature is enabled - await overlays.withRemoteConfig() - - // And my setting is 'always ask' - // And I'm in the 'control' experiment cohort - await overlays.initialSetupIs('always ask', 'default overlay copy') - await overlays.gotoPlayerPage() - - // Then the overlay shows the correct copy for the default variant - await overlays.overlayCopyIsDefault() - }) - - test('displays overlay copy for cohort A1', async ({ page }, workerInfo) => { - const overlays = DuckplayerOverlays.create(page, workerInfo) - - // Given overlays feature is enabled - await overlays.withRemoteConfig() - - // And my setting is 'always ask' - // And I'm in the 'A1' experiment cohort - await overlays.initialSetupIs('always ask', 'overlay copy a1') - await overlays.gotoPlayerPage() - - // Then the overlay shows the correct copy for the A1 variant - await overlays.overlayCopyIsA1() - }) - - test('displays overlay copy for cohort B1', async ({ page }, workerInfo) => { - const overlays = DuckplayerOverlays.create(page, workerInfo) - - // Given overlays feature is enabled - await overlays.withRemoteConfig() - - // And my setting is 'always ask' - // And I'm in the 'B1' experiment cohort - await overlays.initialSetupIs('always ask', 'overlay copy b1') - await overlays.gotoPlayerPage() - - // Then the overlay shows the correct copy for the B1 variant - await overlays.overlayCopyIsB1() - }) - test('forces next video to play in Duck Player', async ({ page }, workerInfo) => { const overlays = DuckplayerOverlays.create(page, workerInfo) diff --git a/integration-test/playwright/page-objects/duckplayer-overlays.js b/integration-test/playwright/page-objects/duckplayer-overlays.js index bc0688595..e3efb3c64 100644 --- a/integration-test/playwright/page-objects/duckplayer-overlays.js +++ b/integration-test/playwright/page-objects/duckplayer-overlays.js @@ -36,18 +36,6 @@ const userValues = { // Possible UI Settings const uiSettings = { - /** @type {import("../../../src/features/duck-player.js").UISettings} */ - 'default overlay copy': { - overlayCopy: 'default' - }, - /** @type {import("../../../src/features/duck-player.js").UISettings} */ - 'overlay copy a1': { - overlayCopy: 'a1' - }, - /** @type {import("../../../src/features/duck-player.js").UISettings} */ - 'overlay copy b1': { - overlayCopy: 'b1' - }, 'play in duck player': { playInDuckPlayer: true } @@ -202,9 +190,9 @@ export class DuckplayerOverlays { async overlayBlocksVideo () { await this.page.locator('ddg-video-overlay').waitFor({ state: 'visible', timeout: 1000 }) - await this.page.getByRole('link', { name: 'Watch in Duck Player' }).waitFor({ state: 'visible', timeout: 1000 }) + await this.page.getByRole('link', { name: 'Turn On Duck Player' }).waitFor({ state: 'visible', timeout: 1000 }) await this.page - .getByText('Duck Player provides a clean viewing experience without personalized ads and prevents viewing activity from influencing your YouTube recommendations.') + .getByText('What you watch in DuckDuckGo won’t influence your recommendations on YouTube.') .waitFor({ timeout: 100 }) } @@ -217,7 +205,7 @@ export class DuckplayerOverlays { // this is added because 'getAttribute' does not auto-wait await expect(async () => { - const link = await this.page.getByRole('link', { name: 'Watch in Duck Player' }).getAttribute('href') + const link = await this.page.getByRole('link', { name: 'Turn On Duck Player' }).getAttribute('href') expect(link).toEqual('duck://player/' + videoID) }).toPass({ timeout: 5000 }) } @@ -405,8 +393,8 @@ export class DuckplayerOverlays { // if we get here, the element was absent } - async watchInDuckPlayer () { - const action = () => this.page.getByRole('link', { name: 'Watch in Duck Player' }).click() + async turnOnDuckPlayer () { + const action = () => this.page.getByRole('link', { name: 'Turn On Duck Player' }).click() await this.build.switch({ 'apple-isolated': async () => { @@ -428,8 +416,8 @@ export class DuckplayerOverlays { }) } - async watchHere () { - await this.page.getByText('Watch Here').click() + async noThanks () { + await this.page.getByText('No Thanks').click() } async rememberMyChoice () { @@ -619,20 +607,6 @@ export class DuckplayerOverlays { * Checks for presence of default overlay copy */ async overlayCopyIsDefault () { - await this.page.locator('ddg-video-overlay').waitFor({ state: 'visible', timeout: 1000 }) - await this.page.getByText('Tired of targeted YouTube ads and recommendations?', { exact: true }).waitFor({ state: 'visible', timeout: 1000 }) - await this.page.getByText('Duck Player provides a clean viewing experience without personalized ads and prevents viewing activity from influencing your YouTube recommendations.', { exact: true }).waitFor({ state: 'visible', timeout: 1000 }) - - await this.page.getByRole('link', { name: 'Watch in Duck Player' }).waitFor({ state: 'visible', timeout: 1000 }) - await this.page.getByRole('button', { name: 'Watch Here' }).waitFor({ state: 'visible', timeout: 1000 }) - - await this.page.getByLabel('Remember my choice').waitFor({ state: 'visible', timeout: 1000 }) - } - - /** - * Checks for presence of overlay copy A1 experiment - */ - async overlayCopyIsA1 () { await this.page.locator('ddg-video-overlay').waitFor({ state: 'visible', timeout: 1000 }) await this.page.getByText('Turn on Duck Player to watch without targeted ads', { exact: true }).waitFor({ state: 'visible', timeout: 1000 }) await this.page.getByText('What you watch in DuckDuckGo won’t influence your recommendations on YouTube.', { exact: true }).waitFor({ state: 'visible', timeout: 1000 }) @@ -642,20 +616,6 @@ export class DuckplayerOverlays { await this.page.getByLabel('Remember my choice').waitFor({ state: 'visible', timeout: 1000 }) } - - /** - * Checks for presence of overlay copy B1 experiment - */ - async overlayCopyIsB1 () { - await this.page.locator('ddg-video-overlay').waitFor({ state: 'visible', timeout: 1000 }) - await this.page.getByText('Drowning in ads on YouTube? Turn on Duck Player.', { exact: true }).waitFor({ state: 'visible', timeout: 1000 }) - await this.page.getByText('What you watch in DuckDuckGo won’t influence your recommendations on YouTube.', { exact: true }).waitFor({ state: 'visible', timeout: 1000 }) - - await this.page.getByRole('link', { name: 'Turn On Duck Player' }).waitFor({ state: 'visible', timeout: 1000 }) - await this.page.getByRole('button', { name: 'No Thanks' }).waitFor({ state: 'visible', timeout: 1000 }) - - await this.page.getByLabel('Remember my choice').waitFor({ state: 'visible', timeout: 1000 }) - } } class DuckplayerOverlaysMobile { diff --git a/integration-test/test-pages/duckplayer/scripts/test.mjs b/integration-test/test-pages/duckplayer/scripts/test.mjs index 2626dc0d8..86a593e54 100644 --- a/integration-test/test-pages/duckplayer/scripts/test.mjs +++ b/integration-test/test-pages/duckplayer/scripts/test.mjs @@ -5,7 +5,7 @@ customElements.define(DDGVideoOverlayMobile.CUSTOM_TAG_NAME, DDGVideoOverlayMobi const elem = /** @type {DDGVideoOverlayMobile} */(document.createElement(DDGVideoOverlayMobile.CUSTOM_TAG_NAME)) elem.testMode = true -elem.text = overlayCopyVariants.a1 +elem.text = overlayCopyVariants.default elem.addEventListener('opt-in', (/** @type {CustomEvent} */e) => { console.log('did opt in?', e.detail) diff --git a/package-lock.json b/package-lock.json index 1b54ea1c3..44163a16e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,11 +22,11 @@ "@canvas/image-data": "^1.0.0", "@fingerprintjs/fingerprintjs": "^4.1.0", "@playwright/test": "^1.38.1", - "@rollup/plugin-commonjs": "^25.0.4", + "@rollup/plugin-commonjs": "^26.0.1", "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-replace": "^5.0.2", + "@rollup/plugin-replace": "^5.0.7", "@types/chrome": "^0.0.248", - "@types/jasmine": "^4.3.1", + "@types/jasmine": "^5.1.4", "@typescript-eslint/eslint-plugin": "^6.9.1", "config-builder": "github:duckduckgo/privacy-configuration#main", "esbuild": "^0.19.5", @@ -36,7 +36,7 @@ "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^6.1.1", "fast-check": "^3.14.0", - "jasmine": "^4.6.0", + "jasmine": "^5.3.0", "json-schema-to-typescript": "^13.1.2", "minimist": "^1.2.8", "puppeteer": "^21.4.1", @@ -717,10 +717,106 @@ "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", "dev": true }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "dev": true }, "node_modules/@jsdevtools/ono": { @@ -764,6 +860,16 @@ "node": ">= 8" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@playwright/test": { "version": "1.40.1", "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.40.1.tgz", @@ -806,23 +912,23 @@ "integrity": "sha512-crJTEu4j06tuhNNQQ0GVTJD6PtuNsqIhkGSYo16jAiBw067ge10+ueb64S4AkPJT2cmiCEg3mgs0j8r3IdUpuw==" }, "node_modules/@rollup/plugin-commonjs": { - "version": "25.0.4", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.4.tgz", - "integrity": "sha512-L92Vz9WUZXDnlQQl3EwbypJR4+DM2EbsO+/KOcEkP4Mc6Ct453EeDB2uH9lgRwj4w5yflgNpq9pHOiY8aoUXBQ==", + "version": "26.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-26.0.1.tgz", + "integrity": "sha512-UnsKoZK6/aGIH6AdkptXhNvhaqftcjq3zZdT+LY5Ftms6JR06nADcDsYp5hTU9E2lbJUEOhdlY5J4DNTneM+jQ==", "dev": true, "dependencies": { "@rollup/pluginutils": "^5.0.1", "commondir": "^1.0.1", "estree-walker": "^2.0.2", - "glob": "^8.0.3", + "glob": "^10.4.1", "is-reference": "1.2.1", - "magic-string": "^0.27.0" + "magic-string": "^0.30.3" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0 || 14 >= 14.17" }, "peerDependencies": { - "rollup": "^2.68.0||^3.0.0" + "rollup": "^2.68.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { "rollup": { @@ -840,46 +946,38 @@ } }, "node_modules/@rollup/plugin-commonjs/node_modules/glob": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", - "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, - "engines": { - "node": ">=12" + "bin": { + "glob": "dist/esm/bin.mjs" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@rollup/plugin-commonjs/node_modules/magic-string": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", - "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", - "dev": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.13" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/@rollup/plugin-commonjs/node_modules/minimatch": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", - "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/@rollup/plugin-node-resolve": { @@ -908,19 +1006,19 @@ } }, "node_modules/@rollup/plugin-replace": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.2.tgz", - "integrity": "sha512-M9YXNekv/C/iHHK+cvORzfRYfPbq0RDD8r0G+bMiTXjNGKulPnCT9O3Ss46WfhI6ZOCgApOP7xAdmCQJ+U2LAA==", + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.7.tgz", + "integrity": "sha512-PqxSfuorkHz/SPpyngLyg5GCEkOcee9M1bkxiVDr41Pd61mqP1PLOoDPbpl44SB2mQGKwV/In74gqQmGITOhEQ==", "dev": true, "dependencies": { "@rollup/pluginutils": "^5.0.1", - "magic-string": "^0.27.0" + "magic-string": "^0.30.3" }, "engines": { "node": ">=14.0.0" }, "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0" + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { "rollup": { @@ -928,18 +1026,6 @@ } } }, - "node_modules/@rollup/plugin-replace/node_modules/magic-string": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", - "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", - "dev": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.13" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/@rollup/pluginutils": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.5.tgz", @@ -1016,9 +1102,9 @@ "dev": true }, "node_modules/@types/jasmine": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-4.3.1.tgz", - "integrity": "sha512-Vu8l+UGcshYmV1VWwULgnV/2RDbBaO6i2Ptx7nd//oJPIZGhoI1YLST4VKagD2Pq/Bc2/7zvtvhM7F3p4SN7kQ==", + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-5.1.4.tgz", + "integrity": "sha512-px7OMFO/ncXxixDe1zR13V1iycqWae0MxTaw62RpFlksUi5QuNWgQJFkTQjIOvrmutJbI7Fp2Y2N1F6D2R4G6w==", "dev": true }, "node_modules/@types/json-schema": { @@ -2273,6 +2359,12 @@ "url": "https://github.com/fb55/domhandler?sponsor=1" } }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -3328,6 +3420,22 @@ "is-callable": "^1.1.3" } }, + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/formdata-polyfill": { "version": "4.0.10", "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", @@ -4203,25 +4311,84 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/jasmine": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-4.6.0.tgz", - "integrity": "sha512-iq7HQ5M8ydNUspjd9vbFW9Lu+6lQ1QLDIqjl0WysEllF5EJZy8XaUyNlhCJVwOx2YFzqTtARWbS56F/f0PzRFw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-5.3.0.tgz", + "integrity": "sha512-Vrv5VWTXVZ/5xcNawlYCmE24pOaZu3KduLr9iAaENoMJ8W8Ryvhfpw2cf3rI4Unc2ajvu2t4tCKjS72TnraBGQ==", "dev": true, "dependencies": { - "glob": "^7.1.6", - "jasmine-core": "^4.6.0" + "glob": "^10.2.2", + "jasmine-core": "~5.3.0" }, "bin": { "jasmine": "bin/jasmine.js" } }, "node_modules/jasmine-core": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.6.0.tgz", - "integrity": "sha512-O236+gd0ZXS8YAjFx8xKaJ94/erqUliEkJTDedyE7iHvv4ZVqi+q+8acJxu05/WJDKm512EUNn809In37nWlAQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.3.0.tgz", + "integrity": "sha512-zsOmeBKESky4toybvWEikRiZ0jHoBEu79wNArLfMdSnlLMZx3Xcp6CSm2sUcYyoJC+Uyj8LBJap/MUbVSfJ27g==", "dev": true }, + "node_modules/jasmine/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/jasmine/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jasmine/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -4383,6 +4550,15 @@ "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", "dev": true }, + "node_modules/magic-string": { + "version": "0.30.11", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", + "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, "node_modules/marked": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", @@ -4466,6 +4642,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/mitt": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", @@ -4726,6 +4911,12 @@ "node": ">= 14" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", + "dev": true + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -4788,6 +4979,28 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -5356,6 +5569,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/sjcl": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/sjcl/-/sjcl-1.0.8.tgz", @@ -5455,6 +5680,21 @@ "node": ">=8" } }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/string.prototype.trim": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", @@ -5512,6 +5752,19 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -6062,6 +6315,24 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -6580,10 +6851,75 @@ "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", "dev": true }, + "@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "requires": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true + }, + "ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + }, + "wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "requires": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + } + } + } + }, "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "dev": true }, "@jsdevtools/ono": { @@ -6618,6 +6954,13 @@ "fastq": "^1.6.0" } }, + "@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true + }, "@playwright/test": { "version": "1.40.1", "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.40.1.tgz", @@ -6648,17 +6991,17 @@ "integrity": "sha512-crJTEu4j06tuhNNQQ0GVTJD6PtuNsqIhkGSYo16jAiBw067ge10+ueb64S4AkPJT2cmiCEg3mgs0j8r3IdUpuw==" }, "@rollup/plugin-commonjs": { - "version": "25.0.4", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.4.tgz", - "integrity": "sha512-L92Vz9WUZXDnlQQl3EwbypJR4+DM2EbsO+/KOcEkP4Mc6Ct453EeDB2uH9lgRwj4w5yflgNpq9pHOiY8aoUXBQ==", + "version": "26.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-26.0.1.tgz", + "integrity": "sha512-UnsKoZK6/aGIH6AdkptXhNvhaqftcjq3zZdT+LY5Ftms6JR06nADcDsYp5hTU9E2lbJUEOhdlY5J4DNTneM+jQ==", "dev": true, "requires": { "@rollup/pluginutils": "^5.0.1", "commondir": "^1.0.1", "estree-walker": "^2.0.2", - "glob": "^8.0.3", + "glob": "^10.4.1", "is-reference": "1.2.1", - "magic-string": "^0.27.0" + "magic-string": "^0.30.3" }, "dependencies": { "brace-expansion": { @@ -6671,31 +7014,23 @@ } }, "glob": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", - "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - } - }, - "magic-string": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", - "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", - "dev": true, - "requires": { - "@jridgewell/sourcemap-codec": "^1.4.13" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" } }, "minimatch": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", - "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "requires": { "brace-expansion": "^2.0.1" @@ -6718,24 +7053,13 @@ } }, "@rollup/plugin-replace": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.2.tgz", - "integrity": "sha512-M9YXNekv/C/iHHK+cvORzfRYfPbq0RDD8r0G+bMiTXjNGKulPnCT9O3Ss46WfhI6ZOCgApOP7xAdmCQJ+U2LAA==", + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.7.tgz", + "integrity": "sha512-PqxSfuorkHz/SPpyngLyg5GCEkOcee9M1bkxiVDr41Pd61mqP1PLOoDPbpl44SB2mQGKwV/In74gqQmGITOhEQ==", "dev": true, "requires": { "@rollup/pluginutils": "^5.0.1", - "magic-string": "^0.27.0" - }, - "dependencies": { - "magic-string": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", - "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", - "dev": true, - "requires": { - "@jridgewell/sourcemap-codec": "^1.4.13" - } - } + "magic-string": "^0.30.3" } }, "@rollup/pluginutils": { @@ -6803,9 +7127,9 @@ "dev": true }, "@types/jasmine": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-4.3.1.tgz", - "integrity": "sha512-Vu8l+UGcshYmV1VWwULgnV/2RDbBaO6i2Ptx7nd//oJPIZGhoI1YLST4VKagD2Pq/Bc2/7zvtvhM7F3p4SN7kQ==", + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-5.1.4.tgz", + "integrity": "sha512-px7OMFO/ncXxixDe1zR13V1iycqWae0MxTaw62RpFlksUi5QuNWgQJFkTQjIOvrmutJbI7Fp2Y2N1F6D2R4G6w==", "dev": true }, "@types/json-schema": { @@ -7670,6 +7994,12 @@ } } }, + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -8441,6 +8771,16 @@ "is-callable": "^1.1.3" } }, + "foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + } + }, "formdata-polyfill": { "version": "4.0.10", "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", @@ -9048,20 +9388,64 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "requires": { + "@isaacs/cliui": "^8.0.2", + "@pkgjs/parseargs": "^0.11.0" + } + }, "jasmine": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-4.6.0.tgz", - "integrity": "sha512-iq7HQ5M8ydNUspjd9vbFW9Lu+6lQ1QLDIqjl0WysEllF5EJZy8XaUyNlhCJVwOx2YFzqTtARWbS56F/f0PzRFw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-5.3.0.tgz", + "integrity": "sha512-Vrv5VWTXVZ/5xcNawlYCmE24pOaZu3KduLr9iAaENoMJ8W8Ryvhfpw2cf3rI4Unc2ajvu2t4tCKjS72TnraBGQ==", "dev": true, "requires": { - "glob": "^7.1.6", - "jasmine-core": "^4.6.0" + "glob": "^10.2.2", + "jasmine-core": "~5.3.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "requires": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + } + }, + "minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } } }, "jasmine-core": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.6.0.tgz", - "integrity": "sha512-O236+gd0ZXS8YAjFx8xKaJ94/erqUliEkJTDedyE7iHvv4ZVqi+q+8acJxu05/WJDKm512EUNn809In37nWlAQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.3.0.tgz", + "integrity": "sha512-zsOmeBKESky4toybvWEikRiZ0jHoBEu79wNArLfMdSnlLMZx3Xcp6CSm2sUcYyoJC+Uyj8LBJap/MUbVSfJ27g==", "dev": true }, "js-tokens": { @@ -9203,6 +9587,15 @@ "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", "dev": true }, + "magic-string": { + "version": "0.30.11", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", + "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==", + "dev": true, + "requires": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, "marked": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", @@ -9262,6 +9655,12 @@ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true }, + "minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true + }, "mitt": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", @@ -9453,6 +9852,12 @@ "netmask": "^2.0.2" } }, + "package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", + "dev": true + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -9500,6 +9905,24 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "requires": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + } + } + }, "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -9884,6 +10307,12 @@ "object-inspect": "^1.9.0" } }, + "signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true + }, "sjcl": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/sjcl/-/sjcl-1.0.8.tgz", @@ -9971,6 +10400,17 @@ "strip-ansi": "^6.0.1" } }, + "string-width-cjs": { + "version": "npm:string-width@4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, "string.prototype.trim": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", @@ -10013,6 +10453,15 @@ "ansi-regex": "^5.0.1" } }, + "strip-ansi-cjs": { + "version": "npm:strip-ansi@6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -10438,6 +10887,17 @@ "strip-ansi": "^6.0.0" } }, + "wrap-ansi-cjs": { + "version": "npm:wrap-ansi@7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/package.json b/package.json index b4eea4c81..d7a396e02 100644 --- a/package.json +++ b/package.json @@ -64,11 +64,11 @@ "@canvas/image-data": "^1.0.0", "@fingerprintjs/fingerprintjs": "^4.1.0", "@playwright/test": "^1.38.1", - "@rollup/plugin-commonjs": "^25.0.4", + "@rollup/plugin-commonjs": "^26.0.1", "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-replace": "^5.0.2", + "@rollup/plugin-replace": "^5.0.7", "@types/chrome": "^0.0.248", - "@types/jasmine": "^4.3.1", + "@types/jasmine": "^5.1.4", "@typescript-eslint/eslint-plugin": "^6.9.1", "config-builder": "github:duckduckgo/privacy-configuration#main", "esbuild": "^0.19.5", @@ -78,7 +78,7 @@ "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^6.1.1", "fast-check": "^3.14.0", - "jasmine": "^4.6.0", + "jasmine": "^5.3.0", "json-schema-to-typescript": "^13.1.2", "minimist": "^1.2.8", "puppeteer": "^21.4.1", diff --git a/src/features/duck-player.js b/src/features/duck-player.js index b8588a5f8..4a86f0ef1 100644 --- a/src/features/duck-player.js +++ b/src/features/duck-player.js @@ -48,7 +48,6 @@ import { Environment, initOverlays } from './duckplayer/overlays.js' /** * @typedef UISettings - UI-specific settings - * @property {'default'|'a1'|'b1'} overlayCopy - Overlay copy experiment variant * @property {boolean} [allowFirstVideo] - should the first video be allowed to load/play? * @property {boolean} [playInDuckPlayer] - Forces next video to be played in Duck Player regardless of user setting */ diff --git a/src/features/duckplayer/components/ddg-video-overlay.js b/src/features/duckplayer/components/ddg-video-overlay.js index 41607e5a0..edf2515e9 100644 --- a/src/features/duckplayer/components/ddg-video-overlay.js +++ b/src/features/duckplayer/components/ddg-video-overlay.js @@ -58,7 +58,7 @@ export class DDGVideoOverlay extends HTMLElement { * @returns {HTMLDivElement} */ createOverlay () { - const overlayCopy = overlayCopyVariants[this.ui?.overlayCopy || 'default'] + const overlayCopy = overlayCopyVariants.default const overlayElement = document.createElement('div') overlayElement.classList.add('ddg-video-player-overlay') const svgIcon = trustedUnsafe(dax) diff --git a/src/features/duckplayer/overlay-messages.js b/src/features/duckplayer/overlay-messages.js index b2eb2772b..76613aa92 100644 --- a/src/features/duckplayer/overlay-messages.js +++ b/src/features/duckplayer/overlay-messages.js @@ -33,9 +33,7 @@ export class DuckPlayerOverlayMessages { overlayInteracted: false, privatePlayerMode: { alwaysAsk: {} } }, - ui: { - overlayCopy: this.environment.getOverlayCopyOverride() || 'default' - } + ui: {} }) } return this.messaging.request(constants.MSG_NAME_INITIAL_SETUP) diff --git a/src/features/duckplayer/overlays.js b/src/features/duckplayer/overlays.js index 3b7eb2660..620f0168a 100644 --- a/src/features/duckplayer/overlays.js +++ b/src/features/duckplayer/overlays.js @@ -243,22 +243,6 @@ export class Environment { return false } - /** - * @returns {import("../duck-player.js").UISettings['overlayCopy'] | null} - */ - getOverlayCopyOverride () { - if (this.isIntegrationMode()) { - const allowedOverlayCopyOverrides = ['default', 'a1', 'b1'] - - const url = new URLSearchParams(window.location.href) - const override = url.get('overlayCopy') - if (override && allowedOverlayCopyOverrides.includes(override)) { - return /** @type {import("../duck-player.js").UISettings['overlayCopy']} */ (override) - } - } - return null - } - isIntegrationMode () { return this.debug === true && this.injectName === 'integration' } diff --git a/src/features/duckplayer/text.js b/src/features/duckplayer/text.js index 35722c81a..dc3d19adb 100644 --- a/src/features/duckplayer/text.js +++ b/src/features/duckplayer/text.js @@ -80,29 +80,15 @@ export function nl2br (text) { */ /** - * @type {Record} + * @type {Record<'default', OverlayCopyTranslation>} */ export const overlayCopyVariants = { default: { - title: i18n.t('videoOverlayTitle'), - subtitle: html`${i18n.t('playText')} ${i18n.t('videoOverlaySubtitle')}`, - buttonOptOut: i18n.t('videoButtonOptOut'), - buttonOpen: i18n.t('videoButtonOpen'), - rememberLabel: i18n.t('rememberLabel') - }, - a1: { title: i18n.t('videoOverlayTitle2'), subtitle: i18n.t('videoOverlaySubtitle2'), buttonOptOut: i18n.t('videoButtonOptOut2'), buttonOpen: i18n.t('videoButtonOpen2'), rememberLabel: i18n.t('rememberLabel') - }, - b1: { - title: nl2br(i18n.t('videoOverlayTitle3')), - subtitle: i18n.t('videoOverlaySubtitle2'), - buttonOptOut: i18n.t('videoButtonOptOut2'), - buttonOpen: i18n.t('videoButtonOpen2'), - rememberLabel: i18n.t('rememberLabel') } }