Automatically handle request/dependency correlation in Azure Functions (#1044)

* Automatically handle request/dependency correlation in Azure Functions

* Update

* Adding tests
This commit is contained in:
Hector Hernandez 2022-12-05 13:08:44 -08:00 коммит произвёл GitHub
Родитель 39213a322c
Коммит 9909cbd9c3
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
15 изменённых файлов: 312 добавлений и 145 удалений

1
.vscode/settings.json поставляемый
Просмотреть файл

@ -3,7 +3,6 @@
"files.exclude": {
"**/*.js": { "when": "$(basename).ts"},
"**/*.js.map": true,
"**/*.d.ts": true,
"out/": true
},
"typescript.tsdk": "./node_modules/typescript/lib",

Просмотреть файл

@ -0,0 +1,76 @@
import { Context, HttpRequest } from "../Library/Functions";
import Logging = require("../Library/Logging");
import TelemetryClient = require("../Library/TelemetryClient");
import { CorrelationContextManager } from "./CorrelationContextManager";
/** Node.js Azure Functions handle incoming HTTP requests before Application Insights SDK is available,
* this code generate incoming request telemetry and generate correlation context to be used
* by outgoing requests and other telemetry, we rely on hooks provided by Azure Functions
*/
export class AutoCollectAzureFunctions {
private _client: TelemetryClient;
private _functionsCoreModule: any;
private _preInvocationHook: any;
constructor(client: TelemetryClient) {
this._client = client;
try {
this._functionsCoreModule = require('@azure/functions-core');
}
catch (error) {
Logging.info("AutoCollectAzureFunctions failed to load, not running in Azure Functions");
}
}
public enable(isEnabled: boolean) {
if (this._functionsCoreModule) {
if (isEnabled) {
this._addPreInvocationHook();
} else {
this._removePreInvocationHook();
}
}
}
public dispose() {
this.enable(false);
this._functionsCoreModule = undefined;
}
private _addPreInvocationHook() {
// Only add hook once
if (!this._preInvocationHook) {
this._preInvocationHook = this._functionsCoreModule.registerHook('preInvocation', (context: any) => {
const originalCallback = context.functionCallback;
context.functionCallback = async (context: Context, req: HttpRequest) => {
const startTime = Date.now(); // Start trackRequest timer
// Start an AI Correlation Context using the provided Function context
const correlationContext = CorrelationContextManager.startOperation(context, req);
if (correlationContext) {
CorrelationContextManager.wrapCallback(async () => {
originalCallback(context, req);
this._client.trackRequest({
name: context?.req?.method + " " + context.req?.url,
resultCode: context?.res?.status,
success: true,
url: (req as HttpRequest)?.url,
time: new Date(startTime),
duration: Date.now() - startTime,
id: correlationContext.operation?.parentId,
});
this._client.flush();
}, correlationContext)();
}
};
});
}
}
private _removePreInvocationHook() {
if (this._preInvocationHook) {
this._preInvocationHook.dispose();
this._preInvocationHook = undefined;
}
}
}

Просмотреть файл

@ -1,6 +1,5 @@
import events = require("events");
import Logging = require("../Library/Logging");
import * as DiagChannel from "./diagnostic-channel/initialization";
import * as azureFunctionsTypes from "../Library/Functions";

Просмотреть файл

@ -11,6 +11,7 @@ import Tracestate = require("../Library/Tracestate");
import Traceparent = require("../Library/Traceparent");
import { HttpRequest } from "../Library/Functions";
/**
* Helper class to read data from the request/response objects and convert them into the telemetry contract
*/
@ -145,7 +146,7 @@ class HttpRequestParser extends RequestParser {
}
public getOperationName(tags: { [key: string]: string }) {
if(tags[HttpRequestParser.keys.operationName]){
if (tags[HttpRequestParser.keys.operationName]) {
return tags[HttpRequestParser.keys.operationName];
}
let pathName = "";
@ -202,7 +203,7 @@ class HttpRequestParser extends RequestParser {
}
catch (ex) {
// Ignore errors
}
}
var absoluteUrl = url.format({
protocol: protocol,
host: request.headers.host,

Просмотреть файл

@ -138,7 +138,7 @@ export interface IBaseConfig {
* @deprecated, please use enableWebInstrumentation instead
* Enable web snippet auto html injection, default to false, this config is NOT exposed in documentation after version 2.3.5
*/
enableAutoWebSnippetInjection?: boolean;
enableAutoWebSnippetInjection?: boolean;
/**
* @deprecated, Please use webInstrumentationConnectionString instead
* Application Insights resource connection string for web snippet, this config is NOT exposed in documentation after version 2.3.5
@ -149,10 +149,14 @@ export interface IBaseConfig {
* Enable web instrumentation and automatic monitoring, default to false
*/
enableWebInstrumentation: boolean;
/**
* Application Insights resource connection string for web instrumentation and automatic monitoring
* Note: if no VALID connection string is provided here, web instrumentation will use the connection string during initializing Nodejs SDK
/**
* Enable automatic incoming request tracking and correct correlation when using Azure Functions
*/
enableAutoCollectAzureFunctions: boolean;
/**
* Application Insights resource connection string for web instrumentation and automatic monitoring
* Note: if no VALID connection string is provided here, web instrumentation will use the connection string during initializing Nodejs SDK
*/
webInstrumentationConnectionString?: string;
/**
* Application Insights web Instrumentation config
@ -163,12 +167,12 @@ export interface IBaseConfig {
* see more Application Insights web Instrumentation config details at: https://github.com/microsoft/ApplicationInsights-JS#configuration
*/
webInstrumentationConfig?: IWebInstrumentationConfig[];
/**
* Application Insights web Instrumentation CDN url
* NOTE: this config can be changed from env variable: APPLICATIONINSIGHTS_WEB_INSTRUMENTATION_SOURCE or Json Config: webInstrumentationSrc
* If no resouce is provided here, default CDN endpoint: https://js.monitor.azure.com/scripts/b/ai will be used
* see more details at: https://github.com/microsoft/ApplicationInsights-JS
*/
/**
* Application Insights web Instrumentation CDN url
* NOTE: this config can be changed from env variable: APPLICATIONINSIGHTS_WEB_INSTRUMENTATION_SOURCE or Json Config: webInstrumentationSrc
* If no resouce is provided here, default CDN endpoint: https://js.monitor.azure.com/scripts/b/ai will be used
* see more details at: https://github.com/microsoft/ApplicationInsights-JS
*/
webInstrumentationSrc?: string;
}
@ -178,9 +182,9 @@ export interface IWebInstrumentationConfig {
* see more Application Insights web Instrumentation config details at: https://github.com/microsoft/ApplicationInsights-JS#configuration
*/
name: string;
/**
* value provided to replace the default config value above
*/
/**
* value provided to replace the default config value above
*/
value: string | boolean | number;
}

Просмотреть файл

@ -43,6 +43,7 @@ class Config implements IConfig {
public enableAutoCollectRequests: boolean;
public enableAutoCollectDependencies: boolean;
public enableAutoDependencyCorrelation: boolean;
public enableAutoCollectAzureFunctions: boolean;
public enableSendLiveMetrics: boolean;
public enableUseDiskRetryCaching: boolean;
public enableUseAsyncHooks: boolean;
@ -169,6 +170,7 @@ class Config implements IConfig {
this.distributedTracingMode = jsonConfig.distributedTracingMode;
this.enableAutoCollectConsole = jsonConfig.enableAutoCollectConsole;
this.enableAutoCollectDependencies = jsonConfig.enableAutoCollectDependencies;
this.enableAutoCollectAzureFunctions = jsonConfig.enableAutoCollectAzureFunctions;
this.enableAutoCollectExceptions = jsonConfig.enableAutoCollectExceptions;
this.enableAutoCollectExtendedMetrics = jsonConfig.enableAutoCollectExtendedMetrics;
this.enableAutoCollectExternalLoggers = jsonConfig.enableAutoCollectExternalLoggers;

Просмотреть файл

@ -4,7 +4,18 @@
* to your function from the Azure Functions runtime on function invocation.
*/
export interface Context {
traceContext: TraceContext
traceContext: TraceContext;
/**
* HTTP request object. Provided to your function when using HTTP Bindings.
*/
req?: HttpRequest;
/**
* HTTP response object. Provided to your function when using HTTP Bindings.
*/
res?: {
[key: string]: any;
};
}
/**

Просмотреть файл

@ -57,6 +57,7 @@ export class JsonConfig implements IJsonConfig {
public enableAutoCollectRequests: boolean;
public enableAutoCollectDependencies: boolean;
public enableAutoDependencyCorrelation: boolean;
public enableAutoCollectAzureFunctions: boolean;
public enableUseAsyncHooks: boolean;
public enableUseDiskRetryCaching: boolean;
public enableResendInterval: number;
@ -205,6 +206,7 @@ export class JsonConfig implements IJsonConfig {
this.enableAutoCollectRequests = jsonConfig.enableAutoCollectRequests;
this.enableAutoCollectDependencies = jsonConfig.enableAutoCollectDependencies;
this.enableAutoDependencyCorrelation = jsonConfig.enableAutoDependencyCorrelation;
this.enableAutoCollectAzureFunctions = jsonConfig.enableAutoCollectAzureFunctions;
this.enableUseAsyncHooks = jsonConfig.enableUseAsyncHooks;
this.enableUseDiskRetryCaching = jsonConfig.enableUseDiskRetryCaching;
this.enableResendInterval = jsonConfig.enableResendInterval;

Просмотреть файл

@ -0,0 +1,51 @@
import assert = require("assert");
import sinon = require("sinon");
import { TelemetryClient } from "../../applicationinsights";
import { AutoCollectAzureFunctions } from "../../AutoCollection/AzureFunctionsHook";
const testModule = {
registerHook(type: string, hook: any) {
}
};
describe("AutoCollection/AutoCollectAzureFunctions", () => {
it("constructor", () => {
let client = new TelemetryClient("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333");
let auto = new AutoCollectAzureFunctions(client);
assert.equal(auto["_functionsCoreModule"], undefined, "Module is not available so it should be undefined unless running in AzFn env");
});
it("enable", () => {
let client = new TelemetryClient("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333");
let auto = new AutoCollectAzureFunctions(client);
auto["_functionsCoreModule"] = testModule;
const addStub = sinon.stub(auto, "_addPreInvocationHook");
const removeStub = sinon.stub(auto, "_removePreInvocationHook");
auto.enable(true);
assert.ok(removeStub.notCalled);
assert.ok(addStub.calledOnce);
});
it("disable", () => {
let client = new TelemetryClient("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333");
let auto = new AutoCollectAzureFunctions(client);
auto["_functionsCoreModule"] = testModule;
const addStub = sinon.stub(auto, "_addPreInvocationHook");
const removeStub = sinon.stub(auto, "_removePreInvocationHook");
auto.enable(false);
assert.ok(removeStub.calledOnce);
assert.ok(addStub.notCalled);
});
it("_addPreInvocationHook", () => {
let client = new TelemetryClient("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333");
let auto = new AutoCollectAzureFunctions(client);
const registerHook = sinon.stub(testModule, "registerHook");
auto["_functionsCoreModule"] = testModule;
auto["_addPreInvocationHook"]();
assert.ok(registerHook.calledOnce);
});
});

Просмотреть файл

@ -247,9 +247,6 @@ if (CorrelationContextManager.isNodeVersionCompatible()) {
const request = {
method: "GET",
url: "/search",
connection: {
encrypted: false
},
headers: {
host: "bing.com",
traceparent: functionContext.traceparent,
@ -327,7 +324,7 @@ if (CorrelationContextManager.isNodeVersionCompatible()) {
it("should return null if the ContextManager is disabled (inside context)", (done) => {
CorrelationContextManager.enable();
CorrelationContextManager.runWithContext(testContext, ()=>{
CorrelationContextManager.runWithContext(testContext, () => {
CorrelationContextManager.disable();
assert.equal(CorrelationContextManager.getCurrentContext(), null);
done();
@ -336,7 +333,7 @@ if (CorrelationContextManager.isNodeVersionCompatible()) {
it("should return null if in a context", (done) => {
CorrelationContextManager.enable();
CorrelationContextManager.runWithContext(testContext, ()=>{
CorrelationContextManager.runWithContext(testContext, () => {
assert.equal(CorrelationContextManager.getCurrentContext(), null);
done();
});
@ -344,8 +341,8 @@ if (CorrelationContextManager.isNodeVersionCompatible()) {
it("should return null if called by an asynchronous callback in a context", (done) => {
CorrelationContextManager.enable();
CorrelationContextManager.runWithContext(testContext, ()=>{
process.nextTick(()=>{
CorrelationContextManager.runWithContext(testContext, () => {
process.nextTick(() => {
assert.equal(CorrelationContextManager.getCurrentContext(), null);
done();
});
@ -354,19 +351,19 @@ if (CorrelationContextManager.isNodeVersionCompatible()) {
it("should return null to asynchronous callbacks occuring in parallel", (done) => {
CorrelationContextManager.enable();
CorrelationContextManager.runWithContext(testContext, ()=>{
process.nextTick(()=>{
CorrelationContextManager.runWithContext(testContext, () => {
process.nextTick(() => {
assert.equal(CorrelationContextManager.getCurrentContext(), null);
});
});
CorrelationContextManager.runWithContext(testContext2, ()=>{
process.nextTick(()=>{
CorrelationContextManager.runWithContext(testContext2, () => {
process.nextTick(() => {
assert.equal(CorrelationContextManager.getCurrentContext(), null);
});
});
setTimeout(()=>done(), 10);
setTimeout(() => done(), 10);
});
});
@ -401,21 +398,21 @@ if (CorrelationContextManager.isNodeVersionCompatible()) {
it("should not return a function that restores a null context at call-time into the supplied function if enabled", (done) => {
CorrelationContextManager.enable();
var sharedFn = ()=> {
var sharedFn = () => {
assert.equal(CorrelationContextManager.getCurrentContext(), null);
};
CorrelationContextManager.runWithContext(testContext, ()=>{
CorrelationContextManager.runWithContext(testContext, () => {
sharedFn = CorrelationContextManager.wrapCallback(sharedFn);
});
CorrelationContextManager.runWithContext(testContext2, ()=>{
setTimeout(()=>{
CorrelationContextManager.runWithContext(testContext2, () => {
setTimeout(() => {
sharedFn();
}, 8);
});
setTimeout(()=>done(), 10);
setTimeout(() => done(), 10);
});
});
});

Просмотреть файл

@ -95,6 +95,7 @@ describe("Library/Config", () => {
assert.equal(config.enableAutoCollectRequests, false);
assert.equal(config.enableAutoCollectDependencies, false);
assert.equal(config.enableAutoDependencyCorrelation, false);
assert.equal(config.enableAutoCollectAzureFunctions, false);
assert.equal(config.enableUseAsyncHooks, false);
assert.equal(config.disableStatsbeat, false);
assert.equal(config.enableAutoCollectExtendedMetrics, false);

Просмотреть файл

@ -24,6 +24,7 @@
"enableAutoCollectRequests": false,
"enableAutoCollectDependencies": false,
"enableAutoDependencyCorrelation": false,
"enableAutoCollectAzureFunctions": false,
"enableUseAsyncHooks": false,
"disableStatsbeat": false,
"noHttpAgentKeepAlive": false,

Просмотреть файл

@ -87,6 +87,7 @@ describe("Json Config", () => {
assert.equal(config.enableAutoCollectRequests, false);
assert.equal(config.enableAutoCollectDependencies, false);
assert.equal(config.enableAutoDependencyCorrelation, false);
assert.equal(config.enableAutoCollectAzureFunctions, false);
assert.equal(config.enableUseAsyncHooks, false);
assert.equal(config.disableStatsbeat, false);
assert.equal(config.enableAutoCollectExtendedMetrics, false);

Просмотреть файл

@ -13,6 +13,7 @@ import QuickPulseClient = require("./Library/QuickPulseStateManager");
import { IncomingMessage } from "http";
import { SpanContext } from "@opentelemetry/api";
import { AutoCollectNativePerformance, IDisabledExtendedMetrics } from "./AutoCollection/NativePerformance";
import { AutoCollectAzureFunctions } from "./AutoCollection/AzureFunctionsHook";
// We export these imports so that SDK users may use these classes directly.
// They're exposed using "export import" so that types are passed along as expected
@ -20,7 +21,6 @@ export import TelemetryClient = require("./Library/NodeClient");
export import Contracts = require("./Declarations/Contracts");
export import azureFunctionsTypes = require("./Library/Functions");
export enum DistributedTracingModes {
/**
* Send Application Insights correlation headers
@ -51,6 +51,7 @@ let _isSendingLiveMetrics = defaultConfig.isSendingLiveMetrics(); // Off by defa
let _isNativePerformance = defaultConfig.isNativePerformance();
let _disabledExtendedMetrics: IDisabledExtendedMetrics;
let _isSnippetInjection = defaultConfig.isSnippetInjection(); // default to false
let _isAzureFunctions = defaultConfig.isAzureFunctions(); // default to true
function _getDefaultAutoCollectConfig() {
return {
@ -66,7 +67,8 @@ function _getDefaultAutoCollectConfig() {
isCorrelating: () => true,
isSendingLiveMetrics: () => false, // Off by default
isNativePerformance: () => true,
isSnippetInjection: () => false
isSnippetInjection: () => false,
isAzureFunctions: () => true
}
}
@ -83,6 +85,7 @@ let _webSnippet: WebSnippet;
let _nativePerformance: AutoCollectNativePerformance;
let _serverRequests: AutoCollectHttpRequests;
let _clientRequests: AutoCollectHttpDependencies;
let _azureFunctions: AutoCollectAzureFunctions;
let _isStarted = false;
@ -119,6 +122,7 @@ export function setup(setupString?: string) {
if (!_nativePerformance) {
_nativePerformance = new AutoCollectNativePerformance(defaultClient);
}
_azureFunctions = new AutoCollectAzureFunctions(defaultClient);
} else {
Logging.info("The default client is already setup");
}
@ -152,6 +156,7 @@ export function start() {
if (liveMetricsClient && _isSendingLiveMetrics) {
liveMetricsClient.enable(_isSendingLiveMetrics);
}
_azureFunctions.enable(_isAzureFunctions);
} else {
Logging.warn("Start cannot be called before setup");
}
@ -172,10 +177,11 @@ function _initializeConfig() {
_forceClsHooked = defaultClient.config.enableUseAsyncHooks !== undefined ? defaultClient.config.enableUseAsyncHooks : _forceClsHooked;
_isSnippetInjection = defaultClient.config.enableWebInstrumentation !== undefined ? defaultClient.config.enableWebInstrumentation : _isSnippetInjection;
_isSnippetInjection = defaultClient.config.enableAutoWebSnippetInjection === true ? true : _isSnippetInjection;
_isAzureFunctions = defaultClient.config.enableAutoCollectAzureFunctions !== undefined ? defaultClient.config.enableAutoCollectAzureFunctions : _isPerformance;
const extendedMetricsConfig = AutoCollectNativePerformance.parseEnabled(defaultClient.config.enableAutoCollectExtendedMetrics, defaultClient.config);
_isNativePerformance = extendedMetricsConfig.isEnabled;
_disabledExtendedMetrics = extendedMetricsConfig.disabledMetrics;
}
/**
@ -324,7 +330,7 @@ export class Configuration {
* @param WebSnippetConnectionString if provided, web snippet injection will use this ConnectionString. Default to use the connectionString in Node.js app initialization
* @returns {Configuration} this class
*/
public static enableAutoWebSnippetInjection(value: boolean, WebSnippetConnectionString?: string ) {
public static enableAutoWebSnippetInjection(value: boolean, WebSnippetConnectionString?: string) {
_isSnippetInjection = value;
_webSnippetConnectionString = WebSnippetConnectionString;
if (_isStarted) {
@ -339,7 +345,7 @@ export class Configuration {
* @param WebSnippetConnectionString if provided, web snippet injection will use this ConnectionString. Default to use the connectionString in Node.js app initialization
* @returns {Configuration} this class
*/
public static enableWebInstrumentation(value: boolean, WebSnippetConnectionString?: string ) {
public static enableWebInstrumentation(value: boolean, WebSnippetConnectionString?: string) {
_isSnippetInjection = value;
_webSnippetConnectionString = WebSnippetConnectionString;
if (_isStarted) {
@ -348,7 +354,7 @@ export class Configuration {
return Configuration;
}
/**
* Sets the state of request tracking (enabled by default)
* @param value if true requests will be sent to Application Insights
@ -425,6 +431,19 @@ export class Configuration {
return Configuration;
}
/**
* Enable automatic incoming request tracking and correct correlation when using Azure Functions
* @param value if true auto collection will be enabled
* @returns {Configuration} this class
*/
public static setAutoCollectAzureFunctions(value: boolean) {
_isAzureFunctions = value;
if (_isStarted) {
_azureFunctions.enable(value);
}
return Configuration;
}
/**
* Enables communication with Application Insights Live Metrics.
* @param enable if true, enables communication with the live metrics service
@ -490,4 +509,7 @@ export function dispose() {
_isSendingLiveMetrics = false;
liveMetricsClient = undefined;
}
if (_azureFunctions) {
_azureFunctions.dispose();
}
}

208
package-lock.json сгенерированный
Просмотреть файл

@ -457,14 +457,14 @@
"dev": true
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "5.43.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.43.0.tgz",
"integrity": "sha512-wNPzG+eDR6+hhW4yobEmpR36jrqqQv1vxBq5LJO3fBAktjkvekfr4BRl+3Fn1CM/A+s8/EiGUbOMDoYqWdbtXA==",
"version": "5.45.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.45.0.tgz",
"integrity": "sha512-CXXHNlf0oL+Yg021cxgOdMHNTXD17rHkq7iW6RFHoybdFgQBjU3yIXhhcPpGwr1CjZlo6ET8C6tzX5juQoXeGA==",
"dev": true,
"dependencies": {
"@typescript-eslint/scope-manager": "5.43.0",
"@typescript-eslint/type-utils": "5.43.0",
"@typescript-eslint/utils": "5.43.0",
"@typescript-eslint/scope-manager": "5.45.0",
"@typescript-eslint/type-utils": "5.45.0",
"@typescript-eslint/utils": "5.45.0",
"debug": "^4.3.4",
"ignore": "^5.2.0",
"natural-compare-lite": "^1.4.0",
@ -490,14 +490,14 @@
}
},
"node_modules/@typescript-eslint/parser": {
"version": "5.43.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.43.0.tgz",
"integrity": "sha512-2iHUK2Lh7PwNUlhFxxLI2haSDNyXvebBO9izhjhMoDC+S3XI9qt2DGFUsiJ89m2k7gGYch2aEpYqV5F/+nwZug==",
"version": "5.45.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.45.0.tgz",
"integrity": "sha512-brvs/WSM4fKUmF5Ot/gEve6qYiCMjm6w4HkHPfS6ZNmxTS0m0iNN4yOChImaCkqc1hRwFGqUyanMXuGal6oyyQ==",
"dev": true,
"dependencies": {
"@typescript-eslint/scope-manager": "5.43.0",
"@typescript-eslint/types": "5.43.0",
"@typescript-eslint/typescript-estree": "5.43.0",
"@typescript-eslint/scope-manager": "5.45.0",
"@typescript-eslint/types": "5.45.0",
"@typescript-eslint/typescript-estree": "5.45.0",
"debug": "^4.3.4"
},
"engines": {
@ -517,13 +517,13 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
"version": "5.43.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.43.0.tgz",
"integrity": "sha512-XNWnGaqAtTJsUiZaoiGIrdJYHsUOd3BZ3Qj5zKp9w6km6HsrjPk/TGZv0qMTWyWj0+1QOqpHQ2gZOLXaGA9Ekw==",
"version": "5.45.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.45.0.tgz",
"integrity": "sha512-noDMjr87Arp/PuVrtvN3dXiJstQR1+XlQ4R1EvzG+NMgXi8CuMCXpb8JqNtFHKceVSQ985BZhfRdowJzbv4yKw==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.43.0",
"@typescript-eslint/visitor-keys": "5.43.0"
"@typescript-eslint/types": "5.45.0",
"@typescript-eslint/visitor-keys": "5.45.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@ -534,13 +534,13 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
"version": "5.43.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.43.0.tgz",
"integrity": "sha512-K21f+KY2/VvYggLf5Pk4tgBOPs2otTaIHy2zjclo7UZGLyFH86VfUOm5iq+OtDtxq/Zwu2I3ujDBykVW4Xtmtg==",
"version": "5.45.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.45.0.tgz",
"integrity": "sha512-DY7BXVFSIGRGFZ574hTEyLPRiQIvI/9oGcN8t1A7f6zIs6ftbrU0nhyV26ZW//6f85avkwrLag424n+fkuoJ1Q==",
"dev": true,
"dependencies": {
"@typescript-eslint/typescript-estree": "5.43.0",
"@typescript-eslint/utils": "5.43.0",
"@typescript-eslint/typescript-estree": "5.45.0",
"@typescript-eslint/utils": "5.45.0",
"debug": "^4.3.4",
"tsutils": "^3.21.0"
},
@ -561,9 +561,9 @@
}
},
"node_modules/@typescript-eslint/types": {
"version": "5.43.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.43.0.tgz",
"integrity": "sha512-jpsbcD0x6AUvV7tyOlyvon0aUsQpF8W+7TpJntfCUWU1qaIKu2K34pMwQKSzQH8ORgUrGYY6pVIh1Pi8TNeteg==",
"version": "5.45.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.45.0.tgz",
"integrity": "sha512-QQij+u/vgskA66azc9dCmx+rev79PzX8uDHpsqSjEFtfF2gBUTRCpvYMh2gw2ghkJabNkPlSUCimsyBEQZd1DA==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@ -574,13 +574,13 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
"version": "5.43.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.43.0.tgz",
"integrity": "sha512-BZ1WVe+QQ+igWal2tDbNg1j2HWUkAa+CVqdU79L4HP9izQY6CNhXfkNwd1SS4+sSZAP/EthI1uiCSY/+H0pROg==",
"version": "5.45.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.45.0.tgz",
"integrity": "sha512-maRhLGSzqUpFcZgXxg1qc/+H0bT36lHK4APhp0AEUVrpSwXiRAomm/JGjSG+kNUio5kAa3uekCYu/47cnGn5EQ==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.43.0",
"@typescript-eslint/visitor-keys": "5.43.0",
"@typescript-eslint/types": "5.45.0",
"@typescript-eslint/visitor-keys": "5.45.0",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
@ -601,16 +601,16 @@
}
},
"node_modules/@typescript-eslint/utils": {
"version": "5.43.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.43.0.tgz",
"integrity": "sha512-8nVpA6yX0sCjf7v/NDfeaOlyaIIqL7OaIGOWSPFqUKK59Gnumd3Wa+2l8oAaYO2lk0sO+SbWFWRSvhu8gLGv4A==",
"version": "5.45.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.45.0.tgz",
"integrity": "sha512-OUg2JvsVI1oIee/SwiejTot2OxwU8a7UfTFMOdlhD2y+Hl6memUSL4s98bpUTo8EpVEr0lmwlU7JSu/p2QpSvA==",
"dev": true,
"dependencies": {
"@types/json-schema": "^7.0.9",
"@types/semver": "^7.3.12",
"@typescript-eslint/scope-manager": "5.43.0",
"@typescript-eslint/types": "5.43.0",
"@typescript-eslint/typescript-estree": "5.43.0",
"@typescript-eslint/scope-manager": "5.45.0",
"@typescript-eslint/types": "5.45.0",
"@typescript-eslint/typescript-estree": "5.45.0",
"eslint-scope": "^5.1.1",
"eslint-utils": "^3.0.0",
"semver": "^7.3.7"
@ -627,12 +627,12 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
"version": "5.43.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.43.0.tgz",
"integrity": "sha512-icl1jNH/d18OVHLfcwdL3bWUKsBeIiKYTGxMJCoGe7xFht+E4QgzOqoWYrU8XSLJWhVw8nTacbm03v23J/hFTg==",
"version": "5.45.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.45.0.tgz",
"integrity": "sha512-jc6Eccbn2RtQPr1s7th6jJWQHBHI6GBVQkCHoJFQ5UreaKm59Vxw+ynQUPPY2u2Amquc+7tmEoC2G52ApsGNNg==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.43.0",
"@typescript-eslint/types": "5.45.0",
"eslint-visitor-keys": "^3.3.0"
},
"engines": {
@ -731,9 +731,9 @@
}
},
"node_modules/anymatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
"dev": true,
"dependencies": {
"normalize-path": "^3.0.0",
@ -2207,9 +2207,9 @@
}
},
"node_modules/globals": {
"version": "13.17.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz",
"integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==",
"version": "13.18.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz",
"integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==",
"dev": true,
"dependencies": {
"type-fest": "^0.20.2"
@ -2372,9 +2372,9 @@
}
},
"node_modules/ignore": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
"integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==",
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz",
"integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==",
"dev": true,
"engines": {
"node": ">= 4"
@ -3010,9 +3010,9 @@
}
},
"node_modules/minipass": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.4.tgz",
"integrity": "sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw==",
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
"integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
"dev": true,
"dependencies": {
"yallist": "^4.0.0"
@ -4912,14 +4912,14 @@
"dev": true
},
"@typescript-eslint/eslint-plugin": {
"version": "5.43.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.43.0.tgz",
"integrity": "sha512-wNPzG+eDR6+hhW4yobEmpR36jrqqQv1vxBq5LJO3fBAktjkvekfr4BRl+3Fn1CM/A+s8/EiGUbOMDoYqWdbtXA==",
"version": "5.45.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.45.0.tgz",
"integrity": "sha512-CXXHNlf0oL+Yg021cxgOdMHNTXD17rHkq7iW6RFHoybdFgQBjU3yIXhhcPpGwr1CjZlo6ET8C6tzX5juQoXeGA==",
"dev": true,
"requires": {
"@typescript-eslint/scope-manager": "5.43.0",
"@typescript-eslint/type-utils": "5.43.0",
"@typescript-eslint/utils": "5.43.0",
"@typescript-eslint/scope-manager": "5.45.0",
"@typescript-eslint/type-utils": "5.45.0",
"@typescript-eslint/utils": "5.45.0",
"debug": "^4.3.4",
"ignore": "^5.2.0",
"natural-compare-lite": "^1.4.0",
@ -4929,53 +4929,53 @@
}
},
"@typescript-eslint/parser": {
"version": "5.43.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.43.0.tgz",
"integrity": "sha512-2iHUK2Lh7PwNUlhFxxLI2haSDNyXvebBO9izhjhMoDC+S3XI9qt2DGFUsiJ89m2k7gGYch2aEpYqV5F/+nwZug==",
"version": "5.45.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.45.0.tgz",
"integrity": "sha512-brvs/WSM4fKUmF5Ot/gEve6qYiCMjm6w4HkHPfS6ZNmxTS0m0iNN4yOChImaCkqc1hRwFGqUyanMXuGal6oyyQ==",
"dev": true,
"requires": {
"@typescript-eslint/scope-manager": "5.43.0",
"@typescript-eslint/types": "5.43.0",
"@typescript-eslint/typescript-estree": "5.43.0",
"@typescript-eslint/scope-manager": "5.45.0",
"@typescript-eslint/types": "5.45.0",
"@typescript-eslint/typescript-estree": "5.45.0",
"debug": "^4.3.4"
}
},
"@typescript-eslint/scope-manager": {
"version": "5.43.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.43.0.tgz",
"integrity": "sha512-XNWnGaqAtTJsUiZaoiGIrdJYHsUOd3BZ3Qj5zKp9w6km6HsrjPk/TGZv0qMTWyWj0+1QOqpHQ2gZOLXaGA9Ekw==",
"version": "5.45.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.45.0.tgz",
"integrity": "sha512-noDMjr87Arp/PuVrtvN3dXiJstQR1+XlQ4R1EvzG+NMgXi8CuMCXpb8JqNtFHKceVSQ985BZhfRdowJzbv4yKw==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.43.0",
"@typescript-eslint/visitor-keys": "5.43.0"
"@typescript-eslint/types": "5.45.0",
"@typescript-eslint/visitor-keys": "5.45.0"
}
},
"@typescript-eslint/type-utils": {
"version": "5.43.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.43.0.tgz",
"integrity": "sha512-K21f+KY2/VvYggLf5Pk4tgBOPs2otTaIHy2zjclo7UZGLyFH86VfUOm5iq+OtDtxq/Zwu2I3ujDBykVW4Xtmtg==",
"version": "5.45.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.45.0.tgz",
"integrity": "sha512-DY7BXVFSIGRGFZ574hTEyLPRiQIvI/9oGcN8t1A7f6zIs6ftbrU0nhyV26ZW//6f85avkwrLag424n+fkuoJ1Q==",
"dev": true,
"requires": {
"@typescript-eslint/typescript-estree": "5.43.0",
"@typescript-eslint/utils": "5.43.0",
"@typescript-eslint/typescript-estree": "5.45.0",
"@typescript-eslint/utils": "5.45.0",
"debug": "^4.3.4",
"tsutils": "^3.21.0"
}
},
"@typescript-eslint/types": {
"version": "5.43.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.43.0.tgz",
"integrity": "sha512-jpsbcD0x6AUvV7tyOlyvon0aUsQpF8W+7TpJntfCUWU1qaIKu2K34pMwQKSzQH8ORgUrGYY6pVIh1Pi8TNeteg==",
"version": "5.45.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.45.0.tgz",
"integrity": "sha512-QQij+u/vgskA66azc9dCmx+rev79PzX8uDHpsqSjEFtfF2gBUTRCpvYMh2gw2ghkJabNkPlSUCimsyBEQZd1DA==",
"dev": true
},
"@typescript-eslint/typescript-estree": {
"version": "5.43.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.43.0.tgz",
"integrity": "sha512-BZ1WVe+QQ+igWal2tDbNg1j2HWUkAa+CVqdU79L4HP9izQY6CNhXfkNwd1SS4+sSZAP/EthI1uiCSY/+H0pROg==",
"version": "5.45.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.45.0.tgz",
"integrity": "sha512-maRhLGSzqUpFcZgXxg1qc/+H0bT36lHK4APhp0AEUVrpSwXiRAomm/JGjSG+kNUio5kAa3uekCYu/47cnGn5EQ==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.43.0",
"@typescript-eslint/visitor-keys": "5.43.0",
"@typescript-eslint/types": "5.45.0",
"@typescript-eslint/visitor-keys": "5.45.0",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
@ -4984,28 +4984,28 @@
}
},
"@typescript-eslint/utils": {
"version": "5.43.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.43.0.tgz",
"integrity": "sha512-8nVpA6yX0sCjf7v/NDfeaOlyaIIqL7OaIGOWSPFqUKK59Gnumd3Wa+2l8oAaYO2lk0sO+SbWFWRSvhu8gLGv4A==",
"version": "5.45.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.45.0.tgz",
"integrity": "sha512-OUg2JvsVI1oIee/SwiejTot2OxwU8a7UfTFMOdlhD2y+Hl6memUSL4s98bpUTo8EpVEr0lmwlU7JSu/p2QpSvA==",
"dev": true,
"requires": {
"@types/json-schema": "^7.0.9",
"@types/semver": "^7.3.12",
"@typescript-eslint/scope-manager": "5.43.0",
"@typescript-eslint/types": "5.43.0",
"@typescript-eslint/typescript-estree": "5.43.0",
"@typescript-eslint/scope-manager": "5.45.0",
"@typescript-eslint/types": "5.45.0",
"@typescript-eslint/typescript-estree": "5.45.0",
"eslint-scope": "^5.1.1",
"eslint-utils": "^3.0.0",
"semver": "^7.3.7"
}
},
"@typescript-eslint/visitor-keys": {
"version": "5.43.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.43.0.tgz",
"integrity": "sha512-icl1jNH/d18OVHLfcwdL3bWUKsBeIiKYTGxMJCoGe7xFht+E4QgzOqoWYrU8XSLJWhVw8nTacbm03v23J/hFTg==",
"version": "5.45.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.45.0.tgz",
"integrity": "sha512-jc6Eccbn2RtQPr1s7th6jJWQHBHI6GBVQkCHoJFQ5UreaKm59Vxw+ynQUPPY2u2Amquc+7tmEoC2G52ApsGNNg==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.43.0",
"@typescript-eslint/types": "5.45.0",
"eslint-visitor-keys": "^3.3.0"
}
},
@ -5070,9 +5070,9 @@
}
},
"anymatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
"dev": true,
"requires": {
"normalize-path": "^3.0.0",
@ -6196,9 +6196,9 @@
}
},
"globals": {
"version": "13.17.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz",
"integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==",
"version": "13.18.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz",
"integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==",
"dev": true,
"requires": {
"type-fest": "^0.20.2"
@ -6310,9 +6310,9 @@
}
},
"ignore": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
"integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==",
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz",
"integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==",
"dev": true
},
"import-fresh": {
@ -6767,9 +6767,9 @@
"dev": true
},
"minipass": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.4.tgz",
"integrity": "sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw==",
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
"integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
"dev": true,
"requires": {
"yallist": "^4.0.0"