From 2fb2a2dfa0ec66e19142f5d11a59cbeadb4a295f Mon Sep 17 00:00:00 2001 From: Stefan Zabka Date: Thu, 23 Nov 2023 10:18:16 +0100 Subject: [PATCH] refactor(Extension): type cleanup (#1069) * refactor(Extension): remove redundant type declarations * refactor(Extension): define privileged interfaces in TS --- Extension/src/background/dns-instrument.ts | 7 +- Extension/src/background/http-instrument.ts | 49 ++--- Extension/src/callstack-instrument.ts | 4 +- Extension/src/feature.ts | 12 +- Extension/src/lib/http-post-parser.ts | 5 +- Extension/src/lib/pending-request.ts | 9 +- Extension/src/lib/pending-response.ts | 14 +- Extension/src/lib/response-body-listener.ts | 3 +- Extension/src/loggingdb.ts | 8 +- Extension/src/socket.ts | 29 ++- .../browser-web-request-event-details.ts | 179 +----------------- Extension/src/types/browser.d.ts | 28 +++ Extension/src/types/window.unimplemented.d.ts | 15 -- 13 files changed, 98 insertions(+), 264 deletions(-) create mode 100644 Extension/src/types/browser.d.ts delete mode 100644 Extension/src/types/window.unimplemented.d.ts diff --git a/Extension/src/background/dns-instrument.ts b/Extension/src/background/dns-instrument.ts index 57ca4109c..bf3dae4d1 100755 --- a/Extension/src/background/dns-instrument.ts +++ b/Extension/src/background/dns-instrument.ts @@ -1,6 +1,5 @@ import { PendingResponse } from "../lib/pending-response"; import { DnsResolved } from "../schema"; -import { WebRequestOnCompletedEventDetails } from "../types/browser-web-request-event-details"; import { allTypes } from "./http-instrument"; import RequestFilter = browser.webRequest.RequestFilter; @@ -29,7 +28,9 @@ export class DnsInstrument { /* * Attach handlers to event listeners */ - this.onCompleteListener = (details: WebRequestOnCompletedEventDetails) => { + this.onCompleteListener = ( + details: browser.webRequest._OnCompletedDetails, + ) => { // Ignore requests made by extensions if (requestStemsFromExtension(details)) { return; @@ -70,7 +71,7 @@ export class DnsInstrument { } private async onCompleteDnsHandler( - details: WebRequestOnCompletedEventDetails, + details: browser.webRequest._OnCompletedDetails, crawlID, ) { // Create and populate DnsResolve object diff --git a/Extension/src/background/http-instrument.ts b/Extension/src/background/http-instrument.ts index a41572bb4..86fcb2955 100644 --- a/Extension/src/background/http-instrument.ts +++ b/Extension/src/background/http-instrument.ts @@ -5,12 +5,7 @@ import { PendingRequest } from "../lib/pending-request"; import { PendingResponse } from "../lib/pending-response"; import { boolToInt, escapeString, escapeUrl } from "../lib/string-utils"; import { HttpRedirect, HttpRequest, HttpResponse } from "../schema"; -import { - WebRequestOnBeforeRedirectEventDetails, - WebRequestOnBeforeRequestEventDetails, - WebRequestOnBeforeSendHeadersEventDetails, - WebRequestOnCompletedEventDetails, -} from "../types/browser-web-request-event-details"; +import { WebRequestOnBeforeSendHeadersEventDetails } from "../types/browser-web-request-event-details"; import ResourceType = browser.webRequest.ResourceType; import RequestFilter = browser.webRequest.RequestFilter; import BlockingResponse = browser.webRequest.BlockingResponse; @@ -52,23 +47,31 @@ const allTypes: ResourceType[] = [ export { allTypes }; export class HttpInstrument { - private readonly dataReceiver; + private readonly dataReceiver: typeof import("../loggingdb"); private pendingRequests: { - [requestId: number]: PendingRequest; + [requestId: string]: PendingRequest; } = {}; private pendingResponses: { - [requestId: number]: PendingResponse; + [requestId: string]: PendingResponse; } = {}; - private onBeforeRequestListener; - private onBeforeSendHeadersListener; - private onBeforeRedirectListener; - private onCompletedListener; - - constructor(dataReceiver) { + private onBeforeRequestListener: ( + details: browser.webRequest._OnBeforeRequestDetails, + ) => BlockingResponse; + private onBeforeSendHeadersListener: ( + details: WebRequestOnBeforeSendHeadersEventDetails, + ) => void; + private onBeforeRedirectListener: ( + details: browser.webRequest._OnBeforeRedirectDetails, + ) => void; + private onCompletedListener: ( + details: browser.webRequest._OnCompletedDetails, + ) => void; + + constructor(dataReceiver: typeof import("../loggingdb")) { this.dataReceiver = dataReceiver; } - public run(crawlID, saveContentOption: SaveContentOption) { + public run(crawlID: number, saveContentOption: SaveContentOption) { const filter: RequestFilter = { urls: [""], types: allTypes }; const requestStemsFromExtension = (details) => { @@ -82,7 +85,7 @@ export class HttpInstrument { */ this.onBeforeRequestListener = ( - details: WebRequestOnBeforeRequestEventDetails, + details: browser.webRequest._OnBeforeRequestDetails, ) => { const blockingResponseThatDoesNothing: BlockingResponse = {}; // Ignore requests made by extensions @@ -216,14 +219,14 @@ export class HttpInstrument { ); } - private getPendingRequest(requestId): PendingRequest { + private getPendingRequest(requestId: string): PendingRequest { if (!this.pendingRequests[requestId]) { this.pendingRequests[requestId] = new PendingRequest(); } return this.pendingRequests[requestId]; } - private getPendingResponse(requestId): PendingResponse { + private getPendingResponse(requestId: string): PendingResponse { if (!this.pendingResponses[requestId]) { this.pendingResponses[requestId] = new PendingResponse(); } @@ -236,7 +239,7 @@ export class HttpInstrument { private async onBeforeSendHeadersHandler( details: WebRequestOnBeforeSendHeadersEventDetails, - crawlID, + crawlID: number, eventOrdinal: number, ) { const tab = @@ -460,7 +463,7 @@ export class HttpInstrument { } private async onBeforeRedirectHandler( - details: WebRequestOnBeforeRedirectEventDetails, + details: browser.webRequest._OnBeforeRedirectDetails, crawlID, eventOrdinal: number, ) { @@ -569,7 +572,7 @@ export class HttpInstrument { */ private async logWithResponseBody( - details: WebRequestOnBeforeRequestEventDetails, + details: browser.webRequest._OnBeforeRequestDetails, update: HttpResponse, ) { const pendingResponse = this.getPendingResponse(details.requestId); @@ -604,7 +607,7 @@ export class HttpInstrument { // Instrument HTTP responses private async onCompletedHandler( - details: WebRequestOnCompletedEventDetails, + details: browser.webRequest._OnCompletedDetails, crawlID, eventOrdinal, saveContent, diff --git a/Extension/src/callstack-instrument.ts b/Extension/src/callstack-instrument.ts index f8665ece8..86b73c040 100644 --- a/Extension/src/callstack-instrument.ts +++ b/Extension/src/callstack-instrument.ts @@ -5,10 +5,10 @@ */ export class CallstackInstrument { dataReceiver: any; - constructor(dataReceiver) { + constructor(dataReceiver: typeof import("./loggingdb")) { this.dataReceiver = dataReceiver; } - run(browser_id) { + run(browser_id: number) { (browser as any).stackDump.onStackAvailable.addListener( (request_id, call_stack) => { const record = { diff --git a/Extension/src/feature.ts b/Extension/src/feature.ts index 1c001b684..e972671b5 100644 --- a/Extension/src/feature.ts +++ b/Extension/src/feature.ts @@ -11,9 +11,10 @@ import { CallstackInstrument } from "./callstack-instrument"; async function main() { // Read the browser configuration from file const filename = "browser_params.json"; - let config = await (browser as any).profileDirIO.readFile(filename); - if (config) { - config = JSON.parse(config); + const raw_config = await browser.profileDirIO.readFile(filename); + let config: any; + if (raw_config) { + config = JSON.parse(raw_config); console.log("Browser Config:", config); } else { config = { @@ -100,10 +101,7 @@ async function main() { dnsInstrument.run(config.browser_id); } - await (browser as any).profileDirIO.writeFile( - "OPENWPM_STARTUP_SUCCESS.txt", - "", - ); + await browser.profileDirIO.writeFile("OPENWPM_STARTUP_SUCCESS.txt", ""); } main(); diff --git a/Extension/src/lib/http-post-parser.ts b/Extension/src/lib/http-post-parser.ts index 6b70950ff..f081598f5 100644 --- a/Extension/src/lib/http-post-parser.ts +++ b/Extension/src/lib/http-post-parser.ts @@ -1,4 +1,3 @@ -import { WebRequestOnBeforeRequestEventDetails } from "../types/browser-web-request-event-details"; import { escapeString, Uint8ToBase64 } from "./string-utils"; export interface ParsedPostRequest { @@ -8,11 +7,11 @@ export interface ParsedPostRequest { } export class HttpPostParser { - private readonly onBeforeRequestEventDetails: WebRequestOnBeforeRequestEventDetails; + private readonly onBeforeRequestEventDetails: browser.webRequest._OnBeforeRequestDetails; private readonly dataReceiver; constructor( - onBeforeRequestEventDetails: WebRequestOnBeforeRequestEventDetails, + onBeforeRequestEventDetails: browser.webRequest._OnBeforeRequestDetails, dataReceiver, ) { this.onBeforeRequestEventDetails = onBeforeRequestEventDetails; diff --git a/Extension/src/lib/pending-request.ts b/Extension/src/lib/pending-request.ts index 0a2fd81e4..ce76e4f54 100644 --- a/Extension/src/lib/pending-request.ts +++ b/Extension/src/lib/pending-request.ts @@ -1,16 +1,13 @@ -import { - WebRequestOnBeforeRequestEventDetails, - WebRequestOnBeforeSendHeadersEventDetails, -} from "../types/browser-web-request-event-details"; +import { WebRequestOnBeforeSendHeadersEventDetails } from "../types/browser-web-request-event-details"; /** * Ties together the two separate events that together holds information about both request headers and body */ export class PendingRequest { - public readonly onBeforeRequestEventDetails: Promise; + public readonly onBeforeRequestEventDetails: Promise; public readonly onBeforeSendHeadersEventDetails: Promise; public resolveOnBeforeRequestEventDetails: ( - details: WebRequestOnBeforeRequestEventDetails, + details: browser.webRequest._OnBeforeRequestDetails, ) => void; public resolveOnBeforeSendHeadersEventDetails: ( details: WebRequestOnBeforeSendHeadersEventDetails, diff --git a/Extension/src/lib/pending-response.ts b/Extension/src/lib/pending-response.ts index d78506810..8cf7c242f 100644 --- a/Extension/src/lib/pending-response.ts +++ b/Extension/src/lib/pending-response.ts @@ -1,21 +1,17 @@ -import { - WebRequestOnBeforeRequestEventDetails, - WebRequestOnCompletedEventDetails, -} from "../types/browser-web-request-event-details"; import { ResponseBodyListener } from "./response-body-listener"; /** * Ties together the two separate events that together holds information about both response headers and body */ export class PendingResponse { - public readonly onBeforeRequestEventDetails: Promise; - public readonly onCompletedEventDetails: Promise; + public readonly onBeforeRequestEventDetails: Promise; + public readonly onCompletedEventDetails: Promise; public responseBodyListener: ResponseBodyListener; public resolveOnBeforeRequestEventDetails: ( - details: WebRequestOnBeforeRequestEventDetails, + details: browser.webRequest._OnBeforeRequestDetails, ) => void; public resolveOnCompletedEventDetails: ( - details: WebRequestOnCompletedEventDetails, + details: browser.webRequest._OnCompletedDetails, ) => void; constructor() { this.onBeforeRequestEventDetails = new Promise((resolve) => { @@ -26,7 +22,7 @@ export class PendingResponse { }); } public addResponseResponseBodyListener( - details: WebRequestOnBeforeRequestEventDetails, + details: browser.webRequest._OnBeforeRequestDetails, ) { this.responseBodyListener = new ResponseBodyListener(details); } diff --git a/Extension/src/lib/response-body-listener.ts b/Extension/src/lib/response-body-listener.ts index 72cb37e92..cac772d14 100644 --- a/Extension/src/lib/response-body-listener.ts +++ b/Extension/src/lib/response-body-listener.ts @@ -1,4 +1,3 @@ -import { WebRequestOnBeforeRequestEventDetails } from "../types/browser-web-request-event-details"; import { digestMessage } from "./sha256"; export class ResponseBodyListener { @@ -7,7 +6,7 @@ export class ResponseBodyListener { private resolveResponseBody: (responseBody: Uint8Array) => void; private resolveContentHash: (contentHash: string) => void; - constructor(details: WebRequestOnBeforeRequestEventDetails) { + constructor(details: browser.webRequest._OnBeforeRequestDetails) { this.responseBody = new Promise((resolve) => { this.resolveResponseBody = resolve; }); diff --git a/Extension/src/loggingdb.ts b/Extension/src/loggingdb.ts index 9f8512f82..38409d63d 100644 --- a/Extension/src/loggingdb.ts +++ b/Extension/src/loggingdb.ts @@ -43,9 +43,9 @@ const listeningSocketCallback = async (data) => { } }; export const open = async function ( - storageControllerAddress, - logAddress, - curr_crawlID, + storageControllerAddress: any[], + logAddress: any[], + curr_crawlID: number, ) { if ( storageControllerAddress == null && @@ -81,7 +81,7 @@ export const open = async function ( listeningSocket = new socket.ListeningSocket(listeningSocketCallback); console.log("Starting socket listening for incoming connections."); await listeningSocket.startListening().then(() => { - (browser as any).profileDirIO.writeFile( + browser.profileDirIO.writeFile( "extension_port.txt", `${listeningSocket.port}`, ); diff --git a/Extension/src/socket.ts b/Extension/src/socket.ts index c4bcb679e..6d16aa5c9 100644 --- a/Extension/src/socket.ts +++ b/Extension/src/socket.ts @@ -1,7 +1,8 @@ /* eslint-disable max-classes-per-file */ + const DataReceiver = { callbacks: new Map(), - onDataReceived: (aSocketId, aData, aJSON) => { + onDataReceived: (aSocketId: number, aData: string, aJSON: boolean): void => { if (!DataReceiver.callbacks.has(aSocketId)) { return; } @@ -12,37 +13,35 @@ const DataReceiver = { }, }; -(browser as any).sockets.onDataReceived.addListener( - DataReceiver.onDataReceived, -); +browser.sockets.onDataReceived.addListener(DataReceiver.onDataReceived); export class ListeningSocket { callback: any; - port: any; + port: number; constructor(callback) { this.callback = callback; } async startListening() { - this.port = await (browser as any).sockets.createServerSocket(); + this.port = await browser.sockets.createServerSocket(); DataReceiver.callbacks.set(this.port, this.callback); - (browser as any).sockets.startListening(this.port); + browser.sockets.startListening(this.port); console.log("Listening on port " + this.port); } } export class SendingSocket { - id: any; + id: number; - async connect(host, port) { - this.id = await (browser as any).sockets.createSendingSocket(); - (browser as any).sockets.connect(this.id, host, port); + async connect(host: string, port: number) { + this.id = await browser.sockets.createSendingSocket(); + browser.sockets.connect(this.id, host, port); console.log(`Connected to ${host}:${port}`); } - send(aData, aJSON = true) { + send(aData: string, aJSON = true): boolean { try { - (browser as any).sockets.sendData(this.id, aData, !!aJSON); + browser.sockets.sendData(this.id, aData, !!aJSON); return true; } catch (err) { console.error(err, err.message); @@ -50,7 +49,7 @@ export class SendingSocket { } } - close() { - (browser as any).sockets.close(this.id); + close(): void { + browser.sockets.close(this.id); } } diff --git a/Extension/src/types/browser-web-request-event-details.ts b/Extension/src/types/browser-web-request-event-details.ts index 20c36173a..febaaf557 100644 --- a/Extension/src/types/browser-web-request-event-details.ts +++ b/Extension/src/types/browser-web-request-event-details.ts @@ -1,191 +1,20 @@ +/* eslint-disable no-underscore-dangle */ + /** * This file contains selected implicit interfaces copied from node_modules/@types/firefox-webext-browser/index.d.ts * Defined and exported here in order for our code to be able to reference them explicitly in helper functions * and class methods that accept arguments of these types. */ -import ResourceType = browser.webRequest.ResourceType; -import UploadData = browser.webRequest.UploadData; -import HttpHeaders = browser.webRequest.HttpHeaders; - export interface FrameAncestor { /** The URL that the document was loaded from. */ url: string; /** The frameId of the document. details.frameAncestors[0].frameId is the same as details.parentFrameId. */ frameId: number; - 0; } -export interface WebRequestOnBeforeSendHeadersEventDetails { - /** - * The ID of the request. Request IDs are unique within a browser session. As a result, they could be used to - * relate different events of the same request. - */ - requestId: string; - url: string; - /** Standard HTTP method. */ - method: string; - /** - * The value 0 indicates that the request happens in the main frame; a positive value indicates the ID of a - * subframe in which the request happens. If the document of a (sub-)frame is loaded (`type` is `main_frame` or - * `sub_frame`), `frameId` indicates the ID of this frame, not the ID of the outer frame. Frame IDs are unique - * within a tab. - */ - frameId: number; - /** ID of frame that wraps the frame which sent the request. Set to -1 if no parent frame exists. */ - parentFrameId: number; +export interface WebRequestOnBeforeSendHeadersEventDetails + extends browser.webRequest._OnBeforeSendHeadersDetails { /** Contains information for each document in the frame hierarchy up to the top-level document. The first element in the array contains information about the immediate parent of the document being requested, and the last element contains information about the top-level document. If the load is actually for the top-level document, then this array is empty. */ frameAncestors: FrameAncestor[]; - /** URL of the resource that triggered this request. */ - originUrl?: string; - /** URL of the page into which the requested resource will be loaded. */ - documentUrl?: string; - /** The ID of the tab in which the request takes place. Set to -1 if the request isn't related to a tab. */ - tabId: number; - /** How the requested resource will be used. */ - type: ResourceType; - /** The time when this signal is triggered, in milliseconds since the epoch. */ - timeStamp: number; - /** The HTTP request headers that are going to be sent out with this request. */ - requestHeaders?: HttpHeaders; -} - -export interface WebRequestOnBeforeRequestEventDetails { - /** - * The ID of the request. Request IDs are unique within a browser session. As a result, they could be used to - * relate different events of the same request. - */ - requestId: string; - url: string; - /** Standard HTTP method. */ - method: string; - /** - * The value 0 indicates that the request happens in the main frame; a positive value indicates the ID of a - * subframe in which the request happens. If the document of a (sub-)frame is loaded (`type` is `main_frame` or - * `sub_frame`), `frameId` indicates the ID of this frame, not the ID of the outer frame. Frame IDs are unique - * within a tab. - */ - frameId: number; - /** ID of frame that wraps the frame which sent the request. Set to -1 if no parent frame exists. */ - parentFrameId: number; - /** URL of the resource that triggered this request. */ - originUrl?: string; - /** URL of the page into which the requested resource will be loaded. */ - documentUrl?: string; - /** Contains the HTTP request body data. Only provided if extraInfoSpec contains 'requestBody'. */ - requestBody?: { - /** Errors when obtaining request body data. */ - error?: string; - /** - * If the request method is POST and the body is a sequence of key-value pairs encoded in UTF8, encoded as - * either multipart/form-data, or application/x-www-form-urlencoded, this dictionary is present and for - * each key contains the list of all values for that key. If the data is of another media type, or if it is - * malformed, the dictionary is not present. An example value of this dictionary is {'key': ['value1', - * 'value2']}. - */ - formData?: object; - /** - * If the request method is PUT or POST, and the body is not already parsed in formData, then the unparsed - * request body elements are contained in this array. - */ - raw?: UploadData[]; - }; - /** The ID of the tab in which the request takes place. Set to -1 if the request isn't related to a tab. */ - tabId: number; - /** How the requested resource will be used. */ - type: ResourceType; - /** The time when this signal is triggered, in milliseconds since the epoch. */ - timeStamp: number; -} - -export interface WebRequestOnBeforeRedirectEventDetails { - /** - * The ID of the request. Request IDs are unique within a browser session. As a result, they could be used to - * relate different events of the same request. - */ - requestId: string; - url: string; - /** Standard HTTP method. */ - method: string; - /** - * The value 0 indicates that the request happens in the main frame; a positive value indicates the ID of a - * subframe in which the request happens. If the document of a (sub-)frame is loaded (`type` is `main_frame` or - * `sub_frame`), `frameId` indicates the ID of this frame, not the ID of the outer frame. Frame IDs are unique - * within a tab. - */ - frameId: number; - /** ID of frame that wraps the frame which sent the request. Set to -1 if no parent frame exists. */ - parentFrameId: number; - /** URL of the resource that triggered this request. */ - originUrl?: string; - /** URL of the page into which the requested resource will be loaded. */ - documentUrl?: string; - /** The ID of the tab in which the request takes place. Set to -1 if the request isn't related to a tab. */ - tabId: number; - /** How the requested resource will be used. */ - type: ResourceType; - /** The time when this signal is triggered, in milliseconds since the epoch. */ - timeStamp: number; - /** - * The server IP address that the request was actually sent to. Note that it may be a literal IPv6 address. - */ - ip?: string; - /** Indicates if this response was fetched from disk cache. */ - fromCache: boolean; - /** Standard HTTP status code returned by the server. */ - statusCode: number; - /** The new URL. */ - redirectUrl: string; - /** The HTTP response headers that were received along with this redirect. */ - responseHeaders?: HttpHeaders; - /** - * HTTP status line of the response or the 'HTTP/0.9 200 OK' string for HTTP/0.9 responses (i.e., responses - * that lack a status line) or an empty string if there are no headers. - */ - statusLine: string; -} - -export interface WebRequestOnCompletedEventDetails { - /** - * The ID of the request. Request IDs are unique within a browser session. As a result, they could be used to - * relate different events of the same request. - */ - requestId: string; - url: string; - /** Standard HTTP method. */ - method: string; - /** - * The value 0 indicates that the request happens in the main frame; a positive value indicates the ID of a - * subframe in which the request happens. If the document of a (sub-)frame is loaded (`type` is `main_frame` or - * `sub_frame`), `frameId` indicates the ID of this frame, not the ID of the outer frame. Frame IDs are unique - * within a tab. - */ - frameId: number; - /** ID of frame that wraps the frame which sent the request. Set to -1 if no parent frame exists. */ - parentFrameId: number; - /** URL of the resource that triggered this request. */ - originUrl?: string; - /** URL of the page into which the requested resource will be loaded. */ - documentUrl?: string; - /** The ID of the tab in which the request takes place. Set to -1 if the request isn't related to a tab. */ - tabId: number; - /** How the requested resource will be used. */ - type: ResourceType; - /** The time when this signal is triggered, in milliseconds since the epoch. */ - timeStamp: number; - /** - * The server IP address that the request was actually sent to. Note that it may be a literal IPv6 address. - */ - ip?: string; - /** Indicates if this response was fetched from disk cache. */ - fromCache: boolean; - /** Standard HTTP status code returned by the server. */ - statusCode: number; - /** The HTTP response headers that were received along with this response. */ - responseHeaders?: HttpHeaders; - /** - * HTTP status line of the response or the 'HTTP/0.9 200 OK' string for HTTP/0.9 responses (i.e., responses - * that lack a status line) or an empty string if there are no headers. - */ - statusLine: string; } diff --git a/Extension/src/types/browser.d.ts b/Extension/src/types/browser.d.ts new file mode 100644 index 000000000..1286d9e3d --- /dev/null +++ b/Extension/src/types/browser.d.ts @@ -0,0 +1,28 @@ +declare namespace browser.profileDirIO { + export function readFile(filename: string): Promise; + export function writeFile(filename: string, content: string): void; +} + +declare namespace browser.sockets { + export const onDataReceived: { + addListener( + receiver: (socketId: number, data: string, isJson: boolean) => void, + ): void; + }; + export type ServerSocketId = number; + export function createServerSocket(): Promise; + export function startListening(id: ServerSocketId): void; + export type SendingSocketId = number; + export function createSendingSocket(): Promise; + export function connect( + id: SendingSocketId, + host: string, + port: number, + ): void; + export function sendData( + id: SendingSocketId, + data: string, + json: boolean, + ): void; + export function close(id: SendingSocketId | ServerSocketId): void; +} diff --git a/Extension/src/types/window.unimplemented.d.ts b/Extension/src/types/window.unimplemented.d.ts deleted file mode 100644 index 6d9135b91..000000000 --- a/Extension/src/types/window.unimplemented.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -export {}; // this file needs to be a module -declare global { - interface Window { - Storage: any; - HTMLCanvasElement: any; - CanvasRenderingContext2D: any; - RTCPeerConnection: any; - AudioContext: any; - OfflineAudioContext: any; - OscillatorNode: any; - AnalyserNode: any; - GainNode: any; - ScriptProcessorNode: any; - } -}