UNPKG

chrome-devtools-frontend

Version:
133 lines (113 loc) 4.96 kB
// Copyright 2026 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import * as Host from '../../../core/host/host.js'; import * as i18n from '../../../core/i18n/i18n.js'; import * as SDK from '../../../core/sdk/sdk.js'; import {bytes} from '../data_formatters/UnitFormatters.js'; import {getCookiesForOrigin, resolveAllowedTargetOrigins} from './CookieUtils.js'; import {calculateDOMStoragesUsage, resolveDOMStorages} from './DOMStorageUtils.js'; import { type BaseToolCapability, type DataHandlerResult, type DataTool, type OriginLockCapability, ToolName, } from './Tool.js'; const lockedString = i18n.i18n.lockedString; export interface StorageBreakdownEntry { storageType: string; usage: string; } export interface GetStorageBreakdownResult { usageBreakdown: StorageBreakdownEntry[]; } export class GetStorageBreakdownTool implements DataTool<Record<string, never>, GetStorageBreakdownResult, BaseToolCapability&OriginLockCapability> { readonly name: ToolName = ToolName.GET_STORAGE_BREAKDOWN; readonly description: string = 'Retrieves total storage usage and quota breakdown across all storage types (IndexedDB, CacheStorage, LocalStorage, SessionStorage, cookies) for the top-level page origin.'; readonly parameters: Host.AidaClient.FunctionObjectParam<never> = { type: Host.AidaClient.ParametersTypes.OBJECT, description: '', nullable: false, properties: {}, required: [], }; displayInfoFromArgs(): { title: string, action: string, } { return { title: lockedString('Retrieving storage breakdown'), action: 'getStorageBreakdown()', }; } async handler( _args: Record<string, never>, context: BaseToolCapability&OriginLockCapability, ): Promise<DataHandlerResult<GetStorageBreakdownResult>> { // eslint-disable-next-line @devtools/no-instance-of-migrated-singletons const targetManager = SDK.TargetManager.TargetManager.instance(); const targetResolution = resolveAllowedTargetOrigins(undefined, context, targetManager); if ('error' in targetResolution) { return {error: targetResolution.error}; } const {targetOrigins, primaryPageTarget} = targetResolution; const pageOrigin = targetOrigins[0]; const mainStorageKey = primaryPageTarget.model(SDK.StorageKeyManager.StorageKeyManager)?.mainStorageKey() || undefined; const localStorages = resolveDOMStorages(pageOrigin, 'localStorage', targetManager, primaryPageTarget, mainStorageKey); const sessionStorages = resolveDOMStorages(pageOrigin, 'sessionStorage', targetManager, primaryPageTarget, mainStorageKey); const [response, localStorageBytes, sessionStorageBytes, cookieResult] = await Promise.all([ primaryPageTarget.storageAgent().invoke_getUsageAndQuota({origin: pageOrigin}), calculateDOMStoragesUsage(localStorages), calculateDOMStoragesUsage(sessionStorages), getCookiesForOrigin(pageOrigin, targetManager, primaryPageTarget), ]); if (response.getError()) { return {error: response.getError() || 'Unknown CDP error'}; } let cookieBytes = 0; if ('cookies' in cookieResult) { for (const cookie of cookieResult.cookies) { cookieBytes += cookie.size(); } } const rawUsageBreakdown: Array<{storageType: string, rawUsage: number}> = (response.usageBreakdown ?? []).filter(entry => entry.usage > 0).map(entry => ({ storageType: entry.storageType, rawUsage: entry.usage, })); rawUsageBreakdown.push( {storageType: 'local_storage', rawUsage: localStorageBytes}, {storageType: 'session_storage', rawUsage: sessionStorageBytes}, {storageType: 'cookies', rawUsage: cookieBytes}, ); rawUsageBreakdown.sort((a, b) => b.rawUsage - a.rawUsage); const usageBreakdown = rawUsageBreakdown.map(entry => ({ storageType: entry.storageType, usage: bytes(entry.rawUsage), })); return { result: { usageBreakdown, }, widgets: [ { name: 'STORAGE_BREAKDOWN', data: { totalUsageBytes: response.usage, totalQuotaBytes: response.quota, usageBreakdown: rawUsageBreakdown.map(entry => ({ storageType: entry.storageType, bytes: entry.rawUsage, })), }, }, ], }; } }