[7.x] [Reporting] Define shims of legacy dependencies (#54082) (#55134)

* [Reporting] Define shims of legacy dependencies (#54082)

* simplify serverfacade definition

* simplify requestfacade definition

* use the shim

* makeRequestFacade

* requestFacade

* import sorting

* originalServer

* reduce loc change

* remove consolelog

* hacks to fix tests

* ServerFacade in index

* Cosmetic

* remove field from serverfacade

* add raw to the request

* fix types

* add fieldFormatServiceFactory to legacy

* Pass the complete request object to sec plugin

* Fix test

* fix test 2

* getUser takes a legacy request

* add unit test for new lib

* add getRawRequest to pass to saved objects method

* update test snapshot

* leave a TODO comment for type import

* variable rename for legacy id

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>

* update legacy to fix ts errors

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
Tim Sullivan 2020-01-21 11:04:02 -07:00 committed by GitHub
parent a8ac40b191
commit 1cb96c2136
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 224 additions and 76 deletions

View file

@ -86,7 +86,6 @@ export const executeJobFactory: ExecuteJobFactory<ESQueueWorkerExecuteFn<
const [formatsMap, uiSettings] = await Promise.all([
(async () => {
// @ts-ignore fieldFormatServiceFactory' does not exist on type 'ServerFacade TODO
const fieldFormats = await server.fieldFormatServiceFactory(uiConfig);
return fieldFormatMapFactory(indexPatternSavedObject, fieldFormats);
})(),

View file

@ -57,7 +57,7 @@ export async function generateCsvSearch(
jobParams: JobParamsDiscoverCsv
): Promise<CsvResultFromSearch> {
const { savedObjects, uiSettingsServiceFactory } = server;
const savedObjectsClient = savedObjects.getScopedSavedObjectsClient(req);
const savedObjectsClient = savedObjects.getScopedSavedObjectsClient(req.getRawRequest());
const { indexPatternSavedObjectId, timerange } = searchPanel;
const savedSearchObjectAttr = searchPanel.attributes as SavedSearchObjectAttributes;
const { indexPatternSavedObject } = await getDataSource(

View file

@ -6,6 +6,9 @@
import { resolve } from 'path';
import { i18n } from '@kbn/i18n';
import { Legacy } from 'kibana';
import { IUiSettingsClient } from 'src/core/server';
import { XPackMainPlugin } from '../xpack_main/server/xpack_main';
import { PLUGIN_ID, UI_SETTINGS_CUSTOM_PDF_LOGO } from './common/constants';
// @ts-ignore untyped module defintition
import { mirrorPluginStatus } from '../../server/lib/mirror_plugin_status';
@ -16,16 +19,35 @@ import {
getExportTypesRegistry,
runValidations,
} from './server/lib';
import { config as reportingConfig } from './config';
import { logConfiguration } from './log_configuration';
import { createBrowserDriverFactory } from './server/browsers';
import { registerReportingUsageCollector } from './server/usage';
import { ReportingConfigOptions, ReportingPluginSpecOptions, ServerFacade } from './types.d';
import { ReportingConfigOptions, ReportingPluginSpecOptions } from './types.d';
import { config as reportingConfig } from './config';
import { logConfiguration } from './log_configuration';
const kbToBase64Length = (kb: number) => {
return Math.floor((kb * 1024 * 8) / 6);
};
type LegacyPlugins = Legacy.Server['plugins'];
export interface ServerFacade {
config: Legacy.Server['config'];
info: Legacy.Server['info'];
log: Legacy.Server['log'];
plugins: {
elasticsearch: LegacyPlugins['elasticsearch'];
security: LegacyPlugins['security'];
xpack_main: XPackMainPlugin & {
status?: any;
};
};
route: Legacy.Server['route'];
savedObjects: Legacy.Server['savedObjects'];
uiSettingsServiceFactory: Legacy.Server['uiSettingsServiceFactory'];
fieldFormatServiceFactory: (uiConfig: IUiSettingsClient) => unknown;
}
export const reporting = (kibana: any) => {
return new kibana.Plugin({
id: PLUGIN_ID,
@ -42,7 +64,7 @@ export const reporting = (kibana: any) => {
embeddableActions: ['plugins/reporting/panel_actions/get_csv_panel_action'],
home: ['plugins/reporting/register_feature'],
managementSections: ['plugins/reporting/views/management'],
injectDefaultVars(server: ServerFacade, options?: ReportingConfigOptions) {
injectDefaultVars(server: Legacy.Server, options?: ReportingConfigOptions) {
const config = server.config();
return {
reportingPollConfig: options ? options.poll : {},
@ -70,9 +92,22 @@ export const reporting = (kibana: any) => {
},
},
// TODO: Decouple Hapi: Build a server facade object based on the server to
// pass through to the libs. Do not pass server directly
async init(server: ServerFacade) {
async init(server: Legacy.Server) {
const serverFacade: ServerFacade = {
config: server.config,
info: server.info,
route: server.route.bind(server),
plugins: {
elasticsearch: server.plugins.elasticsearch,
xpack_main: server.plugins.xpack_main,
security: server.plugins.security,
},
savedObjects: server.savedObjects,
uiSettingsServiceFactory: server.uiSettingsServiceFactory,
// @ts-ignore Property 'fieldFormatServiceFactory' does not exist on type 'Server'.
fieldFormatServiceFactory: server.fieldFormatServiceFactory,
log: server.log.bind(server),
};
const exportTypesRegistry = getExportTypesRegistry();
let isCollectorReady = false;
@ -80,18 +115,18 @@ export const reporting = (kibana: any) => {
const { usageCollection } = server.newPlatform.setup.plugins;
registerReportingUsageCollector(
usageCollection,
server,
serverFacade,
() => isCollectorReady,
exportTypesRegistry
);
const logger = LevelLogger.createForServer(server, [PLUGIN_ID]);
const browserDriverFactory = await createBrowserDriverFactory(server);
const logger = LevelLogger.createForServer(serverFacade, [PLUGIN_ID]);
const browserDriverFactory = await createBrowserDriverFactory(serverFacade);
logConfiguration(server, logger);
runValidations(server, logger, browserDriverFactory);
logConfiguration(serverFacade, logger);
runValidations(serverFacade, logger, browserDriverFactory);
const { xpack_main: xpackMainPlugin } = server.plugins;
const { xpack_main: xpackMainPlugin } = serverFacade.plugins;
mirrorPluginStatus(xpackMainPlugin, this);
const checkLicense = checkLicenseFactory(exportTypesRegistry);
(xpackMainPlugin as any).status.once('green', () => {
@ -104,7 +139,7 @@ export const reporting = (kibana: any) => {
isCollectorReady = true;
// Reporting routes
registerRoutes(server, exportTypesRegistry, browserDriverFactory, logger);
registerRoutes(serverFacade, exportTypesRegistry, browserDriverFactory, logger);
},
deprecations({ unused }: any) {

View file

@ -4,8 +4,14 @@
* you may not use this file except in compliance with the Elastic License.
*/
export function getUserFactory(server) {
return async request => {
import { Legacy } from 'kibana';
import { ServerFacade } from '../../types';
export function getUserFactory(server: ServerFacade) {
/*
* Legacy.Request because this is called from routing middleware
*/
return async (request: Legacy.Request) => {
if (!server.plugins.security) {
return null;
}
@ -13,7 +19,7 @@ export function getUserFactory(server) {
try {
return await server.plugins.security.getUser(request);
} catch (err) {
server.log(['reporting', 'getUser', 'debug'], err);
server.log(['reporting', 'getUser', 'error'], err);
return null;
}
};

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
type ServerLog = (tags: string[], msg: string) => void;
import { ServerFacade } from '../../types';
const trimStr = (toTrim: string) => {
return typeof toTrim === 'string' ? toTrim.trim() : toTrim;
@ -16,12 +16,12 @@ export class LevelLogger {
public warn: (msg: string, tags?: string[]) => void;
static createForServer(server: any, tags: string[]) {
const serverLog: ServerLog = (tgs: string[], msg: string) => server.log(tgs, msg);
static createForServer(server: ServerFacade, tags: string[]) {
const serverLog: ServerFacade['log'] = (tgs: string[], msg: string) => server.log(tgs, msg);
return new LevelLogger(serverLog, tags);
}
constructor(logger: ServerLog, tags: string[]) {
constructor(logger: ServerFacade['log'], tags: string[]) {
this._logger = logger;
this._tags = tags;

View file

@ -27,10 +27,6 @@ export function oncePerServer(fn: ServerFn) {
throw new TypeError('This function expects to be called with a single argument');
}
if (!server || typeof server.expose !== 'function') {
throw new TypeError('This function expects to be passed the server');
}
// @ts-ignore
return fn.call(this, server);
});

View file

@ -4,16 +4,18 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { Legacy } from 'kibana';
import boom from 'boom';
import Joi from 'joi';
import rison from 'rison-node';
import { API_BASE_URL } from '../../common/constants';
import { ServerFacade, RequestFacade, ReportingResponseToolkit } from '../../types';
import { ServerFacade, ReportingResponseToolkit } from '../../types';
import {
getRouteConfigFactoryReportingPre,
GetRouteConfigFactoryFn,
RouteConfigFactory,
} from './lib/route_config_factories';
import { makeRequestFacade } from './lib/make_request_facade';
import { HandlerErrorFunction, HandlerFunction } from './types';
const BASE_GENERATE = `${API_BASE_URL}/generate`;
@ -54,7 +56,8 @@ export function registerGenerateFromJobParams(
path: `${BASE_GENERATE}/{exportType}`,
method: 'POST',
options: getRouteConfig(),
handler: async (request: RequestFacade, h: ReportingResponseToolkit) => {
handler: async (legacyRequest: Legacy.Request, h: ReportingResponseToolkit) => {
const request = makeRequestFacade(legacyRequest);
let jobParamsRison: string | null;
if (request.payload) {
@ -80,7 +83,7 @@ export function registerGenerateFromJobParams(
if (!jobParams) {
throw new Error('missing jobParams!');
}
response = await handler(exportType, jobParams, request, h);
response = await handler(exportType, jobParams, legacyRequest, h);
} catch (err) {
throw boom.badRequest(`invalid rison: ${jobParamsRison}`);
}

View file

@ -4,11 +4,13 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { Legacy } from 'kibana';
import { get } from 'lodash';
import { API_BASE_GENERATE_V1, CSV_FROM_SAVEDOBJECT_JOB_TYPE } from '../../common/constants';
import { ServerFacade, RequestFacade, ReportingResponseToolkit } from '../../types';
import { ServerFacade, ReportingResponseToolkit } from '../../types';
import { HandlerErrorFunction, HandlerFunction, QueuedJobPayload } from './types';
import { getRouteOptionsCsv } from './lib/route_config_factories';
import { makeRequestFacade } from './lib/make_request_facade';
import { getJobParamsFromRequest } from '../../export_types/csv_from_savedobject/server/lib/get_job_params_from_request';
/*
@ -31,17 +33,18 @@ export function registerGenerateCsvFromSavedObject(
path: `${API_BASE_GENERATE_V1}/csv/saved-object/{savedObjectType}:{savedObjectId}`,
method: 'POST',
options: routeOptions,
handler: async (request: RequestFacade, h: ReportingResponseToolkit) => {
handler: async (legacyRequest: Legacy.Request, h: ReportingResponseToolkit) => {
const requestFacade = makeRequestFacade(legacyRequest);
/*
* 1. Build `jobParams` object: job data that execution will need to reference in various parts of the lifecycle
* 2. Pass the jobParams and other common params to `handleRoute`, a shared function to enqueue the job with the params
* 3. Ensure that details for a queued job were returned
*/
let result: QueuedJobPayload<any>;
try {
const jobParams = getJobParamsFromRequest(request, { isImmediate: false });
result = await handleRoute(CSV_FROM_SAVEDOBJECT_JOB_TYPE, jobParams, request, h);
const jobParams = getJobParamsFromRequest(requestFacade, { isImmediate: false });
result = await handleRoute(CSV_FROM_SAVEDOBJECT_JOB_TYPE, jobParams, legacyRequest, h); // pass the original request because the handler will make the request facade on its own
} catch (err) {
throw handleRouteError(CSV_FROM_SAVEDOBJECT_JOB_TYPE, err);
}

View file

@ -4,11 +4,11 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { Legacy } from 'kibana';
import { API_BASE_GENERATE_V1 } from '../../common/constants';
import { createJobFactory, executeJobFactory } from '../../export_types/csv_from_savedobject';
import {
ServerFacade,
RequestFacade,
ResponseFacade,
HeadlessChromiumDriverFactory,
ReportingResponseToolkit,
@ -16,8 +16,9 @@ import {
JobDocOutputExecuted,
} from '../../types';
import { JobDocPayloadPanelCsv } from '../../export_types/csv_from_savedobject/types';
import { getRouteOptionsCsv } from './lib/route_config_factories';
import { getJobParamsFromRequest } from '../../export_types/csv_from_savedobject/server/lib/get_job_params_from_request';
import { getRouteOptionsCsv } from './lib/route_config_factories';
import { makeRequestFacade } from './lib/make_request_facade';
/*
* This function registers API Endpoints for immediate Reporting jobs. The API inputs are:
@ -43,7 +44,8 @@ export function registerGenerateCsvFromSavedObjectImmediate(
path: `${API_BASE_GENERATE_V1}/immediate/csv/saved-object/{savedObjectType}:{savedObjectId}`,
method: 'POST',
options: routeOptions,
handler: async (request: RequestFacade, h: ReportingResponseToolkit) => {
handler: async (legacyRequest: Legacy.Request, h: ReportingResponseToolkit) => {
const request = makeRequestFacade(legacyRequest);
const logger = parentLogger.clone(['savedobject-csv']);
const jobParams = getJobParamsFromRequest(request, { isImmediate: true });

View file

@ -5,12 +5,12 @@
*/
import boom from 'boom';
import { Legacy } from 'kibana';
import { API_BASE_URL } from '../../common/constants';
import {
ServerFacade,
ExportTypesRegistry,
HeadlessChromiumDriverFactory,
RequestFacade,
ReportingResponseToolkit,
Logger,
} from '../../types';
@ -19,6 +19,7 @@ import { registerGenerateCsvFromSavedObject } from './generate_from_savedobject'
import { registerGenerateCsvFromSavedObjectImmediate } from './generate_from_savedobject_immediate';
import { registerLegacy } from './legacy';
import { createQueueFactory, enqueueJobFactory } from '../lib';
import { makeRequestFacade } from './lib/make_request_facade';
export function registerJobGenerationRoutes(
server: ServerFacade,
@ -40,9 +41,10 @@ export function registerJobGenerationRoutes(
async function handler(
exportTypeId: string,
jobParams: object,
request: RequestFacade,
legacyRequest: Legacy.Request,
h: ReportingResponseToolkit
) {
const request = makeRequestFacade(legacyRequest);
const user = request.pre.user;
const headers = request.headers;

View file

@ -4,16 +4,17 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { Legacy } from 'kibana';
import boom from 'boom';
import { API_BASE_URL } from '../../common/constants';
import {
ServerFacade,
ExportTypesRegistry,
Logger,
RequestFacade,
ReportingResponseToolkit,
JobDocOutput,
JobSource,
ListQuery,
} from '../../types';
// @ts-ignore
import { jobsQueryFactory } from '../lib/jobs_query';
@ -23,6 +24,7 @@ import {
getRouteConfigFactoryDownloadPre,
getRouteConfigFactoryManagementPre,
} from './lib/route_config_factories';
import { makeRequestFacade } from './lib/make_request_facade';
const MAIN_ENTRY = `${API_BASE_URL}/jobs`;
@ -40,8 +42,9 @@ export function registerJobInfoRoutes(
path: `${MAIN_ENTRY}/list`,
method: 'GET',
options: getRouteConfig(),
handler: (request: RequestFacade) => {
const { page: queryPage, size: querySize, ids: queryIds } = request.query;
handler: (legacyRequest: Legacy.Request) => {
const request = makeRequestFacade(legacyRequest);
const { page: queryPage, size: querySize, ids: queryIds } = request.query as ListQuery;
const page = parseInt(queryPage, 10) || 0;
const size = Math.min(100, parseInt(querySize, 10) || 10);
const jobIds = queryIds ? queryIds.split(',') : null;
@ -62,7 +65,8 @@ export function registerJobInfoRoutes(
path: `${MAIN_ENTRY}/count`,
method: 'GET',
options: getRouteConfig(),
handler: (request: RequestFacade) => {
handler: (legacyRequest: Legacy.Request) => {
const request = makeRequestFacade(legacyRequest);
const results = jobsQuery.count(request.pre.management.jobTypes, request.pre.user);
return results;
},
@ -73,7 +77,8 @@ export function registerJobInfoRoutes(
path: `${MAIN_ENTRY}/output/{docId}`,
method: 'GET',
options: getRouteConfig(),
handler: (request: RequestFacade) => {
handler: (legacyRequest: Legacy.Request) => {
const request = makeRequestFacade(legacyRequest);
const { docId } = request.params;
return jobsQuery.get(request.pre.user, docId, { includeContent: true }).then(
@ -98,7 +103,8 @@ export function registerJobInfoRoutes(
path: `${MAIN_ENTRY}/info/{docId}`,
method: 'GET',
options: getRouteConfig(),
handler: (request: RequestFacade) => {
handler: (legacyRequest: Legacy.Request) => {
const request = makeRequestFacade(legacyRequest);
const { docId } = request.params;
return jobsQuery
@ -130,7 +136,8 @@ export function registerJobInfoRoutes(
path: `${MAIN_ENTRY}/download/{docId}`,
method: 'GET',
options: getRouteConfigDownload(),
handler: async (request: RequestFacade, h: ReportingResponseToolkit) => {
handler: async (legacyRequest: Legacy.Request, h: ReportingResponseToolkit) => {
const request = makeRequestFacade(legacyRequest);
const { docId } = request.params;
let response = await jobResponseHandler(

View file

@ -4,9 +4,10 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { Legacy } from 'kibana';
import querystring from 'querystring';
import { API_BASE_URL } from '../../common/constants';
import { ServerFacade, RequestFacade, ReportingResponseToolkit } from '../../types';
import { ServerFacade, ReportingResponseToolkit } from '../../types';
import {
getRouteConfigFactoryReportingPre,
GetRouteConfigFactoryFn,
@ -31,7 +32,7 @@ export function registerLegacy(
path,
method: 'POST',
options: getStaticFeatureConfig(getRouteConfig, exportTypeId),
handler: async (request: RequestFacade, h: ReportingResponseToolkit) => {
handler: async (request: Legacy.Request, h: ReportingResponseToolkit) => {
const message = `The following URL is deprecated and will stop working in the next major version: ${request.url.path}`;
server.log(['warning', 'reporting', 'deprecation'], message);

View file

@ -0,0 +1,62 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { Legacy } from 'kibana';
import { makeRequestFacade } from './make_request_facade';
describe('makeRequestFacade', () => {
test('creates a default object', () => {
const legacyRequest = ({
getBasePath: () => 'basebase',
params: {
param1: 123,
},
payload: {
payload1: 123,
},
headers: {
user: 123,
},
} as unknown) as Legacy.Request;
expect(makeRequestFacade(legacyRequest)).toMatchInlineSnapshot(`
Object {
"getBasePath": [Function],
"getRawRequest": [Function],
"getSavedObjectsClient": undefined,
"headers": Object {
"user": 123,
},
"params": Object {
"param1": 123,
},
"payload": Object {
"payload1": 123,
},
"pre": undefined,
"query": undefined,
"route": undefined,
}
`);
});
test('getRawRequest', () => {
const legacyRequest = ({
getBasePath: () => 'basebase',
params: {
param1: 123,
},
payload: {
payload1: 123,
},
headers: {
user: 123,
},
} as unknown) as Legacy.Request;
expect(makeRequestFacade(legacyRequest).getRawRequest()).toBe(legacyRequest);
});
});

View file

@ -0,0 +1,32 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { RequestQuery } from 'hapi';
import { Legacy } from 'kibana';
import {
RequestFacade,
ReportingRequestPayload,
ReportingRequestPre,
ReportingRequestQuery,
} from '../../../types';
export function makeRequestFacade(request: Legacy.Request): RequestFacade {
// This condition is for unit tests
const getSavedObjectsClient = request.getSavedObjectsClient
? request.getSavedObjectsClient.bind(request)
: request.getSavedObjectsClient;
return {
getSavedObjectsClient,
headers: request.headers,
params: request.params,
payload: (request.payload as object) as ReportingRequestPayload,
query: ((request.query as RequestQuery) as object) as ReportingRequestQuery,
pre: (request.pre as Record<string, any>) as ReportingRequestPre,
getBasePath: request.getBasePath,
route: request.route,
getRawRequest: () => request,
};
}

View file

@ -4,12 +4,13 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { Legacy } from 'kibana';
import { RequestFacade, ReportingResponseToolkit, JobDocPayload } from '../../types';
export type HandlerFunction = (
exportType: string,
jobParams: object,
request: RequestFacade,
request: Legacy.Request,
h: ReportingResponseToolkit
) => any;

View file

@ -7,7 +7,6 @@
import { ResponseObject } from 'hapi';
import { EventEmitter } from 'events';
import { Legacy } from 'kibana';
import { XPackMainPlugin } from '../xpack_main/server/xpack_main';
import {
ElasticsearchPlugin,
CallCluster,
@ -16,6 +15,7 @@ import { CancellationToken } from './common/cancellation_token';
import { LevelLogger } from './server/lib/level_logger';
import { HeadlessChromiumDriverFactory } from './server/browsers/chromium/driver_factory';
import { BrowserType } from './server/browsers/types';
import { ServerFacade } from './index';
export type ReportingPlugin = object; // For Plugin contract
@ -53,7 +53,7 @@ export interface NetworkPolicy {
rules: NetworkPolicyRule[];
}
interface ListQuery {
export interface ListQuery {
page: string;
size: string;
ids?: string; // optional field forbids us from extending RequestQuery
@ -64,9 +64,6 @@ interface GenerateQuery {
interface GenerateExportTypePayload {
jobParams: string;
}
interface DownloadParams {
docId: string;
}
/*
* Legacy System
@ -74,26 +71,6 @@ interface DownloadParams {
export type ReportingPluginSpecOptions = Legacy.PluginSpecOptions;
export type ServerFacade = Legacy.Server & {
plugins: {
xpack_main?: XPackMainPlugin & {
status?: any;
};
};
};
interface ReportingRequest {
query: ListQuery & GenerateQuery;
params: DownloadParams;
payload: GenerateExportTypePayload;
pre: {
management: {
jobTypes: any;
};
user: any;
};
}
export type EnqueueJobFn = <JobParamsType>(
parentLogger: LevelLogger,
exportTypeId: string,
@ -103,7 +80,27 @@ export type EnqueueJobFn = <JobParamsType>(
request: RequestFacade
) => Promise<Job>;
export type RequestFacade = ReportingRequest & Legacy.Request;
export type ReportingRequestPayload = GenerateExportTypePayload | JobParamPostPayload;
export type ReportingRequestQuery = ListQuery | GenerateQuery;
export interface ReportingRequestPre {
management: {
jobTypes: any;
};
user: any; // TODO import AuthenticatedUser from security/server
}
export interface RequestFacade {
getBasePath: Legacy.Request['getBasePath'];
getSavedObjectsClient: Legacy.Request['getSavedObjectsClient'];
headers: Legacy.Request['headers'];
params: Legacy.Request['params'];
payload: JobParamPostPayload | GenerateExportTypePayload;
query: ReportingRequestQuery;
route: Legacy.Request['route'];
pre: ReportingRequestPre;
getRawRequest: () => Legacy.Request;
}
export type ResponseFacade = ResponseObject & {
isBoom: boolean;
@ -355,3 +352,5 @@ export interface InterceptedRequest {
frameId: string;
resourceType: string;
}
export { ServerFacade };