diff --git a/injected/package.json b/injected/package.json index 9ce0ca5d7b..4b4f785a4b 100644 --- a/injected/package.json +++ b/injected/package.json @@ -37,9 +37,9 @@ "devDependencies": { "@canvas/image-data": "^1.0.0", "@fingerprintjs/fingerprintjs": "^4.6.2", - "@types/chrome": "^0.1.1", - "@types/jasmine": "^5.1.9", - "@types/node": "^24.1.0", + "@types/chrome": "^0.1.24", + "@types/jasmine": "^5.1.12", + "@types/node": "^24.9.1", "@typescript-eslint/eslint-plugin": "^8.46.0", "fast-check": "^4.2.0", "jasmine": "^5.12.0", diff --git a/injected/src/config-feature.js b/injected/src/config-feature.js index 81e8acd92d..95056496e8 100644 --- a/injected/src/config-feature.js +++ b/injected/src/config-feature.js @@ -30,6 +30,7 @@ export default class ConfigFeature { * platform: import('./utils.js').Platform, * desktopModeEnabled?: boolean, * forcedZoomEnabled?: boolean, + * isDdgWebView?: boolean, * featureSettings?: Record, * assets?: import('./content-feature.js').AssetConfig | undefined, * site: import('./content-feature.js').Site, diff --git a/injected/src/features/autofill-import.js b/injected/src/features/autofill-import.js index 9710a5ac42..1b5e3513d2 100644 --- a/injected/src/features/autofill-import.js +++ b/injected/src/features/autofill-import.js @@ -8,7 +8,7 @@ export const BACKGROUND_COLOR_START = 'rgba(85, 127, 243, 0.10)'; export const BACKGROUND_COLOR_END = 'rgba(85, 127, 243, 0.25)'; export const OVERLAY_ID = 'ddg-password-import-overlay'; export const DELAY_BEFORE_ANIMATION = 300; -const TAKEOUT_DOWNLOAD_URL_BASE = '/takeout/download'; +const MANAGE_ARCHIVE_DEFAULT_BASE = '/manage/archive'; /** * @typedef ButtonAnimationStyle @@ -55,8 +55,6 @@ export default class AutofillImport extends ActionExecutorBase { #domLoaded; - #exportId; - #processingBookmark; #isBookmarkModalVisible = false; @@ -589,22 +587,23 @@ export default class AutofillImport extends ActionExecutorBase { } /** Bookmark import code */ + get defaultRetrySettings() { + return { + maxAttempts: this.getFeatureSetting('downloadRetryLimit') ?? Infinity, + interval: this.getFeatureSetting('downloadRetryInterval') ?? 1000, + }; + } + async downloadData() { // Run with retry forever until the download link is available, // Android is the one that timesout anyway and closes the whole tab if this doesn't complete - const downloadRetryLimit = this.getFeatureSetting('downloadRetryLimit') ?? Infinity; - const downloadRetryInterval = this.getFeatureSetting('downloadRetryInterval') ?? 1000; - - const userIdElement = await this.runWithRetry( - () => document.querySelector(this.bookmarkImportSelectorSettings.userIdLink), - downloadRetryLimit, - downloadRetryInterval, - 'linear', - ); - const userIdLink = userIdElement?.getAttribute('href'); - const userId = userIdLink ? new URL(userIdLink, window.location.origin).searchParams.get('user') : null; - if (!userId || !this.#exportId) { + const exportId = window.location.pathname + .split('/') + .filter((segment) => segment) + .pop(); + + if (!exportId) { this.postBookmarkImportMessage('actionCompleted', { result: new ErrorResponse({ actionID: 'download-data', @@ -614,20 +613,17 @@ export default class AutofillImport extends ActionExecutorBase { return; } - await this.runWithRetry( - () => document.querySelector(`a[href="./manage/archive/${this.#exportId}"]`), - downloadRetryLimit, - downloadRetryInterval, - 'linear', + const downloadLinkSelector = this.bookmarkImportSelectorSettings.downloadLink ?? `a[href*="&i=0&user="]`; + const downloadButton = /** @type {HTMLAnchorElement|null} */ ( + await this.runWithRetry(() => document.querySelector(downloadLinkSelector), 5, 1000, 'linear') ); + if (downloadButton == null) { + // If there was no download link, it was likely a 404 + // so we reload the page to try again + window.location.reload(); + } - const downloadURL = `${TAKEOUT_DOWNLOAD_URL_BASE}?j=${this.#exportId}&i=0&user=${userId}`; - - // Sleep before downloading to ensure the download link is available - const downloadNavigationDelayMs = this.getFeatureSetting('downloadNavigationDelayMs') ?? 2000; - await new Promise((resolve) => setTimeout(resolve, downloadNavigationDelayMs)); - - window.location.href = downloadURL; + downloadButton?.click(); } /** @@ -635,9 +631,10 @@ export default class AutofillImport extends ActionExecutorBase { * as for now the retry doesn't need to be per action. */ retryConfigFor(_) { + const { interval, maxAttempts } = this.defaultRetrySettings; return { - interval: { ms: 1000 }, - maxAttempts: 30, + interval: { ms: interval }, + maxAttempts, }; } @@ -660,14 +657,17 @@ export default class AutofillImport extends ActionExecutorBase { async handleBookmarkImportPath(pathname) { if (pathname === '/' && !this.#isBookmarkModalVisible) { for (const action of this.bookmarkImportActionSettings) { - // Before clicking on the manage button, we need to store the export id - if (action.id === 'manage-button-click') { - await this.storeExportId(); - } - await this.patchMessagingAndProcessAction(action); } + + // Parse the export id from the page and then navigate to the 'manage' page + const exportId = await this.getExportId(); + window.location.href = `${MANAGE_ARCHIVE_DEFAULT_BASE}/${exportId}`; + } else if (pathname.startsWith(MANAGE_ARCHIVE_DEFAULT_BASE)) { + // If we're on the 'manage' page, we can download the data await this.downloadData(); + } else { + // Unhandled path, we bail out } } @@ -681,11 +681,13 @@ export default class AutofillImport extends ActionExecutorBase { findExportId() { const panels = document.querySelectorAll(this.bookmarkImportSelectorSettings.tabPanel); const exportPanel = panels[panels.length - 1]; - return exportPanel.querySelector('div[data-archive-id]')?.getAttribute('data-archive-id'); + const dataArchiveIdSelector = this.bookmarkImportSelectorSettings.dataArchiveId ?? `div[data-archive-id]`; + return exportPanel.querySelector(dataArchiveIdSelector)?.getAttribute('data-archive-id'); } - async storeExportId() { - this.#exportId = await this.runWithRetry(() => this.findExportId(), 30, 1000, 'linear'); + async getExportId() { + const { maxAttempts, interval } = this.defaultRetrySettings; + return await this.runWithRetry(() => this.findExportId(), maxAttempts, interval, 'linear'); } urlChanged() { diff --git a/injected/src/features/page-context.js b/injected/src/features/page-context.js index 57e7dd0c38..8fe72741c7 100644 --- a/injected/src/features/page-context.js +++ b/injected/src/features/page-context.js @@ -424,17 +424,26 @@ export default class PageContext extends ContentFeature { const content = { favicon: getFaviconList(), title: this.getPageTitle(), - metaDescription: this.getMetaDescription(), content: mainContent, truncated, fullContentLength: this.fullContentLength, // Include full content length before truncation - headings: this.getHeadings(), - links: this.getLinks(), - images: this.getImages(), timestamp: Date.now(), url: window.location.href, }; + if (this.getFeatureSettingEnabled('includeMetaDescription', 'disabled')) { + content.metaDescription = this.getMetaDescription(); + } + if (this.getFeatureSettingEnabled('includeHeadings', 'disabled')) { + content.headings = this.getHeadings(); + } + if (this.getFeatureSettingEnabled('includeLinks', 'disabled')) { + content.links = this.getLinks(); + } + if (this.getFeatureSettingEnabled('includeImages', 'disabled')) { + content.images = this.getImages(); + } + // Cache the result - setter handles timestamp and observer this.cachedContent = content; return content; diff --git a/injected/src/features/windows-permission-usage.js b/injected/src/features/windows-permission-usage.js index f0eedebe65..4f28f828eb 100644 --- a/injected/src/features/windows-permission-usage.js +++ b/injected/src/features/windows-permission-usage.js @@ -17,7 +17,12 @@ export default class WindowsPermissionUsage extends ContentFeature { Paused: 'paused', }; - const isFrameInsideFrame = window.self !== window.top && window.parent !== window.top; + // isDdgWebView is a Windows-specific property injected via userPreferences + const isDdgWebView = this.args?.isDdgWebView; + + const isFrameInsideFrameInWebView2 = isDdgWebView + ? false // In DDG WebView, we can handle nested frames properly + : window.self !== window.top && window.parent !== window.top; // In WebView2, we need to deny permission for nested frames function windowsPostMessage(name, data) { // @ts-expect-error https://app.asana.com/0/1201614831475344/1203979574128023/f @@ -38,8 +43,8 @@ export default class WindowsPermissionUsage extends ContentFeature { // proxy for navigator.geolocation.watchPosition -> show red geolocation indicator const watchPositionProxy = new DDGProxy(this, Geolocation.prototype, 'watchPosition', { apply(target, thisArg, args) { - if (isFrameInsideFrame) { - // we can't communicate with iframes inside iframes -> deny permission instead of putting users at risk + if (isFrameInsideFrameInWebView2) { + // we can't communicate with iframes inside iframes in WebView2 -> deny permission instead of putting users at risk throw new DOMException('Permission denied'); } @@ -313,8 +318,8 @@ export default class WindowsPermissionUsage extends ContentFeature { if (window.MediaDevices) { const getUserMediaProxy = new DDGProxy(this, MediaDevices.prototype, 'getUserMedia', { apply(target, thisArg, args) { - if (isFrameInsideFrame) { - // we can't communicate with iframes inside iframes -> deny permission instead of putting users at risk + if (isFrameInsideFrameInWebView2) { + // we can't communicate with iframes inside iframes in WebView2-> deny permission instead of putting users at risk return Promise.reject(new DOMException('Permission denied')); } diff --git a/package-lock.json b/package-lock.json index d6fc5cf6ad..8c5a1871b8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,8 +28,8 @@ "stylelint-config-standard": "^34.0.0", "stylelint-csstree-validator": "^3.0.0", "ts-json-schema-generator": "^2.4.0", - "typedoc": "^0.28.8", - "typescript": "^5.8.3", + "typedoc": "^0.28.14", + "typescript": "^5.9.3", "typescript-eslint": "^8.36.0", "wait-on": "^9.0.1" } @@ -48,9 +48,9 @@ "devDependencies": { "@canvas/image-data": "^1.0.0", "@fingerprintjs/fingerprintjs": "^4.6.2", - "@types/chrome": "^0.1.1", - "@types/jasmine": "^5.1.9", - "@types/node": "^24.1.0", + "@types/chrome": "^0.1.24", + "@types/jasmine": "^5.1.12", + "@types/node": "^24.9.1", "@typescript-eslint/eslint-plugin": "^8.46.0", "fast-check": "^4.2.0", "jasmine": "^5.12.0", @@ -1151,16 +1151,16 @@ } }, "node_modules/@gerrit0/mini-shiki": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-3.8.1.tgz", - "integrity": "sha512-HVZW+8pxoOExr5ZMPK15U79jQAZTO/S6i5byQyyZGjtNj+qaYd82cizTncwFzTQgiLo8uUBym6vh+/1tfJklTw==", + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-3.14.0.tgz", + "integrity": "sha512-c5X8fwPLOtUS8TVdqhynz9iV0GlOtFUT1ppXYzUUlEXe4kbZ/mvMT8wXoT8kCwUka+zsiloq7sD3pZ3+QVTuNQ==", "dev": true, "license": "MIT", "dependencies": { - "@shikijs/engine-oniguruma": "^3.8.1", - "@shikijs/langs": "^3.8.1", - "@shikijs/themes": "^3.8.1", - "@shikijs/types": "^3.8.1", + "@shikijs/engine-oniguruma": "^3.14.0", + "@shikijs/langs": "^3.14.0", + "@shikijs/themes": "^3.14.0", + "@shikijs/types": "^3.14.0", "@shikijs/vscode-textmate": "^10.0.2" } }, @@ -1566,40 +1566,40 @@ "license": "MIT" }, "node_modules/@shikijs/engine-oniguruma": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.8.1.tgz", - "integrity": "sha512-KGQJZHlNY7c656qPFEQpIoqOuC4LrxjyNndRdzk5WKB/Ie87+NJCF1xo9KkOUxwxylk7rT6nhlZyTGTC4fCe1g==", + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.14.0.tgz", + "integrity": "sha512-TNcYTYMbJyy+ZjzWtt0bG5y4YyMIWC2nyePz+CFMWqm+HnZZyy9SWMgo8Z6KBJVIZnx8XUXS8U2afO6Y0g1Oug==", "dev": true, "license": "MIT", "dependencies": { - "@shikijs/types": "3.8.1", + "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "node_modules/@shikijs/langs": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.8.1.tgz", - "integrity": "sha512-TjOFg2Wp1w07oKnXjs0AUMb4kJvujML+fJ1C5cmEj45lhjbUXtziT1x2bPQb9Db6kmPhkG5NI2tgYW1/DzhUuQ==", + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.14.0.tgz", + "integrity": "sha512-DIB2EQY7yPX1/ZH7lMcwrK5pl+ZkP/xoSpUzg9YC8R+evRCCiSQ7yyrvEyBsMnfZq4eBzLzBlugMyTAf13+pzg==", "dev": true, "license": "MIT", "dependencies": { - "@shikijs/types": "3.8.1" + "@shikijs/types": "3.14.0" } }, "node_modules/@shikijs/themes": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.8.1.tgz", - "integrity": "sha512-Vu3t3BBLifc0GB0UPg2Pox1naTemrrvyZv2lkiSw3QayVV60me1ujFQwPZGgUTmwXl1yhCPW8Lieesm0CYruLQ==", + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.14.0.tgz", + "integrity": "sha512-fAo/OnfWckNmv4uBoUu6dSlkcBc+SA1xzj5oUSaz5z3KqHtEbUypg/9xxgJARtM6+7RVm0Q6Xnty41xA1ma1IA==", "dev": true, "license": "MIT", "dependencies": { - "@shikijs/types": "3.8.1" + "@shikijs/types": "3.14.0" } }, "node_modules/@shikijs/types": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.8.1.tgz", - "integrity": "sha512-5C39Q8/8r1I26suLh+5TPk1DTrbY/kn3IdWA5HdizR0FhlhD05zx5nKCqhzSfDHH3p4S0ZefxWd77DLV+8FhGg==", + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.14.0.tgz", + "integrity": "sha512-bQGgC6vrY8U/9ObG1Z/vTro+uclbjjD/uG58RvfxKZVD5p9Yc1ka3tVyEFy7BNJLzxuWyHH5NWynP9zZZS59eQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1622,9 +1622,9 @@ "license": "MIT" }, "node_modules/@types/chrome": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.1.1.tgz", - "integrity": "sha512-MLtFW++/n+OPQIaf5hA6pmURd3Zn+OxuvASyf2mYh8B8pHDpbhHjwlVHMw3H/aJC9Z7Z3itO0AFaZeegrGk0yA==", + "version": "0.1.24", + "resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.1.24.tgz", + "integrity": "sha512-9iO9HL2bMeGS4C8m6gNFWUyuPE5HEUFk+rGh+7oriUjg+ata4Fc9PoVlu8xvGm7yoo3AmS3J6fAjoFj61NL2rw==", "dev": true, "license": "MIT", "dependencies": { @@ -1674,9 +1674,9 @@ } }, "node_modules/@types/jasmine": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-5.1.9.tgz", - "integrity": "sha512-8t4HtkW4wxiPVedMpeZ63n3vlWxEIquo/zc1Tm8ElU+SqVV7+D3Na2PWaJUp179AzTragMWVwkMv7mvty0NfyQ==", + "version": "5.1.12", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-5.1.12.tgz", + "integrity": "sha512-1BzPxNsFDLDfj9InVR3IeY0ZVf4o9XV+4mDqoCfyPkbsA7dYyKAPAb2co6wLFlHcvxPlt1wShm7zQdV7uTfLGA==", "dev": true, "license": "MIT" }, @@ -1714,13 +1714,13 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.1.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.1.0.tgz", - "integrity": "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w==", + "version": "24.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.1.tgz", + "integrity": "sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~7.8.0" + "undici-types": "~7.16.0" } }, "node_modules/@types/normalize-package-data": { @@ -1969,16 +1969,17 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.36.0.tgz", - "integrity": "sha512-FuYgkHwZLuPbZjQHzJXrtXreJdFMKl16BFYyRrLxDhWr6Qr7Kbcu2s1Yhu8tsiMXw1S0W1pjfFfYEt+R604s+Q==", + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.2.tgz", + "integrity": "sha512-BnOroVl1SgrPLywqxyqdJ4l3S2MsKVLDVxZvjI1Eoe8ev2r3kGDo+PcMihNmDE+6/KjkTubSJnmqGZZjQSBq/g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.36.0", - "@typescript-eslint/types": "8.36.0", - "@typescript-eslint/typescript-estree": "8.36.0", - "@typescript-eslint/visitor-keys": "8.36.0", + "@typescript-eslint/scope-manager": "8.46.2", + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/typescript-estree": "8.46.2", + "@typescript-eslint/visitor-keys": "8.46.2", "debug": "^4.3.4" }, "engines": { @@ -1990,18 +1991,19 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.36.0.tgz", - "integrity": "sha512-JAhQFIABkWccQYeLMrHadu/fhpzmSQ1F1KXkpzqiVxA/iYI6UnRt2trqXHt1sYEcw1mxLnB9rKMsOxXPxowN/g==", + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.2.tgz", + "integrity": "sha512-PULOLZ9iqwI7hXcmL4fVfIsBi6AN9YxRc0frbvmg8f+4hQAjQ5GYNKK0DIArNo+rOKmR/iBYwkpBmnIwin4wBg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.36.0", - "@typescript-eslint/types": "^8.36.0", + "@typescript-eslint/tsconfig-utils": "^8.46.2", + "@typescript-eslint/types": "^8.46.2", "debug": "^4.3.4" }, "engines": { @@ -2012,18 +2014,19 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.36.0.tgz", - "integrity": "sha512-wCnapIKnDkN62fYtTGv2+RY8FlnBYA3tNm0fm91kc2BjPhV2vIjwwozJ7LToaLAyb1ca8BxrS7vT+Pvvf7RvqA==", + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.2.tgz", + "integrity": "sha512-LF4b/NmGvdWEHD2H4MsHD8ny6JpiVNDzrSZr3CsckEgCbAGZbYM4Cqxvi9L+WqDMT+51Ozy7lt2M+d0JLEuBqA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "@typescript-eslint/types": "8.36.0", - "@typescript-eslint/visitor-keys": "8.36.0" + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/visitor-keys": "8.46.2" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2034,11 +2037,12 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.36.0.tgz", - "integrity": "sha512-Nhh3TIEgN18mNbdXpd5Q8mSCBnrZQeY9V7Ca3dqYvNDStNIGRmJA6dmrIPMJ0kow3C7gcQbpsG2rPzy1Ks/AnA==", + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.2.tgz", + "integrity": "sha512-a7QH6fw4S57+F5y2FIxxSDyi5M4UfGF+Jl1bCGd7+L4KsaUY80GsiF/t0UoRFDHAguKlBaACWJRmdrc6Xfkkag==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -2047,7 +2051,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/type-utils": { @@ -2257,11 +2261,12 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.36.0.tgz", - "integrity": "sha512-xGms6l5cTJKQPZOKM75Dl9yBfNdGeLRsIyufewnxT4vZTrjC0ImQT4fj8QmtJK84F58uSh5HVBSANwcfiXxABQ==", + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.2.tgz", + "integrity": "sha512-lNCWCbq7rpg7qDsQrd3D6NyWYu+gkTENkG5IKYhUIcxSb59SQC/hEQ+MrG4sTgBVghTonNWq42bA/d4yYumldQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -2271,16 +2276,17 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.36.0.tgz", - "integrity": "sha512-JaS8bDVrfVJX4av0jLpe4ye0BpAaUW7+tnS4Y4ETa3q7NoZgzYbN9zDQTJ8kPb5fQ4n0hliAt9tA4Pfs2zA2Hg==", + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.2.tgz", + "integrity": "sha512-f7rW7LJ2b7Uh2EiQ+7sza6RDZnajbNbemn54Ob6fRwQbgcIn+GWfyuHDHRYgRoZu1P4AayVScrRW+YfbTvPQoQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "@typescript-eslint/project-service": "8.36.0", - "@typescript-eslint/tsconfig-utils": "8.36.0", - "@typescript-eslint/types": "8.36.0", - "@typescript-eslint/visitor-keys": "8.36.0", + "@typescript-eslint/project-service": "8.46.2", + "@typescript-eslint/tsconfig-utils": "8.46.2", + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/visitor-keys": "8.46.2", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -2296,7 +2302,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { @@ -2305,6 +2311,7 @@ "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -2315,6 +2322,7 @@ "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -2326,11 +2334,12 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "dev": true, "license": "ISC", + "peer": true, "bin": { "semver": "bin/semver.js" }, @@ -2338,38 +2347,15 @@ "node": ">=10" } }, - "node_modules/@typescript-eslint/utils": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.36.0.tgz", - "integrity": "sha512-VOqmHu42aEMT+P2qYjylw6zP/3E/HvptRwdn/PZxyV27KhZg2IOszXod4NcXisWzPAGSS4trE/g4moNj6XmH2g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.36.0", - "@typescript-eslint/types": "8.36.0", - "@typescript-eslint/typescript-estree": "8.36.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.36.0.tgz", - "integrity": "sha512-vZrhV2lRPWDuGoxcmrzRZyxAggPL+qp3WzUrlZD+slFueDiYHxeBa34dUXPuC0RmGKzl4lS5kFJYvKCq9cnNDA==", + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.2.tgz", + "integrity": "sha512-tUFMXI4gxzzMXt4xpGJEsBsTox0XbNQ1y94EwlD/CuZwFcQP79xfQqMhau9HsRc/J0cAPA/HZt1dZPtGn9V/7w==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "@typescript-eslint/types": "8.36.0", + "@typescript-eslint/types": "8.46.2", "eslint-visitor-keys": "^4.2.1" }, "engines": { @@ -10367,17 +10353,17 @@ "license": "MIT" }, "node_modules/typedoc": { - "version": "0.28.8", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.28.8.tgz", - "integrity": "sha512-16GfLopc8icHfdvqZDqdGBoS2AieIRP2rpf9mU+MgN+gGLyEQvAO0QgOa6NJ5QNmQi0LFrDY9in4F2fUNKgJKA==", + "version": "0.28.14", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.28.14.tgz", + "integrity": "sha512-ftJYPvpVfQvFzpkoSfHLkJybdA/geDJ8BGQt/ZnkkhnBYoYW6lBgPQXu6vqLxO4X75dA55hX8Af847H5KXlEFA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@gerrit0/mini-shiki": "^3.7.0", + "@gerrit0/mini-shiki": "^3.12.0", "lunr": "^2.3.9", "markdown-it": "^14.1.0", "minimatch": "^9.0.5", - "yaml": "^2.8.0" + "yaml": "^2.8.1" }, "bin": { "typedoc": "bin/typedoc" @@ -10387,7 +10373,7 @@ "pnpm": ">= 10" }, "peerDependencies": { - "typescript": "5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x" + "typescript": "5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x || 5.9.x" } }, "node_modules/typedoc/node_modules/brace-expansion": { @@ -10421,9 +10407,9 @@ "link": true }, "node_modules/typescript": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", - "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -10487,7 +10473,7 @@ "typescript": ">=4.8.4 <5.9.0" } }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/type-utils": { + "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { "version": "8.36.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.36.0.tgz", "integrity": "sha512-5aaGYG8cVDd6cxfk/ynpYzxBRZJk7w/ymto6uiyUFtdCozQIsQWh7M28/6r57Fwkbweng8qAzoMCPwSJfWlmsg==", @@ -10511,6 +10497,319 @@ "typescript": ">=4.8.4 <5.9.0" } }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.36.0.tgz", + "integrity": "sha512-JaS8bDVrfVJX4av0jLpe4ye0BpAaUW7+tnS4Y4ETa3q7NoZgzYbN9zDQTJ8kPb5fQ4n0hliAt9tA4Pfs2zA2Hg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.36.0", + "@typescript-eslint/tsconfig-utils": "8.36.0", + "@typescript-eslint/types": "8.36.0", + "@typescript-eslint/visitor-keys": "8.36.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/project-service": { + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.36.0.tgz", + "integrity": "sha512-JAhQFIABkWccQYeLMrHadu/fhpzmSQ1F1KXkpzqiVxA/iYI6UnRt2trqXHt1sYEcw1mxLnB9rKMsOxXPxowN/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.36.0", + "@typescript-eslint/types": "^8.36.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.36.0.tgz", + "integrity": "sha512-Nhh3TIEgN18mNbdXpd5Q8mSCBnrZQeY9V7Ca3dqYvNDStNIGRmJA6dmrIPMJ0kow3C7gcQbpsG2rPzy1Ks/AnA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": { + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.36.0.tgz", + "integrity": "sha512-FuYgkHwZLuPbZjQHzJXrtXreJdFMKl16BFYyRrLxDhWr6Qr7Kbcu2s1Yhu8tsiMXw1S0W1pjfFfYEt+R604s+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.36.0", + "@typescript-eslint/types": "8.36.0", + "@typescript-eslint/typescript-estree": "8.36.0", + "@typescript-eslint/visitor-keys": "8.36.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.36.0.tgz", + "integrity": "sha512-JaS8bDVrfVJX4av0jLpe4ye0BpAaUW7+tnS4Y4ETa3q7NoZgzYbN9zDQTJ8kPb5fQ4n0hliAt9tA4Pfs2zA2Hg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.36.0", + "@typescript-eslint/tsconfig-utils": "8.36.0", + "@typescript-eslint/types": "8.36.0", + "@typescript-eslint/visitor-keys": "8.36.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/project-service": { + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.36.0.tgz", + "integrity": "sha512-JAhQFIABkWccQYeLMrHadu/fhpzmSQ1F1KXkpzqiVxA/iYI6UnRt2trqXHt1sYEcw1mxLnB9rKMsOxXPxowN/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.36.0", + "@typescript-eslint/types": "^8.36.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.36.0.tgz", + "integrity": "sha512-Nhh3TIEgN18mNbdXpd5Q8mSCBnrZQeY9V7Ca3dqYvNDStNIGRmJA6dmrIPMJ0kow3C7gcQbpsG2rPzy1Ks/AnA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": { + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.36.0.tgz", + "integrity": "sha512-wCnapIKnDkN62fYtTGv2+RY8FlnBYA3tNm0fm91kc2BjPhV2vIjwwozJ7LToaLAyb1ca8BxrS7vT+Pvvf7RvqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.36.0", + "@typescript-eslint/visitor-keys": "8.36.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/types": { + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.36.0.tgz", + "integrity": "sha512-xGms6l5cTJKQPZOKM75Dl9yBfNdGeLRsIyufewnxT4vZTrjC0ImQT4fj8QmtJK84F58uSh5HVBSANwcfiXxABQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.36.0.tgz", + "integrity": "sha512-VOqmHu42aEMT+P2qYjylw6zP/3E/HvptRwdn/PZxyV27KhZg2IOszXod4NcXisWzPAGSS4trE/g4moNj6XmH2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.36.0", + "@typescript-eslint/types": "8.36.0", + "@typescript-eslint/typescript-estree": "8.36.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.36.0.tgz", + "integrity": "sha512-JaS8bDVrfVJX4av0jLpe4ye0BpAaUW7+tnS4Y4ETa3q7NoZgzYbN9zDQTJ8kPb5fQ4n0hliAt9tA4Pfs2zA2Hg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.36.0", + "@typescript-eslint/tsconfig-utils": "8.36.0", + "@typescript-eslint/types": "8.36.0", + "@typescript-eslint/visitor-keys": "8.36.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/project-service": { + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.36.0.tgz", + "integrity": "sha512-JAhQFIABkWccQYeLMrHadu/fhpzmSQ1F1KXkpzqiVxA/iYI6UnRt2trqXHt1sYEcw1mxLnB9rKMsOxXPxowN/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.36.0", + "@typescript-eslint/types": "^8.36.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.36.0.tgz", + "integrity": "sha512-Nhh3TIEgN18mNbdXpd5Q8mSCBnrZQeY9V7Ca3dqYvNDStNIGRmJA6dmrIPMJ0kow3C7gcQbpsG2rPzy1Ks/AnA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.36.0.tgz", + "integrity": "sha512-vZrhV2lRPWDuGoxcmrzRZyxAggPL+qp3WzUrlZD+slFueDiYHxeBa34dUXPuC0RmGKzl4lS5kFJYvKCq9cnNDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.36.0", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/typescript-eslint/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, "node_modules/typescript-eslint/node_modules/ignore": { "version": "7.0.5", "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", @@ -10521,6 +10820,35 @@ "node": ">= 4" } }, + "node_modules/typescript-eslint/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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/typescript-eslint/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/uc.micro": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", @@ -10555,9 +10883,9 @@ } }, "node_modules/undici-types": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz", - "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "dev": true, "license": "MIT" }, @@ -11439,9 +11767,9 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", - "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", + "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", "dev": true, "license": "ISC", "bin": { @@ -11558,7 +11886,7 @@ "json-schema-to-typescript": "^15.0.4" }, "devDependencies": { - "@types/jasmine": "^5.1.9", + "@types/jasmine": "^5.1.12", "jasmine": "^5.12.0" } } diff --git a/package.json b/package.json index f5db61fb9e..affeb08b9b 100644 --- a/package.json +++ b/package.json @@ -48,8 +48,8 @@ "stylelint-config-standard": "^34.0.0", "stylelint-csstree-validator": "^3.0.0", "ts-json-schema-generator": "^2.4.0", - "typedoc": "^0.28.8", - "typescript": "^5.8.3", + "typedoc": "^0.28.14", + "typescript": "^5.9.3", "typescript-eslint": "^8.36.0", "wait-on": "^9.0.1" }, diff --git a/special-pages/pages/history/app/components/Item.js b/special-pages/pages/history/app/components/Item.js index 7dc90bfa02..7ad81274e6 100644 --- a/special-pages/pages/history/app/components/Item.js +++ b/special-pages/pages/history/app/components/Item.js @@ -18,7 +18,7 @@ export const Item = memo( * @param {string} props.url - The text to be displayed for the item. * @param {string} props.domain - The text to be displayed for the domain * @param {number} props.kind - The kind or type of the item that determines its visual style. - * @param {string} props.dateTimeOfDay - the time of day, like 11.00am. + * @param {string} [props.dateTimeOfDay] - the time of day, like 11.00am. * @param {string} props.dateRelativeDay - the time of day, like 11.00am. * @param {string|null} props.etldPlusOne * @param {number} props.index - original index @@ -63,7 +63,7 @@ export const Item = memo( {props.domain} - {dateTimeOfDay} + {dateTimeOfDay && {dateTimeOfDay}} diff --git a/special-pages/pages/history/app/components/Sidebar.js b/special-pages/pages/history/app/components/Sidebar.js index 240414470d..47f07229c8 100644 --- a/special-pages/pages/history/app/components/Sidebar.js +++ b/special-pages/pages/history/app/components/Sidebar.js @@ -28,6 +28,7 @@ const iconMap = { saturday: 'icons/day.svg', sunday: 'icons/day.svg', older: 'icons/older.svg', + sites: 'icons/sites.svg', }; /** @type {Record string) => string>} */ @@ -43,6 +44,7 @@ const titleMap = { saturday: (t) => t('range_saturday'), sunday: (t) => t('range_sunday'), older: (t) => t('range_older'), + sites: (t) => t('range_sites'), }; /** @@ -106,7 +108,7 @@ function Item({ current, range, onClick, onDelete, count }) { if (range === 'all' && current.value === null) { return cn(styles.item, styles.active); } - return cn(styles.item, current.value === range && styles.active); + return cn(styles.item, current.value === range && styles.active, styles[`item_${range}`]); }); return ( @@ -182,6 +184,7 @@ function labels(range, t) { case 'thursday': case 'friday': case 'saturday': + case 'sites': case 'sunday': return { linkLabel: t('show_history_for', { range }), buttonLabel: t('delete_history_for', { range }) }; case 'older': diff --git a/special-pages/pages/history/app/components/Sidebar.module.css b/special-pages/pages/history/app/components/Sidebar.module.css index fa57a82031..6b15d6e30c 100644 --- a/special-pages/pages/history/app/components/Sidebar.module.css +++ b/special-pages/pages/history/app/components/Sidebar.module.css @@ -39,6 +39,23 @@ background: var(--color-white-at-6); } } + + &.item_sites { + margin-top: 16px; + + &::before { + content: ''; + position: absolute; + top: -8px; + left: 16px; + right: 16px; + border-top: 1px solid var(--color-black-at-6); + } + + [data-theme="dark"] &::before { + border-top: 1px solid var(--color-white-at-6); + } + } } .item:hover .delete[aria-disabled="true"] { diff --git a/special-pages/pages/history/app/history.service.js b/special-pages/pages/history/app/history.service.js index 75e6df3c80..50c3814670 100644 --- a/special-pages/pages/history/app/history.service.js +++ b/special-pages/pages/history/app/history.service.js @@ -421,6 +421,7 @@ export function toRange(input) { 'sunday', 'recentlyOpened', 'older', + 'sites', ]; return valid.includes(input) ? /** @type {import('../types/history.js').RangeId} */ (input) : null; } diff --git a/special-pages/pages/history/app/mocks/mock-transport.js b/special-pages/pages/history/app/mocks/mock-transport.js index 65966a1807..d7b4d2948e 100644 --- a/special-pages/pages/history/app/mocks/mock-transport.js +++ b/special-pages/pages/history/app/mocks/mock-transport.js @@ -40,6 +40,7 @@ export function mockTransport() { { id: 'saturday', count: 1 }, { id: 'friday', count: 1 }, { id: 'older', count: 1 }, + { id: 'sites', count: 1 }, ], }; @@ -268,8 +269,10 @@ function queryResponseFrom(memory, msg) { const response = asResponse(memory.slice(0, 10), msg.params.offset, msg.params.limit); const range = msg.params.query.range; response.value = response.value.map((item) => { + if (!('range' in msg.params.query)) return item; // unreachable return { ...item, + dateTimeOfDay: msg.params.query.range === 'sites' ? undefined : item.dateTimeOfDay, title: 'range:' + range + ' ' + item.title, }; }); diff --git a/special-pages/pages/history/app/strings.json b/special-pages/pages/history/app/strings.json index ae93ea6f7e..823926070b 100644 --- a/special-pages/pages/history/app/strings.json +++ b/special-pages/pages/history/app/strings.json @@ -106,5 +106,9 @@ "range_older": { "title": "Older", "note": "Label on a button that shows older history entries." + }, + "range_sites": { + "title": "Sites", + "note": "Label on a button that shows which sites have been visited" } } \ No newline at end of file diff --git a/special-pages/pages/history/integration-tests/history.page.js b/special-pages/pages/history/integration-tests/history.page.js index 6cdb93e074..3e12d6fd1c 100644 --- a/special-pages/pages/history/integration-tests/history.page.js +++ b/special-pages/pages/history/integration-tests/history.page.js @@ -601,6 +601,15 @@ export class HistoryTestPage { const rgb = `rgb(${[r, g, b].join(', ')})`; await expect(this.page.locator('[data-layout-mode="normal"]')).toHaveCSS('background-color', rgb, { timeout: 50 }); } + + async lastItemDividerHasColor({ rgb }) { + const lastItem = this.sidebar().locator('.Sidebar_item').last(); + const borderTopColor = await lastItem.evaluate((el) => { + const before = window.getComputedStyle(el, '::before'); + return before.borderTopColor; + }); + expect(borderTopColor).toBe(rgb); + } } /** diff --git a/special-pages/pages/history/integration-tests/history.screenshots.spec.js-snapshots/full-empty-dark-integration-darwin.png b/special-pages/pages/history/integration-tests/history.screenshots.spec.js-snapshots/full-empty-dark-integration-darwin.png index 4a8146047d..8495afa3af 100644 Binary files a/special-pages/pages/history/integration-tests/history.screenshots.spec.js-snapshots/full-empty-dark-integration-darwin.png and b/special-pages/pages/history/integration-tests/history.screenshots.spec.js-snapshots/full-empty-dark-integration-darwin.png differ diff --git a/special-pages/pages/history/integration-tests/history.screenshots.spec.js-snapshots/full-empty-light-integration-darwin.png b/special-pages/pages/history/integration-tests/history.screenshots.spec.js-snapshots/full-empty-light-integration-darwin.png index 895480eb1c..894636d932 100644 Binary files a/special-pages/pages/history/integration-tests/history.screenshots.spec.js-snapshots/full-empty-light-integration-darwin.png and b/special-pages/pages/history/integration-tests/history.screenshots.spec.js-snapshots/full-empty-light-integration-darwin.png differ diff --git a/special-pages/pages/history/integration-tests/history.screenshots.spec.js-snapshots/full-short-dark-integration-darwin.png b/special-pages/pages/history/integration-tests/history.screenshots.spec.js-snapshots/full-short-dark-integration-darwin.png index 05fcbccc9f..851c14572a 100644 Binary files a/special-pages/pages/history/integration-tests/history.screenshots.spec.js-snapshots/full-short-dark-integration-darwin.png and b/special-pages/pages/history/integration-tests/history.screenshots.spec.js-snapshots/full-short-dark-integration-darwin.png differ diff --git a/special-pages/pages/history/integration-tests/history.screenshots.spec.js-snapshots/full-short-light-integration-darwin.png b/special-pages/pages/history/integration-tests/history.screenshots.spec.js-snapshots/full-short-light-integration-darwin.png index c2b99224dc..9d8430594d 100644 Binary files a/special-pages/pages/history/integration-tests/history.screenshots.spec.js-snapshots/full-short-light-integration-darwin.png and b/special-pages/pages/history/integration-tests/history.screenshots.spec.js-snapshots/full-short-light-integration-darwin.png differ diff --git a/special-pages/pages/history/messages/types/history-item.json b/special-pages/pages/history/messages/types/history-item.json index 4dc26a01de..ce59b515a2 100644 --- a/special-pages/pages/history/messages/types/history-item.json +++ b/special-pages/pages/history/messages/types/history-item.json @@ -5,7 +5,6 @@ "id", "dateRelativeDay", "dateShort", - "dateTimeOfDay", "domain", "time", "title", diff --git a/special-pages/pages/history/messages/types/range.json b/special-pages/pages/history/messages/types/range.json index 473685ba63..2dd15c0ce1 100644 --- a/special-pages/pages/history/messages/types/range.json +++ b/special-pages/pages/history/messages/types/range.json @@ -29,7 +29,8 @@ "friday", "saturday", "sunday", - "older" + "older", + "sites" ] } }, diff --git a/special-pages/pages/history/public/icons/sites.svg b/special-pages/pages/history/public/icons/sites.svg new file mode 100644 index 0000000000..27eb7ad66c --- /dev/null +++ b/special-pages/pages/history/public/icons/sites.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/special-pages/pages/history/public/locales/de/history.json b/special-pages/pages/history/public/locales/de/history.json index 93977cc52b..ab7c51cd8e 100644 --- a/special-pages/pages/history/public/locales/de/history.json +++ b/special-pages/pages/history/public/locales/de/history.json @@ -115,5 +115,9 @@ "range_older" : { "title" : "Älter", "note" : "Label on a button that shows older history entries." + }, + "range_sites" : { + "title" : "Websites", + "note" : "Label on a button that shows which sites have been visited" } } \ No newline at end of file diff --git a/special-pages/pages/history/public/locales/en/history.json b/special-pages/pages/history/public/locales/en/history.json index b544b6e5a1..3250c691fd 100644 --- a/special-pages/pages/history/public/locales/en/history.json +++ b/special-pages/pages/history/public/locales/en/history.json @@ -116,5 +116,9 @@ "range_older": { "title": "Older", "note": "Label on a button that shows older history entries." + }, + "range_sites": { + "title": "Sites", + "note": "Label on a button that shows which sites have been visited" } } \ No newline at end of file diff --git a/special-pages/pages/history/public/locales/es/history.json b/special-pages/pages/history/public/locales/es/history.json index b5b4d3c5f3..d674579764 100644 --- a/special-pages/pages/history/public/locales/es/history.json +++ b/special-pages/pages/history/public/locales/es/history.json @@ -115,5 +115,9 @@ "range_older" : { "title" : "Más antiguo", "note" : "Label on a button that shows older history entries." + }, + "range_sites" : { + "title" : "Sitios", + "note" : "Label on a button that shows which sites have been visited" } } \ No newline at end of file diff --git a/special-pages/pages/history/public/locales/fr/history.json b/special-pages/pages/history/public/locales/fr/history.json index 3868f3fad1..0f537238af 100644 --- a/special-pages/pages/history/public/locales/fr/history.json +++ b/special-pages/pages/history/public/locales/fr/history.json @@ -115,5 +115,9 @@ "range_older" : { "title" : "Anciennes", "note" : "Label on a button that shows older history entries." + }, + "range_sites" : { + "title" : "Sites", + "note" : "Label on a button that shows which sites have been visited" } } \ No newline at end of file diff --git a/special-pages/pages/history/public/locales/it/history.json b/special-pages/pages/history/public/locales/it/history.json index cebab3b832..fc0831e2e6 100644 --- a/special-pages/pages/history/public/locales/it/history.json +++ b/special-pages/pages/history/public/locales/it/history.json @@ -115,5 +115,9 @@ "range_older" : { "title" : "Più vecchio", "note" : "Label on a button that shows older history entries." + }, + "range_sites" : { + "title" : "Siti", + "note" : "Label on a button that shows which sites have been visited" } } \ No newline at end of file diff --git a/special-pages/pages/history/public/locales/nl/history.json b/special-pages/pages/history/public/locales/nl/history.json index 2da2a03975..fe9de50a62 100644 --- a/special-pages/pages/history/public/locales/nl/history.json +++ b/special-pages/pages/history/public/locales/nl/history.json @@ -115,5 +115,9 @@ "range_older" : { "title" : "Ouder", "note" : "Label on a button that shows older history entries." + }, + "range_sites" : { + "title" : "Sites", + "note" : "Label on a button that shows which sites have been visited" } } \ No newline at end of file diff --git a/special-pages/pages/history/public/locales/pl/history.json b/special-pages/pages/history/public/locales/pl/history.json index 286b8a6be4..bc97eb4321 100644 --- a/special-pages/pages/history/public/locales/pl/history.json +++ b/special-pages/pages/history/public/locales/pl/history.json @@ -17,7 +17,7 @@ "note" : "Placeholder text when there's no results to show" }, "no_results_title" : { - "title" : "Brak wyników dla {term}", + "title" : "Brak wyników dla „{term}”", "note" : "The placeholder {term} will be dynamically replaced with the search term entered by the user. For example, if the user searches for 'cats', the title will become 'No results found for cats'." }, "no_results_text" : { @@ -115,5 +115,9 @@ "range_older" : { "title" : "Starsze", "note" : "Label on a button that shows older history entries." + }, + "range_sites" : { + "title" : "Witryny", + "note" : "Label on a button that shows which sites have been visited" } } \ No newline at end of file diff --git a/special-pages/pages/history/public/locales/pt/history.json b/special-pages/pages/history/public/locales/pt/history.json index ff37136faf..3dac530bd0 100644 --- a/special-pages/pages/history/public/locales/pt/history.json +++ b/special-pages/pages/history/public/locales/pt/history.json @@ -115,5 +115,9 @@ "range_older" : { "title" : "Mais antigas", "note" : "Label on a button that shows older history entries." + }, + "range_sites" : { + "title" : "Sites", + "note" : "Label on a button that shows which sites have been visited" } } \ No newline at end of file diff --git a/special-pages/pages/history/public/locales/ru/history.json b/special-pages/pages/history/public/locales/ru/history.json index 0a06bc6b9d..e7cba7de92 100644 --- a/special-pages/pages/history/public/locales/ru/history.json +++ b/special-pages/pages/history/public/locales/ru/history.json @@ -115,5 +115,9 @@ "range_older" : { "title" : "Более старые записи", "note" : "Label on a button that shows older history entries." + }, + "range_sites" : { + "title" : "Сайты", + "note" : "Label on a button that shows which sites have been visited" } } \ No newline at end of file diff --git a/special-pages/pages/history/types/history.ts b/special-pages/pages/history/types/history.ts index 2635f8f2f1..967558d6bf 100644 --- a/special-pages/pages/history/types/history.ts +++ b/special-pages/pages/history/types/history.ts @@ -31,7 +31,8 @@ export type RangeId = | "friday" | "saturday" | "sunday" - | "older"; + | "older" + | "sites"; export type QueryKind = SearchTerm | DomainFilter | RangeFilter; /** * Indicates the query was triggered before the UI was rendered @@ -266,7 +267,7 @@ export interface HistoryItem { /** * The time of day in 24-hour format (e.g., '11:01'). */ - dateTimeOfDay: string; + dateTimeOfDay?: string; /** * The eTLD+1 version of the domain, representing the domain and its top-level domain (e.g., 'example.com', 'localhost'). This differs from 'domain', which may include subdomains (e.g., 'www.youtube.com'). */ diff --git a/special-pages/pages/new-tab/app/customizer/components/CustomizerDrawerInner.module.css b/special-pages/pages/new-tab/app/customizer/components/CustomizerDrawerInner.module.css index 0b5f187e72..1467f541b8 100644 --- a/special-pages/pages/new-tab/app/customizer/components/CustomizerDrawerInner.module.css +++ b/special-pages/pages/new-tab/app/customizer/components/CustomizerDrawerInner.module.css @@ -176,12 +176,10 @@ @keyframes fade-in { 0% { - opacity: 0; visibility: hidden; } 100% { - opacity: 1; visibility: visible; } } diff --git a/special-pages/pages/new-tab/app/next-steps/nextsteps.data.js b/special-pages/pages/new-tab/app/next-steps/nextsteps.data.js index 2746ef12cc..cac2f196e5 100644 --- a/special-pages/pages/new-tab/app/next-steps/nextsteps.data.js +++ b/special-pages/pages/new-tab/app/next-steps/nextsteps.data.js @@ -60,6 +60,14 @@ export const variants = { summary: t('nextSteps_pinAppToTaskbarWindows_summary'), actionText: t('nextSteps_pinAppToTaskbarWindows_actionText'), }), + /** @param {(translationId: keyof enStrings) => string} t */ + subscription: (t) => ({ + id: 'subscription', + icon: 'Subscription', + title: t('nextSteps_subscription_title'), + summary: t('nextSteps_subscription_summary'), + actionText: t('nextSteps_subscription_actionText'), + }), }; export const otherText = { diff --git a/special-pages/pages/new-tab/app/next-steps/strings.json b/special-pages/pages/new-tab/app/next-steps/strings.json index 24095660cd..3c5d9bbf7c 100644 --- a/special-pages/pages/new-tab/app/next-steps/strings.json +++ b/special-pages/pages/new-tab/app/next-steps/strings.json @@ -94,5 +94,17 @@ "nextSteps_pinAppToTaskbarWindows_confirmationText": { "title": "Pinned to Taskbar!", "note": "Button text after clicking on the Next Steps card for adding DDG app to OS dock" + }, + "nextSteps_subscription_title": { + "title": "Unlock Your Free Trial", + "note": "Title of the Next Steps card for unlocking your free trial of DuckDuckGo subscription" + }, + "nextSteps_subscription_summary": { + "title": "Try our subscription featuring a VPN + 3 more premium features.", + "note": "Summary of the Next Steps card about the DuckDuckGo subscription" + }, + "nextSteps_subscription_actionText": { + "title": "Try Free for 7 Days", + "note": "Button text of the Next Steps card for trying the DuckDuckGo subscription" } } diff --git a/special-pages/pages/new-tab/app/omnibar/components/SearchForm.module.css b/special-pages/pages/new-tab/app/omnibar/components/SearchForm.module.css index d17d2954e7..25732bb4c8 100644 --- a/special-pages/pages/new-tab/app/omnibar/components/SearchForm.module.css +++ b/special-pages/pages/new-tab/app/omnibar/components/SearchForm.module.css @@ -21,7 +21,7 @@ color: var(--ntp-text-tertiary); } - [data-platform="windows"] &::selection { + [data-platform='windows'] &::selection { background: var(--ntp-selection-background-color); color: var(--ntp-selection-color); } @@ -78,7 +78,13 @@ visibility: visible; } - [data-entry-point="omnibar"]:has([role="listbox"]) & { + [data-entry-point='omnibar']:has([role='listbox']) & { visibility: visible; } } + +[data-platform='windows'] { + .input { + line-height: normal; + } +} \ No newline at end of file diff --git a/special-pages/pages/new-tab/messages/types/next-steps.json b/special-pages/pages/new-tab/messages/types/next-steps.json index 36092e01e7..5db336cb51 100644 --- a/special-pages/pages/new-tab/messages/types/next-steps.json +++ b/special-pages/pages/new-tab/messages/types/next-steps.json @@ -30,7 +30,8 @@ "emailProtection", "duckplayer", "addAppToDockMac", - "pinAppToTaskbarWindows" + "pinAppToTaskbarWindows", + "subscription" ] } } @@ -39,4 +40,4 @@ ] } } -} \ No newline at end of file +} diff --git a/special-pages/pages/new-tab/public/icons/Subscription-128.svg b/special-pages/pages/new-tab/public/icons/Subscription-128.svg new file mode 100644 index 0000000000..9a163dafee --- /dev/null +++ b/special-pages/pages/new-tab/public/icons/Subscription-128.svg @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/special-pages/pages/new-tab/public/locales/de/new-tab.json b/special-pages/pages/new-tab/public/locales/de/new-tab.json index 50019c1679..40792553b1 100644 --- a/special-pages/pages/new-tab/public/locales/de/new-tab.json +++ b/special-pages/pages/new-tab/public/locales/de/new-tab.json @@ -296,6 +296,18 @@ "title" : "An die Taskleiste angeheftet!", "note" : "Button text after clicking on the Next Steps card for adding DDG app to OS dock" }, + "nextSteps_subscription_title" : { + "title" : "Schalte deine kostenlose Testversion frei", + "note" : "Title of the Next Steps card for unlocking your free trial of DuckDuckGo subscription" + }, + "nextSteps_subscription_summary" : { + "title" : "Teste unser Abonnement mit VPN + 3 weiteren Premium-Funktionen.", + "note" : "Summary of the Next Steps card about the DuckDuckGo subscription" + }, + "nextSteps_subscription_actionText" : { + "title" : "7 Tage lang kostenlos testen", + "note" : "Button text of the Next Steps card for trying the DuckDuckGo subscription" + }, "favorites_show_less" : { "title" : "Weniger anzeigen", "note" : "Button label to display fewer items" diff --git a/special-pages/pages/new-tab/public/locales/en/new-tab.json b/special-pages/pages/new-tab/public/locales/en/new-tab.json index 49f78a7ece..b5b40a40ac 100644 --- a/special-pages/pages/new-tab/public/locales/en/new-tab.json +++ b/special-pages/pages/new-tab/public/locales/en/new-tab.json @@ -297,6 +297,18 @@ "title": "Pinned to Taskbar!", "note": "Button text after clicking on the Next Steps card for adding DDG app to OS dock" }, + "nextSteps_subscription_title": { + "title": "Unlock Your Free Trial", + "note": "Title of the Next Steps card for unlocking your free trial of DuckDuckGo subscription" + }, + "nextSteps_subscription_summary": { + "title": "Try our subscription featuring a VPN + 3 more premium features.", + "note": "Summary of the Next Steps card about the DuckDuckGo subscription" + }, + "nextSteps_subscription_actionText": { + "title": "Try Free for 7 Days", + "note": "Button text of the Next Steps card for trying the DuckDuckGo subscription" + }, "favorites_show_less": { "title": "Show less", "note": "Button label to display fewer items" diff --git a/special-pages/pages/new-tab/public/locales/es/new-tab.json b/special-pages/pages/new-tab/public/locales/es/new-tab.json index 3fd8414ca9..241b894a3e 100644 --- a/special-pages/pages/new-tab/public/locales/es/new-tab.json +++ b/special-pages/pages/new-tab/public/locales/es/new-tab.json @@ -296,6 +296,18 @@ "title" : "¡Anclada a tu barra de tareas!", "note" : "Button text after clicking on the Next Steps card for adding DDG app to OS dock" }, + "nextSteps_subscription_title" : { + "title" : "Accede a tu prueba gratuita", + "note" : "Title of the Next Steps card for unlocking your free trial of DuckDuckGo subscription" + }, + "nextSteps_subscription_summary" : { + "title" : "Prueba nuestra suscripción con una VPN y 3 funciones prémium adicionales.", + "note" : "Summary of the Next Steps card about the DuckDuckGo subscription" + }, + "nextSteps_subscription_actionText" : { + "title" : "Prueba gratuita durante 7 días", + "note" : "Button text of the Next Steps card for trying the DuckDuckGo subscription" + }, "favorites_show_less" : { "title" : "Mostrar menos", "note" : "Button label to display fewer items" diff --git a/special-pages/pages/new-tab/public/locales/fr/new-tab.json b/special-pages/pages/new-tab/public/locales/fr/new-tab.json index 98954f26e2..b8891c105b 100644 --- a/special-pages/pages/new-tab/public/locales/fr/new-tab.json +++ b/special-pages/pages/new-tab/public/locales/fr/new-tab.json @@ -296,6 +296,18 @@ "title" : "Épinglée à la barre des tâches !", "note" : "Button text after clicking on the Next Steps card for adding DDG app to OS dock" }, + "nextSteps_subscription_title" : { + "title" : "Accédez à votre essai gratuit", + "note" : "Title of the Next Steps card for unlocking your free trial of DuckDuckGo subscription" + }, + "nextSteps_subscription_summary" : { + "title" : "Essayez notre abonnement comprenant un VPN + 3 fonctionnalités premium supplémentaires.", + "note" : "Summary of the Next Steps card about the DuckDuckGo subscription" + }, + "nextSteps_subscription_actionText" : { + "title" : "Essayez gratuitement pendant 7 jours", + "note" : "Button text of the Next Steps card for trying the DuckDuckGo subscription" + }, "favorites_show_less" : { "title" : "Réduire", "note" : "Button label to display fewer items" diff --git a/special-pages/pages/new-tab/public/locales/it/new-tab.json b/special-pages/pages/new-tab/public/locales/it/new-tab.json index 9bc834f3f4..99c524f04c 100644 --- a/special-pages/pages/new-tab/public/locales/it/new-tab.json +++ b/special-pages/pages/new-tab/public/locales/it/new-tab.json @@ -296,6 +296,18 @@ "title" : "Aggiunto alla barra delle applicazioni!", "note" : "Button text after clicking on the Next Steps card for adding DDG app to OS dock" }, + "nextSteps_subscription_title" : { + "title" : "Sblocca la tua prova gratuita", + "note" : "Title of the Next Steps card for unlocking your free trial of DuckDuckGo subscription" + }, + "nextSteps_subscription_summary" : { + "title" : "Prova il nostro abbonamento con una VPN + altre 3 funzionalità premium.", + "note" : "Summary of the Next Steps card about the DuckDuckGo subscription" + }, + "nextSteps_subscription_actionText" : { + "title" : "Prova gratis per 7 giorni", + "note" : "Button text of the Next Steps card for trying the DuckDuckGo subscription" + }, "favorites_show_less" : { "title" : "Mostra meno", "note" : "Button label to display fewer items" diff --git a/special-pages/pages/new-tab/public/locales/nl/new-tab.json b/special-pages/pages/new-tab/public/locales/nl/new-tab.json index 96adab6522..9fc40e0ef9 100644 --- a/special-pages/pages/new-tab/public/locales/nl/new-tab.json +++ b/special-pages/pages/new-tab/public/locales/nl/new-tab.json @@ -296,6 +296,18 @@ "title" : "Vastgemaakt aan de taakbalk!", "note" : "Button text after clicking on the Next Steps card for adding DDG app to OS dock" }, + "nextSteps_subscription_title" : { + "title" : "Ontgrendel je gratis proefperiode", + "note" : "Title of the Next Steps card for unlocking your free trial of DuckDuckGo subscription" + }, + "nextSteps_subscription_summary" : { + "title" : "Probeer ons abonnement met een VPN en nog drie extra premiumfuncties.", + "note" : "Summary of the Next Steps card about the DuckDuckGo subscription" + }, + "nextSteps_subscription_actionText" : { + "title" : "Probeer 7 dagen gratis", + "note" : "Button text of the Next Steps card for trying the DuckDuckGo subscription" + }, "favorites_show_less" : { "title" : "Minder weergeven", "note" : "Button label to display fewer items" diff --git a/special-pages/pages/new-tab/public/locales/pl/new-tab.json b/special-pages/pages/new-tab/public/locales/pl/new-tab.json index b214407ac1..d048f347f6 100644 --- a/special-pages/pages/new-tab/public/locales/pl/new-tab.json +++ b/special-pages/pages/new-tab/public/locales/pl/new-tab.json @@ -296,6 +296,18 @@ "title" : "Przypięto do paska zadań!", "note" : "Button text after clicking on the Next Steps card for adding DDG app to OS dock" }, + "nextSteps_subscription_title" : { + "title" : "Rozpocznij darmowy okres próbny", + "note" : "Title of the Next Steps card for unlocking your free trial of DuckDuckGo subscription" + }, + "nextSteps_subscription_summary" : { + "title" : "Wypróbuj subskrypcję obejmującą sieć VPN i 3 inne funkcje premium.", + "note" : "Summary of the Next Steps card about the DuckDuckGo subscription" + }, + "nextSteps_subscription_actionText" : { + "title" : "Wypróbuj za darmo przez 7 dni", + "note" : "Button text of the Next Steps card for trying the DuckDuckGo subscription" + }, "favorites_show_less" : { "title" : "Pokaż mniej", "note" : "Button label to display fewer items" diff --git a/special-pages/pages/new-tab/public/locales/pt/new-tab.json b/special-pages/pages/new-tab/public/locales/pt/new-tab.json index de6e71ccc3..e3a50afdc5 100644 --- a/special-pages/pages/new-tab/public/locales/pt/new-tab.json +++ b/special-pages/pages/new-tab/public/locales/pt/new-tab.json @@ -296,6 +296,18 @@ "title" : "Afixado na barra de tarefas!", "note" : "Button text after clicking on the Next Steps card for adding DDG app to OS dock" }, + "nextSteps_subscription_title" : { + "title" : "Desbloqueia a tua avaliação gratuita", + "note" : "Title of the Next Steps card for unlocking your free trial of DuckDuckGo subscription" + }, + "nextSteps_subscription_summary" : { + "title" : "Experimenta a nossa subscrição com uma VPN + 3 funcionalidades premium adicionais.", + "note" : "Summary of the Next Steps card about the DuckDuckGo subscription" + }, + "nextSteps_subscription_actionText" : { + "title" : "Experimentar grátis durante 7 dias", + "note" : "Button text of the Next Steps card for trying the DuckDuckGo subscription" + }, "favorites_show_less" : { "title" : "Mostrar menos", "note" : "Button label to display fewer items" diff --git a/special-pages/pages/new-tab/public/locales/ru/new-tab.json b/special-pages/pages/new-tab/public/locales/ru/new-tab.json index b1905972fe..5577c14398 100644 --- a/special-pages/pages/new-tab/public/locales/ru/new-tab.json +++ b/special-pages/pages/new-tab/public/locales/ru/new-tab.json @@ -296,6 +296,18 @@ "title" : "Закреплено на панели задач!", "note" : "Button text after clicking on the Next Steps card for adding DDG app to OS dock" }, + "nextSteps_subscription_title" : { + "title" : "Получите бесплатную пробную версию", + "note" : "Title of the Next Steps card for unlocking your free trial of DuckDuckGo subscription" + }, + "nextSteps_subscription_summary" : { + "title" : "Попробуйте нашу подписку, включающую VPN и еще 3 премиум-функции.", + "note" : "Summary of the Next Steps card about the DuckDuckGo subscription" + }, + "nextSteps_subscription_actionText" : { + "title" : "Пробная версия на 7 дней", + "note" : "Button text of the Next Steps card for trying the DuckDuckGo subscription" + }, "favorites_show_less" : { "title" : "Показать меньше результатов", "note" : "Button label to display fewer items" @@ -444,4 +456,4 @@ "title" : "Свернуть", "note" : "Button label that hides the expanded browsing history items." } -} +} \ No newline at end of file diff --git a/special-pages/pages/new-tab/readme.md b/special-pages/pages/new-tab/readme.md index 35d116338f..d0b7853414 100644 --- a/special-pages/pages/new-tab/readme.md +++ b/special-pages/pages/new-tab/readme.md @@ -121,6 +121,28 @@ - **Example**: `?rmf-delay=10000` - **Options**: Time in milliseconds + ### Next Steps Cards + - **Purpose**: Displays the different Next Steps cards + - **Parameter**: `next-steps` + - **Example**: `?next-steps=bringStuff` + - **Options**: + - `bringStuff` + - `defaultApp` + - `blockCookies` + - `emailProtection` + - `duckplayer` + - `addAppToDockMac` + - `pinAppToTaskbarWindows` + - `subscription` + + ### Freemium PIR Banner + - **Purpose**: Tests different PIR banner states + - **Parameter**: `pir` + - **Example**: `?pir=onboarding` + - **Options**: + - `onboarding` - Shows onboarding PIR banner + - `scan_results` - Shows scan results PIR banner + ## Privacy Protections widget ### Activity @@ -170,15 +192,7 @@ - **Options**: Any positive integer - ## Experiment Parameters - ### Freemium PIR Banner - - **Purpose**: Tests different PIR banner states - - **Parameter**: `pir` - - **Example**: `?pir=onboarding` - - **Options**: - - `onboarding` - Shows onboarding PIR banner - - `scan_results` - Shows scan results PIR banner ### Subscription Win-back Banner - **Purpose**: Tests different win-back banner states diff --git a/special-pages/pages/new-tab/types/new-tab.ts b/special-pages/pages/new-tab/types/new-tab.ts index 41205f9521..560fc8bd02 100644 --- a/special-pages/pages/new-tab/types/new-tab.ts +++ b/special-pages/pages/new-tab/types/new-tab.ts @@ -93,7 +93,8 @@ export type NextStepsCardTypes = | "emailProtection" | "duckplayer" | "addAppToDockMac" - | "pinAppToTaskbarWindows"; + | "pinAppToTaskbarWindows" + | "subscription"; export type NextStepsCards = { id: NextStepsCardTypes; }[]; diff --git a/types-generator/package.json b/types-generator/package.json index c14fc7a885..15973a4cbe 100644 --- a/types-generator/package.json +++ b/types-generator/package.json @@ -9,6 +9,6 @@ }, "devDependencies": { "jasmine": "^5.12.0", - "@types/jasmine": "^5.1.9" + "@types/jasmine": "^5.1.12" } }